@proveanything/smartlinks 2.1.12 → 2.1.14
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/authKit.d.ts +17 -1
- package/dist/api/authKit.js +24 -0
- package/dist/docs/API_SUMMARY.md +120 -7
- package/dist/docs/auth-kit.md +50 -0
- package/dist/docs/connectors.md +42 -4
- package/dist/docs/entitlements.md +90 -0
- package/dist/docs/integrations.md +159 -9
- package/dist/docs/interactions.md +545 -540
- package/dist/docs/loyalty.md +17 -0
- package/dist/docs/server-functions.md +2 -0
- package/dist/openapi.yaml +258 -2
- package/dist/types/appManifest.d.ts +19 -1
- package/dist/types/authKit.d.ts +45 -1
- package/dist/types/integrations.d.ts +148 -3
- package/docs/API_SUMMARY.md +120 -7
- package/docs/auth-kit.md +50 -0
- package/docs/connectors.md +42 -4
- package/docs/entitlements.md +90 -0
- package/docs/integrations.md +159 -9
- package/docs/interactions.md +545 -540
- package/docs/loyalty.md +17 -0
- package/docs/server-functions.md +2 -0
- package/openapi.yaml +258 -2
- package/package.json +87 -87
package/dist/docs/loyalty.md
CHANGED
|
@@ -302,6 +302,23 @@ A loyalty failure never causes the interaction event to fail — errors are caug
|
|
|
302
302
|
|
|
303
303
|
---
|
|
304
304
|
|
|
305
|
+
## External loyalty platforms
|
|
306
|
+
|
|
307
|
+
The schemes above are SmartLinks' own points. When a brand runs its programme on an external loyalty or
|
|
308
|
+
engagement platform, the platform stays the record of truth and SmartLinks connects to it through a
|
|
309
|
+
**connector app** and the integration engine — no member base is mirrored here:
|
|
310
|
+
|
|
311
|
+
| Flow | How |
|
|
312
|
+
|---|---|
|
|
313
|
+
| **Earn** — what happens on a pack or in a Hub awards points there | an outbound flow with `sourceEntity: 'interaction' \| 'event'`, an `eventMapping` onto the provider's registered events, signed delivery, retries — [integrations.md](integrations.md#event-sourced-flows-and-the-envelope) |
|
|
314
|
+
| **Profile** — member id, tier and points on the contact | the connector's webhook function calls `ctx.sl.members.apply(...)`; the contact gets `customFields.loyalty` and flat `loyaltyTier / loyaltyPoints / loyaltyMemberId`, usable in segments and comms targeting — [connectors.md](connectors.md#loyalty-and-crm-connectors) |
|
|
315
|
+
| **Gate / display** — "Gold members only", live balance | the entitlement check, answered on demand from a signed claim, the connector's cached `lookup`, or the contact's fields — [entitlements.md](entitlements.md) |
|
|
316
|
+
|
|
317
|
+
A collection runs one loyalty source: the native schemes here, or an external provider through a
|
|
318
|
+
connector.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
305
322
|
## TypeScript Types
|
|
306
323
|
|
|
307
324
|
```typescript
|
|
@@ -517,6 +517,8 @@ Prefer the platform primitives above over a dependency; when you do need one, pi
|
|
|
517
517
|
| Check a tapped tag is real | `ctx.sl.tags.resolve(proofId)` → `{ id, claimSetId, code }` or `null` | `sl:tags:read` |
|
|
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
|
+
| 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
|
+
| 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` |
|
|
520
522
|
| 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) |
|
|
521
523
|
|
|
522
524
|
Notes:
|
package/dist/openapi.yaml
CHANGED
|
@@ -9641,6 +9641,38 @@ paths:
|
|
|
9641
9641
|
description: Unauthorized
|
|
9642
9642
|
404:
|
|
9643
9643
|
description: Not found
|
|
9644
|
+
/authkit/{clientId}/auth/microsoft:
|
|
9645
|
+
post:
|
|
9646
|
+
tags:
|
|
9647
|
+
- authKit
|
|
9648
|
+
summary: authKit.microsoftLogin
|
|
9649
|
+
operationId: authKit_microsoftLogin
|
|
9650
|
+
security: []
|
|
9651
|
+
parameters:
|
|
9652
|
+
- name: clientId
|
|
9653
|
+
in: path
|
|
9654
|
+
required: true
|
|
9655
|
+
schema:
|
|
9656
|
+
type: string
|
|
9657
|
+
responses:
|
|
9658
|
+
200:
|
|
9659
|
+
description: Success
|
|
9660
|
+
content:
|
|
9661
|
+
application/json:
|
|
9662
|
+
schema:
|
|
9663
|
+
$ref: "#/components/schemas/AuthLoginResponse"
|
|
9664
|
+
400:
|
|
9665
|
+
description: Bad request
|
|
9666
|
+
401:
|
|
9667
|
+
description: Unauthorized
|
|
9668
|
+
404:
|
|
9669
|
+
description: Not found
|
|
9670
|
+
requestBody:
|
|
9671
|
+
required: true
|
|
9672
|
+
content:
|
|
9673
|
+
application/json:
|
|
9674
|
+
schema:
|
|
9675
|
+
$ref: "#/components/schemas/MicrosoftLoginOptions"
|
|
9644
9676
|
/authkit/{clientId}/auth/phone/send-code:
|
|
9645
9677
|
post:
|
|
9646
9678
|
tags:
|
|
@@ -21248,6 +21280,10 @@ components:
|
|
|
21248
21280
|
type: string
|
|
21249
21281
|
fetch:
|
|
21250
21282
|
type: string
|
|
21283
|
+
describeEvents:
|
|
21284
|
+
type: string
|
|
21285
|
+
lookup:
|
|
21286
|
+
type: string
|
|
21251
21287
|
panels:
|
|
21252
21288
|
type: array
|
|
21253
21289
|
items:
|
|
@@ -23933,6 +23969,35 @@ components:
|
|
|
23933
23969
|
additionalProperties: true
|
|
23934
23970
|
required:
|
|
23935
23971
|
- success
|
|
23972
|
+
MicrosoftLoginOptions:
|
|
23973
|
+
type: object
|
|
23974
|
+
properties:
|
|
23975
|
+
returnOrigin:
|
|
23976
|
+
type: string
|
|
23977
|
+
trustedDeviceToken:
|
|
23978
|
+
type: string
|
|
23979
|
+
AuthKitAccess:
|
|
23980
|
+
type: object
|
|
23981
|
+
properties:
|
|
23982
|
+
mode:
|
|
23983
|
+
type: string
|
|
23984
|
+
enum:
|
|
23985
|
+
- anyone
|
|
23986
|
+
- organisation
|
|
23987
|
+
domains:
|
|
23988
|
+
type: array
|
|
23989
|
+
items:
|
|
23990
|
+
type: string
|
|
23991
|
+
emails:
|
|
23992
|
+
type: array
|
|
23993
|
+
items:
|
|
23994
|
+
type: string
|
|
23995
|
+
microsoftTenants:
|
|
23996
|
+
type: object
|
|
23997
|
+
additionalProperties:
|
|
23998
|
+
type: string
|
|
23999
|
+
required:
|
|
24000
|
+
- mode
|
|
23936
24001
|
AppleLoginOptions:
|
|
23937
24002
|
type: object
|
|
23938
24003
|
properties:
|
|
@@ -24449,6 +24514,10 @@ components:
|
|
|
24449
24514
|
enum:
|
|
24450
24515
|
- open
|
|
24451
24516
|
- invite
|
|
24517
|
+
access:
|
|
24518
|
+
$ref: "#/components/schemas/AuthKitAccess"
|
|
24519
|
+
microsoftClientId:
|
|
24520
|
+
type: string
|
|
24452
24521
|
required:
|
|
24453
24522
|
- id
|
|
24454
24523
|
AuthKitInviteRequest:
|
|
@@ -24581,6 +24650,7 @@ components:
|
|
|
24581
24650
|
- ACCOUNT_EXISTS_UNVERIFIED
|
|
24582
24651
|
- APPLE_AUTH_FAILED
|
|
24583
24652
|
- SIGN_UP_CLOSED
|
|
24653
|
+
- NOT_IN_ORGANISATION
|
|
24584
24654
|
MfaFactor:
|
|
24585
24655
|
type: string
|
|
24586
24656
|
enum:
|
|
@@ -28948,9 +29018,48 @@ components:
|
|
|
28948
29018
|
additionalProperties: true
|
|
28949
29019
|
required:
|
|
28950
29020
|
- appId
|
|
29021
|
+
EventMappingRule:
|
|
29022
|
+
type: object
|
|
29023
|
+
properties:
|
|
29024
|
+
id:
|
|
29025
|
+
type: string
|
|
29026
|
+
match:
|
|
29027
|
+
type: object
|
|
29028
|
+
additionalProperties: true
|
|
29029
|
+
event:
|
|
29030
|
+
type: string
|
|
29031
|
+
attributes:
|
|
29032
|
+
type: object
|
|
29033
|
+
additionalProperties:
|
|
29034
|
+
type: object
|
|
29035
|
+
additionalProperties: true
|
|
29036
|
+
required:
|
|
29037
|
+
- event
|
|
29038
|
+
EventMapping:
|
|
29039
|
+
type: object
|
|
29040
|
+
properties:
|
|
29041
|
+
rules:
|
|
29042
|
+
type: array
|
|
29043
|
+
items:
|
|
29044
|
+
$ref: "#/components/schemas/EventMappingRule"
|
|
29045
|
+
unmatched:
|
|
29046
|
+
type: string
|
|
29047
|
+
enum:
|
|
29048
|
+
- skip
|
|
29049
|
+
- passthrough
|
|
29050
|
+
required:
|
|
29051
|
+
- rules
|
|
28951
29052
|
IntegrationFlowConfig:
|
|
28952
29053
|
type: object
|
|
28953
29054
|
properties:
|
|
29055
|
+
signing:
|
|
29056
|
+
type: object
|
|
29057
|
+
additionalProperties: true
|
|
29058
|
+
identity:
|
|
29059
|
+
type: object
|
|
29060
|
+
additionalProperties: true
|
|
29061
|
+
eventMapping:
|
|
29062
|
+
$ref: "#/components/schemas/EventMapping"
|
|
28954
29063
|
connection:
|
|
28955
29064
|
$ref: "#/components/schemas/FlowConnection"
|
|
28956
29065
|
fieldMappings:
|
|
@@ -28983,9 +29092,11 @@ components:
|
|
|
28983
29092
|
schedule:
|
|
28984
29093
|
type: string
|
|
28985
29094
|
sourceEntity:
|
|
28986
|
-
type:
|
|
29095
|
+
type: object
|
|
29096
|
+
additionalProperties: true
|
|
28987
29097
|
targetEntity:
|
|
28988
|
-
type:
|
|
29098
|
+
type: object
|
|
29099
|
+
additionalProperties: true
|
|
28989
29100
|
config:
|
|
28990
29101
|
$ref: "#/components/schemas/IntegrationFlowConfig"
|
|
28991
29102
|
createdBy:
|
|
@@ -29358,6 +29469,131 @@ components:
|
|
|
29358
29469
|
settings:
|
|
29359
29470
|
type: object
|
|
29360
29471
|
additionalProperties: true
|
|
29472
|
+
ConnectorEventsSchema:
|
|
29473
|
+
type: object
|
|
29474
|
+
properties:
|
|
29475
|
+
events:
|
|
29476
|
+
type: array
|
|
29477
|
+
items:
|
|
29478
|
+
type: object
|
|
29479
|
+
additionalProperties: true
|
|
29480
|
+
limits:
|
|
29481
|
+
type: object
|
|
29482
|
+
additionalProperties: true
|
|
29483
|
+
required:
|
|
29484
|
+
- events
|
|
29485
|
+
ConnectorLookupInput:
|
|
29486
|
+
type: object
|
|
29487
|
+
properties:
|
|
29488
|
+
installation:
|
|
29489
|
+
$ref: "#/components/schemas/ConnectorInstallation"
|
|
29490
|
+
identity:
|
|
29491
|
+
type: object
|
|
29492
|
+
additionalProperties: true
|
|
29493
|
+
want:
|
|
29494
|
+
type: array
|
|
29495
|
+
items:
|
|
29496
|
+
type: string
|
|
29497
|
+
required:
|
|
29498
|
+
- installation
|
|
29499
|
+
- identity
|
|
29500
|
+
ConnectorLookupResult:
|
|
29501
|
+
type: object
|
|
29502
|
+
properties:
|
|
29503
|
+
found:
|
|
29504
|
+
type: boolean
|
|
29505
|
+
memberId:
|
|
29506
|
+
type: string
|
|
29507
|
+
tier:
|
|
29508
|
+
type: string
|
|
29509
|
+
points:
|
|
29510
|
+
type: number
|
|
29511
|
+
status:
|
|
29512
|
+
type: string
|
|
29513
|
+
attributes:
|
|
29514
|
+
type: object
|
|
29515
|
+
additionalProperties: true
|
|
29516
|
+
asOf:
|
|
29517
|
+
type: string
|
|
29518
|
+
required:
|
|
29519
|
+
- found
|
|
29520
|
+
EventEnvelope:
|
|
29521
|
+
type: object
|
|
29522
|
+
properties:
|
|
29523
|
+
id:
|
|
29524
|
+
type: string
|
|
29525
|
+
type:
|
|
29526
|
+
type: string
|
|
29527
|
+
entityType:
|
|
29528
|
+
type: string
|
|
29529
|
+
entityId:
|
|
29530
|
+
type: string
|
|
29531
|
+
occurredAt:
|
|
29532
|
+
type: string
|
|
29533
|
+
collectionId:
|
|
29534
|
+
type: string
|
|
29535
|
+
orgId:
|
|
29536
|
+
type: string
|
|
29537
|
+
appId:
|
|
29538
|
+
type: string
|
|
29539
|
+
identity:
|
|
29540
|
+
type: object
|
|
29541
|
+
additionalProperties: true
|
|
29542
|
+
contactId:
|
|
29543
|
+
type: string
|
|
29544
|
+
userId:
|
|
29545
|
+
type: string
|
|
29546
|
+
externalIds:
|
|
29547
|
+
type: object
|
|
29548
|
+
additionalProperties:
|
|
29549
|
+
type: string
|
|
29550
|
+
emailHash:
|
|
29551
|
+
type: string
|
|
29552
|
+
phoneHash:
|
|
29553
|
+
type: string
|
|
29554
|
+
hashAlgorithm:
|
|
29555
|
+
type: string
|
|
29556
|
+
enum:
|
|
29557
|
+
- hmac-sha256
|
|
29558
|
+
email:
|
|
29559
|
+
type: string
|
|
29560
|
+
phone:
|
|
29561
|
+
type: string
|
|
29562
|
+
identityPolicy:
|
|
29563
|
+
$ref: "#/components/schemas/IdentityPolicy"
|
|
29564
|
+
product:
|
|
29565
|
+
type: object
|
|
29566
|
+
additionalProperties: true
|
|
29567
|
+
proof:
|
|
29568
|
+
type: object
|
|
29569
|
+
additionalProperties: true
|
|
29570
|
+
subject:
|
|
29571
|
+
type: object
|
|
29572
|
+
additionalProperties: true
|
|
29573
|
+
event:
|
|
29574
|
+
type: object
|
|
29575
|
+
additionalProperties: true
|
|
29576
|
+
attributes:
|
|
29577
|
+
type: object
|
|
29578
|
+
additionalProperties: true
|
|
29579
|
+
required:
|
|
29580
|
+
- id
|
|
29581
|
+
- type
|
|
29582
|
+
- entityType
|
|
29583
|
+
- entityId
|
|
29584
|
+
- occurredAt
|
|
29585
|
+
- collectionId
|
|
29586
|
+
- orgId
|
|
29587
|
+
- appId
|
|
29588
|
+
- identity
|
|
29589
|
+
- contactId
|
|
29590
|
+
- userId
|
|
29591
|
+
- externalIds
|
|
29592
|
+
- identityPolicy
|
|
29593
|
+
- product
|
|
29594
|
+
- proof
|
|
29595
|
+
- subject
|
|
29596
|
+
- attributes
|
|
29361
29597
|
CapturedRequest:
|
|
29362
29598
|
type: object
|
|
29363
29599
|
properties:
|
|
@@ -29697,6 +29933,24 @@ components:
|
|
|
29697
29933
|
- webhook
|
|
29698
29934
|
- oauth2
|
|
29699
29935
|
- none
|
|
29936
|
+
IdentityPolicy:
|
|
29937
|
+
type: string
|
|
29938
|
+
enum:
|
|
29939
|
+
- externalIds
|
|
29940
|
+
- hashed
|
|
29941
|
+
- raw
|
|
29942
|
+
FlowSourceEntity:
|
|
29943
|
+
type: string
|
|
29944
|
+
enum:
|
|
29945
|
+
- product
|
|
29946
|
+
- interaction
|
|
29947
|
+
- contact
|
|
29948
|
+
- event
|
|
29949
|
+
FlowTargetEntity:
|
|
29950
|
+
type: string
|
|
29951
|
+
enum:
|
|
29952
|
+
- product
|
|
29953
|
+
- contact
|
|
29700
29954
|
UpdateFlowInput:
|
|
29701
29955
|
$ref: "#/components/schemas/CreateFlowInput"
|
|
29702
29956
|
ConnectorConsoleStep:
|
|
@@ -29707,6 +29961,8 @@ components:
|
|
|
29707
29961
|
- sample
|
|
29708
29962
|
- shape
|
|
29709
29963
|
- serialize
|
|
29964
|
+
- describeEvents
|
|
29965
|
+
- lookup
|
|
29710
29966
|
RunTrigger:
|
|
29711
29967
|
type: string
|
|
29712
29968
|
enum:
|
|
@@ -1078,6 +1078,18 @@ export interface AppConnectorDeclaration {
|
|
|
1078
1078
|
send?: string;
|
|
1079
1079
|
/** (ConnectorFetchInput) → ConnectorRecords: inbound pull, one page per call. */
|
|
1080
1080
|
fetch?: string;
|
|
1081
|
+
/**
|
|
1082
|
+
* Loyalty / engagement providers: → ConnectorEventsSchema, the event names (and attributes) the
|
|
1083
|
+
* provider has registered for this installation. A flow's eventMapping is validated against it when
|
|
1084
|
+
* saved, so a mapping that names an unregistered event or breaks a limit is refused with the reason.
|
|
1085
|
+
*/
|
|
1086
|
+
describeEvents?: string;
|
|
1087
|
+
/**
|
|
1088
|
+
* (ConnectorLookupInput) → ConnectorLookupResult: one identity → member id, tier, points, status.
|
|
1089
|
+
* Called by the entitlement check (see docs/entitlements.md) through a cache keyed on an identity
|
|
1090
|
+
* hash, for the TTL the collection sets — one call per active person per TTL, never a sync.
|
|
1091
|
+
*/
|
|
1092
|
+
lookup?: string;
|
|
1081
1093
|
};
|
|
1082
1094
|
panels?: ConnectorPanel[];
|
|
1083
1095
|
/** Path (under the app's public files) of a guide the AI mapping assistant reads. */
|
|
@@ -1088,9 +1100,15 @@ export interface AppConnectorDeclaration {
|
|
|
1088
1100
|
* Default 'id'; a flow can override it with `config.upsert.externalIdPath`.
|
|
1089
1101
|
*/
|
|
1090
1102
|
recordId?: string;
|
|
1091
|
-
/**
|
|
1103
|
+
/**
|
|
1104
|
+
* Requests per second toward the provider, shared by every SmartLinks worker; and, for providers that
|
|
1105
|
+
* cap registered events, how many distinct events / attributes per event they accept (a flow's
|
|
1106
|
+
* eventMapping is checked against them when saved).
|
|
1107
|
+
*/
|
|
1092
1108
|
limits?: {
|
|
1093
1109
|
requestsPerSecond?: number;
|
|
1110
|
+
maxEvents?: number;
|
|
1111
|
+
maxAttributes?: number;
|
|
1094
1112
|
};
|
|
1095
1113
|
}
|
|
1096
1114
|
/**
|
package/dist/types/authKit.d.ts
CHANGED
|
@@ -98,6 +98,40 @@ export type RefreshErrorCode = 'MISSING_REFRESH_TOKEN' | 'INVALID_REFRESH_TOKEN'
|
|
|
98
98
|
* Options for {@link authKit.appleLogin}. All fields are optional — only the
|
|
99
99
|
* `identityToken` (passed as a positional argument) is required by the server.
|
|
100
100
|
*/
|
|
101
|
+
/** Options for {@link authKit.microsoftLogin}. */
|
|
102
|
+
export interface MicrosoftLoginOptions {
|
|
103
|
+
/**
|
|
104
|
+
* The site the session will be handed to, when signing in through a popup page on another address
|
|
105
|
+
* (the SmartLinks Microsoft sign-in page does this). The server refuses unless it's one of the login
|
|
106
|
+
* setup's own sites (`MICROSOFT_ORIGIN_NOT_ALLOWED`). Leave it out when signing in on the site itself.
|
|
107
|
+
*/
|
|
108
|
+
returnOrigin?: string;
|
|
109
|
+
/** Skip the step-up MFA challenge on a recognised device. */
|
|
110
|
+
trustedDeviceToken?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Who can sign in through a login setup, whatever the method (password, magic link, phone, WhatsApp,
|
|
114
|
+
* Google, Apple, LinkedIn, Microsoft):
|
|
115
|
+
* - `anyone` (also: no `access`) — anyone, as before;
|
|
116
|
+
* - `organisation` — people from the listed organisations: a VERIFIED email at one of `domains`, one of
|
|
117
|
+
* the listed `emails`, or signing in with Microsoft from the domain's own Microsoft organisation. A
|
|
118
|
+
* Microsoft email alone doesn't count (an organisation can give its users any address), so on save
|
|
119
|
+
* the server looks up each domain's Microsoft organisation itself — nobody types a tenant id.
|
|
120
|
+
*
|
|
121
|
+
* Checked every time a session is issued (tightening it shuts people out from their next sign-in);
|
|
122
|
+
* refused with `NOT_IN_ORGANISATION` (403). Registration refuses outside addresses up front and never
|
|
123
|
+
* signs an unverified address straight in. Accounts with no email (phone / WhatsApp only) can't show
|
|
124
|
+
* they're from an organisation. The public config returns only `{ mode, domains }`.
|
|
125
|
+
*/
|
|
126
|
+
export interface AuthKitAccess {
|
|
127
|
+
mode: 'anyone' | 'organisation';
|
|
128
|
+
/** e.g. `['acme.com']` (no `@`; exact domains — list subsidiaries' domains too). Up to 50. */
|
|
129
|
+
domains?: string[];
|
|
130
|
+
/** Particular people allowed besides the organisations, e.g. a contractor. Up to 50. Never public. */
|
|
131
|
+
emails?: string[];
|
|
132
|
+
/** Server-filled on save: `{ 'acme.com': '<Microsoft tenant id>' }` for domains with a Microsoft organisation. Read-only. */
|
|
133
|
+
microsoftTenants?: Record<string, string>;
|
|
134
|
+
}
|
|
101
135
|
export interface AppleLoginOptions {
|
|
102
136
|
/** Apple authorization code. Accepted but ignored by the server for now (reserved for future server-side token exchange). */
|
|
103
137
|
authorizationCode?: string;
|
|
@@ -128,7 +162,7 @@ export interface AppleLoginOptions {
|
|
|
128
162
|
* `ACCOUNT_EXISTS_UNVERIFIED` case also carries `requiresEmailVerification: true`
|
|
129
163
|
* in `SmartlinksApiError.details`.
|
|
130
164
|
*/
|
|
131
|
-
export type AuthKitErrorCode = 'MISSING_APPLE_TOKEN' | 'APPLE_AUTH_NOT_CONFIGURED' | 'INVALID_APPLE_TOKEN' | 'ACCOUNT_EXISTS_UNVERIFIED' | 'APPLE_AUTH_FAILED' | 'SIGN_UP_CLOSED';
|
|
165
|
+
export type AuthKitErrorCode = 'MISSING_APPLE_TOKEN' | 'APPLE_AUTH_NOT_CONFIGURED' | 'INVALID_APPLE_TOKEN' | 'ACCOUNT_EXISTS_UNVERIFIED' | 'APPLE_AUTH_FAILED' | 'SIGN_UP_CLOSED' | 'NOT_IN_ORGANISATION' | 'MISSING_MICROSOFT_TOKEN' | 'MICROSOFT_AUTH_NOT_CONFIGURED' | 'INVALID_MICROSOFT_TOKEN' | 'MICROSOFT_ORIGIN_NOT_ALLOWED' | 'MICROSOFT_AUTH_FAILED';
|
|
132
166
|
/** A second-step method: a code by email or text message, or from an authenticator app. */
|
|
133
167
|
export type MfaFactor = 'email' | 'sms' | 'totp';
|
|
134
168
|
/**
|
|
@@ -445,6 +479,16 @@ export interface AuthKitConfig {
|
|
|
445
479
|
* Setting `invite` needs own logins first (`OWN_LOGINS_REQUIRED`, 409).
|
|
446
480
|
*/
|
|
447
481
|
signUp?: 'open' | 'invite';
|
|
482
|
+
/** Who can sign in — see {@link AuthKitAccess}. Absent = anyone. */
|
|
483
|
+
access?: AuthKitAccess;
|
|
484
|
+
/**
|
|
485
|
+
* Sign in with Microsoft: add `'microsoft'` to `enabledProviders`. SmartLinks' own Microsoft app serves
|
|
486
|
+
* every organisation and personal Microsoft accounts, so nothing else is needed. Set this only to show
|
|
487
|
+
* your OWN name on Microsoft's sign-in screen: the Application (client) ID of your own multitenant app
|
|
488
|
+
* registration (redirect URI: https://smartlinks.app/apps/account/stable/microsoft-proxy.html). On the
|
|
489
|
+
* public config it's the effective id (yours, else SmartLinks').
|
|
490
|
+
*/
|
|
491
|
+
microsoftClientId?: string;
|
|
448
492
|
}
|
|
449
493
|
/** Body of {@link authKit.invite}. */
|
|
450
494
|
export interface AuthKitInviteRequest {
|
|
@@ -38,7 +38,60 @@ export interface FlowConnectorRef {
|
|
|
38
38
|
/** Per-flow settings, layered over the installation's. */
|
|
39
39
|
settings?: Record<string, unknown>;
|
|
40
40
|
}
|
|
41
|
+
import type { ConnectorInstallation } from './appManifest.js';
|
|
42
|
+
/** What about a person an event-sourced flow lets leave. Default 'hashed'. */
|
|
43
|
+
export type IdentityPolicy = 'externalIds' | 'hashed' | 'raw';
|
|
44
|
+
/**
|
|
45
|
+
* Many SmartLinks events → the provider's few registered event names. Rules are tried in order; the
|
|
46
|
+
* first match names the provider event and renders its attributes (a literal, a Liquid template over
|
|
47
|
+
* the envelope, or `{ path, default }`). An unmatched event is skipped (recorded as such) unless
|
|
48
|
+
* `unmatched: 'passthrough'`. Validated against the connector's `describeEvents` when the flow is saved.
|
|
49
|
+
*/
|
|
50
|
+
export interface EventMappingRule {
|
|
51
|
+
id?: string;
|
|
52
|
+
match?: {
|
|
53
|
+
types?: string[];
|
|
54
|
+
interactionIds?: string[];
|
|
55
|
+
outcomes?: string[];
|
|
56
|
+
appIds?: string[];
|
|
57
|
+
};
|
|
58
|
+
/** The provider's registered event name. */
|
|
59
|
+
event: string;
|
|
60
|
+
attributes?: Record<string, string | number | boolean | {
|
|
61
|
+
path: string;
|
|
62
|
+
default?: unknown;
|
|
63
|
+
} | {
|
|
64
|
+
value: unknown;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
export interface EventMapping {
|
|
68
|
+
rules: EventMappingRule[];
|
|
69
|
+
unmatched?: 'skip' | 'passthrough';
|
|
70
|
+
}
|
|
71
|
+
/** What an outbound flow reads: the product that changed, or ONE spine event as the envelope. */
|
|
72
|
+
export type FlowSourceEntity = 'product' | 'interaction' | 'contact' | 'event';
|
|
73
|
+
/** What an inbound flow writes. */
|
|
74
|
+
export type FlowTargetEntity = 'product' | 'contact';
|
|
41
75
|
export interface IntegrationFlowConfig {
|
|
76
|
+
/**
|
|
77
|
+
* Signed deliveries: X-SmartLinks-Signature `t=<unix>,v1=<hex HMAC-SHA256(secret, t + '.' + body)>`
|
|
78
|
+
* over the exact bytes sent. `previousCredentialRef` keeps the old secret signing during a rotation.
|
|
79
|
+
*/
|
|
80
|
+
signing?: {
|
|
81
|
+
credentialRef: string;
|
|
82
|
+
previousCredentialRef?: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Event-sourced flows: what about the person leaves (default 'hashed': ids + HMAC hashes of email and
|
|
86
|
+
* phone, never the values). `hashKeyCredentialRef` names the brand's own hash key, so hashes match a
|
|
87
|
+
* mirror they built; otherwise a per-collection platform key is used.
|
|
88
|
+
*/
|
|
89
|
+
identity?: {
|
|
90
|
+
policy?: IdentityPolicy;
|
|
91
|
+
hashKeyCredentialRef?: string;
|
|
92
|
+
};
|
|
93
|
+
/** Event-sourced flows: fold SmartLinks events into the provider's registered events. */
|
|
94
|
+
eventMapping?: EventMapping;
|
|
42
95
|
connection?: FlowConnection;
|
|
43
96
|
fieldMappings?: FieldMapping[];
|
|
44
97
|
/** Run this flow through a connector app's functions instead of the built-in mapper/transport. */
|
|
@@ -57,8 +110,10 @@ export interface IntegrationFlow {
|
|
|
57
110
|
eventTypes: string[];
|
|
58
111
|
/** Cron/interval string for scheduled flows, or null. */
|
|
59
112
|
schedule: string | null;
|
|
60
|
-
|
|
61
|
-
|
|
113
|
+
/** Outbound: what the flow reads (product | interaction | contact | event). */
|
|
114
|
+
sourceEntity: FlowSourceEntity | string | null;
|
|
115
|
+
/** Inbound: what the flow writes (product | contact). */
|
|
116
|
+
targetEntity: FlowTargetEntity | string | null;
|
|
62
117
|
config: IntegrationFlowConfig;
|
|
63
118
|
createdBy: string | null;
|
|
64
119
|
createdAt: string;
|
|
@@ -267,7 +322,97 @@ export interface SaveConnectorInstallationInput {
|
|
|
267
322
|
settings?: Record<string, unknown>;
|
|
268
323
|
}
|
|
269
324
|
/** Steps the console may run directly (send and fetch only run inside a flow; shape/serialize as dry runs). */
|
|
270
|
-
export type ConnectorConsoleStep = 'testConnection' | 'describeTarget' | 'sample' | 'shape' | 'serialize';
|
|
325
|
+
export type ConnectorConsoleStep = 'testConnection' | 'describeTarget' | 'sample' | 'shape' | 'serialize' | 'describeEvents' | 'lookup';
|
|
326
|
+
/** `describeEvents` → what the provider has registered for this installation (loyalty / engagement). */
|
|
327
|
+
export interface ConnectorEventsSchema {
|
|
328
|
+
events: Array<{
|
|
329
|
+
name: string;
|
|
330
|
+
title?: string;
|
|
331
|
+
attributes?: Array<{
|
|
332
|
+
name: string;
|
|
333
|
+
type?: string;
|
|
334
|
+
required?: boolean;
|
|
335
|
+
}>;
|
|
336
|
+
}>;
|
|
337
|
+
limits?: {
|
|
338
|
+
maxEvents?: number;
|
|
339
|
+
maxAttributes?: number;
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/** `lookup` input: one identity, as the collection's lookup policy sends it (raw, or hashed). */
|
|
343
|
+
export interface ConnectorLookupInput {
|
|
344
|
+
installation: ConnectorInstallation;
|
|
345
|
+
identity: {
|
|
346
|
+
externalId?: string | null;
|
|
347
|
+
email?: string | null;
|
|
348
|
+
phone?: string | null;
|
|
349
|
+
emailHash?: string | null;
|
|
350
|
+
phoneHash?: string | null;
|
|
351
|
+
contactId?: string | null;
|
|
352
|
+
};
|
|
353
|
+
/** Attribute names the gate wants, e.g. ['tier', 'points', 'status']. */
|
|
354
|
+
want?: string[];
|
|
355
|
+
}
|
|
356
|
+
/** `lookup` result. Throw (or return non-2xx) for an outage — never `found: false`. */
|
|
357
|
+
export interface ConnectorLookupResult {
|
|
358
|
+
found: boolean;
|
|
359
|
+
memberId?: string | null;
|
|
360
|
+
tier?: string | null;
|
|
361
|
+
points?: number | null;
|
|
362
|
+
status?: string | null;
|
|
363
|
+
attributes?: Record<string, unknown>;
|
|
364
|
+
/** When the provider's answer is from (ISO). */
|
|
365
|
+
asOf?: string | null;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* The one shape a SmartLinks event has when it leaves the platform — what event-sourced flows hand a
|
|
369
|
+
* connector's `serialize` / `send`, after the flow's identity policy and event mapping.
|
|
370
|
+
*/
|
|
371
|
+
export interface EventEnvelope {
|
|
372
|
+
/** The event's id: stable across retries; use it as the provider's transaction / idempotency id. */
|
|
373
|
+
id: string;
|
|
374
|
+
/** Spine event name, e.g. 'interaction.submitted:<typeId>', 'contact.updated', 'tag.scanned:scan_redirect'. */
|
|
375
|
+
type: string;
|
|
376
|
+
entityType: string | null;
|
|
377
|
+
entityId: string | null;
|
|
378
|
+
occurredAt: string;
|
|
379
|
+
collectionId: string;
|
|
380
|
+
orgId: string;
|
|
381
|
+
appId: string | null;
|
|
382
|
+
identity: {
|
|
383
|
+
contactId: string | null;
|
|
384
|
+
userId: string | null;
|
|
385
|
+
/** Ids other systems know this person by, keyed by system (a connector's `provider`). */
|
|
386
|
+
externalIds: Record<string, string>;
|
|
387
|
+
emailHash?: string | null;
|
|
388
|
+
phoneHash?: string | null;
|
|
389
|
+
hashAlgorithm?: 'hmac-sha256' | null;
|
|
390
|
+
/** Only under identity policy 'raw'. */
|
|
391
|
+
email?: string | null;
|
|
392
|
+
phone?: string | null;
|
|
393
|
+
};
|
|
394
|
+
identityPolicy: IdentityPolicy;
|
|
395
|
+
product: {
|
|
396
|
+
id: string;
|
|
397
|
+
name?: string | null;
|
|
398
|
+
sku?: string | null;
|
|
399
|
+
gtin?: string | null;
|
|
400
|
+
variantId?: string | null;
|
|
401
|
+
batchId?: string | null;
|
|
402
|
+
} | null;
|
|
403
|
+
proof: {
|
|
404
|
+
id: string;
|
|
405
|
+
} | null;
|
|
406
|
+
/** The event's own fields: an interaction's interactionId / outcome / metadata, a scan's codeId / country, a contact's profile. */
|
|
407
|
+
subject: Record<string, unknown>;
|
|
408
|
+
/** From the flow's event mapping, when it has one. */
|
|
409
|
+
event?: {
|
|
410
|
+
name: string;
|
|
411
|
+
attributes: Record<string, unknown>;
|
|
412
|
+
rule: string | null;
|
|
413
|
+
};
|
|
414
|
+
attributes: Record<string, unknown>;
|
|
415
|
+
}
|
|
271
416
|
export type RunTrigger = 'manual' | 'event' | 'schedule' | 'test';
|
|
272
417
|
export type FlowRunStatus = 'running' | 'success' | 'partial' | 'failed' | 'skipped';
|
|
273
418
|
export type FlowRunItemStatus = 'sent' | 'failed' | 'skipped';
|