Skip to main content

Connector reference

This page defines the connector contract: manifest fields, configuration schema, SDK lifecycle, document fields, state, and local validation. For a guided introduction, start with Build a connector.

Manifest

manifest.json declares the connector to Gety. Gety reads the manifest when you install the connector, so manifest changes require reinstalling the connector.

FieldRequiredDescription
idYesStable connector ID. Must match ^[a-z0-9][a-z0-9_-]*$: start with a lowercase letter or digit, then use lowercase letters, digits, _, or -. Do not use uppercase letters, dots, or a leading _ or -.
nameYesDisplay name shown in Gety's connector list and install dialog.
versionYesSemVer version of the connector.
min_gety_app_versionYesMinimum Gety app version, as SemVer.
entryYesRelative path to the built entry inside the connector root, usually dist/main.js.
capabilitiesYesNon-empty array of host integration points. A polling data source declares ["data-source"], currently the only supported value. Unknown values are rejected.
descriptionNoShort description shown in the install dialog.
authorNoAuthor object, for example { "name": "Gety" }.
iconNoRelative path to a PNG or SVG in the connector root. Gety shows it in the connector list and install dialog.
scheduleNoUpdate strategy. If omitted, Gety uses its default interval behavior. See Schedule.
configNoConfiguration form schema. See Config fields.
doc_linkNoDeclares how documents open. See Doc link.
schema.extra_gety_indexed_fieldsNoMakes extra metadata keys searchable. See Indexed fields.

entry and icon must stay inside the connector root. Unknown manifest fields are rejected.

Schedule

schedule controls how Gety polls the source.

ShapeBehavior
{ "strategy": "manual" }Gety doesn't poll automatically. Users can still run Update now.
{ "strategy": "interval", "interval_seconds": 3600 }Poll every interval_seconds. Values below 60 are clamped to 60.
{ "strategy": "daily", "time": "09:00" }Poll once per day at time, using local time. HH:mm and HH:mm:ss are supported.

Config fields

config.fields is an ordered array. Each field renders an input in Gety's install and configuration UI, and becomes a typed property on this.config.

PropertyRequiredDescription
idYesField key. It becomes a property on the generated ManifestConfig type.
titleYesLabel shown in the UI.
typeYesInput type. One of text, password, number, checkbox, dropdown, or directory.
descriptionNoHelper text shown under the field.
placeholderNoPlaceholder text for text-like inputs.
requiredNoWhether the field must be filled in. Defaults to false.
default_valueNoPre-filled value when the field is empty. The value must match the field type.
optionsFor dropdownOrdered array of { "value": "...", "label": "..." }.

Field types:

TypeUse for
textSingle-line text, such as a URL or username.
passwordAPI keys and tokens. Values are masked in the UI.
numberNumeric values.
checkboxBoolean on/off options.
dropdownA fixed choice from ordered options.
directoryA local folder path chosen with a picker.
Handling API keys

Use type: "password" for API keys and tokens. For local validation, the sample runner maps field IDs to environment variables. It uppercases the field path and tries the GETY_CONFIG_ prefix first, then the bare name:

  • api_key reads GETY_CONFIG_API_KEY first, then API_KEY.
  • auth.api_key reads GETY_CONFIG_AUTH_API_KEY first, then AUTH_API_KEY.

doc_link declares once, for the whole connector, how documents open.

{ "kind": "url", "field": "url" }
PropertyDescription
kindurl opens a browser link; file opens a local filesystem path.
fieldThe doc field or metadata key to read the link value from.

Resolution rules:

  • field is either a core doc field (id, parent_id, title, content, or doc_type) or a direct metadata key.
  • "field": "url" reads metadata.url. Use the direct key, not a dot path like "metadata.url".
  • Missing, empty, or non-string values mean the document has no link.
  • url links open in the browser. Gety doesn't fetch their content.
  • file links must be stable local paths, not temporary cache files.

Open, display, and copy actions come from doc_link, not from content_format. content_format only controls how Gety renders the text preview.

Indexed fields

Gety always indexes title and content. schema.extra_gety_indexed_fields makes additional metadata keys searchable. Each entry needs both field and strategy:

{
"schema": {
"extra_gety_indexed_fields": [
{ "field": "status", "strategy": "fast_text" }
]
}
}
StrategyBest for
fast_textShort values that need exact, substring, fuzzy, or pinyin matching, such as names, tags, folders, or statuses.
full_textLonger text that benefits from SQLite FTS5 keyword search, BM25 ranking, and tokenization.
semanticMeaningful prose that should match by vector similarity. Requires the embedding model.

SDK lifecycle

A connector is a default-exported class extending Connector<Config, State>.

import { Connector, type PollResult, del, upsert } from '@gety-ai/connector-sdk';
import type { ManifestConfig } from './gen/manifest.d.ts';

type State = {
cursor?: string;
};

export default class MyConnector extends Connector<ManifestConfig, State> {
async onLoad(): Promise<void> {
// Optional. Runs once in a fresh runtime process before poll().
}

async *poll(): AsyncGenerator<PollResult, void, unknown> {
let cursor = this.lastState?.cursor;

for await (const page of fetchPages(this.config.api_key, cursor, this.signal)) {
yield {
updates: page.items.map((item) => upsert(toDoc(item))),
state: { cursor: page.next_cursor },
};
cursor = page.next_cursor;
}
}
}
MemberDescription
this.configTyped configuration injected from Gety's install or configuration form, shaped by config.fields.
this.lastStateHost-persisted state from the last successful poll progress, or undefined on the first run.
this.signalAbortSignal that aborts when the user disables or restarts the connector. Pass it to fetches.
onLoad()Optional, may be async. Runs once in a fresh runtime process before poll().
poll()Required async generator. Yields PollResult batches.

Lifecycle facts:

  • Each scheduled poll starts a fresh connector runtime process.
  • Class fields don't persist across polls. Use state or an explicit on-disk cache for durable data.

WireDoc fields

Build documents with upsert(doc) and remove them with del(id).

upsert({
id: issue.id,
title: issue.title,
content: markdown,
content_format: 'markdown',
doc_type: 'linear:issue',
doc_updated_at: issue.updatedAt,
original_file_size: markdown.length,
metadata: {
url: issue.url,
created_at: issue.createdAt,
status: issue.status,
},
});
FieldRequiredDescription
idYesStable document ID, unchanged across polls.
titleYesDocument title. Always indexed.
contentNoText Gety indexes and previews.
content_formatNoplaintext (default) or markdown. markdown enables Markdown rendering in the text preview. It controls rendering, not source type or how the document opens. Use markdown only for real Markdown.
doc_typeNoUsually <namespace>:<type>, such as linear:issue, for external records. Use file:<ext> only when the document is genuinely file-like and should use file-extension presentation. Don't label an external record as a file just to get Markdown preview; set the real record type and use content_format for rendering.
doc_updated_atNoRFC 3339 source update time with Z or an offset. Use the source document's update time, not the indexing time.
parent_idNoID of a parent document for hierarchical relationships.
hide_from_searchNoHides the document from search while preserving it for parent or relationship use.
original_file_sizeNoSize in bytes, used for display.
metadataNoArbitrary key/value map. metadata.url is the conventional link target. If present, metadata.created_at must be an RFC 3339 string or the poll fails. Extra keys become searchable through schema.extra_gety_indexed_fields.

Only id and title are required; other unset fields are dropped from the wire. Gety limits document content to about 10 MB. Emit pages or chunks instead of huge individual documents or metadata blobs.

Poll and state

poll() yields PollResult batches. Each batch carries updates and an optional state checkpoint.

yield {
updates: [
upsert(docA),
upsert(docB),
del(staleId),
],
state: { cursor: page.next_cursor },
};

Rules:

  • Checkpoint after updates. The state you yield with a batch should describe progress reached after that batch's updates. It becomes lastState in the next poll.
  • Don't advance state early. Never commit state for documents you haven't yielded yet. If a poll fails after a yielded batch, Gety retries from the last committed state.
  • Emit deletes from real signals. Call del(id) only when the source proves the document disappeared or left scope.
  • Yield at retry-safe boundaries. For remote APIs, yield per page or durable cursor. For local enumerations, yield per retry-safe file or chunk.
  • Handle timestamp cursors carefully. Keep enough state to avoid missing updates that share the same timestamp.
  • Page or stream the source. Gety can split large output across messages safely, but your connector should still page or stream source data instead of holding everything in memory.

Validation

Run the sample verification task before installing:

deno task verify

verify runs fix, check, test, and build:

  • fix runs formatting and lint fixes.
  • check generates the config type and type-checks the project.
  • test runs tests.
  • build writes the bundled entry loaded by Gety.

You can also run the steps individually:

deno task fix
deno task check
deno task test
deno task build

Exercise the real lifecycle with the local runner:

cp .env.example .env
deno task runner -- --reset-state
deno task runner -- --polls 2

The runner persists incremental state at dev/.runner/state.json. --reset-state ignores it for a clean first poll. Each run writes a snapshot under dev/runs/<timestamp>/:

dev/runs/<timestamp>/
summary.json
state.before.json
state.after.json
updates.json
deletes.json
docs/
0001-<doc_type>__<doc_id>.md
0001-<doc_type>__<doc_id>.json

The content file is .md for content_format: "markdown" and .txt otherwise. It is omitted when the document has no content. The .json sidecar is always written. Inspect the output for stable IDs, expected content, correct metadata.url, RFC 3339 timestamps, deletes, and before/after state behavior.

After editing src/index.ts, run deno task build, then click Restart in Gety to load the new dist/main.js.