@proveanything/smartlinks 1.16.7 → 1.17.0

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.
@@ -0,0 +1,141 @@
1
+ # Integrations
2
+
3
+ An **integration flow** is one input/output pipeline between SmartLinks and an external
4
+ system. There are two directions:
5
+
6
+ - **outbound** — read a SmartLinks entity (v1: a product), transform it with field
7
+ mappings, and send it to an external endpoint.
8
+ - **inbound** — fetch from an external system and write a SmartLinks entity. *(Executor is
9
+ outbound-first; inbound lands in a later increment.)*
10
+
11
+ Flows are triggered three ways, all converging on the same executor:
12
+
13
+ - **manual** — `integrations.runFlow(...)`, inline (returns a run summary) or enqueued.
14
+ - **event** — an outbound flow subscribed to an event type (e.g. `product.updated`) fires
15
+ automatically when that entity changes.
16
+ - **schedule** — a flow carrying a cron/interval `schedule` is run by the scan job. *(next)*
17
+
18
+ Credentials are **never** stored on the flow. The connection holds an opaque
19
+ `credentialRef` into the **sealed-secret store** (`secrets` namespace); the value is sealed
20
+ at rest and resolved server-side only, at execution.
21
+
22
+ ---
23
+
24
+ ## The flow model
25
+
26
+ ```ts
27
+ interface IntegrationFlow {
28
+ id: string
29
+ direction: 'inbound' | 'outbound'
30
+ name: string
31
+ status: 'draft' | 'active' | 'paused' | 'error' // only 'active' flows fire on events/schedule
32
+ eventTypes: string[] // e.g. ['product.updated']
33
+ schedule: string | null // cron/interval for scheduled flows
34
+ sourceEntity: string | null // outbound source, v1: 'product'
35
+ targetEntity: string | null // inbound target
36
+ config: {
37
+ connection?: {
38
+ baseUrl?: string
39
+ sendEndpoint?: string // outbound: appended to baseUrl
40
+ defaultHeaders?: Record<string, string>
41
+ auth?: { method: 'api_key' | 'bearer' | 'basic' | ..., headerName?: string, credentialRef?: string }
42
+ }
43
+ fieldMappings?: FieldMapping[]
44
+ }
45
+ // ...run watermark/telemetry: lastRunAt, lastRunStatus, lastRunCount, totalSynced
46
+ }
47
+ ```
48
+
49
+ ### Field mappings (transform)
50
+
51
+ Each mapping produces one field on the target payload:
52
+
53
+ | transformType | uses | meaning |
54
+ |---|---|---|
55
+ | `direct` | `sourcePath` | copy the value at that dot-path |
56
+ | `static` | `transformExpression` | a constant |
57
+ | `template` | `transformExpression` | a Liquid template rendered against the source record |
58
+ | `jsonata` / `ai` | — | recognised but not yet executed; reported as a per-field error |
59
+
60
+ A single field's failure is collected and the rest continue (partial success) — it never
61
+ aborts the whole record.
62
+
63
+ ---
64
+
65
+ ## Secrets (write-only)
66
+
67
+ The secret store is **write-only from the client**: you can set, rotate, list (refs +
68
+ masked hints + metadata) and delete — but a value never comes back over the API.
69
+
70
+ ```ts
71
+ import { secrets, integrations } from '@proveanything/smartlinks'
72
+
73
+ // 1. Store the destination credential — keep the returned ref.
74
+ const { ref } = await secrets.set(collectionId, {
75
+ name: 'Acme API key',
76
+ purpose: 'integration',
77
+ value: 'sk_live_…', // sent once; never retrievable
78
+ })
79
+
80
+ // list shows refs + masked hints only (safe to render)
81
+ const { secrets: list } = await secrets.list(collectionId)
82
+ // → [{ ref, name: 'Acme API key', hint: '…live_1a2b', purpose, createdAt, ... }]
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Creating and running a flow
88
+
89
+ ```ts
90
+ // 2. Create an outbound flow that pushes products to Acme, authed by the secret above.
91
+ const flow = await integrations.createFlow(collectionId, {
92
+ appId: 'my-integration-app',
93
+ direction: 'outbound',
94
+ name: 'Push products to Acme',
95
+ status: 'active',
96
+ eventTypes: ['product.updated'], // fire whenever a product changes
97
+ sourceEntity: 'product',
98
+ config: {
99
+ connection: {
100
+ baseUrl: 'https://api.acme.example',
101
+ sendEndpoint: '/v1/products',
102
+ auth: { method: 'api_key', headerName: 'X-API-Key', credentialRef: ref },
103
+ },
104
+ fieldMappings: [
105
+ { targetPath: 'sku', sourcePath: 'sku', transformType: 'direct' },
106
+ { targetPath: 'name', sourcePath: 'name', transformType: 'direct' },
107
+ { targetPath: 'label', transformType: 'template', transformExpression: '{{name}} ({{sku}})' },
108
+ ],
109
+ },
110
+ })
111
+
112
+ // 3a. Test it now against one product — inline, returns a summary.
113
+ const result = await integrations.runFlow(collectionId, flow.id, { entityId: 'P1045716' })
114
+ if (integrations.isRunSummary(result)) {
115
+ console.log(result) // { records: 1, sent: 1, failed: 0, status: 'success' }
116
+ }
117
+
118
+ // 3b. Or enqueue on the worker (returns immediately).
119
+ await integrations.runFlow(collectionId, flow.id, { entityId: 'P1045716', async: true })
120
+ ```
121
+
122
+ Once `status: 'active'` with `eventTypes: ['product.updated']`, editing that product in the
123
+ admin API fires the flow automatically — no manual run needed.
124
+
125
+ ---
126
+
127
+ ## Reference
128
+
129
+ | Function | HTTP |
130
+ |---|---|
131
+ | `integrations.listFlows(collectionId, query?)` | `GET /integrations/flows` |
132
+ | `integrations.createFlow(collectionId, input)` | `POST /integrations/flows` |
133
+ | `integrations.getFlow(collectionId, id)` | `GET /integrations/flows/:id` |
134
+ | `integrations.updateFlow(collectionId, id, input)` | `PUT /integrations/flows/:id` |
135
+ | `integrations.deleteFlow(collectionId, id)` | `DELETE /integrations/flows/:id` |
136
+ | `integrations.runFlow(collectionId, id, opts?)` | `POST /integrations/flows/:id/run` |
137
+ | `secrets.list(collectionId, query?)` | `GET /secrets` |
138
+ | `secrets.set(collectionId, input)` | `POST /secrets` |
139
+ | `secrets.get(collectionId, ref)` | `GET /secrets/:ref` |
140
+ | `secrets.rotate(collectionId, ref, input)` | `PUT /secrets/:ref` |
141
+ | `secrets.remove(collectionId, ref)` | `DELETE /secrets/:ref` |
package/openapi.yaml CHANGED
@@ -22860,6 +22860,276 @@ components:
22860
22860
  UploadMessage:
22861
22861
  type: object
22862
22862
  additionalProperties: true
22863
+ FieldMapping:
22864
+ type: object
22865
+ properties:
22866
+ targetPath:
22867
+ type: string
22868
+ sourcePath:
22869
+ type: string
22870
+ transformType:
22871
+ $ref: "#/components/schemas/TransformType"
22872
+ transformExpression:
22873
+ type: string
22874
+ required:
22875
+ - targetPath
22876
+ - transformType
22877
+ FlowConnectionAuth:
22878
+ type: object
22879
+ properties:
22880
+ method:
22881
+ $ref: "#/components/schemas/FlowAuthMethod"
22882
+ headerName:
22883
+ type: string
22884
+ credentialRef:
22885
+ type: string
22886
+ required:
22887
+ - method
22888
+ FlowConnection:
22889
+ type: object
22890
+ properties:
22891
+ baseUrl:
22892
+ type: string
22893
+ sendEndpoint:
22894
+ type: string
22895
+ fetchEndpoint:
22896
+ type: string
22897
+ defaultHeaders:
22898
+ type: object
22899
+ additionalProperties:
22900
+ type: string
22901
+ auth:
22902
+ $ref: "#/components/schemas/FlowConnectionAuth"
22903
+ IntegrationFlowConfig:
22904
+ type: object
22905
+ properties:
22906
+ connection:
22907
+ $ref: "#/components/schemas/FlowConnection"
22908
+ fieldMappings:
22909
+ type: array
22910
+ items:
22911
+ $ref: "#/components/schemas/FieldMapping"
22912
+ IntegrationFlow:
22913
+ type: object
22914
+ properties:
22915
+ id:
22916
+ type: string
22917
+ orgId:
22918
+ type: string
22919
+ collectionId:
22920
+ type: string
22921
+ appId:
22922
+ type: string
22923
+ direction:
22924
+ $ref: "#/components/schemas/FlowDirection"
22925
+ name:
22926
+ type: string
22927
+ status:
22928
+ $ref: "#/components/schemas/FlowStatus"
22929
+ eventTypes:
22930
+ type: array
22931
+ items:
22932
+ type: string
22933
+ schedule:
22934
+ type: string
22935
+ sourceEntity:
22936
+ type: string
22937
+ targetEntity:
22938
+ type: string
22939
+ config:
22940
+ $ref: "#/components/schemas/IntegrationFlowConfig"
22941
+ createdBy:
22942
+ type: string
22943
+ createdAt:
22944
+ type: string
22945
+ updatedAt:
22946
+ type: string
22947
+ deletedAt:
22948
+ type: string
22949
+ lastRunAt:
22950
+ type: string
22951
+ lastRunStatus:
22952
+ type: string
22953
+ lastRunError:
22954
+ type: string
22955
+ lastRunCount:
22956
+ type: number
22957
+ lastPollAt:
22958
+ type: string
22959
+ lastCursor:
22960
+ type: string
22961
+ totalSynced:
22962
+ type: number
22963
+ required:
22964
+ - id
22965
+ - orgId
22966
+ - collectionId
22967
+ - appId
22968
+ - direction
22969
+ - name
22970
+ - status
22971
+ - eventTypes
22972
+ - schedule
22973
+ - sourceEntity
22974
+ - targetEntity
22975
+ - config
22976
+ - createdBy
22977
+ - createdAt
22978
+ - updatedAt
22979
+ CreateFlowInput:
22980
+ type: object
22981
+ properties:
22982
+ appId:
22983
+ type: string
22984
+ direction:
22985
+ $ref: "#/components/schemas/FlowDirection"
22986
+ name:
22987
+ type: string
22988
+ status:
22989
+ $ref: "#/components/schemas/FlowStatus"
22990
+ eventTypes:
22991
+ type: array
22992
+ items:
22993
+ type: string
22994
+ schedule:
22995
+ type: string
22996
+ sourceEntity:
22997
+ type: string
22998
+ targetEntity:
22999
+ type: string
23000
+ config:
23001
+ $ref: "#/components/schemas/IntegrationFlowConfig"
23002
+ required:
23003
+ - appId
23004
+ - direction
23005
+ - name
23006
+ ListFlowsQuery:
23007
+ type: object
23008
+ properties:
23009
+ direction:
23010
+ $ref: "#/components/schemas/FlowDirection"
23011
+ status:
23012
+ $ref: "#/components/schemas/FlowStatus"
23013
+ appId:
23014
+ type: string
23015
+ FlowList:
23016
+ type: object
23017
+ properties:
23018
+ flows:
23019
+ type: array
23020
+ items:
23021
+ $ref: "#/components/schemas/IntegrationFlow"
23022
+ required:
23023
+ - flows
23024
+ RunFlowInput:
23025
+ type: object
23026
+ properties:
23027
+ entityId:
23028
+ type: string
23029
+ RunFlowSummary:
23030
+ type: object
23031
+ properties:
23032
+ flowId:
23033
+ type: string
23034
+ direction:
23035
+ $ref: "#/components/schemas/FlowDirection"
23036
+ records:
23037
+ type: number
23038
+ sent:
23039
+ type: number
23040
+ failed:
23041
+ type: number
23042
+ status:
23043
+ $ref: "#/components/schemas/RunStatus"
23044
+ required:
23045
+ - flowId
23046
+ - direction
23047
+ - records
23048
+ - sent
23049
+ - failed
23050
+ - status
23051
+ RunFlowEnqueued:
23052
+ type: object
23053
+ properties:
23054
+ enqueued:
23055
+ type: object
23056
+ additionalProperties: true
23057
+ flowId:
23058
+ type: string
23059
+ entityId:
23060
+ type: string
23061
+ required:
23062
+ - enqueued
23063
+ - flowId
23064
+ - entityId
23065
+ SecretMeta:
23066
+ type: object
23067
+ properties:
23068
+ ref:
23069
+ type: string
23070
+ name:
23071
+ type: string
23072
+ purpose:
23073
+ type: string
23074
+ hint:
23075
+ type: string
23076
+ keyVersion:
23077
+ type: number
23078
+ createdBy:
23079
+ type: string
23080
+ createdAt:
23081
+ type: string
23082
+ updatedAt:
23083
+ type: string
23084
+ rotatedAt:
23085
+ type: string
23086
+ required:
23087
+ - ref
23088
+ - name
23089
+ - purpose
23090
+ - hint
23091
+ - keyVersion
23092
+ - createdBy
23093
+ - createdAt
23094
+ - updatedAt
23095
+ SecretList:
23096
+ type: object
23097
+ properties:
23098
+ secrets:
23099
+ type: array
23100
+ items:
23101
+ $ref: "#/components/schemas/SecretMeta"
23102
+ required:
23103
+ - secrets
23104
+ SetSecretInput:
23105
+ type: object
23106
+ properties:
23107
+ value:
23108
+ type: string
23109
+ name:
23110
+ type: string
23111
+ purpose:
23112
+ type: string
23113
+ required:
23114
+ - value
23115
+ SetSecretResult:
23116
+ type: object
23117
+ properties:
23118
+ ref:
23119
+ type: string
23120
+ hint:
23121
+ type: string
23122
+ required:
23123
+ - ref
23124
+ - hint
23125
+ ListSecretsQuery:
23126
+ type: object
23127
+ properties:
23128
+ purpose:
23129
+ type: string
23130
+ RunFlowResult:
23131
+ type: object
23132
+ additionalProperties: true
22863
23133
  AdminInteractionsQueryRequest:
22864
23134
  type: object
22865
23135
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.16.7",
3
+ "version": "1.17.0",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "keywords": [
29
29
  "smartlinks",
30
30
  "api",
31
- "authentication",
31
+ "authentication",
32
32
  "traceability",
33
33
  "blockchain",
34
34
  "typescript",