@syncmatters/connector-sdk 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/04-meta-objects-fields.md +1 -0
- package/docs/05-query.md +35 -0
- package/docs/09-testing.md +7 -0
- package/lib/connector.d.ts +2 -0
- package/package.json +3 -3
|
@@ -70,6 +70,7 @@ same as "no list support". See [the query capability bar](#the-query-capability-
|
|
|
70
70
|
| `type` | `"string"` · `"number"` · `"boolean"` · `"object"` · `"array"` · `"file"` · `"any"` |
|
|
71
71
|
| `isKey: true` | this field is the row's unique id — its value becomes `row.meta.key`. Assign this (or `isUserKey`) to exactly one `queryFields`, plus one `upsertFields`, plus one `deleteFields` |
|
|
72
72
|
| `isUserKey: true` | user-supplied natural key that can both add and update — see below |
|
|
73
|
+
| `isAlternateKey: true` | scalar `queryFields` field holding a unique value the connector can resolve rows by (`queryOptions.idsFilterField`) — a COMMITMENT to honor that filter, see [05-query.md](./05-query.md) |
|
|
73
74
|
| `canMatch: true` | field may be referenced by match rules (set on id/name/email-like fields; apply recursively into nested object fields where meaningful) |
|
|
74
75
|
| `optionValues` | picklist options `[{ id, name?, group? }]` |
|
|
75
76
|
| `canUpdateOptions: true` | new picklist options may be added via `upsertFieldOptions()` |
|
package/docs/05-query.md
CHANGED
|
@@ -84,6 +84,7 @@ Rules that follow from the lifecycle:
|
|
|
84
84
|
| `queryOptions.fields` | field paths the caller needs (used to fetch less when the API supports it) |
|
|
85
85
|
| `queryOptions.file` | LEGACY - ignore; modern connectors include file content when `fields` contains a file-typed field's path (13) |
|
|
86
86
|
| `queryOptions.idsFilter` | `string[]` of row keys — return exactly those rows; row with the key not found? omit it, do not report an error |
|
|
87
|
+
| `queryOptions.idsFilterField` | path of the alternate key field the `idsFilter` values refer to (absent = internal row id) — below |
|
|
87
88
|
| `queryOptions.checkpointFilter` | `{ value?: string }` — rows changed since your last checkpoint (undefined value = first differential run: return everything) |
|
|
88
89
|
| `queryOptions.matchFilter` | find rows matching people/records — below |
|
|
89
90
|
| `queryOptions.relatedFilter` | rows related to another object's rows — below |
|
|
@@ -106,6 +107,40 @@ null/empty ids so you never emit `id = 'undefined'`.
|
|
|
106
107
|
|
|
107
108
|
When the row does not exist on the target system (e.g. deleted), do not report an error (e.g. API returns 404), simply do not return the row.
|
|
108
109
|
|
|
110
|
+
### idsFilterField (alternate key lookup)
|
|
111
|
+
|
|
112
|
+
When `queryOptions.idsFilterField` accompanies `idsFilter`, the ids are NOT row keys — they are
|
|
113
|
+
values of the alternate key field at that path (a field you flagged `isAlternateKey: true` in
|
|
114
|
+
`queryFields`). The platform only sends this option for flagged fields, so flagging a field is
|
|
115
|
+
your commitment to honor it. The contract:
|
|
116
|
+
|
|
117
|
+
- return only rows that matched one of the requested values (unmatched values: omit, do not
|
|
118
|
+
error — same as `idsFilter`)
|
|
119
|
+
- the platform correlates each returned row back to a requested value. Two ways to support that:
|
|
120
|
+
1. **annotate the row**: set `row.relationship = { srcRowId: <requested value> }` — the same
|
|
121
|
+
annotation the related/match flows use. REQUIRED when a row can match via anything other
|
|
122
|
+
than the field's stored value verbatim (aliases such as HubSpot's `hs_additional_emails`,
|
|
123
|
+
case-insensitive resolution). A row that matched multiple requested values is returned once
|
|
124
|
+
per value, each annotated.
|
|
125
|
+
2. **rely on the field value**: when matching is exact, it is enough to include the alternate
|
|
126
|
+
key field in each returned row's `data` (even when the caller narrowed the response with
|
|
127
|
+
`fields`) — the platform reads the value from the row.
|
|
128
|
+
- `row.meta.key` remains the REAL internal row id, never the alternate value
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const path = options.queryOptions?.idsFilterField;
|
|
132
|
+
if (path) {
|
|
133
|
+
const propName = path[path.length - 1]?.path; // e.g. properties.my_unique_prop -> my_unique_prop
|
|
134
|
+
// resolve via your alternate-id capable endpoint (e.g. HubSpot batch-read with idProperty),
|
|
135
|
+
// then annotate each row with the requested value it matched
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
You MUST throw `SDK.ErrorCode.InvalidFilterParameter` if the path does not resolve to a field
|
|
140
|
+
you can retrieve by (unknown, or no longer unique — possible when stored metadata is newer than
|
|
141
|
+
the deployed connector). The platform does NOT pre-validate this option — your throw is the only
|
|
142
|
+
thing standing between a bad path and silently empty results.
|
|
143
|
+
|
|
109
144
|
### checkpointFilter (differential sync)
|
|
110
145
|
|
|
111
146
|
The contract is a round-trip: you emit `checkpoint` (any string — ISO date is conventional) on
|
package/docs/09-testing.md
CHANGED
|
@@ -248,6 +248,13 @@ The harness always executes platform-side. What each entry point actually runs:
|
|
|
248
248
|
| `sm test --only query` | Every object's plain list query only — no ids/checkpoint/match/related, no writes. |
|
|
249
249
|
| Web UI (connector → test results → run) | Same engine, feature selection via the run dialog. |
|
|
250
250
|
|
|
251
|
+
Each feature test records the inputs it ran with and what the connector returned — pass or
|
|
252
|
+
fail — onto the saved result as diagnostic `details` (the ids an `idsFilter` ran with and the
|
|
253
|
+
rows returned; expected vs actual rows per match rule / relationship; upserted rows and their
|
|
254
|
+
query-back). Review them on the web UI's test results screen instead of re-running with extra
|
|
255
|
+
logging. Payloads over the size budget are dropped and flagged `truncated`; details hold real
|
|
256
|
+
connection data and are scrubbed ~48 hours after the run (statuses are kept).
|
|
257
|
+
|
|
251
258
|
Do not mistake a passing `--only connection` or `--only query` for suite coverage — only the
|
|
252
259
|
full run exercises the prepare hooks and write features. `sm test` needs a developer token
|
|
253
260
|
with the `scripts:read`, `connections:read` and `scripts:execute` scopes; a 403 from the CLI
|
package/lib/connector.d.ts
CHANGED
|
@@ -110,6 +110,8 @@ export interface QueryOptions {
|
|
|
110
110
|
randomFilter?: boolean;
|
|
111
111
|
/** filter for rows by row id (key) */
|
|
112
112
|
idsFilter?: Array<string>;
|
|
113
|
+
/** path of the alternate key field that the idsFilter values refer to, if applicable */
|
|
114
|
+
idsFilterField?: Array<JsonValuePathPart>;
|
|
113
115
|
/** filter for rows related to other rows */
|
|
114
116
|
relatedFilter?: QueryRelatedFilter;
|
|
115
117
|
/** filter for rows that meet a specific matching rule */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncmatters/connector-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "TypeScript type definitions for the SyncMatters connector SDK (types only - connectors execute on the SyncMatters platform)",
|
|
5
5
|
"types": "./index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"author": "SyncMatters",
|
|
14
14
|
"homepage": "https://syncmatters.com",
|
|
15
|
-
"typesContentHash": "
|
|
15
|
+
"typesContentHash": "bc9f5a1637b46d39ef65a04b24338624b3c51f60df16d6646113067bdec0aa86",
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@types/node": "*",
|
|
18
|
-
"@syncmatters/script-api": "^1.0.
|
|
18
|
+
"@syncmatters/script-api": "^1.0.9"
|
|
19
19
|
}
|
|
20
20
|
}
|