@proveanything/smartlinks 2.0.56 → 2.0.57
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 +21 -1
- package/dist/api/integrations.js +25 -0
- package/dist/docs/API_SUMMARY.md +199 -2
- package/dist/docs/app-manifest.md +7 -0
- package/dist/docs/connectors.md +204 -0
- package/dist/docs/integrations.md +4 -0
- package/dist/docs/overview.md +1 -0
- package/dist/openapi.yaml +330 -1
- package/dist/types/appManifest.d.ts +155 -0
- package/dist/types/integrations.d.ts +43 -1
- package/docs/API_SUMMARY.md +199 -2
- package/docs/app-manifest.md +7 -0
- package/docs/connectors.md +204 -0
- package/docs/integrations.md +4 -0
- package/docs/overview.md +1 -0
- package/openapi.yaml +330 -1
- package/package.json +1 -1
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.57 | Generated: 2026-10-13T11:42:19.247Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -65,6 +65,7 @@ For detailed guides on specific features:
|
|
|
65
65
|
- **[Analytics Metadata Conventions](analytics-metadata-conventions.md)** - Standard recommended keys and conventions for analytics metadata fields
|
|
66
66
|
- **[Loyalty: Points, Members & Earning Rules](loyalty.md)** - Loyalty schemes, automatic point earning via interaction rules, member balances, transaction history, and manual adjustments
|
|
67
67
|
- **[Integrations](integrations.md)** - Inbound/outbound integration flows + the sealed-secret store; triggers (manual/event/schedule), field mappings, and the Syndigo/Event Hub outbound path
|
|
68
|
+
- **[Connectors](connectors.md)** - Connector apps: a manifest `connector` block + server functions (testConnection/describeTarget/sample/transform/send/fetch) that the integration engine and console call for one external provider
|
|
68
69
|
- **[AI Tools & Skills](ai-tools-and-skills.md)** - The AI capability catalog: skills apps invoke by name (e.g. research.brand), the tools the AI reaches for (web fetch/screenshot/brand assets/image gen), the agent loop, and how apps discover them
|
|
69
70
|
- **[Deep Link Discovery](deep-link-discovery.md)** - Registering and discovering navigable app states for portal menus and AI orchestration
|
|
70
71
|
- **[AI Guide Template](ai-guide-template.md)** - A sample for an app on how to build an AI setup guide
|
|
@@ -2853,10 +2854,156 @@ interface AppManifest {
|
|
|
2853
2854
|
realtime?: { channels: RealtimeChannelDeclaration[] };
|
|
2854
2855
|
data?: AppDataDeclaration;
|
|
2855
2856
|
headless?: AppHeadlessDeclaration;
|
|
2857
|
+
connector?: AppConnectorDeclaration;
|
|
2856
2858
|
[key: string]: any;
|
|
2857
2859
|
}
|
|
2858
2860
|
```
|
|
2859
2861
|
|
|
2862
|
+
**ConnectorConnectionField** (interface)
|
|
2863
|
+
```typescript
|
|
2864
|
+
interface ConnectorConnectionField {
|
|
2865
|
+
name: string
|
|
2866
|
+
label: string
|
|
2867
|
+
description?: string
|
|
2868
|
+
secret?: string
|
|
2869
|
+
required?: boolean
|
|
2870
|
+
type?: 'text' | 'url' | 'select' | 'number' | 'boolean'
|
|
2871
|
+
options?: Array<{ value: string; label: string }>
|
|
2872
|
+
placeholder?: string
|
|
2873
|
+
}
|
|
2874
|
+
```
|
|
2875
|
+
|
|
2876
|
+
**ConnectorPreset** (interface)
|
|
2877
|
+
```typescript
|
|
2878
|
+
interface ConnectorPreset {
|
|
2879
|
+
id: string
|
|
2880
|
+
title: string
|
|
2881
|
+
description?: string
|
|
2882
|
+
direction: 'inbound' | 'outbound'
|
|
2883
|
+
entity: string
|
|
2884
|
+
flow?: Record<string, unknown>
|
|
2885
|
+
}
|
|
2886
|
+
```
|
|
2887
|
+
|
|
2888
|
+
**ConnectorPanel** (interface)
|
|
2889
|
+
```typescript
|
|
2890
|
+
interface ConnectorPanel {
|
|
2891
|
+
id: string
|
|
2892
|
+
title: string
|
|
2893
|
+
component: string
|
|
2894
|
+
}
|
|
2895
|
+
```
|
|
2896
|
+
|
|
2897
|
+
**AppConnectorDeclaration** (interface)
|
|
2898
|
+
```typescript
|
|
2899
|
+
interface AppConnectorDeclaration {
|
|
2900
|
+
provider: string
|
|
2901
|
+
title?: string
|
|
2902
|
+
directions: Array<'inbound' | 'outbound'>
|
|
2903
|
+
entities: string[]
|
|
2904
|
+
connection?: { fields: ConnectorConnectionField[] }
|
|
2905
|
+
settings?: Record<string, unknown>
|
|
2906
|
+
presets?: ConnectorPreset[]
|
|
2907
|
+
functions: {
|
|
2908
|
+
testConnection?: string
|
|
2909
|
+
describeTarget?: string
|
|
2910
|
+
sample?: string
|
|
2911
|
+
transform?: string
|
|
2912
|
+
send?: string
|
|
2913
|
+
fetch?: string
|
|
2914
|
+
}
|
|
2915
|
+
panels?: ConnectorPanel[]
|
|
2916
|
+
aiGuide?: string
|
|
2917
|
+
}
|
|
2918
|
+
```
|
|
2919
|
+
|
|
2920
|
+
**ConnectorInstallation** (interface)
|
|
2921
|
+
```typescript
|
|
2922
|
+
interface ConnectorInstallation {
|
|
2923
|
+
collectionId: string
|
|
2924
|
+
appId: string
|
|
2925
|
+
flowId?: string | null
|
|
2926
|
+
connection: Record<string, unknown>
|
|
2927
|
+
settings: Record<string, unknown>
|
|
2928
|
+
}
|
|
2929
|
+
```
|
|
2930
|
+
|
|
2931
|
+
**ConnectorTestResult** (interface)
|
|
2932
|
+
```typescript
|
|
2933
|
+
interface ConnectorTestResult {
|
|
2934
|
+
ok: boolean
|
|
2935
|
+
message: string
|
|
2936
|
+
}
|
|
2937
|
+
```
|
|
2938
|
+
|
|
2939
|
+
**ConnectorTargetField** (interface)
|
|
2940
|
+
```typescript
|
|
2941
|
+
interface ConnectorTargetField {
|
|
2942
|
+
path: string
|
|
2943
|
+
label?: string
|
|
2944
|
+
type?: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array'
|
|
2945
|
+
required?: boolean
|
|
2946
|
+
description?: string
|
|
2947
|
+
enum?: string[]
|
|
2948
|
+
}
|
|
2949
|
+
```
|
|
2950
|
+
|
|
2951
|
+
**ConnectorTargetSchema** (interface)
|
|
2952
|
+
```typescript
|
|
2953
|
+
interface ConnectorTargetSchema {
|
|
2954
|
+
fields: ConnectorTargetField[]
|
|
2955
|
+
}
|
|
2956
|
+
```
|
|
2957
|
+
|
|
2958
|
+
**ConnectorRecords** (interface)
|
|
2959
|
+
```typescript
|
|
2960
|
+
interface ConnectorRecords {
|
|
2961
|
+
records: Array<Record<string, unknown>>
|
|
2962
|
+
nextCursor?: string | null
|
|
2963
|
+
}
|
|
2964
|
+
```
|
|
2965
|
+
|
|
2966
|
+
**ConnectorTransformInput** (interface)
|
|
2967
|
+
```typescript
|
|
2968
|
+
interface ConnectorTransformInput {
|
|
2969
|
+
installation: ConnectorInstallation
|
|
2970
|
+
records: Array<Record<string, unknown>>
|
|
2971
|
+
mapping: FieldMapping[]
|
|
2972
|
+
}
|
|
2973
|
+
```
|
|
2974
|
+
|
|
2975
|
+
**ConnectorTransformResult** (interface)
|
|
2976
|
+
```typescript
|
|
2977
|
+
interface ConnectorTransformResult {
|
|
2978
|
+
payloads: Array<unknown | null>
|
|
2979
|
+
skipped?: Array<{ index: number; reason: string }>
|
|
2980
|
+
}
|
|
2981
|
+
```
|
|
2982
|
+
|
|
2983
|
+
**ConnectorSendInput** (interface)
|
|
2984
|
+
```typescript
|
|
2985
|
+
interface ConnectorSendInput {
|
|
2986
|
+
installation: ConnectorInstallation
|
|
2987
|
+
payloads: unknown[]
|
|
2988
|
+
}
|
|
2989
|
+
```
|
|
2990
|
+
|
|
2991
|
+
**ConnectorSendResult** (interface)
|
|
2992
|
+
```typescript
|
|
2993
|
+
interface ConnectorSendResult {
|
|
2994
|
+
results: Array<{ index: number; ok: boolean; status?: number; error?: string; externalId?: string }>
|
|
2995
|
+
}
|
|
2996
|
+
```
|
|
2997
|
+
|
|
2998
|
+
**ConnectorFetchInput** (interface)
|
|
2999
|
+
```typescript
|
|
3000
|
+
interface ConnectorFetchInput {
|
|
3001
|
+
installation: ConnectorInstallation
|
|
3002
|
+
cursor?: string | null
|
|
3003
|
+
limit?: number
|
|
3004
|
+
}
|
|
3005
|
+
```
|
|
3006
|
+
|
|
2860
3007
|
**CollectionAppWidget** (interface)
|
|
2861
3008
|
```typescript
|
|
2862
3009
|
interface CollectionAppWidget {
|
|
@@ -6899,11 +7046,21 @@ interface FlowConnection {
|
|
|
6899
7046
|
}
|
|
6900
7047
|
```
|
|
6901
7048
|
|
|
7049
|
+
**FlowConnectorRef** (interface)
|
|
7050
|
+
```typescript
|
|
7051
|
+
interface FlowConnectorRef {
|
|
7052
|
+
appId: string
|
|
7053
|
+
preset?: string
|
|
7054
|
+
settings?: Record<string, unknown>
|
|
7055
|
+
}
|
|
7056
|
+
```
|
|
7057
|
+
|
|
6902
7058
|
**IntegrationFlowConfig** (interface)
|
|
6903
7059
|
```typescript
|
|
6904
7060
|
interface IntegrationFlowConfig {
|
|
6905
7061
|
connection?: FlowConnection
|
|
6906
7062
|
fieldMappings?: FieldMapping[]
|
|
7063
|
+
connector?: FlowConnectorRef
|
|
6907
7064
|
[key: string]: any
|
|
6908
7065
|
}
|
|
6909
7066
|
```
|
|
@@ -6982,13 +7139,37 @@ interface RunFlowSummary {
|
|
|
6982
7139
|
flowId: string
|
|
6983
7140
|
direction: FlowDirection
|
|
6984
7141
|
records: number
|
|
6985
|
-
sent
|
|
7142
|
+
sent?: number
|
|
6986
7143
|
failed: number
|
|
7144
|
+
created?: number
|
|
7145
|
+
updated?: number
|
|
7146
|
+
skipped?: number
|
|
6987
7147
|
status: RunStatus
|
|
6988
7148
|
runId?: string
|
|
6989
7149
|
}
|
|
6990
7150
|
```
|
|
6991
7151
|
|
|
7152
|
+
**InstalledConnector** (interface)
|
|
7153
|
+
```typescript
|
|
7154
|
+
interface InstalledConnector {
|
|
7155
|
+
appId: string
|
|
7156
|
+
name: string
|
|
7157
|
+
channel: string
|
|
7158
|
+
version: string | null
|
|
7159
|
+
connector: import('./appManifest').AppConnectorDeclaration
|
|
7160
|
+
installation: { connection: Record<string, unknown>; settings: Record<string, unknown> }
|
|
7161
|
+
secrets: Record<string, { set: boolean; hint?: string | null }>
|
|
7162
|
+
}
|
|
7163
|
+
```
|
|
7164
|
+
|
|
7165
|
+
**SaveConnectorInstallationInput** (interface)
|
|
7166
|
+
```typescript
|
|
7167
|
+
interface SaveConnectorInstallationInput {
|
|
7168
|
+
connection?: Record<string, unknown>
|
|
7169
|
+
settings?: Record<string, unknown>
|
|
7170
|
+
}
|
|
7171
|
+
```
|
|
7172
|
+
|
|
6992
7173
|
**CapturedRequest** (interface)
|
|
6993
7174
|
```typescript
|
|
6994
7175
|
interface CapturedRequest {
|
|
@@ -7193,6 +7374,8 @@ interface RecordTypesResponse {
|
|
|
7193
7374
|
|
|
7194
7375
|
**UpdateFlowInput** = `Partial<Omit<CreateFlowInput, 'direction'>> & {`
|
|
7195
7376
|
|
|
7377
|
+
**ConnectorConsoleStep** = `'testConnection' | 'describeTarget' | 'sample' | 'transform'`
|
|
7378
|
+
|
|
7196
7379
|
**RunTrigger** = `'manual' | 'event' | 'schedule' | 'test'`
|
|
7197
7380
|
|
|
7198
7381
|
**FlowRunStatus** = `'running' | 'success' | 'partial' | 'failed' | 'skipped'`
|
|
@@ -11507,6 +11690,20 @@ Enable enhanced logging. POST /integrations/logging/:connectionId (omit ttlMinut
|
|
|
11507
11690
|
**cancelLogging**(collectionId: string, connectionId: string) → `Promise<`
|
|
11508
11691
|
Cancel enhanced logging now. DELETE /integrations/logging/:connectionId
|
|
11509
11692
|
|
|
11693
|
+
**listConnectors**(collectionId: string) → `Promise<`
|
|
11694
|
+
The collection's installed connector apps. GET /integrations/connectors
|
|
11695
|
+
|
|
11696
|
+
**saveConnectorInstallation**(collectionId: string,
|
|
11697
|
+
appId: string,
|
|
11698
|
+
input: SaveConnectorInstallationInput) → `Promise<`
|
|
11699
|
+
Save a connector's non-secret Connect-form values and/or settings. PUT /integrations/connectors/:appId/installation
|
|
11700
|
+
|
|
11701
|
+
**runConnectorStep**(collectionId: string,
|
|
11702
|
+
appId: string,
|
|
11703
|
+
step: ConnectorConsoleStep,
|
|
11704
|
+
input: Record<string, unknown> & { flowId?: string } = {}) → `Promise<T>`
|
|
11705
|
+
Run a connector step from the console: `testConnection` → ConnectorTestResult, `describeTarget` → ConnectorTargetSchema, `sample` → ConnectorRecords, `transform` (a dry run) → ConnectorTransformResult. The server adds the installation; pass `flowId` to layer that flow's settings. POST /integrations/connectors/:appId/steps/:step
|
|
11706
|
+
|
|
11510
11707
|
### interactions
|
|
11511
11708
|
|
|
11512
11709
|
**query**(collectionId: string,
|
package/docs/app-manifest.md
CHANGED
|
@@ -436,6 +436,13 @@ this is just the manifest shape.
|
|
|
436
436
|
| `definitions[].authority` | string | `caller` \| `collection` — whose authority it runs as |
|
|
437
437
|
| `definitions[].capabilities` | string[] | Least-privilege grants (`sl:<res>:<read\|write>`, `network[:<host>]`, `secrets:<ref>`) |
|
|
438
438
|
|
|
439
|
+
#### `connector`
|
|
440
|
+
|
|
441
|
+
Marks the app as an integration **connector** for one external provider: the integrations console
|
|
442
|
+
lists it and draws its connect form and settings, and the integration engine calls its server
|
|
443
|
+
functions (`testConnection`, `describeTarget`, `sample`, `transform`, `send`, `fetch`). The full
|
|
444
|
+
contract is in the **[Connectors guide](connectors.md)**.
|
|
445
|
+
|
|
439
446
|
---
|
|
440
447
|
|
|
441
448
|
## `app.admin.json`
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Integration connectors
|
|
2
|
+
|
|
3
|
+
A **connector** is an app that knows one external provider (a PIM, a content network, a shop
|
|
4
|
+
platform…). It is installed on a collection like any app, versioned and released like any app, and
|
|
5
|
+
it adds a manifest `connector` block plus a handful of [server functions](server-functions.md) the
|
|
6
|
+
integration engine and the integrations console call by convention.
|
|
7
|
+
|
|
8
|
+
Three layers, each with one job:
|
|
9
|
+
|
|
10
|
+
| Layer | Holds |
|
|
11
|
+
|---|---|
|
|
12
|
+
| **Engine** (the API) | [Integration flows](integrations.md), runs and their logs, triggers (events, schedule, Run now), the secret store, the deterministic field mapper, generic transports (HTTP, Event Hub). No provider code. |
|
|
13
|
+
| **Integrations console** (a core app) | The one admin screen: installed connectors, connect forms, settings, the mapper with AI assist, flows, runs. |
|
|
14
|
+
| **Connector apps** | One per provider: its connect form, settings, target schema, transform, send/fetch, and any provider-specific panels. |
|
|
15
|
+
|
|
16
|
+
A flow that only posts JSON to a webhook or an Event Hub needs no connector; it uses the engine's
|
|
17
|
+
generic transports (see [integrations.md](integrations.md)).
|
|
18
|
+
|
|
19
|
+
**No AI at run time.** The AI helps an admin *author* a mapping in the console (from the connector's
|
|
20
|
+
target schema plus real sample records); a person approves it, and it is saved as data and runs
|
|
21
|
+
deterministically. A connector's `transform` must be deterministic too.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## The manifest block
|
|
26
|
+
|
|
27
|
+
```jsonc
|
|
28
|
+
// app.manifest.json
|
|
29
|
+
"connector": {
|
|
30
|
+
"provider": "oneworldsync",
|
|
31
|
+
"title": "1WorldSync",
|
|
32
|
+
"directions": ["inbound"],
|
|
33
|
+
"entities": ["product"],
|
|
34
|
+
"connection": {
|
|
35
|
+
"fields": [
|
|
36
|
+
{ "name": "appId", "label": "App ID", "secret": "oneworldsync-app-id", "required": true },
|
|
37
|
+
{ "name": "secretKey", "label": "Secret key", "secret": "oneworldsync-secret-key", "required": true },
|
|
38
|
+
{ "name": "environment", "label": "Environment", "type": "select",
|
|
39
|
+
"options": [ { "value": "preprod", "label": "Pre-production" }, { "value": "production", "label": "Production" } ] }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"settings": { // JSON Schema → a form in the console
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": { "targetMarket": { "type": "string", "default": "GB" } }
|
|
45
|
+
},
|
|
46
|
+
"presets": [
|
|
47
|
+
{ "id": "import-products", "title": "Import products", "direction": "inbound", "entity": "product" }
|
|
48
|
+
],
|
|
49
|
+
"functions": { // names of this app's server functions
|
|
50
|
+
"testConnection": "testConnection",
|
|
51
|
+
"describeTarget": "describeTarget",
|
|
52
|
+
"sample": "sample",
|
|
53
|
+
"fetch": "fetch"
|
|
54
|
+
},
|
|
55
|
+
"panels": [ { "id": "explorer", "title": "Explorer", "component": "Explorer" } ],
|
|
56
|
+
"aiGuide": "connector-ai-guide.md"
|
|
57
|
+
},
|
|
58
|
+
"functions": {
|
|
59
|
+
"files": { "js": { "umd": "dist/functions.umd.js" } },
|
|
60
|
+
"definitions": [
|
|
61
|
+
{ "name": "testConnection", "trigger": { "type": "http", "method": "POST" },
|
|
62
|
+
"visibility": "admin", "authority": "collection",
|
|
63
|
+
"capabilities": ["network:content1-api.1worldsync.com", "secrets:oneworldsync-app-id", "secrets:oneworldsync-secret-key"] }
|
|
64
|
+
// …one definition per function named above
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Types: `AppConnectorDeclaration` and friends in `@proveanything/smartlinks` (`src/types/appManifest.ts`).
|
|
70
|
+
|
|
71
|
+
| Field | Meaning |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `provider` | Stable provider key (`syndigo`, `oneworldsync`). |
|
|
74
|
+
| `title` | Provider display name; defaults to the app name. |
|
|
75
|
+
| `directions` | `inbound` (provider → SmartLinks), `outbound` (SmartLinks → provider), or both. |
|
|
76
|
+
| `entities` | SmartLinks entities it maps, e.g. `["product"]`. |
|
|
77
|
+
| `connection.fields[]` | The console's **Connect** form. A field with `secret` is stored as this app's secret of that name (write-only; never returned to the browser). Other fields are saved in the installation's connection settings. |
|
|
78
|
+
| `settings` | JSON Schema for installation settings; the console renders it as a form. |
|
|
79
|
+
| `presets[]` | Ready-made flows ("Products → provider") with flow defaults. |
|
|
80
|
+
| `functions` | Which of this app's server functions implement each step (below). Fill in only what applies. |
|
|
81
|
+
| `panels[]` | Provider-specific screens the console mounts (an API explorer, a status page). |
|
|
82
|
+
| `aiGuide` | A guide the mapping assistant reads: the provider's quirks, required fields, good defaults. |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## The functions
|
|
87
|
+
|
|
88
|
+
Each step names one of the app's server functions. Declare them as **http POST, `visibility:
|
|
89
|
+
"admin"`, `authority: "collection"`**: the engine calls them with no signed-in user (a product edit, a
|
|
90
|
+
schedule), and the console calls the same functions while an admin configures the flow
|
|
91
|
+
(`functions.callAdmin(collectionId, name, input, { appId })`). The input arrives as `event.body`;
|
|
92
|
+
return the result as JSON. Capabilities still cap what each one can do: declare the provider's hosts
|
|
93
|
+
(`network:<host>`) and the secrets it reads (`secrets:<name>`).
|
|
94
|
+
|
|
95
|
+
| Step | Called by | Input (`event.body`) | Returns |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `testConnection` | Connect form, **Test** | `{ installation }` | `ConnectorTestResult` `{ ok, message }` |
|
|
98
|
+
| `describeTarget` | Mapper opens | `{ installation }` | `ConnectorTargetSchema` `{ fields: [{ path, label, type, required, enum }] }`: the provider's fields *for this customer* |
|
|
99
|
+
| `sample` | Mapper, AI assist, dry run | `{ installation, limit }` | `ConnectorRecords` `{ records }`: real provider records |
|
|
100
|
+
| `transform` | Every run | `ConnectorTransformInput` `{ installation, records, mapping }` | `ConnectorTransformResult` `{ payloads, skipped }`: one payload per record, same order; `null` skips one |
|
|
101
|
+
| `send` | Every outbound run | `ConnectorSendInput` `{ installation, payloads }` | `ConnectorSendResult` `{ results: [{ index, ok, status, error, externalId }] }` |
|
|
102
|
+
| `fetch` | Every inbound run | `ConnectorFetchInput` `{ installation, cursor, limit }` | `ConnectorRecords` `{ records, nextCursor }`: one page per call |
|
|
103
|
+
|
|
104
|
+
What happens when a step is left out:
|
|
105
|
+
|
|
106
|
+
- **No `transform`:** the engine's own mapper runs the flow's `fieldMappings` (direct, static, Liquid
|
|
107
|
+
template).
|
|
108
|
+
- **No `send`:** the flow's own transport: HTTP (`config.connection`), or Azure Event Hub with
|
|
109
|
+
`config.transport: 'eventhub'` and `config.eventHub`.
|
|
110
|
+
- **No `describeTarget`:** the mapper offers free-text target paths.
|
|
111
|
+
|
|
112
|
+
### `installation`
|
|
113
|
+
|
|
114
|
+
Every step receives the installation it serves:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
interface ConnectorInstallation {
|
|
118
|
+
collectionId: string
|
|
119
|
+
appId: string // the connector app
|
|
120
|
+
flowId?: string | null // when called for a flow
|
|
121
|
+
connection: Record<string, unknown> // non-secret Connect-form fields
|
|
122
|
+
settings: Record<string, unknown> // installation settings, with the flow's overrides on top
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Secrets are never in it. Read them in the function with `ctx.secrets.get('<name>')`, which needs the
|
|
127
|
+
matching `secrets:<name>` capability.
|
|
128
|
+
|
|
129
|
+
### Example: `fetch`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// src/functions/index.ts (the app's functions bundle)
|
|
133
|
+
import type { ConnectorFetchInput, ConnectorRecords } from '@proveanything/smartlinks'
|
|
134
|
+
|
|
135
|
+
export async function fetch(ctx: any, event: any): Promise<ConnectorRecords> {
|
|
136
|
+
const { installation, cursor, limit = 50 } = event.body as ConnectorFetchInput
|
|
137
|
+
const appId = await ctx.secrets.get('provider-app-id')
|
|
138
|
+
const key = await ctx.secrets.get('provider-secret-key')
|
|
139
|
+
const res = await ctx.fetch(buildSignedUrl(installation, { cursor, limit }, appId, key))
|
|
140
|
+
const page = await res.json()
|
|
141
|
+
return { records: page.items, nextCursor: page.next ?? null }
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Where configuration lives
|
|
148
|
+
|
|
149
|
+
| What | Where |
|
|
150
|
+
|---|---|
|
|
151
|
+
| Connect-form values (non-secret), installation settings | The connector app's config on the collection: `appConfiguration` for `appId`, under `connector.connection` and `connector.settings`. |
|
|
152
|
+
| Credentials | The connector app's secrets, by the names its fields declare. |
|
|
153
|
+
| One flow's use of the connector | The flow: `config.connector = { appId, preset?, settings? }` (per-flow settings override the installation's), plus `config.fieldMappings`. |
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
await integrations.createFlow(collectionId, {
|
|
157
|
+
appId: 'core-integrations',
|
|
158
|
+
direction: 'inbound',
|
|
159
|
+
name: 'Import products from 1WorldSync',
|
|
160
|
+
status: 'active',
|
|
161
|
+
schedule: '0 * * * *',
|
|
162
|
+
targetEntity: 'product',
|
|
163
|
+
config: {
|
|
164
|
+
connector: { appId: 'oneworldsync', preset: 'import-products' },
|
|
165
|
+
fieldMappings: [ { targetPath: 'name', sourcePath: 'item.tradeItemDescription', transformType: 'direct' } ],
|
|
166
|
+
},
|
|
167
|
+
})
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## From the console
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { integrations, secrets } from '@proveanything/smartlinks'
|
|
176
|
+
|
|
177
|
+
const { connectors } = await integrations.listConnectors(collectionId)
|
|
178
|
+
// → [{ appId, name, version, connector, installation: { connection, settings }, secrets: { 'provider-key': { set, hint } } }]
|
|
179
|
+
|
|
180
|
+
await secrets.put(collectionId, 'provider-key', value, { appId }) // a secret field
|
|
181
|
+
await integrations.saveConnectorInstallation(collectionId, appId, { connection: { environment: 'production' } })
|
|
182
|
+
const test = await integrations.runConnectorStep(collectionId, appId, 'testConnection')
|
|
183
|
+
const target = await integrations.runConnectorStep(collectionId, appId, 'describeTarget')
|
|
184
|
+
const dryRun = await integrations.runConnectorStep(collectionId, appId, 'transform', { records, mapping })
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`send` and `fetch` only run inside a flow. A flow run's summary carries `sent` (outbound) or
|
|
188
|
+
`created` / `updated` / `skipped` (inbound), and every run, inbound or outbound, is in the run history.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Panels
|
|
193
|
+
|
|
194
|
+
A connector can contribute screens to the integrations console (an API explorer, say). Each
|
|
195
|
+
`panels[]` entry names a component exported from the app's widgets bundle; the console mounts it host-side and passes it the
|
|
196
|
+
collection and the installation. Panels are admin-only and call the connector's own functions.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Who can build connectors
|
|
201
|
+
|
|
202
|
+
First-party connectors run in-process, like any app server function. Third-party connectors will run
|
|
203
|
+
in the isolated runner (see [server-functions.md](server-functions.md)) once that opens up; the contract
|
|
204
|
+
does not change.
|
package/docs/integrations.md
CHANGED
|
@@ -15,6 +15,10 @@ Flows are triggered three ways, all converging on the same executor:
|
|
|
15
15
|
automatically when that entity changes.
|
|
16
16
|
- **schedule** — a flow carrying a cron/interval `schedule` is run by the scan job. *(next)*
|
|
17
17
|
|
|
18
|
+
Provider-specific logic (a provider's payload format, its API, its connect form) lives in a
|
|
19
|
+
**connector app**, not in the engine: see **[Connectors](connectors.md)**. A flow uses one with
|
|
20
|
+
`config.connector = { appId }`.
|
|
21
|
+
|
|
18
22
|
Credentials are **never** stored on the flow. The connection holds an opaque
|
|
19
23
|
`credentialRef` into the **sealed-secret store** (`secrets` namespace); the value is sealed
|
|
20
24
|
at rest and resolved server-side only, at execution.
|
package/docs/overview.md
CHANGED
|
@@ -94,6 +94,7 @@ The SmartLinks SDK (`@proveanything/smartlinks`) includes comprehensive document
|
|
|
94
94
|
| **Lots** | `docs/lots.md` | Cross-SKU production "Lot" entity |
|
|
95
95
|
| **Loyalty** | `docs/loyalty.md` | Points, members, earning rules |
|
|
96
96
|
| **Integrations** | `docs/integrations.md` | Inbound/outbound external-system integration flows |
|
|
97
|
+
| **Connectors** | `docs/connectors.md` | Connector apps: the manifest `connector` block + the functions the integration engine calls |
|
|
97
98
|
| **Item Context** | `docs/item-context.md` | The `itemContext` container prop (serial / NFC authenticity context) |
|
|
98
99
|
| **Native Facade** | `docs/native-facade.md` | `host.native` / `SL.native` device-capability facade |
|
|
99
100
|
| **Product Facets** | `docs/PRODUCT_FACETS_SDK.md` | Facet API reference (admin + public endpoints, types) |
|