@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.
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/integrations.d.ts +28 -0
- package/dist/api/integrations.js +82 -0
- package/dist/api/secrets.d.ts +15 -0
- package/dist/api/secrets.js +52 -0
- package/dist/docs/API_SUMMARY.md +237 -1
- package/dist/docs/integrations.md +141 -0
- package/dist/openapi.yaml +270 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/integrations.d.ts +136 -0
- package/dist/types/integrations.js +10 -0
- package/docs/API_SUMMARY.md +237 -1
- package/docs/integrations.md +141 -0
- package/openapi.yaml +270 -0
- package/package.json +2 -2
package/dist/api/index.d.ts
CHANGED
|
@@ -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 = {}));
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.
|
|
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` |
|