# DemoClient

`DemoClient` is the sample client class used by the predefined custom import script package. It demonstrates the contract that YouTrack calls while importing data from an external source.

## Import Client Lifecycle

Procedure: How YouTrack uses an import client:

1. Loads the import script package and calls `exports.Client(context)` to create a client instance.

2. Passes connection parameters, secrets, and settings through the `context` object.

3. Calls `prepareToImport()` when the client defines initialization logic.

4. Requests projects, users, groups, issues, articles, attachments, and other entities through the methods implemented by the client.

5. Calls update methods during continuous import to fetch changes since the previous import.

For a guided walkthrough of the built-in demo package, see [Demo Import
Script](demo-import-script.html). For the end-to-end import flow, see [How Import Scripts
Work](how-import-scripts-work.html).

## Required and Optional Methods

| Method | Status | Purpose |
| --- | --- | --- |
| `exports.Client(context)` | Required | Returns the client instance that YouTrack calls during import. |
| `constructor(context)` | Required for class-based clients | Reads import parameters, prepares credentials, and creates reusable connections. |
| `prepareToImport()` | Optional | Runs startup checks or caches source metadata before YouTrack starts reading entities. |
| `getServerInfo()` | Recommended | Returns source version and time information for diagnostics and import logs. |
| `getProjects()` | Required for project import | Lists projects that can be imported from the source system. |
| `getProject(projectInfo)` | Required for project import | Returns full project data for a selected source project. |
| `getIssues(projectInfo, after, top)` | Required for issue import | Returns one page of issues for a project. |
| `getUsers(group, skip, top)` | Required when users or groups are imported | Returns users for a group or page of users requested by YouTrack. |
| `getArticles(projectInfo, after, top)` | Optional | Returns one page of articles for a project. |
| `getAttachmentContent(project, document, attachment)` | Optional | Returns binary content and metadata for attachments referenced by imported entities. |
| `getLinkTypes()` | Optional | Returns link type definitions used by imported issues. |
| `getTimestampFormats()` | Optional | Lists date and date-time formats that the importer can parse from source data. |
| `getUserTimeZoneId()` | Optional | Defines the time zone used when source timestamps do not include one. |

## Pagination Contract

> **Note: Use Stable Cursors**
> Methods that accept `after`, `top`, or `updatedAfter` must return a deterministic page from the source. Treat `top` as the maximum number of entities to return. Treat `after` as the cursor or offset supplied by YouTrack. Treat `updatedAfter` as the lower bound for continuous import updates.

| Parameter | Used by | Expected behavior |
| --- | --- | --- |
| `after` | `getIssues`, `getArticles` | Start reading after the item or cursor from the previous page. |
| `top` | Page-based read methods | Return no more than this number of entities. |
| `updatedAfter` | Continuous import update methods | Return only entities changed after this timestamp. |

## Continuous Import Methods

Continuous import uses update methods to fetch changes after the initial import. Implement these methods when the source can expose reliable update timestamps or change streams.

| Method | Use it to |
| --- | --- |
| `getIssueUpdates(projectInfo, after, updatedAfter, top)` | Return changed issues for a project since the previous synchronization. |
| `getArticleUpdates(projectInfo, after, updatedAfter, top)` | Return changed articles for a project since the previous synchronization. |

> **Warning: Do Not Mix Full and Incremental Reads**
> Update methods should not return the entire source data set unless the source has no reliable way to identify changes. Returning full data on every continuous import can make synchronization slow and can hide pagination defects.

## HTTP Connection Setup

A client that reads from a web API usually creates a reusable HTTP connection in the constructor. For details about the HTTP module, see [http](v1-http.html).

```JAVASCRIPT
const http = require('@jetbrains/youtrack-scripting-api/http');

class DemoClient {
  constructor(context) {
    const params = context.parameters;
    this.url = params.loadValue('url');
    this.sslKeyName = params.loadValue('sslKeyName');
    this.token = params.loadValue('password');

    this.connection = new http.Connection(this.url, this.sslKeyName)
      .addHeader('Authorization', `Bearer ${this.token}`);
  }
}
```

## Minimal Client Skeleton

Start with the smallest client that can list projects and issues, then add optional methods as the source data requires. For instructions on editing and running custom scripts, see [Working with Import Scripts](working-with-import-scripts.html).

```JAVASCRIPT
const http = require('@jetbrains/youtrack-scripting-api/http');

class DemoClient {
  constructor(context) {
    const params = context.parameters;
    this.url = params.loadValue('url');
    this.token = params.loadValue('password');
    this.connection = new http.Connection(this.url)
      .addHeader('Authorization', `Bearer ${this.token}`);
  }

  prepareToImport() {
    // Validate credentials or warm up source metadata here.
  }

  getServerInfo() {
    return {
      version: 'external-source',
      time: new Date().toISOString()
    };
  }

  getProjects() {
    return [];
  }

  getProject(projectInfo) {
    return projectInfo;
  }

  getIssues(projectInfo, after, top) {
    return [];
  }

  getUsers(group, skip, top) {
    return [];
  }

  getIssueUpdates(projectInfo, after, updatedAfter, top) {
    return [];
  }
}

exports.Client = (context) => new DemoClient(context);
```

## See also

[Demo Import Script](demo-import-script.html) [How Import Scripts Work](how-import-scripts-work.html) [http](v1-http.html) [Working with Import Scripts](working-with-import-scripts.html)

