@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.
@@ -37,6 +37,8 @@ export { containers } from "./containers";
37
37
  export { lots } from "./lots";
38
38
  export { loyalty } from "./loyalty";
39
39
  export { translations } from "./translations";
40
+ export { integrations } from "./integrations";
41
+ export { secrets } from "./secrets";
40
42
  export { config } from "./config";
41
43
  export { http } from "./http";
42
44
  export { navigation } from "./navigation";
package/dist/api/index.js CHANGED
@@ -40,6 +40,8 @@ export { containers } from "./containers";
40
40
  export { lots } from "./lots";
41
41
  export { loyalty } from "./loyalty";
42
42
  export { translations } from "./translations";
43
+ export { integrations } from "./integrations";
44
+ export { secrets } from "./secrets";
43
45
  export { config } from "./config";
44
46
  export { http } from "./http";
45
47
  export { navigation } from "./navigation";
@@ -0,0 +1,28 @@
1
+ import type { IntegrationFlow, CreateFlowInput, UpdateFlowInput, ListFlowsQuery, FlowList, RunFlowInput, RunFlowResult, RunFlowSummary, RunFlowEnqueued } from "../types/integrations";
2
+ export declare namespace integrations {
3
+ /** List flows in a collection. GET /integrations/flows */
4
+ function listFlows(collectionId: string, query?: ListFlowsQuery): Promise<FlowList>;
5
+ /** Create a flow. POST /integrations/flows */
6
+ function createFlow(collectionId: string, input: CreateFlowInput): Promise<IntegrationFlow>;
7
+ /** Get one flow. GET /integrations/flows/:id */
8
+ function getFlow(collectionId: string, id: string): Promise<IntegrationFlow>;
9
+ /** Update whitelisted fields. PUT /integrations/flows/:id */
10
+ function updateFlow(collectionId: string, id: string, input: UpdateFlowInput): Promise<IntegrationFlow>;
11
+ /** Soft-delete a flow. DELETE /integrations/flows/:id */
12
+ function deleteFlow(collectionId: string, id: string): Promise<{
13
+ deleted: boolean;
14
+ }>;
15
+ /**
16
+ * Run a flow now. POST /integrations/flows/:id/run
17
+ * - inline (default): resolves and returns the run summary.
18
+ * - options.async: enqueue on the worker, returns { enqueued: true }.
19
+ * Pass options.entityId to run for a single source entity.
20
+ */
21
+ function runFlow(collectionId: string, id: string, options?: RunFlowInput & {
22
+ async?: boolean;
23
+ }): Promise<RunFlowResult>;
24
+ /** Type guard: the run executed inline and returned a summary. */
25
+ function isRunSummary(r: RunFlowResult): r is RunFlowSummary;
26
+ /** Type guard: the run was enqueued (async). */
27
+ function isRunEnqueued(r: RunFlowResult): r is RunFlowEnqueued;
28
+ }
@@ -0,0 +1,82 @@
1
+ // src/api/integrations.ts
2
+ //
3
+ // Integration flow management + execution. Flows model input/output pipelines
4
+ // (inbound: fetch external -> write entity; outbound: read entity -> transform ->
5
+ // send). Credentials live in the secret store (see the `secrets` namespace); a flow
6
+ // only carries an opaque credentialRef in config.connection.auth.
7
+ //
8
+ // Endpoints: /admin/collection/:collectionId/integrations/flows
9
+ var __rest = (this && this.__rest) || function (s, e) {
10
+ var t = {};
11
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
12
+ t[p] = s[p];
13
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
14
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
15
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
16
+ t[p[i]] = s[p[i]];
17
+ }
18
+ return t;
19
+ };
20
+ import { request, post, put, del } from "../http";
21
+ function enc(v) { return encodeURIComponent(v); }
22
+ function encodeQuery(params = {}) {
23
+ const search = new URLSearchParams();
24
+ for (const [key, value] of Object.entries(params)) {
25
+ if (value === undefined || value === null || value === "")
26
+ continue;
27
+ search.set(key, typeof value === "boolean" ? (value ? "true" : "false") : String(value));
28
+ }
29
+ const qs = search.toString();
30
+ return qs ? `?${qs}` : "";
31
+ }
32
+ export var integrations;
33
+ (function (integrations) {
34
+ const base = (collectionId) => `/admin/collection/${enc(collectionId)}/integrations/flows`;
35
+ /** List flows in a collection. GET /integrations/flows */
36
+ async function listFlows(collectionId, query = {}) {
37
+ return request(`${base(collectionId)}${encodeQuery(query)}`);
38
+ }
39
+ integrations.listFlows = listFlows;
40
+ /** Create a flow. POST /integrations/flows */
41
+ async function createFlow(collectionId, input) {
42
+ return post(base(collectionId), input);
43
+ }
44
+ integrations.createFlow = createFlow;
45
+ /** Get one flow. GET /integrations/flows/:id */
46
+ async function getFlow(collectionId, id) {
47
+ return request(`${base(collectionId)}/${enc(id)}`);
48
+ }
49
+ integrations.getFlow = getFlow;
50
+ /** Update whitelisted fields. PUT /integrations/flows/:id */
51
+ async function updateFlow(collectionId, id, input) {
52
+ return put(`${base(collectionId)}/${enc(id)}`, input);
53
+ }
54
+ integrations.updateFlow = updateFlow;
55
+ /** Soft-delete a flow. DELETE /integrations/flows/:id */
56
+ async function deleteFlow(collectionId, id) {
57
+ return del(`${base(collectionId)}/${enc(id)}`);
58
+ }
59
+ integrations.deleteFlow = deleteFlow;
60
+ /**
61
+ * Run a flow now. POST /integrations/flows/:id/run
62
+ * - inline (default): resolves and returns the run summary.
63
+ * - options.async: enqueue on the worker, returns { enqueued: true }.
64
+ * Pass options.entityId to run for a single source entity.
65
+ */
66
+ async function runFlow(collectionId, id, options = {}) {
67
+ const { async: runAsync } = options, body = __rest(options, ["async"]);
68
+ const qs = runAsync ? "?async=true" : "";
69
+ return post(`${base(collectionId)}/${enc(id)}/run${qs}`, body);
70
+ }
71
+ integrations.runFlow = runFlow;
72
+ /** Type guard: the run executed inline and returned a summary. */
73
+ function isRunSummary(r) {
74
+ return r.status !== undefined;
75
+ }
76
+ integrations.isRunSummary = isRunSummary;
77
+ /** Type guard: the run was enqueued (async). */
78
+ function isRunEnqueued(r) {
79
+ return r.enqueued === true;
80
+ }
81
+ integrations.isRunEnqueued = isRunEnqueued;
82
+ })(integrations || (integrations = {}));
@@ -0,0 +1,15 @@
1
+ import type { SecretMeta, SecretList, SetSecretInput, SetSecretResult, ListSecretsQuery } from "../types/integrations";
2
+ export declare namespace secrets {
3
+ /** List secrets as refs + masked hints + metadata (never values). GET /secrets */
4
+ function list(collectionId: string, query?: ListSecretsQuery): Promise<SecretList>;
5
+ /** Create a secret. POST /secrets → { ref, hint }. Store the ref on a flow. */
6
+ function set(collectionId: string, input: SetSecretInput): Promise<SetSecretResult>;
7
+ /** Metadata for one secret (never the value). GET /secrets/:ref */
8
+ function get(collectionId: string, ref: string): Promise<SecretMeta>;
9
+ /** Rotate/update a secret's value (and optionally name/purpose). PUT /secrets/:ref → { ref, hint } */
10
+ function rotate(collectionId: string, ref: string, input: SetSecretInput): Promise<SetSecretResult>;
11
+ /** Soft-delete a secret. DELETE /secrets/:ref */
12
+ function remove(collectionId: string, ref: string): Promise<{
13
+ deleted: boolean;
14
+ }>;
15
+ }
@@ -0,0 +1,52 @@
1
+ // src/api/secrets.ts
2
+ //
3
+ // Sealed-secret store — the credentials that back integration flows and other
4
+ // server-side handlers. WRITE-ONLY from the client: you can set, rotate, list
5
+ // (refs + masked hints + metadata) and delete, but a value NEVER comes back over the
6
+ // API. It is sealed at rest and resolved server-side only, at execution time.
7
+ //
8
+ // Typical use: `set` a credential, take the returned `ref`, and put it on a flow's
9
+ // config.connection.auth.credentialRef.
10
+ //
11
+ // Endpoints: /admin/collection/:collectionId/secrets
12
+ import { request, post, put, del } from "../http";
13
+ function enc(v) { return encodeURIComponent(v); }
14
+ function encodeQuery(params = {}) {
15
+ const search = new URLSearchParams();
16
+ for (const [key, value] of Object.entries(params)) {
17
+ if (value === undefined || value === null || value === "")
18
+ continue;
19
+ search.set(key, String(value));
20
+ }
21
+ const qs = search.toString();
22
+ return qs ? `?${qs}` : "";
23
+ }
24
+ export var secrets;
25
+ (function (secrets) {
26
+ const base = (collectionId) => `/admin/collection/${enc(collectionId)}/secrets`;
27
+ /** List secrets as refs + masked hints + metadata (never values). GET /secrets */
28
+ async function list(collectionId, query = {}) {
29
+ return request(`${base(collectionId)}${encodeQuery(query)}`);
30
+ }
31
+ secrets.list = list;
32
+ /** Create a secret. POST /secrets → { ref, hint }. Store the ref on a flow. */
33
+ async function set(collectionId, input) {
34
+ return post(base(collectionId), input);
35
+ }
36
+ secrets.set = set;
37
+ /** Metadata for one secret (never the value). GET /secrets/:ref */
38
+ async function get(collectionId, ref) {
39
+ return request(`${base(collectionId)}/${enc(ref)}`);
40
+ }
41
+ secrets.get = get;
42
+ /** Rotate/update a secret's value (and optionally name/purpose). PUT /secrets/:ref → { ref, hint } */
43
+ async function rotate(collectionId, ref, input) {
44
+ return put(`${base(collectionId)}/${enc(ref)}`, input);
45
+ }
46
+ secrets.rotate = rotate;
47
+ /** Soft-delete a secret. DELETE /secrets/:ref */
48
+ async function remove(collectionId, ref) {
49
+ return del(`${base(collectionId)}/${enc(ref)}`);
50
+ }
51
+ secrets.remove = remove;
52
+ })(secrets || (secrets = {}));
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.16.7 | Generated: 2026-09-09T11:29:21.917Z
3
+ Version: 1.17.0 | Generated: 2026-09-13T07:38:31.861Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -134,6 +134,7 @@ The Smartlinks SDK is organized into the following namespaces:
134
134
  - **containers** - Functions for containers operations
135
135
  - **facets** - Functions for facets operations
136
136
  - **http** - Functions for http operations
137
+ - **integrations** - Functions for integrations operations
137
138
  - **jobs** - Functions for jobs operations
138
139
  - **journeysAnalytics** - Functions for journeysAnalytics operations
139
140
  - **location** - Functions for location operations
@@ -142,6 +143,7 @@ The Smartlinks SDK is organized into the following namespaces:
142
143
  - **order** - Functions for order operations
143
144
  - **products** - Functions for products operations
144
145
  - **realtime** - Functions for realtime operations
146
+ - **secrets** - Functions for secrets operations
145
147
  - **tags** - Functions for tags operations
146
148
  - **template** - Functions for template operations
147
149
  - **translations** - Functions for translations operations
@@ -5768,6 +5770,195 @@ interface UploadDoneMessage {
5768
5770
 
5769
5771
  **UploadMessage** = ``
5770
5772
 
5773
+ ### integrations
5774
+
5775
+ **FieldMapping** (interface)
5776
+ ```typescript
5777
+ interface FieldMapping {
5778
+ targetPath: string
5779
+ sourcePath?: string
5780
+ transformType: TransformType
5781
+ transformExpression?: string
5782
+ }
5783
+ ```
5784
+
5785
+ **FlowConnectionAuth** (interface)
5786
+ ```typescript
5787
+ interface FlowConnectionAuth {
5788
+ method: FlowAuthMethod
5789
+ headerName?: string
5790
+ credentialRef?: string
5791
+ }
5792
+ ```
5793
+
5794
+ **FlowConnection** (interface)
5795
+ ```typescript
5796
+ interface FlowConnection {
5797
+ baseUrl?: string
5798
+ sendEndpoint?: string
5799
+ fetchEndpoint?: string
5800
+ defaultHeaders?: Record<string, string>
5801
+ auth?: FlowConnectionAuth
5802
+ }
5803
+ ```
5804
+
5805
+ **IntegrationFlowConfig** (interface)
5806
+ ```typescript
5807
+ interface IntegrationFlowConfig {
5808
+ connection?: FlowConnection
5809
+ fieldMappings?: FieldMapping[]
5810
+ [key: string]: any
5811
+ }
5812
+ ```
5813
+
5814
+ **IntegrationFlow** (interface)
5815
+ ```typescript
5816
+ interface IntegrationFlow {
5817
+ id: string
5818
+ orgId: string
5819
+ collectionId: string
5820
+ appId: string
5821
+ direction: FlowDirection
5822
+ name: string
5823
+ status: FlowStatus
5824
+ eventTypes: string[]
5825
+ schedule: string | null
5826
+ sourceEntity: string | null
5827
+ targetEntity: string | null
5828
+ config: IntegrationFlowConfig
5829
+ createdBy: string | null
5830
+ createdAt: string
5831
+ updatedAt: string
5832
+ deletedAt?: string | null
5833
+ lastRunAt?: string | null
5834
+ lastRunStatus?: string | null
5835
+ lastRunError?: string | null
5836
+ lastRunCount?: number | null
5837
+ lastPollAt?: string | null
5838
+ lastCursor?: string | null
5839
+ totalSynced?: number | null
5840
+ }
5841
+ ```
5842
+
5843
+ **CreateFlowInput** (interface)
5844
+ ```typescript
5845
+ interface CreateFlowInput {
5846
+ appId: string
5847
+ direction: FlowDirection
5848
+ name: string
5849
+ status?: FlowStatus
5850
+ eventTypes?: string[]
5851
+ schedule?: string | null
5852
+ sourceEntity?: string | null
5853
+ targetEntity?: string | null
5854
+ config?: IntegrationFlowConfig
5855
+ }
5856
+ ```
5857
+
5858
+ **ListFlowsQuery** (interface)
5859
+ ```typescript
5860
+ interface ListFlowsQuery {
5861
+ direction?: FlowDirection
5862
+ status?: FlowStatus
5863
+ appId?: string
5864
+ }
5865
+ ```
5866
+
5867
+ **FlowList** (interface)
5868
+ ```typescript
5869
+ interface FlowList {
5870
+ flows: IntegrationFlow[]
5871
+ }
5872
+ ```
5873
+
5874
+ **RunFlowInput** (interface)
5875
+ ```typescript
5876
+ interface RunFlowInput {
5877
+ entityId?: string
5878
+ }
5879
+ ```
5880
+
5881
+ **RunFlowSummary** (interface)
5882
+ ```typescript
5883
+ interface RunFlowSummary {
5884
+ flowId: string
5885
+ direction: FlowDirection
5886
+ records: number
5887
+ sent: number
5888
+ failed: number
5889
+ status: RunStatus
5890
+ }
5891
+ ```
5892
+
5893
+ **RunFlowEnqueued** (interface)
5894
+ ```typescript
5895
+ interface RunFlowEnqueued {
5896
+ enqueued: true
5897
+ flowId: string
5898
+ entityId: string | null
5899
+ }
5900
+ ```
5901
+
5902
+ **SecretMeta** (interface)
5903
+ ```typescript
5904
+ interface SecretMeta {
5905
+ ref: string
5906
+ name: string | null
5907
+ purpose: string
5908
+ hint: string
5909
+ keyVersion: number
5910
+ createdBy: string | null
5911
+ createdAt: string
5912
+ updatedAt: string
5913
+ rotatedAt?: string | null
5914
+ }
5915
+ ```
5916
+
5917
+ **SecretList** (interface)
5918
+ ```typescript
5919
+ interface SecretList {
5920
+ secrets: SecretMeta[]
5921
+ }
5922
+ ```
5923
+
5924
+ **SetSecretInput** (interface)
5925
+ ```typescript
5926
+ interface SetSecretInput {
5927
+ value: string
5928
+ name?: string
5929
+ purpose?: string
5930
+ }
5931
+ ```
5932
+
5933
+ **SetSecretResult** (interface)
5934
+ ```typescript
5935
+ interface SetSecretResult {
5936
+ ref: string
5937
+ hint: string
5938
+ }
5939
+ ```
5940
+
5941
+ **ListSecretsQuery** (interface)
5942
+ ```typescript
5943
+ interface ListSecretsQuery {
5944
+ purpose?: string
5945
+ }
5946
+ ```
5947
+
5948
+ **FlowDirection** = `'inbound' | 'outbound'`
5949
+
5950
+ **FlowStatus** = `'draft' | 'active' | 'paused' | 'error'`
5951
+
5952
+ **RunStatus** = `'success' | 'partial' | 'error'`
5953
+
5954
+ **TransformType** = `'direct' | 'static' | 'template' | 'jsonata' | 'ai'`
5955
+
5956
+ **FlowAuthMethod** = `'api_key' | 'bearer' | 'basic' | 'webhook' | 'oauth2' | 'none'`
5957
+
5958
+ **UpdateFlowInput** = `Partial<Omit<CreateFlowInput, 'direction'>> & {`
5959
+
5960
+ **RunFlowResult** = `RunFlowSummary | RunFlowEnqueued`
5961
+
5771
5962
  ### interaction
5772
5963
 
5773
5964
  **AdminInteractionsQueryRequest** (interface)
@@ -9921,6 +10112,34 @@ Perform a PATCH request to any API endpoint.
9921
10112
  **del**(path: string) → `Promise<T>`
9922
10113
  Perform a DELETE request to any API endpoint.
9923
10114
 
10115
+ ### integrations
10116
+
10117
+ **listFlows**(collectionId: string, query: ListFlowsQuery = {}) → `Promise<FlowList>`
10118
+ List flows in a collection. GET /integrations/flows
10119
+
10120
+ **createFlow**(collectionId: string, input: CreateFlowInput) → `Promise<IntegrationFlow>`
10121
+ Create a flow. POST /integrations/flows
10122
+
10123
+ **getFlow**(collectionId: string, id: string) → `Promise<IntegrationFlow>`
10124
+ Get one flow. GET /integrations/flows/:id
10125
+
10126
+ **updateFlow**(collectionId: string, id: string, input: UpdateFlowInput) → `Promise<IntegrationFlow>`
10127
+ Update whitelisted fields. PUT /integrations/flows/:id
10128
+
10129
+ **deleteFlow**(collectionId: string, id: string) → `Promise<`
10130
+ Soft-delete a flow. DELETE /integrations/flows/:id
10131
+
10132
+ **runFlow**(collectionId: string,
10133
+ id: string,
10134
+ options: RunFlowInput & { async?: boolean } = {}) → `Promise<RunFlowResult>`
10135
+ Run a flow now. POST /integrations/flows/:id/run - inline (default): resolves and returns the run summary. - options.async: enqueue on the worker, returns { enqueued: true }. Pass options.entityId to run for a single source entity.
10136
+
10137
+ **isRunSummary**(r: RunFlowResult) → `r is RunFlowSummary`
10138
+ Type guard: the run executed inline and returned a summary.
10139
+
10140
+ **isRunEnqueued**(r: RunFlowResult) → `r is RunFlowEnqueued`
10141
+ Type guard: the run was enqueued (async).
10142
+
9924
10143
  ### interactions
9925
10144
 
9926
10145
  **query**(collectionId: string,
@@ -10613,6 +10832,23 @@ Get an Ably token for public (user-scoped) real-time communication. This endpoin
10613
10832
  **getAdminToken**() → `Promise<AblyTokenRequest>`
10614
10833
  Get an Ably token for admin real-time communication. This endpoint returns an Ably TokenRequest that can be used to initialize an Ably client with admin permissions to receive system notifications and alerts. Admin users get subscribe-only (read-only) access to the interaction:{userId} channel pattern. Requires admin authentication (Bearer token). ```ts const tokenRequest = await realtime.getAdminToken() // Use with Ably const ably = new Ably.Realtime.Promise({ authCallback: async (data, callback) => { callback(null, tokenRequest) } }) // Subscribe to admin interaction channel const userId = 'my-user-id' const channel = ably.channels.get(`interaction:${userId}`) await channel.subscribe((message) => { console.log('Admin notification:', message.data) }) ```
10615
10834
 
10835
+ ### secrets
10836
+
10837
+ **list**(collectionId: string, query: ListSecretsQuery = {}) → `Promise<SecretList>`
10838
+ List secrets as refs + masked hints + metadata (never values). GET /secrets
10839
+
10840
+ **set**(collectionId: string, input: SetSecretInput) → `Promise<SetSecretResult>`
10841
+ Create a secret. POST /secrets → { ref, hint }. Store the ref on a flow.
10842
+
10843
+ **get**(collectionId: string, ref: string) → `Promise<SecretMeta>`
10844
+ Metadata for one secret (never the value). GET /secrets/:ref
10845
+
10846
+ **rotate**(collectionId: string, ref: string, input: SetSecretInput) → `Promise<SetSecretResult>`
10847
+ Rotate/update a secret's value (and optionally name/purpose). PUT /secrets/:ref → { ref, hint }
10848
+
10849
+ **remove**(collectionId: string, ref: string) → `Promise<`
10850
+ Soft-delete a secret. DELETE /secrets/:ref
10851
+
10616
10852
  ### segments
10617
10853
 
10618
10854
  **create**(collectionId: string,
@@ -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` |