@proveanything/smartlinks 2.1.14 → 2.1.16
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/claimSet.d.ts +9 -1
- package/dist/api/claimSet.js +15 -0
- package/dist/api/integrations.d.ts +28 -0
- package/dist/api/integrations.js +28 -0
- package/dist/docs/API_SUMMARY.md +81 -6
- package/dist/docs/connectors.md +56 -0
- package/dist/docs/integrations.md +8 -0
- package/dist/docs/server-functions.md +1 -0
- package/dist/docs/tag-ranges.md +21 -0
- package/dist/openapi.yaml +168 -1
- package/dist/types/appManifest.d.ts +23 -0
- package/dist/types/claimSet.d.ts +59 -8
- package/dist/types/integrations.d.ts +20 -0
- package/docs/API_SUMMARY.md +81 -6
- package/docs/connectors.md +56 -0
- package/docs/integrations.md +8 -0
- package/docs/server-functions.md +1 -0
- package/docs/tag-ranges.md +21 -0
- package/openapi.yaml +168 -1
- package/package.json +1 -1
package/dist/api/claimSet.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClaimSetScope, ClaimSetRange, CreateClaimSetRangeRequest, UpdateClaimSetRangeRequest, ClaimSetRangeTagsPage, ClaimSetRangeTag, ClaimSetRangeNextTag, ImportClaimSetRangeUidsRequest, ImportClaimSetRangeUidsResponse, AssignClaimSetRangeRequest, AssignClaimSetRangeResponse, ClaimSetRangeFile, UpdateClaimDataRequest, AssignClaimsRequest, CreateClaimSetTagRequest, CreateClaimSetTagResponse, CreateClaimSetRequest, ImportClaimSetTagsRequest, ImportClaimSetTagsResponse } from "../types/index.js";
|
|
1
|
+
import { ClaimSetScope, ClaimSetRange, CreateClaimSetRangeRequest, UpdateClaimSetRangeRequest, ClaimSetRangeTagsPage, ClaimSetRangeTag, ClaimSetRangeNextTag, ImportClaimSetRangeUidsRequest, ImportClaimSetRangeUidsResponse, AssignClaimSetRangeRequest, AddClaimSetRangeMemberRequest, AddClaimSetRangeMemberResponse, CloseClaimSetRangeResponse, AssignClaimSetRangeResponse, ClaimSetRangeFile, UpdateClaimDataRequest, AssignClaimsRequest, CreateClaimSetTagRequest, CreateClaimSetTagResponse, CreateClaimSetRequest, ImportClaimSetTagsRequest, ImportClaimSetTagsResponse } from "../types/index.js";
|
|
2
2
|
export declare namespace claimSet {
|
|
3
3
|
/**
|
|
4
4
|
* Get all claim sets.
|
|
@@ -106,6 +106,14 @@ export declare namespace claimSet {
|
|
|
106
106
|
function update(scope: ClaimSetScope, claimSetId: string, rangeId: string, params: UpdateClaimSetRangeRequest): Promise<ClaimSetRange>;
|
|
107
107
|
/** Finish minting a range that was interrupted. */
|
|
108
108
|
function resume(scope: ClaimSetScope, claimSetId: string, rangeId: string): Promise<ClaimSetRange>;
|
|
109
|
+
/** Close an open range: it becomes a range with the quantity it reached (removed if nothing was minted). */
|
|
110
|
+
function close(scope: ClaimSetScope, claimSetId: string, rangeId: string): Promise<CloseClaimSetRangeResponse>;
|
|
111
|
+
/** Put an existing tag of the set into a group (by code or chip UID), assigning it if a collection is given. */
|
|
112
|
+
function addMember(scope: ClaimSetScope, claimSetId: string, groupId: string, params: AddClaimSetRangeMemberRequest): Promise<AddClaimSetRangeMemberResponse>;
|
|
113
|
+
/** Take a tag out of a group. Its assignment is left as it is. */
|
|
114
|
+
function removeMember(scope: ClaimSetScope, claimSetId: string, groupId: string, code: string): Promise<{
|
|
115
|
+
range: ClaimSetRange;
|
|
116
|
+
}>;
|
|
109
117
|
/** The range's tags in index order, a page at a time (keys: owners/admins only). */
|
|
110
118
|
function tags(scope: ClaimSetScope, claimSetId: string, rangeId: string, options?: {
|
|
111
119
|
from?: number;
|
package/dist/api/claimSet.js
CHANGED
|
@@ -190,6 +190,21 @@ export var claimSet;
|
|
|
190
190
|
return post(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(rangeId)}/resume`, {});
|
|
191
191
|
}
|
|
192
192
|
ranges.resume = resume;
|
|
193
|
+
/** Close an open range: it becomes a range with the quantity it reached (removed if nothing was minted). */
|
|
194
|
+
async function close(scope, claimSetId, rangeId) {
|
|
195
|
+
return post(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(rangeId)}/close`, {});
|
|
196
|
+
}
|
|
197
|
+
ranges.close = close;
|
|
198
|
+
/** Put an existing tag of the set into a group (by code or chip UID), assigning it if a collection is given. */
|
|
199
|
+
async function addMember(scope, claimSetId, groupId, params) {
|
|
200
|
+
return post(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(groupId)}/members`, params);
|
|
201
|
+
}
|
|
202
|
+
ranges.addMember = addMember;
|
|
203
|
+
/** Take a tag out of a group. Its assignment is left as it is. */
|
|
204
|
+
async function removeMember(scope, claimSetId, groupId, code) {
|
|
205
|
+
return del(`${rangesBase(scope, claimSetId)}/${encodeURIComponent(groupId)}/members/${encodeURIComponent(code)}`);
|
|
206
|
+
}
|
|
207
|
+
ranges.removeMember = removeMember;
|
|
193
208
|
/** The range's tags in index order, a page at a time (keys: owners/admins only). */
|
|
194
209
|
async function tags(scope, claimSetId, rangeId, options = {}) {
|
|
195
210
|
const q = new URLSearchParams();
|
|
@@ -105,4 +105,32 @@ export declare namespace integrations {
|
|
|
105
105
|
function runConnectorStep<T = unknown>(collectionId: string, appId: string, step: ConnectorConsoleStep, input?: Record<string, unknown> & {
|
|
106
106
|
flowId?: string;
|
|
107
107
|
}): Promise<T>;
|
|
108
|
+
/**
|
|
109
|
+
* Invoke a connector ACTION from the console (any visibility): redeem, enrol, adjust points, issue a
|
|
110
|
+
* coupon… The connector's function runs with its own credentials and is told who asked.
|
|
111
|
+
* POST /integrations/connectors/:appId/actions/:action { input }
|
|
112
|
+
*/
|
|
113
|
+
function runConnectorAction<T = unknown>(collectionId: string, appId: string, action: string, input?: Record<string, unknown>): Promise<T>;
|
|
114
|
+
/**
|
|
115
|
+
* PUBLIC (the Hub, a site): the connector actions the caller may invoke — those declared `public`,
|
|
116
|
+
* plus `member` ones when signed in.
|
|
117
|
+
* GET /public/collection/:collectionId/connectors/:appId/actions
|
|
118
|
+
*/
|
|
119
|
+
function listConnectorActions(collectionId: string, appId: string): Promise<{
|
|
120
|
+
actions: Array<{
|
|
121
|
+
name: string;
|
|
122
|
+
title: string;
|
|
123
|
+
description?: string;
|
|
124
|
+
visibility: 'public' | 'member' | 'admin';
|
|
125
|
+
input?: Record<string, unknown>;
|
|
126
|
+
output?: Record<string, unknown>;
|
|
127
|
+
}>;
|
|
128
|
+
}>;
|
|
129
|
+
/**
|
|
130
|
+
* PUBLIC (the Hub, a site): invoke a connector action — e.g. redeem a reward for the signed-in member.
|
|
131
|
+
* 401 SIGN_IN_REQUIRED for a `member` action without a session; 403 for an admin-only one;
|
|
132
|
+
* 400 with `missing[]` when a required input is absent.
|
|
133
|
+
* POST /public/collection/:collectionId/connectors/:appId/actions/:action { input }
|
|
134
|
+
*/
|
|
135
|
+
function callConnectorAction<T = unknown>(collectionId: string, appId: string, action: string, input?: Record<string, unknown>): Promise<T>;
|
|
108
136
|
}
|
package/dist/api/integrations.js
CHANGED
|
@@ -200,4 +200,32 @@ export var integrations;
|
|
|
200
200
|
return post(`${connectorsBase(collectionId)}/${enc(appId)}/steps/${enc(step)}`, input);
|
|
201
201
|
}
|
|
202
202
|
integrations.runConnectorStep = runConnectorStep;
|
|
203
|
+
/**
|
|
204
|
+
* Invoke a connector ACTION from the console (any visibility): redeem, enrol, adjust points, issue a
|
|
205
|
+
* coupon… The connector's function runs with its own credentials and is told who asked.
|
|
206
|
+
* POST /integrations/connectors/:appId/actions/:action { input }
|
|
207
|
+
*/
|
|
208
|
+
async function runConnectorAction(collectionId, appId, action, input = {}) {
|
|
209
|
+
return post(`${connectorsBase(collectionId)}/${enc(appId)}/actions/${enc(action)}`, { input });
|
|
210
|
+
}
|
|
211
|
+
integrations.runConnectorAction = runConnectorAction;
|
|
212
|
+
/**
|
|
213
|
+
* PUBLIC (the Hub, a site): the connector actions the caller may invoke — those declared `public`,
|
|
214
|
+
* plus `member` ones when signed in.
|
|
215
|
+
* GET /public/collection/:collectionId/connectors/:appId/actions
|
|
216
|
+
*/
|
|
217
|
+
async function listConnectorActions(collectionId, appId) {
|
|
218
|
+
return request(`/public/collection/${enc(collectionId)}/connectors/${enc(appId)}/actions`);
|
|
219
|
+
}
|
|
220
|
+
integrations.listConnectorActions = listConnectorActions;
|
|
221
|
+
/**
|
|
222
|
+
* PUBLIC (the Hub, a site): invoke a connector action — e.g. redeem a reward for the signed-in member.
|
|
223
|
+
* 401 SIGN_IN_REQUIRED for a `member` action without a session; 403 for an admin-only one;
|
|
224
|
+
* 400 with `missing[]` when a required input is absent.
|
|
225
|
+
* POST /public/collection/:collectionId/connectors/:appId/actions/:action { input }
|
|
226
|
+
*/
|
|
227
|
+
async function callConnectorAction(collectionId, appId, action, input = {}) {
|
|
228
|
+
return post(`/public/collection/${enc(collectionId)}/connectors/${enc(appId)}/actions/${enc(action)}`, { input });
|
|
229
|
+
}
|
|
230
|
+
integrations.callConnectorAction = callConnectorAction;
|
|
203
231
|
})(integrations || (integrations = {}));
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.16 | Generated: 2026-11-10T17:19:48.505Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -65,7 +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), event patterns, the event envelope (interaction/contact/event sources), identity policy, event mapping, signed deliveries, contact as a target, field mappings
|
|
68
|
-
- **[Connectors](connectors.md)** - Connector apps (adapters for one external provider): a manifest `connector` block + server functions (testConnection/describeTarget/sample/fetch/shape/serialize/send/describeEvents/lookup); loyalty and CRM connectors; core does the mapping
|
|
68
|
+
- **[Connectors](connectors.md)** - Connector apps (adapters for one external provider): a manifest `connector` block + server functions (testConnection/describeTarget/sample/fetch/shape/serialize/send/describeEvents/lookup); loyalty and CRM connectors; actions (provider operations on demand); core does the mapping
|
|
69
69
|
- **[Entitlements](entitlements.md)** - "Is this person gold or above?" answered on demand from signed claims, a connector lookup (cached), or the contact — never a mirrored member base; gates on interaction types and in server functions
|
|
70
70
|
- **[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
|
|
71
71
|
- **[Deep Link Discovery](deep-link-discovery.md)** - Registering and discovering navigable app states for portal menus and AI orchestration
|
|
@@ -3112,6 +3112,19 @@ interface ConnectorPanel {
|
|
|
3112
3112
|
}
|
|
3113
3113
|
```
|
|
3114
3114
|
|
|
3115
|
+
**ConnectorAction** (interface)
|
|
3116
|
+
```typescript
|
|
3117
|
+
interface ConnectorAction {
|
|
3118
|
+
name: string
|
|
3119
|
+
title?: string
|
|
3120
|
+
description?: string
|
|
3121
|
+
function: string
|
|
3122
|
+
visibility?: 'admin' | 'member' | 'public'
|
|
3123
|
+
input?: Record<string, unknown>
|
|
3124
|
+
output?: Record<string, unknown>
|
|
3125
|
+
}
|
|
3126
|
+
```
|
|
3127
|
+
|
|
3115
3128
|
**AppConnectorDeclaration** (interface)
|
|
3116
3129
|
```typescript
|
|
3117
3130
|
interface AppConnectorDeclaration {
|
|
@@ -3134,6 +3147,7 @@ interface AppConnectorDeclaration {
|
|
|
3134
3147
|
lookup?: string
|
|
3135
3148
|
}
|
|
3136
3149
|
panels?: ConnectorPanel[]
|
|
3150
|
+
actions?: ConnectorAction[]
|
|
3137
3151
|
aiGuide?: string
|
|
3138
3152
|
recordId?: string
|
|
3139
3153
|
limits?: { requestsPerSecond?: number; maxEvents?: number; maxAttributes?: number }
|
|
@@ -5761,10 +5775,11 @@ interface ClaimSetRange {
|
|
|
5761
5775
|
id: string
|
|
5762
5776
|
claimSetId: string
|
|
5763
5777
|
namespace: string
|
|
5778
|
+
kind: ClaimSetRangeKind
|
|
5764
5779
|
name: string
|
|
5765
5780
|
notes: string | null
|
|
5766
|
-
startIndex: number
|
|
5767
|
-
endIndex: number
|
|
5781
|
+
startIndex: number | null
|
|
5782
|
+
endIndex: number | null
|
|
5768
5783
|
quantity: number
|
|
5769
5784
|
tagType: ClaimSetTagType
|
|
5770
5785
|
fulfilment: 'printer' | 'sidekick'
|
|
@@ -5787,8 +5802,9 @@ interface ClaimSetRange {
|
|
|
5787
5802
|
**CreateClaimSetRangeRequest** (interface)
|
|
5788
5803
|
```typescript
|
|
5789
5804
|
interface CreateClaimSetRangeRequest {
|
|
5805
|
+
kind?: ClaimSetRangeKind
|
|
5790
5806
|
name: string
|
|
5791
|
-
quantity
|
|
5807
|
+
quantity?: number
|
|
5792
5808
|
intendedCollectionId?: string
|
|
5793
5809
|
intendedProductId?: string
|
|
5794
5810
|
intendedBatchId?: string
|
|
@@ -5823,6 +5839,8 @@ interface ClaimSetRangeTag {
|
|
|
5823
5839
|
productId: string | null
|
|
5824
5840
|
batchId: string | null
|
|
5825
5841
|
proofId: string | null
|
|
5842
|
+
rangeId: string | null
|
|
5843
|
+
groupId: string | null
|
|
5826
5844
|
programmedAt: string | null
|
|
5827
5845
|
scans: number
|
|
5828
5846
|
}
|
|
@@ -5836,6 +5854,29 @@ interface ClaimSetRangeTagsPage {
|
|
|
5836
5854
|
}
|
|
5837
5855
|
```
|
|
5838
5856
|
|
|
5857
|
+
**AddClaimSetRangeMemberRequest** (interface)
|
|
5858
|
+
```typescript
|
|
5859
|
+
interface AddClaimSetRangeMemberRequest {
|
|
5860
|
+
code?: string
|
|
5861
|
+
uid?: string
|
|
5862
|
+
collectionId?: string
|
|
5863
|
+
productId?: string
|
|
5864
|
+
batchId?: string
|
|
5865
|
+
data?: Record<string, unknown>
|
|
5866
|
+
clear?: boolean
|
|
5867
|
+
}
|
|
5868
|
+
```
|
|
5869
|
+
|
|
5870
|
+
**AddClaimSetRangeMemberResponse** (interface)
|
|
5871
|
+
```typescript
|
|
5872
|
+
interface AddClaimSetRangeMemberResponse {
|
|
5873
|
+
tag: ClaimSetRangeTag
|
|
5874
|
+
range: ClaimSetRange
|
|
5875
|
+
assigned: { changed: number; skipped: Array<{ code: string; index: number | null; reason: 'other_range' | 'has_proof' | 'assigned_elsewhere'; collectionId?: string }> }
|
|
5876
|
+
movedFrom: string | null
|
|
5877
|
+
}
|
|
5878
|
+
```
|
|
5879
|
+
|
|
5839
5880
|
**ImportClaimSetRangeUidsRequest** (interface)
|
|
5840
5881
|
```typescript
|
|
5841
5882
|
interface ImportClaimSetRangeUidsRequest {
|
|
@@ -5944,7 +5985,11 @@ type ClaimSetScope = { collectionId: string }
|
|
|
5944
5985
|
|
|
5945
5986
|
**ClaimSetTagType** = `'ntag424' | 'ntag21x' | 'qr'`
|
|
5946
5987
|
|
|
5947
|
-
**
|
|
5988
|
+
**ClaimSetRangeKind** = `'range' | 'open' | 'group'`
|
|
5989
|
+
|
|
5990
|
+
**ClaimSetRangeStatus** = `'minting' | 'minted' | 'sent' | 'received' | 'assigned' | 'open' | 'group'`
|
|
5991
|
+
|
|
5992
|
+
**CloseClaimSetRangeResponse** = `ClaimSetRange | { id: string`
|
|
5948
5993
|
|
|
5949
5994
|
**ClaimSetImportResult** = ``
|
|
5950
5995
|
|
|
@@ -7980,6 +8025,7 @@ interface IntegrationFlowConfig {
|
|
|
7980
8025
|
signing?: { credentialRef: string; previousCredentialRef?: string }
|
|
7981
8026
|
identity?: { policy?: IdentityPolicy; hashKeyCredentialRef?: string }
|
|
7982
8027
|
eventMapping?: EventMapping
|
|
8028
|
+
envelopeFormat?: 'cloudevents'
|
|
7983
8029
|
connection?: FlowConnection
|
|
7984
8030
|
fieldMappings?: FieldMapping[]
|
|
7985
8031
|
connector?: FlowConnectorRef
|
|
@@ -8222,6 +8268,7 @@ interface ConnectorLookupResult {
|
|
|
8222
8268
|
**EventEnvelope** (interface)
|
|
8223
8269
|
```typescript
|
|
8224
8270
|
interface EventEnvelope {
|
|
8271
|
+
specVersion: number
|
|
8225
8272
|
id: string
|
|
8226
8273
|
type: string
|
|
8227
8274
|
entityType: string | null
|
|
@@ -8234,6 +8281,8 @@ interface EventEnvelope {
|
|
|
8234
8281
|
contactId: string | null
|
|
8235
8282
|
userId: string | null
|
|
8236
8283
|
externalIds: Record<string, string>
|
|
8284
|
+
anonymousId: string | null
|
|
8285
|
+
sessionId: string | null
|
|
8237
8286
|
emailHash?: string | null
|
|
8238
8287
|
phoneHash?: string | null
|
|
8239
8288
|
hashAlgorithm?: 'hmac-sha256' | null
|
|
@@ -8243,6 +8292,7 @@ interface EventEnvelope {
|
|
|
8243
8292
|
identityPolicy: IdentityPolicy
|
|
8244
8293
|
product: { id: string; name?: string | null; sku?: string | null; gtin?: string | null; variantId?: string | null; batchId?: string | null } | null
|
|
8245
8294
|
proof: { id: string } | null
|
|
8295
|
+
consent: { channels: Record<'email' | 'sms' | 'push' | 'whatsapp', 'opted_in' | 'opted_out' | 'suppressed' | 'unknown'>; topics: Record<string, boolean>; updatedAt: string | null } | null
|
|
8246
8296
|
subject: Record<string, unknown>
|
|
8247
8297
|
event?: { name: string; attributes: Record<string, unknown>; rule: string | null }
|
|
8248
8298
|
attributes: Record<string, unknown>
|
|
@@ -12445,6 +12495,15 @@ Name, notes, order details, or a stage move (sent to the printer, received).
|
|
|
12445
12495
|
**resume**(scope: ClaimSetScope, claimSetId: string, rangeId: string) → `Promise<ClaimSetRange>`
|
|
12446
12496
|
Finish minting a range that was interrupted.
|
|
12447
12497
|
|
|
12498
|
+
**close**(scope: ClaimSetScope, claimSetId: string, rangeId: string) → `Promise<CloseClaimSetRangeResponse>`
|
|
12499
|
+
Close an open range: it becomes a range with the quantity it reached (removed if nothing was minted).
|
|
12500
|
+
|
|
12501
|
+
**addMember**(scope: ClaimSetScope, claimSetId: string, groupId: string, params: AddClaimSetRangeMemberRequest) → `Promise<AddClaimSetRangeMemberResponse>`
|
|
12502
|
+
Put an existing tag of the set into a group (by code or chip UID), assigning it if a collection is given.
|
|
12503
|
+
|
|
12504
|
+
**removeMember**(scope: ClaimSetScope, claimSetId: string, groupId: string, code: string) → `Promise<`
|
|
12505
|
+
Take a tag out of a group. Its assignment is left as it is.
|
|
12506
|
+
|
|
12448
12507
|
**tags**(scope: ClaimSetScope, claimSetId: string, rangeId: string,
|
|
12449
12508
|
options: { from?: number; limit?: number; keys?: boolean } = {}) → `Promise<ClaimSetRangeTagsPage>`
|
|
12450
12509
|
The range's tags in index order, a page at a time (keys: owners/admins only).
|
|
@@ -12984,6 +13043,22 @@ Save a connector's non-secret Connect-form values and/or settings. PUT /integrat
|
|
|
12984
13043
|
input: Record<string, unknown> & { flowId?: string } = {}) → `Promise<T>`
|
|
12985
13044
|
Run a connector step from the console: `testConnection` → ConnectorTestResult, `describeTarget` → ConnectorTargetSchema, `sample` → ConnectorRecords, and dry runs of `shape` ({ records }) → ConnectorShapeResult and `serialize` ({ documents }) → ConnectorSerializeResult. The server adds the installation; pass `flowId` to layer that flow's settings. POST /integrations/connectors/:appId/steps/:step
|
|
12986
13045
|
|
|
13046
|
+
**runConnectorAction**(collectionId: string,
|
|
13047
|
+
appId: string,
|
|
13048
|
+
action: string,
|
|
13049
|
+
input: Record<string, unknown> = {}) → `Promise<T>`
|
|
13050
|
+
Invoke a connector ACTION from the console (any visibility): redeem, enrol, adjust points, issue a coupon… The connector's function runs with its own credentials and is told who asked. POST /integrations/connectors/:appId/actions/:action { input }
|
|
13051
|
+
|
|
13052
|
+
**listConnectorActions**(collectionId: string,
|
|
13053
|
+
appId: string) → `Promise<`
|
|
13054
|
+
PUBLIC (the Hub, a site): the connector actions the caller may invoke — those declared `public`, plus `member` ones when signed in. GET /public/collection/:collectionId/connectors/:appId/actions
|
|
13055
|
+
|
|
13056
|
+
**callConnectorAction**(collectionId: string,
|
|
13057
|
+
appId: string,
|
|
13058
|
+
action: string,
|
|
13059
|
+
input: Record<string, unknown> = {}) → `Promise<T>`
|
|
13060
|
+
PUBLIC (the Hub, a site): invoke a connector action — e.g. redeem a reward for the signed-in member. 401 SIGN_IN_REQUIRED for a `member` action without a session; 403 for an admin-only one; 400 with `missing[]` when a required input is absent. POST /public/collection/:collectionId/connectors/:appId/actions/:action { input }
|
|
13061
|
+
|
|
12987
13062
|
### interactions
|
|
12988
13063
|
|
|
12989
13064
|
**query**(collectionId: string,
|
package/dist/docs/connectors.md
CHANGED
|
@@ -92,6 +92,7 @@ Types: `AppConnectorDeclaration` and friends in `@proveanything/smartlinks` (`sr
|
|
|
92
92
|
| `aiGuide` | A guide the mapping assistant reads: the provider's quirks, required fields, good defaults. |
|
|
93
93
|
| `recordId` | Path of the provider's own id in a fetched record (e.g. `gtin`). Inbound records are landed and matched by it, so a re-import updates the same product instead of creating another. Default `id`; a flow can override it (`config.upsert.externalIdPath`). |
|
|
94
94
|
| `limits` | `{ requestsPerSecond }` toward the provider, enforced across every SmartLinks worker; `{ maxEvents, maxAttributes }` when the provider caps registered events — a flow's `eventMapping` is checked against them when saved. |
|
|
95
|
+
| `actions[]` | Provider operations invoked on demand (redeem, enrol, issue…): name, title, function, `visibility`, input schema. See [Actions](#actions-provider-operations-on-demand). |
|
|
95
96
|
|
|
96
97
|
---
|
|
97
98
|
|
|
@@ -219,6 +220,61 @@ A connector should ship an `eventMapping` **preset** with the provider's standar
|
|
|
219
220
|
|
|
220
221
|
---
|
|
221
222
|
|
|
223
|
+
## Actions: provider operations on demand
|
|
224
|
+
|
|
225
|
+
Steps are called by the engine. **Actions** are called when someone asks: redeem a reward, enrol a
|
|
226
|
+
member, issue a coupon, raise a ticket, send a receipt, check a balance. A connector declares them in
|
|
227
|
+
the manifest and implements each as a server function; the platform decides who may call them and
|
|
228
|
+
runs them with the connector's credentials, telling the function who asked.
|
|
229
|
+
|
|
230
|
+
```jsonc
|
|
231
|
+
"connector": {
|
|
232
|
+
"actions": [
|
|
233
|
+
{ "name": "redeem", "title": "Redeem a reward", "function": "redeemReward", "visibility": "member",
|
|
234
|
+
"input": { "type": "object", "required": ["rewardId"], "properties": { "rewardId": { "type": "string" } } } },
|
|
235
|
+
{ "name": "enrol", "title": "Join the programme", "function": "enrolMember", "visibility": "member" },
|
|
236
|
+
{ "name": "coupon-status", "title": "Coupon status", "function": "couponStatus", "visibility": "public" },
|
|
237
|
+
{ "name": "adjust-points", "title": "Adjust points", "function": "adjustPoints" } // admin only (the default)
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
| `visibility` | Who may invoke it |
|
|
243
|
+
|---|---|
|
|
244
|
+
| `admin` (default) | the console and admin API; any app function |
|
|
245
|
+
| `member` | also a signed-in person through the Hub / a site |
|
|
246
|
+
| `public` | also anyone |
|
|
247
|
+
|
|
248
|
+
The function receives `event.body = { input, installation, caller: { userId, contactId, role, surface } }`
|
|
249
|
+
and returns JSON (or a `Response`). `input.required` fields from the declared schema are checked before
|
|
250
|
+
the function runs (400 with `missing[]`); fuller validation is the connector's job.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
export async function redeemReward(ctx: any, event: any) {
|
|
254
|
+
const { input, caller } = event.body
|
|
255
|
+
if (!caller.contactId) return new Response(JSON.stringify({ error: 'no_contact' }), { status: 400 })
|
|
256
|
+
const memberId = (await ctx.sl.contacts.forCaller())?.customFields?.loyaltyMemberId // written by Profile
|
|
257
|
+
const res = await ctx.fetch(`${api}/members/${memberId}/redemptions`, { method: 'POST', headers: auth(await ctx.secrets.get('apiKey')), body: JSON.stringify({ reward: input.rewardId }) })
|
|
258
|
+
return res.json()
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Calling an action:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
// From the Hub or a site (visibility public / member):
|
|
266
|
+
const { actions } = await integrations.listConnectorActions(collectionId, 'acme-loyalty')
|
|
267
|
+
const out = await integrations.callConnectorAction(collectionId, 'acme-loyalty', 'redeem', { rewardId: 'R-5' })
|
|
268
|
+
|
|
269
|
+
// From another app's server function (any visibility; needs sl:connectors:write):
|
|
270
|
+
const out = await ctx.sl.connectors.call('acme-loyalty', 'redeem', { rewardId: 'R-5' })
|
|
271
|
+
|
|
272
|
+
// From the console (any visibility):
|
|
273
|
+
await integrations.runConnectorAction(collectionId, 'acme-loyalty', 'adjust-points', { memberId, delta: 100 })
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
222
278
|
## Where configuration lives
|
|
223
279
|
|
|
224
280
|
| What | Where |
|
|
@@ -118,6 +118,7 @@ mapped with the flow's field mappings (or handed to a connector's `serialize`):
|
|
|
118
118
|
|
|
119
119
|
```jsonc
|
|
120
120
|
{
|
|
121
|
+
"specVersion": 1, // bumped only when a consumer could break
|
|
121
122
|
"id": "0b2b…", // the event's id — stable across retries; use it as the destination's idempotency / transaction id
|
|
122
123
|
"type": "interaction.submitted:quiz-1",
|
|
123
124
|
"entityType": "interaction", "entityId": "0b2b…",
|
|
@@ -126,12 +127,14 @@ mapped with the flow's field mappings (or handed to a connector's `serialize`):
|
|
|
126
127
|
"identity": {
|
|
127
128
|
"contactId": "…", "userId": "…",
|
|
128
129
|
"externalIds": { "acme-loyalty": "M-9", "crm": "C-1" }, // ids other systems know this person by
|
|
130
|
+
"anonymousId": "v-77", "sessionId": "s-1", // the visitor / device and session, before anyone signed in (every policy)
|
|
129
131
|
"emailHash": "…", "phoneHash": "…", "hashAlgorithm": "hmac-sha256" // policy 'hashed' (default)
|
|
130
132
|
// "email", "phone": only under policy 'raw'
|
|
131
133
|
},
|
|
132
134
|
"identityPolicy": "hashed",
|
|
133
135
|
"product": { "id": "P1", "name": "Widget", "sku": "W-1", "gtin": "0500…", "variantId": null, "batchId": null },
|
|
134
136
|
"proof": { "id": "…" },
|
|
137
|
+
"consent": { "channels": { "email": "opted_in", "sms": "suppressed", "push": "unknown", "whatsapp": "unknown" }, "topics": { "offers": true }, "updatedAt": "…" }, // null when about nobody we hold
|
|
135
138
|
"subject": { "interactionId": "quiz-1", "outcome": "completed", "metadata": { "score": 9 }, "source": "hub" },
|
|
136
139
|
"event": { "name": "engagement_completed", "attributes": { "kind": "quiz", "score": 9 }, "rule": "quiz" }, // from eventMapping
|
|
137
140
|
"attributes": {}
|
|
@@ -142,6 +145,11 @@ Field mappings read envelope paths (`identity.externalIds.acme-loyalty`, `subjec
|
|
|
142
145
|
`event.name`, `product.sku`). With no mappings the envelope itself is sent. A failed event delivery
|
|
143
146
|
keeps its envelope and is retried from it; a product is re-read instead.
|
|
144
147
|
|
|
148
|
+
**CloudEvents.** `config.envelopeFormat: 'cloudevents'` wraps each delivered body (mapped or not) as a
|
|
149
|
+
CloudEvents 1.0 structured event — `{ specversion: '1.0', id, type, source: 'urn:smartlinks:collection:<id>',
|
|
150
|
+
subject, time, datacontenttype, dataschema: 'urn:smartlinks:envelope:v1', data }` — the shape every event
|
|
151
|
+
bus, lake and serverless tool already consumes.
|
|
152
|
+
|
|
145
153
|
```ts
|
|
146
154
|
const flow = await integrations.createFlow(collectionId, {
|
|
147
155
|
appId: 'core-integrations', direction: 'outbound', name: 'Engagement → loyalty', status: 'active',
|
|
@@ -518,6 +518,7 @@ Prefer the platform primitives above over a dependency; when you do need one, pi
|
|
|
518
518
|
| Put a visitor's details on a contact | `ctx.sl.contacts.upsert({ email, firstName, … })` → `{ contactId, created }` (fills empty fields only) | `sl:contacts:write` |
|
|
519
519
|
| Record "they did X" | `ctx.sl.interactions.record({ interactionId, contactId, outcome, metadata })` | `sl:interactions:write` |
|
|
520
520
|
| Land a loyalty / CRM provider's view of a person (member id, tier, points, tags, external ids) | `ctx.sl.members.apply({ identity, contact?, loyalty?, tags?, externalIds? }, { provider })` → `{ contactId, op }` — matches by id, external id, email or phone; profile fields fill-empty only; see [connectors.md](connectors.md#loyalty-and-crm-connectors) | `sl:members:write` |
|
|
521
|
+
| Invoke a connector's action — redeem, enrol, issue a coupon, raise a ticket — with the connector's credentials | `ctx.sl.connectors.call('acme-loyalty', 'redeem', { rewardId })` → the action's result; `ctx.sl.connectors.actions(appId)` lists them; see [connectors.md](connectors.md#actions-provider-operations-on-demand) | `sl:connectors:write` |
|
|
521
522
|
| Ask "is this person gold or above?" without holding their member record | `ctx.sl.entitlements.check('tier>=gold')` → `{ allowed, basis, asOf, attributes }` for the signed-in caller (or `{ identity, token, fallback }`); see [entitlements.md](entitlements.md) | `sl:entitlements:read` |
|
|
522
523
|
| Take a booking with your own checks (hours, queue token, payment) | `ctx.sl.bookings.create({ slotId \| resource + time, contactId, status, idempotencyKey })` — never oversold, never double-booked; also `confirm` / `cancel` / `move` / `mine` / `freebusy` / `message` (everyone booked, hydrated) / `slots.*` / `blocks.*` (see [bookings.md](bookings.md)) | `sl:bookings:write` (`sl:bookings:read` to read) |
|
|
523
524
|
|
package/dist/docs/tag-ranges.md
CHANGED
|
@@ -55,6 +55,27 @@ tag without a chip, with its URL and key; write it, then `ranges.recordTag(scope
|
|
|
55
55
|
|
|
56
56
|
To find where a chip or code went, `partner.lookupTags(partner.id, { uid })` or `{ code }` searches every set the partner owns and returns each hit's set, tag and range, never a key.
|
|
57
57
|
|
|
58
|
+
## Open ranges and groups
|
|
59
|
+
|
|
60
|
+
A range's count is fixed when it is minted. Two phone-side jobs don't know their count in advance, so a range
|
|
61
|
+
has a `kind`:
|
|
62
|
+
|
|
63
|
+
- **`open`**: blank tags programmed on Sidekick one at a time. `ranges.create(scope, set.id, { kind: 'open', name })`
|
|
64
|
+
reserves only a start index; each `ranges.next()` hands back a free minted code or mints one more, so
|
|
65
|
+
`quantity`/`endIndex` grow as tags are written (`remaining` is null). One open range per set, and nothing can
|
|
66
|
+
be minted behind it (`409 RANGE_OPEN`) until `ranges.close(scope, set.id, range.id)` turns it into an ordinary
|
|
67
|
+
range (an open range that minted nothing is removed instead).
|
|
68
|
+
- **`group`**: tags that already exist, added by tapping, assigned by hand, and moved together later. Assigners may
|
|
69
|
+
make one: `ranges.create(scope, set.id, { kind: 'group', name, intendedCollectionId? })`. Each tap goes through
|
|
70
|
+
`ranges.addMember(scope, set.id, group.id, { code | uid, collectionId, productId? })`, which stamps the tag with
|
|
71
|
+
the group and assigns it with the single-tag rules; `assigned.skipped` says when a tag was left alone (claimed,
|
|
72
|
+
or in a collection you don't administer). `ranges.assign(scope, set.id, group.id, { collectionId })` moves every
|
|
73
|
+
member in one go; `ranges.removeMember` takes one out. Groups have no printer file, instructions, import or
|
|
74
|
+
`next` (`400 NOT_A_RANGE`). Its tags must be codes of the group's set; a chip that is a code elsewhere is
|
|
75
|
+
`409 OTHER_SET`.
|
|
76
|
+
|
|
77
|
+
Status reads `open` or `group` for these (and `assigned` once every member of a group is assigned).
|
|
78
|
+
|
|
58
79
|
## The printer file
|
|
59
80
|
|
|
60
81
|
One row per tag, in index order. The manufacturer fills in `UID` and sends the same file back; rows are
|