@proveanything/smartlinks 2.0.58 → 2.0.60
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/dist/api/integrations.d.ts +15 -1
- package/dist/api/integrations.js +18 -0
- package/dist/docs/API_SUMMARY.md +50 -2
- package/dist/docs/connectors.md +7 -2
- package/dist/docs/integrations.md +8 -0
- package/dist/openapi.yaml +72 -4
- package/dist/types/appManifest.d.ts +14 -0
- package/dist/types/integrations.d.ts +29 -1
- package/docs/API_SUMMARY.md +50 -2
- package/docs/connectors.md +7 -2
- package/docs/integrations.md +8 -0
- package/openapi.yaml +72 -4
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IntegrationFlow, CreateFlowInput, UpdateFlowInput, ListFlowsQuery, FlowList, RunFlowInput, RunFlowResult, RunFlowSummary, RunFlowEnqueued, RecordTypesResponse, FlowRun, ListRunsQuery, RunList, ListRunItemsQuery, RunItemList, LoggingWindow, SetLoggingInput, InstalledConnector, SaveConnectorInstallationInput, ConnectorConsoleStep } from "../types/integrations.js";
|
|
1
|
+
import type { IntegrationFlow, CreateFlowInput, UpdateFlowInput, ListFlowsQuery, FlowList, RunFlowInput, RunFlowResult, RunFlowSummary, RunFlowEnqueued, RecordTypesResponse, FlowRun, ListRunsQuery, RunList, ListRunItemsQuery, RunItemList, LoggingWindow, SetLoggingInput, InstalledConnector, SaveConnectorInstallationInput, ConnectorConsoleStep, FailedRecordList } from "../types/integrations.js";
|
|
2
2
|
export declare namespace integrations {
|
|
3
3
|
/** List flows in a collection. GET /integrations/flows */
|
|
4
4
|
function listFlows(collectionId: string, query?: ListFlowsQuery): Promise<FlowList>;
|
|
@@ -53,6 +53,20 @@ export declare namespace integrations {
|
|
|
53
53
|
function setLogging(collectionId: string, connectionId: string, input?: SetLoggingInput): Promise<{
|
|
54
54
|
window: LoggingWindow;
|
|
55
55
|
}>;
|
|
56
|
+
/** A flow's failed / dead records. GET /integrations/flows/:id/failed */
|
|
57
|
+
function listFailed(collectionId: string, flowId: string, query?: {
|
|
58
|
+
status?: 'failed' | 'dead';
|
|
59
|
+
limit?: number;
|
|
60
|
+
cursor?: string;
|
|
61
|
+
}): Promise<FailedRecordList>;
|
|
62
|
+
/** Retry failed / dead records now (all of them when `ids` is omitted). POST /integrations/flows/:id/failed/retry */
|
|
63
|
+
function retryFailed(collectionId: string, flowId: string, ids?: string[]): Promise<{
|
|
64
|
+
retrying: number;
|
|
65
|
+
}>;
|
|
66
|
+
/** Resume a flow that paused itself (circuit open): held records go out now. POST /integrations/flows/:id/resume */
|
|
67
|
+
function resumeFlow(collectionId: string, flowId: string): Promise<{
|
|
68
|
+
resumed: boolean;
|
|
69
|
+
}>;
|
|
56
70
|
/** Cancel enhanced logging now. DELETE /integrations/logging/:connectionId */
|
|
57
71
|
function cancelLogging(collectionId: string, connectionId: string): Promise<{
|
|
58
72
|
canceled: boolean;
|
package/dist/api/integrations.js
CHANGED
|
@@ -130,6 +130,24 @@ export var integrations;
|
|
|
130
130
|
return post(`/admin/collection/${enc(collectionId)}/integrations/logging/${enc(connectionId)}`, input);
|
|
131
131
|
}
|
|
132
132
|
integrations.setLogging = setLogging;
|
|
133
|
+
// --- Failed records + resume -----------------------------------------------
|
|
134
|
+
// A failed record is retried on its own with backoff; a permanent failure, or one out of attempts, is
|
|
135
|
+
// 'dead' and waits for someone to retry it (or for the record to change).
|
|
136
|
+
/** A flow's failed / dead records. GET /integrations/flows/:id/failed */
|
|
137
|
+
async function listFailed(collectionId, flowId, query = {}) {
|
|
138
|
+
return request(`${base(collectionId)}/${enc(flowId)}/failed${encodeQuery(query)}`);
|
|
139
|
+
}
|
|
140
|
+
integrations.listFailed = listFailed;
|
|
141
|
+
/** Retry failed / dead records now (all of them when `ids` is omitted). POST /integrations/flows/:id/failed/retry */
|
|
142
|
+
async function retryFailed(collectionId, flowId, ids) {
|
|
143
|
+
return post(`${base(collectionId)}/${enc(flowId)}/failed/retry`, ids ? { ids } : {});
|
|
144
|
+
}
|
|
145
|
+
integrations.retryFailed = retryFailed;
|
|
146
|
+
/** Resume a flow that paused itself (circuit open): held records go out now. POST /integrations/flows/:id/resume */
|
|
147
|
+
async function resumeFlow(collectionId, flowId) {
|
|
148
|
+
return post(`${base(collectionId)}/${enc(flowId)}/resume`, {});
|
|
149
|
+
}
|
|
150
|
+
integrations.resumeFlow = resumeFlow;
|
|
133
151
|
/** Cancel enhanced logging now. DELETE /integrations/logging/:connectionId */
|
|
134
152
|
async function cancelLogging(collectionId, connectionId) {
|
|
135
153
|
return del(`/admin/collection/${enc(collectionId)}/integrations/logging/${enc(connectionId)}`);
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.60 | Generated: 2026-10-13T16:25:55.817Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -2915,6 +2915,8 @@ interface AppConnectorDeclaration {
|
|
|
2915
2915
|
}
|
|
2916
2916
|
panels?: ConnectorPanel[]
|
|
2917
2917
|
aiGuide?: string
|
|
2918
|
+
recordId?: string
|
|
2919
|
+
limits?: { requestsPerSecond?: number }
|
|
2918
2920
|
}
|
|
2919
2921
|
```
|
|
2920
2922
|
|
|
@@ -3008,7 +3010,15 @@ interface ConnectorSendInput {
|
|
|
3008
3010
|
**ConnectorSendResult** (interface)
|
|
3009
3011
|
```typescript
|
|
3010
3012
|
interface ConnectorSendResult {
|
|
3011
|
-
results: Array<{
|
|
3013
|
+
results: Array<{
|
|
3014
|
+
index: number
|
|
3015
|
+
ok: boolean
|
|
3016
|
+
status?: number
|
|
3017
|
+
error?: string
|
|
3018
|
+
externalId?: string
|
|
3019
|
+
retryable?: boolean
|
|
3020
|
+
retryAfterSeconds?: number
|
|
3021
|
+
}>
|
|
3012
3022
|
}
|
|
3013
3023
|
```
|
|
3014
3024
|
|
|
@@ -7108,6 +7118,32 @@ interface IntegrationFlow {
|
|
|
7108
7118
|
lastPollAt?: string | null
|
|
7109
7119
|
lastCursor?: string | null
|
|
7110
7120
|
totalSynced?: number | null
|
|
7121
|
+
circuitOpenedAt?: string | null
|
|
7122
|
+
circuitProbeAt?: string | null
|
|
7123
|
+
circuitReason?: string | null
|
|
7124
|
+
}
|
|
7125
|
+
```
|
|
7126
|
+
|
|
7127
|
+
**FailedRecord** (interface)
|
|
7128
|
+
```typescript
|
|
7129
|
+
interface FailedRecord {
|
|
7130
|
+
id: string
|
|
7131
|
+
entityId?: string | null
|
|
7132
|
+
externalId?: string
|
|
7133
|
+
status: 'failed' | 'dead'
|
|
7134
|
+
attempts: number
|
|
7135
|
+
nextAttemptAt?: string | null
|
|
7136
|
+
lastError?: string | null
|
|
7137
|
+
updatedAt?: string
|
|
7138
|
+
}
|
|
7139
|
+
```
|
|
7140
|
+
|
|
7141
|
+
**FailedRecordList** (interface)
|
|
7142
|
+
```typescript
|
|
7143
|
+
interface FailedRecordList {
|
|
7144
|
+
direction: FlowDirection
|
|
7145
|
+
items: FailedRecord[]
|
|
7146
|
+
nextCursor: string | null
|
|
7111
7147
|
}
|
|
7112
7148
|
```
|
|
7113
7149
|
|
|
@@ -7161,6 +7197,7 @@ interface RunFlowSummary {
|
|
|
7161
7197
|
created?: number
|
|
7162
7198
|
updated?: number
|
|
7163
7199
|
skipped?: number
|
|
7200
|
+
held?: number
|
|
7164
7201
|
status: RunStatus
|
|
7165
7202
|
runId?: string
|
|
7166
7203
|
}
|
|
@@ -11704,6 +11741,17 @@ Is enhanced logging active for a connection? GET /integrations/logging/:connecti
|
|
|
11704
11741
|
**setLogging**(collectionId: string, connectionId: string, input: SetLoggingInput = {}) → `Promise<`
|
|
11705
11742
|
Enable enhanced logging. POST /integrations/logging/:connectionId (omit ttlMinutes = until cancelled)
|
|
11706
11743
|
|
|
11744
|
+
**listFailed**(collectionId: string,
|
|
11745
|
+
flowId: string,
|
|
11746
|
+
query: { status?: 'failed' | 'dead'; limit?: number; cursor?: string } = {}) → `Promise<FailedRecordList>`
|
|
11747
|
+
A flow's failed / dead records. GET /integrations/flows/:id/failed
|
|
11748
|
+
|
|
11749
|
+
**retryFailed**(collectionId: string, flowId: string, ids?: string[]) → `Promise<`
|
|
11750
|
+
Retry failed / dead records now (all of them when `ids` is omitted). POST /integrations/flows/:id/failed/retry
|
|
11751
|
+
|
|
11752
|
+
**resumeFlow**(collectionId: string, flowId: string) → `Promise<`
|
|
11753
|
+
Resume a flow that paused itself (circuit open): held records go out now. POST /integrations/flows/:id/resume
|
|
11754
|
+
|
|
11707
11755
|
**cancelLogging**(collectionId: string, connectionId: string) → `Promise<`
|
|
11708
11756
|
Cancel enhanced logging now. DELETE /integrations/logging/:connectionId
|
|
11709
11757
|
|
package/dist/docs/connectors.md
CHANGED
|
@@ -90,6 +90,8 @@ Types: `AppConnectorDeclaration` and friends in `@proveanything/smartlinks` (`sr
|
|
|
90
90
|
| `functions` | Which of this app's server functions implement each step (below). Fill in only what applies. |
|
|
91
91
|
| `panels[]` | Provider-specific screens the console mounts (an API explorer, a status page). |
|
|
92
92
|
| `aiGuide` | A guide the mapping assistant reads: the provider's quirks, required fields, good defaults. |
|
|
93
|
+
| `recordId` | Path of the provider's own id in a fetched record (e.g. `gtin`). Inbound records are landed and matched by it, so a re-import updates the same product instead of creating another. Default `id`; a flow can override it (`config.upsert.externalIdPath`). |
|
|
94
|
+
| `limits` | `{ requestsPerSecond }` toward the provider, enforced across every SmartLinks worker. |
|
|
93
95
|
|
|
94
96
|
---
|
|
95
97
|
|
|
@@ -112,9 +114,12 @@ declare the provider's hosts (`network:<host>`) and the secrets it reads (`secre
|
|
|
112
114
|
| `send` | Every outbound run | `ConnectorSendInput` `{ installation, payloads }` | `ConnectorSendResult` `{ results: [{ index, ok, status, error, externalId }] }` |
|
|
113
115
|
|
|
114
116
|
**How a run flows:**
|
|
115
|
-
- **Inbound:** `fetch` (paged) → `shape` → core maps the documents
|
|
117
|
+
- **Inbound:** `fetch` (paged; every record is landed as received) → `shape` → core maps the documents
|
|
118
|
+
with the flow's mapping → upsert, matched by `recordId`. Unchanged records aren't processed again; a
|
|
119
|
+
changed flow configuration replays the landed records without fetching.
|
|
116
120
|
- **Outbound:** gather the SmartLinks records → core maps them to the provider's fields → `serialize`
|
|
117
|
-
→ `send` (or a generic transport).
|
|
121
|
+
→ `send` (or a generic transport). A record identical to its last successful delivery isn't sent again.
|
|
122
|
+
- Large runs are processed in short slices that resume after an interruption; there's no record cap.
|
|
118
123
|
|
|
119
124
|
**What happens when a step is left out:**
|
|
120
125
|
- **No `shape`:** core maps the provider records as they come.
|
|
@@ -19,6 +19,14 @@ Provider-specific logic (a provider's payload format, its API, its connect form)
|
|
|
19
19
|
**connector app**, not in the engine: see **[Connectors](connectors.md)**. A flow uses one with
|
|
20
20
|
`config.connector = { appId }`.
|
|
21
21
|
|
|
22
|
+
**Reliability.** A record that fails is retried on its own with exponential backoff (honouring the
|
|
23
|
+
destination's `Retry-After`); a permanent failure (most 4xx) or one out of attempts is **dead** and
|
|
24
|
+
waits in `integrations.listFailed` for `integrations.retryFailed`. A destination that keeps failing
|
|
25
|
+
**pauses the flow automatically** (`flow.circuitOpenedAt`): edits are held, small probes check for
|
|
26
|
+
recovery, and it resumes on its own (or with `integrations.resumeFlow`). Every product and record
|
|
27
|
+
change is recorded durably before it's dispatched, so an edit can't be missed; scheduled sweeps are
|
|
28
|
+
the reconciliation net.
|
|
29
|
+
|
|
22
30
|
Credentials are **never** stored on the flow. The connection holds an opaque
|
|
23
31
|
`credentialRef` into the **sealed-secret store** (`secrets` namespace); the value is sealed
|
|
24
32
|
at rest and resolved server-side only, at execution.
|
package/dist/openapi.yaml
CHANGED
|
@@ -19780,6 +19780,11 @@ components:
|
|
|
19780
19780
|
$ref: "#/components/schemas/ConnectorPanel"
|
|
19781
19781
|
aiGuide:
|
|
19782
19782
|
type: string
|
|
19783
|
+
recordId:
|
|
19784
|
+
type: string
|
|
19785
|
+
limits:
|
|
19786
|
+
type: object
|
|
19787
|
+
additionalProperties: true
|
|
19783
19788
|
required:
|
|
19784
19789
|
- provider
|
|
19785
19790
|
- directions
|
|
@@ -19933,12 +19938,26 @@ components:
|
|
|
19933
19938
|
type: object
|
|
19934
19939
|
properties:
|
|
19935
19940
|
results:
|
|
19936
|
-
type:
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19941
|
+
type: object
|
|
19942
|
+
additionalProperties: true
|
|
19943
|
+
index:
|
|
19944
|
+
type: number
|
|
19945
|
+
ok:
|
|
19946
|
+
type: boolean
|
|
19947
|
+
status:
|
|
19948
|
+
type: number
|
|
19949
|
+
error:
|
|
19950
|
+
type: string
|
|
19951
|
+
externalId:
|
|
19952
|
+
type: string
|
|
19953
|
+
retryable:
|
|
19954
|
+
type: boolean
|
|
19955
|
+
retryAfterSeconds:
|
|
19956
|
+
type: number
|
|
19940
19957
|
required:
|
|
19941
19958
|
- results
|
|
19959
|
+
- index
|
|
19960
|
+
- ok
|
|
19942
19961
|
ConnectorFetchInput:
|
|
19943
19962
|
type: object
|
|
19944
19963
|
properties:
|
|
@@ -26278,6 +26297,12 @@ components:
|
|
|
26278
26297
|
type: string
|
|
26279
26298
|
totalSynced:
|
|
26280
26299
|
type: number
|
|
26300
|
+
circuitOpenedAt:
|
|
26301
|
+
type: string
|
|
26302
|
+
circuitProbeAt:
|
|
26303
|
+
type: string
|
|
26304
|
+
circuitReason:
|
|
26305
|
+
type: string
|
|
26281
26306
|
required:
|
|
26282
26307
|
- id
|
|
26283
26308
|
- orgId
|
|
@@ -26294,6 +26319,47 @@ components:
|
|
|
26294
26319
|
- createdBy
|
|
26295
26320
|
- createdAt
|
|
26296
26321
|
- updatedAt
|
|
26322
|
+
FailedRecord:
|
|
26323
|
+
type: object
|
|
26324
|
+
properties:
|
|
26325
|
+
id:
|
|
26326
|
+
type: string
|
|
26327
|
+
entityId:
|
|
26328
|
+
type: string
|
|
26329
|
+
externalId:
|
|
26330
|
+
type: string
|
|
26331
|
+
status:
|
|
26332
|
+
type: string
|
|
26333
|
+
enum:
|
|
26334
|
+
- failed
|
|
26335
|
+
- dead
|
|
26336
|
+
attempts:
|
|
26337
|
+
type: number
|
|
26338
|
+
nextAttemptAt:
|
|
26339
|
+
type: string
|
|
26340
|
+
lastError:
|
|
26341
|
+
type: string
|
|
26342
|
+
updatedAt:
|
|
26343
|
+
type: string
|
|
26344
|
+
required:
|
|
26345
|
+
- id
|
|
26346
|
+
- status
|
|
26347
|
+
- attempts
|
|
26348
|
+
FailedRecordList:
|
|
26349
|
+
type: object
|
|
26350
|
+
properties:
|
|
26351
|
+
direction:
|
|
26352
|
+
$ref: "#/components/schemas/FlowDirection"
|
|
26353
|
+
items:
|
|
26354
|
+
type: array
|
|
26355
|
+
items:
|
|
26356
|
+
$ref: "#/components/schemas/FailedRecord"
|
|
26357
|
+
nextCursor:
|
|
26358
|
+
type: string
|
|
26359
|
+
required:
|
|
26360
|
+
- direction
|
|
26361
|
+
- items
|
|
26362
|
+
- nextCursor
|
|
26297
26363
|
CreateFlowInput:
|
|
26298
26364
|
type: object
|
|
26299
26365
|
properties:
|
|
@@ -26365,6 +26431,8 @@ components:
|
|
|
26365
26431
|
type: number
|
|
26366
26432
|
skipped:
|
|
26367
26433
|
type: number
|
|
26434
|
+
held:
|
|
26435
|
+
type: number
|
|
26368
26436
|
status:
|
|
26369
26437
|
$ref: "#/components/schemas/RunStatus"
|
|
26370
26438
|
runId:
|
|
@@ -926,6 +926,16 @@ export interface AppConnectorDeclaration {
|
|
|
926
926
|
panels?: ConnectorPanel[];
|
|
927
927
|
/** Path (under the app's public files) of a guide the AI mapping assistant reads. */
|
|
928
928
|
aiGuide?: string;
|
|
929
|
+
/**
|
|
930
|
+
* Path of the provider's own id in a fetched record (e.g. 'gtin', 'item.id'). Inbound records are
|
|
931
|
+
* landed and matched to SmartLinks entities by it, so a re-import updates rather than duplicates.
|
|
932
|
+
* Default 'id'; a flow can override it with `config.upsert.externalIdPath`.
|
|
933
|
+
*/
|
|
934
|
+
recordId?: string;
|
|
935
|
+
/** Requests per second toward the provider, shared by every SmartLinks worker. */
|
|
936
|
+
limits?: {
|
|
937
|
+
requestsPerSecond?: number;
|
|
938
|
+
};
|
|
929
939
|
}
|
|
930
940
|
/**
|
|
931
941
|
* What every connector function receives about the installation it serves. The engine assembles it
|
|
@@ -1008,6 +1018,10 @@ export interface ConnectorSendResult {
|
|
|
1008
1018
|
status?: number;
|
|
1009
1019
|
error?: string;
|
|
1010
1020
|
externalId?: string;
|
|
1021
|
+
/** Worth retrying? Default: by status (408/425/429/5xx/none yes; other 4xx no). */
|
|
1022
|
+
retryable?: boolean;
|
|
1023
|
+
/** The provider asked to wait this long before retrying (e.g. its Retry-After). */
|
|
1024
|
+
retryAfterSeconds?: number;
|
|
1011
1025
|
}>;
|
|
1012
1026
|
}
|
|
1013
1027
|
export interface ConnectorFetchInput {
|
|
@@ -71,6 +71,32 @@ export interface IntegrationFlow {
|
|
|
71
71
|
lastPollAt?: string | null;
|
|
72
72
|
lastCursor?: string | null;
|
|
73
73
|
totalSynced?: number | null;
|
|
74
|
+
/**
|
|
75
|
+
* Circuit breaker: set while the flow has paused itself because its destination / provider keeps
|
|
76
|
+
* failing. Nothing is sent or fetched (edits are held as retries) until a probe gets through —
|
|
77
|
+
* `circuitProbeAt` is the next one — or someone resumes it (`integrations.resumeFlow`).
|
|
78
|
+
*/
|
|
79
|
+
circuitOpenedAt?: string | null;
|
|
80
|
+
circuitProbeAt?: string | null;
|
|
81
|
+
circuitReason?: string | null;
|
|
82
|
+
}
|
|
83
|
+
/** A record that failed: retried on its own with backoff ('failed'), or given up on ('dead'). */
|
|
84
|
+
export interface FailedRecord {
|
|
85
|
+
/** Outbound: the SmartLinks entity id. Inbound: the landed record's id (pass it to retryFailed). */
|
|
86
|
+
id: string;
|
|
87
|
+
entityId?: string | null;
|
|
88
|
+
/** Inbound: the provider's id for the record. */
|
|
89
|
+
externalId?: string;
|
|
90
|
+
status: 'failed' | 'dead';
|
|
91
|
+
attempts: number;
|
|
92
|
+
nextAttemptAt?: string | null;
|
|
93
|
+
lastError?: string | null;
|
|
94
|
+
updatedAt?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface FailedRecordList {
|
|
97
|
+
direction: FlowDirection;
|
|
98
|
+
items: FailedRecord[];
|
|
99
|
+
nextCursor: string | null;
|
|
74
100
|
}
|
|
75
101
|
export interface CreateFlowInput {
|
|
76
102
|
appId: string;
|
|
@@ -109,10 +135,12 @@ export interface RunFlowSummary {
|
|
|
109
135
|
/** Outbound: records delivered. */
|
|
110
136
|
sent?: number;
|
|
111
137
|
failed: number;
|
|
112
|
-
/** Inbound: products created / updated, and records the connector skipped. */
|
|
138
|
+
/** Inbound: products created / updated, and records the connector skipped (outbound: unchanged). */
|
|
113
139
|
created?: number;
|
|
114
140
|
updated?: number;
|
|
115
141
|
skipped?: number;
|
|
142
|
+
/** Outbound: changes held because the destination is paused (circuit open); sent after it recovers. */
|
|
143
|
+
held?: number;
|
|
116
144
|
status: RunStatus;
|
|
117
145
|
/** Id of the persisted run row (deep-link into its detail). */
|
|
118
146
|
runId?: string;
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.60 | Generated: 2026-10-13T16:25:55.817Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -2915,6 +2915,8 @@ interface AppConnectorDeclaration {
|
|
|
2915
2915
|
}
|
|
2916
2916
|
panels?: ConnectorPanel[]
|
|
2917
2917
|
aiGuide?: string
|
|
2918
|
+
recordId?: string
|
|
2919
|
+
limits?: { requestsPerSecond?: number }
|
|
2918
2920
|
}
|
|
2919
2921
|
```
|
|
2920
2922
|
|
|
@@ -3008,7 +3010,15 @@ interface ConnectorSendInput {
|
|
|
3008
3010
|
**ConnectorSendResult** (interface)
|
|
3009
3011
|
```typescript
|
|
3010
3012
|
interface ConnectorSendResult {
|
|
3011
|
-
results: Array<{
|
|
3013
|
+
results: Array<{
|
|
3014
|
+
index: number
|
|
3015
|
+
ok: boolean
|
|
3016
|
+
status?: number
|
|
3017
|
+
error?: string
|
|
3018
|
+
externalId?: string
|
|
3019
|
+
retryable?: boolean
|
|
3020
|
+
retryAfterSeconds?: number
|
|
3021
|
+
}>
|
|
3012
3022
|
}
|
|
3013
3023
|
```
|
|
3014
3024
|
|
|
@@ -7108,6 +7118,32 @@ interface IntegrationFlow {
|
|
|
7108
7118
|
lastPollAt?: string | null
|
|
7109
7119
|
lastCursor?: string | null
|
|
7110
7120
|
totalSynced?: number | null
|
|
7121
|
+
circuitOpenedAt?: string | null
|
|
7122
|
+
circuitProbeAt?: string | null
|
|
7123
|
+
circuitReason?: string | null
|
|
7124
|
+
}
|
|
7125
|
+
```
|
|
7126
|
+
|
|
7127
|
+
**FailedRecord** (interface)
|
|
7128
|
+
```typescript
|
|
7129
|
+
interface FailedRecord {
|
|
7130
|
+
id: string
|
|
7131
|
+
entityId?: string | null
|
|
7132
|
+
externalId?: string
|
|
7133
|
+
status: 'failed' | 'dead'
|
|
7134
|
+
attempts: number
|
|
7135
|
+
nextAttemptAt?: string | null
|
|
7136
|
+
lastError?: string | null
|
|
7137
|
+
updatedAt?: string
|
|
7138
|
+
}
|
|
7139
|
+
```
|
|
7140
|
+
|
|
7141
|
+
**FailedRecordList** (interface)
|
|
7142
|
+
```typescript
|
|
7143
|
+
interface FailedRecordList {
|
|
7144
|
+
direction: FlowDirection
|
|
7145
|
+
items: FailedRecord[]
|
|
7146
|
+
nextCursor: string | null
|
|
7111
7147
|
}
|
|
7112
7148
|
```
|
|
7113
7149
|
|
|
@@ -7161,6 +7197,7 @@ interface RunFlowSummary {
|
|
|
7161
7197
|
created?: number
|
|
7162
7198
|
updated?: number
|
|
7163
7199
|
skipped?: number
|
|
7200
|
+
held?: number
|
|
7164
7201
|
status: RunStatus
|
|
7165
7202
|
runId?: string
|
|
7166
7203
|
}
|
|
@@ -11704,6 +11741,17 @@ Is enhanced logging active for a connection? GET /integrations/logging/:connecti
|
|
|
11704
11741
|
**setLogging**(collectionId: string, connectionId: string, input: SetLoggingInput = {}) → `Promise<`
|
|
11705
11742
|
Enable enhanced logging. POST /integrations/logging/:connectionId (omit ttlMinutes = until cancelled)
|
|
11706
11743
|
|
|
11744
|
+
**listFailed**(collectionId: string,
|
|
11745
|
+
flowId: string,
|
|
11746
|
+
query: { status?: 'failed' | 'dead'; limit?: number; cursor?: string } = {}) → `Promise<FailedRecordList>`
|
|
11747
|
+
A flow's failed / dead records. GET /integrations/flows/:id/failed
|
|
11748
|
+
|
|
11749
|
+
**retryFailed**(collectionId: string, flowId: string, ids?: string[]) → `Promise<`
|
|
11750
|
+
Retry failed / dead records now (all of them when `ids` is omitted). POST /integrations/flows/:id/failed/retry
|
|
11751
|
+
|
|
11752
|
+
**resumeFlow**(collectionId: string, flowId: string) → `Promise<`
|
|
11753
|
+
Resume a flow that paused itself (circuit open): held records go out now. POST /integrations/flows/:id/resume
|
|
11754
|
+
|
|
11707
11755
|
**cancelLogging**(collectionId: string, connectionId: string) → `Promise<`
|
|
11708
11756
|
Cancel enhanced logging now. DELETE /integrations/logging/:connectionId
|
|
11709
11757
|
|
package/docs/connectors.md
CHANGED
|
@@ -90,6 +90,8 @@ Types: `AppConnectorDeclaration` and friends in `@proveanything/smartlinks` (`sr
|
|
|
90
90
|
| `functions` | Which of this app's server functions implement each step (below). Fill in only what applies. |
|
|
91
91
|
| `panels[]` | Provider-specific screens the console mounts (an API explorer, a status page). |
|
|
92
92
|
| `aiGuide` | A guide the mapping assistant reads: the provider's quirks, required fields, good defaults. |
|
|
93
|
+
| `recordId` | Path of the provider's own id in a fetched record (e.g. `gtin`). Inbound records are landed and matched by it, so a re-import updates the same product instead of creating another. Default `id`; a flow can override it (`config.upsert.externalIdPath`). |
|
|
94
|
+
| `limits` | `{ requestsPerSecond }` toward the provider, enforced across every SmartLinks worker. |
|
|
93
95
|
|
|
94
96
|
---
|
|
95
97
|
|
|
@@ -112,9 +114,12 @@ declare the provider's hosts (`network:<host>`) and the secrets it reads (`secre
|
|
|
112
114
|
| `send` | Every outbound run | `ConnectorSendInput` `{ installation, payloads }` | `ConnectorSendResult` `{ results: [{ index, ok, status, error, externalId }] }` |
|
|
113
115
|
|
|
114
116
|
**How a run flows:**
|
|
115
|
-
- **Inbound:** `fetch` (paged) → `shape` → core maps the documents
|
|
117
|
+
- **Inbound:** `fetch` (paged; every record is landed as received) → `shape` → core maps the documents
|
|
118
|
+
with the flow's mapping → upsert, matched by `recordId`. Unchanged records aren't processed again; a
|
|
119
|
+
changed flow configuration replays the landed records without fetching.
|
|
116
120
|
- **Outbound:** gather the SmartLinks records → core maps them to the provider's fields → `serialize`
|
|
117
|
-
→ `send` (or a generic transport).
|
|
121
|
+
→ `send` (or a generic transport). A record identical to its last successful delivery isn't sent again.
|
|
122
|
+
- Large runs are processed in short slices that resume after an interruption; there's no record cap.
|
|
118
123
|
|
|
119
124
|
**What happens when a step is left out:**
|
|
120
125
|
- **No `shape`:** core maps the provider records as they come.
|
package/docs/integrations.md
CHANGED
|
@@ -19,6 +19,14 @@ Provider-specific logic (a provider's payload format, its API, its connect form)
|
|
|
19
19
|
**connector app**, not in the engine: see **[Connectors](connectors.md)**. A flow uses one with
|
|
20
20
|
`config.connector = { appId }`.
|
|
21
21
|
|
|
22
|
+
**Reliability.** A record that fails is retried on its own with exponential backoff (honouring the
|
|
23
|
+
destination's `Retry-After`); a permanent failure (most 4xx) or one out of attempts is **dead** and
|
|
24
|
+
waits in `integrations.listFailed` for `integrations.retryFailed`. A destination that keeps failing
|
|
25
|
+
**pauses the flow automatically** (`flow.circuitOpenedAt`): edits are held, small probes check for
|
|
26
|
+
recovery, and it resumes on its own (or with `integrations.resumeFlow`). Every product and record
|
|
27
|
+
change is recorded durably before it's dispatched, so an edit can't be missed; scheduled sweeps are
|
|
28
|
+
the reconciliation net.
|
|
29
|
+
|
|
22
30
|
Credentials are **never** stored on the flow. The connection holds an opaque
|
|
23
31
|
`credentialRef` into the **sealed-secret store** (`secrets` namespace); the value is sealed
|
|
24
32
|
at rest and resolved server-side only, at execution.
|
package/openapi.yaml
CHANGED
|
@@ -19780,6 +19780,11 @@ components:
|
|
|
19780
19780
|
$ref: "#/components/schemas/ConnectorPanel"
|
|
19781
19781
|
aiGuide:
|
|
19782
19782
|
type: string
|
|
19783
|
+
recordId:
|
|
19784
|
+
type: string
|
|
19785
|
+
limits:
|
|
19786
|
+
type: object
|
|
19787
|
+
additionalProperties: true
|
|
19783
19788
|
required:
|
|
19784
19789
|
- provider
|
|
19785
19790
|
- directions
|
|
@@ -19933,12 +19938,26 @@ components:
|
|
|
19933
19938
|
type: object
|
|
19934
19939
|
properties:
|
|
19935
19940
|
results:
|
|
19936
|
-
type:
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19941
|
+
type: object
|
|
19942
|
+
additionalProperties: true
|
|
19943
|
+
index:
|
|
19944
|
+
type: number
|
|
19945
|
+
ok:
|
|
19946
|
+
type: boolean
|
|
19947
|
+
status:
|
|
19948
|
+
type: number
|
|
19949
|
+
error:
|
|
19950
|
+
type: string
|
|
19951
|
+
externalId:
|
|
19952
|
+
type: string
|
|
19953
|
+
retryable:
|
|
19954
|
+
type: boolean
|
|
19955
|
+
retryAfterSeconds:
|
|
19956
|
+
type: number
|
|
19940
19957
|
required:
|
|
19941
19958
|
- results
|
|
19959
|
+
- index
|
|
19960
|
+
- ok
|
|
19942
19961
|
ConnectorFetchInput:
|
|
19943
19962
|
type: object
|
|
19944
19963
|
properties:
|
|
@@ -26278,6 +26297,12 @@ components:
|
|
|
26278
26297
|
type: string
|
|
26279
26298
|
totalSynced:
|
|
26280
26299
|
type: number
|
|
26300
|
+
circuitOpenedAt:
|
|
26301
|
+
type: string
|
|
26302
|
+
circuitProbeAt:
|
|
26303
|
+
type: string
|
|
26304
|
+
circuitReason:
|
|
26305
|
+
type: string
|
|
26281
26306
|
required:
|
|
26282
26307
|
- id
|
|
26283
26308
|
- orgId
|
|
@@ -26294,6 +26319,47 @@ components:
|
|
|
26294
26319
|
- createdBy
|
|
26295
26320
|
- createdAt
|
|
26296
26321
|
- updatedAt
|
|
26322
|
+
FailedRecord:
|
|
26323
|
+
type: object
|
|
26324
|
+
properties:
|
|
26325
|
+
id:
|
|
26326
|
+
type: string
|
|
26327
|
+
entityId:
|
|
26328
|
+
type: string
|
|
26329
|
+
externalId:
|
|
26330
|
+
type: string
|
|
26331
|
+
status:
|
|
26332
|
+
type: string
|
|
26333
|
+
enum:
|
|
26334
|
+
- failed
|
|
26335
|
+
- dead
|
|
26336
|
+
attempts:
|
|
26337
|
+
type: number
|
|
26338
|
+
nextAttemptAt:
|
|
26339
|
+
type: string
|
|
26340
|
+
lastError:
|
|
26341
|
+
type: string
|
|
26342
|
+
updatedAt:
|
|
26343
|
+
type: string
|
|
26344
|
+
required:
|
|
26345
|
+
- id
|
|
26346
|
+
- status
|
|
26347
|
+
- attempts
|
|
26348
|
+
FailedRecordList:
|
|
26349
|
+
type: object
|
|
26350
|
+
properties:
|
|
26351
|
+
direction:
|
|
26352
|
+
$ref: "#/components/schemas/FlowDirection"
|
|
26353
|
+
items:
|
|
26354
|
+
type: array
|
|
26355
|
+
items:
|
|
26356
|
+
$ref: "#/components/schemas/FailedRecord"
|
|
26357
|
+
nextCursor:
|
|
26358
|
+
type: string
|
|
26359
|
+
required:
|
|
26360
|
+
- direction
|
|
26361
|
+
- items
|
|
26362
|
+
- nextCursor
|
|
26297
26363
|
CreateFlowInput:
|
|
26298
26364
|
type: object
|
|
26299
26365
|
properties:
|
|
@@ -26365,6 +26431,8 @@ components:
|
|
|
26365
26431
|
type: number
|
|
26366
26432
|
skipped:
|
|
26367
26433
|
type: number
|
|
26434
|
+
held:
|
|
26435
|
+
type: number
|
|
26368
26436
|
status:
|
|
26369
26437
|
$ref: "#/components/schemas/RunStatus"
|
|
26370
26438
|
runId:
|