@proveanything/smartlinks 1.6.0 → 1.6.3

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.
@@ -1,4 +1,4 @@
1
- import type { CommunicationEvent, CommsQueryByUser, CommsRecipientIdsQuery, CommsRecipientsWithoutActionQuery, CommsRecipientsWithActionQuery, RecipientId, RecipientWithOutcome, LogCommunicationEventBody, LogBulkCommunicationEventsBody, AppendResult, AppendBulkResult } from "../types/comms";
1
+ import type { CommunicationEvent, CommsQueryByUser, CommsRecipientIdsQuery, CommsRecipientsWithoutActionQuery, CommsRecipientsWithActionQuery, RecipientId, RecipientWithOutcome, LogCommunicationEventBody, LogBulkCommunicationEventsBody, AppendResult, AppendBulkResult, TransactionalSendRequest, TransactionalSendResult } from "../types/comms";
2
2
  /**
3
3
  * Communications namespace for sending notifications and managing user communications
4
4
  */
@@ -101,6 +101,32 @@ export declare namespace comms {
101
101
  * POST /admin/collection/:collectionId/comm/query/recipients/with-action
102
102
  */
103
103
  function queryRecipientsWithAction(collectionId: string, body: CommsRecipientsWithActionQuery): Promise<RecipientId[] | RecipientWithOutcome[]>;
104
+ /**
105
+ * Send a single transactional message to one contact using a template.
106
+ * No broadcast record is created. The send is logged to the contact's
107
+ * communication history with sourceType: 'transactional'.
108
+ *
109
+ * POST /admin/collection/:collectionId/comm/send
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const result = await comms.sendTransactional(collectionId, {
114
+ * contactId: 'e4f2a1b0-...',
115
+ * templateId: 'warranty-update',
116
+ * channel: 'preferred',
117
+ * props: { claimRef: 'CLM-0042', decision: 'approved' },
118
+ * include: { productId: 'prod-abc123', appCase: 'c9d1e2f3-...' },
119
+ * ref: 'warranty-decision-notification',
120
+ * appId: 'warrantyApp',
121
+ * })
122
+ * if (result.ok) {
123
+ * console.log(`Sent via ${result.channel}`, result.messageId)
124
+ * } else {
125
+ * console.error('Send failed:', result.error)
126
+ * }
127
+ * ```
128
+ */
129
+ function sendTransactional(collectionId: string, body: TransactionalSendRequest): Promise<TransactionalSendResult>;
104
130
  /**
105
131
  * Logging: Append a single communication event.
106
132
  * POST /admin/collection/:collectionId/comm/log
package/dist/api/comms.js CHANGED
@@ -196,6 +196,36 @@ export var comms;
196
196
  return post(path, body);
197
197
  }
198
198
  comms.queryRecipientsWithAction = queryRecipientsWithAction;
199
+ /**
200
+ * Send a single transactional message to one contact using a template.
201
+ * No broadcast record is created. The send is logged to the contact's
202
+ * communication history with sourceType: 'transactional'.
203
+ *
204
+ * POST /admin/collection/:collectionId/comm/send
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * const result = await comms.sendTransactional(collectionId, {
209
+ * contactId: 'e4f2a1b0-...',
210
+ * templateId: 'warranty-update',
211
+ * channel: 'preferred',
212
+ * props: { claimRef: 'CLM-0042', decision: 'approved' },
213
+ * include: { productId: 'prod-abc123', appCase: 'c9d1e2f3-...' },
214
+ * ref: 'warranty-decision-notification',
215
+ * appId: 'warrantyApp',
216
+ * })
217
+ * if (result.ok) {
218
+ * console.log(`Sent via ${result.channel}`, result.messageId)
219
+ * } else {
220
+ * console.error('Send failed:', result.error)
221
+ * }
222
+ * ```
223
+ */
224
+ async function sendTransactional(collectionId, body) {
225
+ const path = `/admin/collection/${encodeURIComponent(collectionId)}/comm/send`;
226
+ return post(path, body);
227
+ }
228
+ comms.sendTransactional = sendTransactional;
199
229
  /**
200
230
  * Logging: Append a single communication event.
201
231
  * POST /admin/collection/:collectionId/comm/log
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.6.0 | Generated: 2026-02-26T10:54:21.851Z
3
+ Version: 1.6.3 | Generated: 2026-02-26T11:49:31.908Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -20,6 +20,7 @@ For detailed guides on specific features:
20
20
  - **[Proof Claiming Methods](proof-claiming-methods.md)** - All methods for claiming/registering product ownership (NFC tags, serial numbers, auto-generated claims)
21
21
  - **[App Data Storage](app-data-storage.md)** - User-specific and collection-scoped app data storage
22
22
  - **[App Objects: Cases, Threads & Records](app-objects.md)** - Generic app-scoped building blocks for support cases, discussions, bookings, registrations, and more
23
+ - **[Communications](comms.md)** - Transactional sends, multi-channel broadcasts, consent management, push registration, and analytics
23
24
  - **[AI Guide Template](ai-guide-template.md)** - A sample for an app on how to build an AI setup guide
24
25
 
25
26
  ## API Namespaces
@@ -42,7 +43,7 @@ The Smartlinks SDK is organized into the following namespaces:
42
43
  - **contact** - Manage customer contacts; CRUD, lookup, upsert, erase.
43
44
 
44
45
  — Messaging & Audience —
45
- - **comms** - Send notifications (push, email, wallet); templating, severity, delivery status.
46
+ - **comms** - Send notifications (push, email, wallet); templating, severity, delivery status. → [Guide](comms.md)
46
47
  - **broadcasts** - Define broadcast campaigns; append recipients/events; analytics and CRUD.
47
48
  - **segments** - Define dynamic/static audience segments; estimate and list recipients; schedule calculations.
48
49
 
@@ -2333,6 +2334,55 @@ interface SubscriptionsResolveResponse {
2333
2334
  }
2334
2335
  ```
2335
2336
 
2337
+ **TransactionalSendRequest** (interface)
2338
+ ```typescript
2339
+ interface TransactionalSendRequest {
2340
+ contactId: string
2341
+ templateId: string
2342
+ * Channel to send on. Defaults to 'preferred', which auto-selects the
2343
+ * contact's best available channel respecting consent, suppression, and
2344
+ * template availability (priority: email → push → sms → wallet).
2345
+ channel?: 'email' | 'sms' | 'push' | 'wallet' | 'preferred'
2346
+ props?: Record<string, unknown>
2347
+ include?: {
2348
+ collection?: boolean
2349
+ productId?: string
2350
+ proofId?: string
2351
+ user?: boolean
2352
+ appCase?: string
2353
+ appThread?: string
2354
+ appRecord?: string
2355
+ }
2356
+ ref?: string
2357
+ appId?: string
2358
+ }
2359
+ ```
2360
+
2361
+ **TransactionalSendResponse** (interface)
2362
+ ```typescript
2363
+ interface TransactionalSendResponse {
2364
+ ok: true
2365
+ channel: 'email' | 'sms' | 'push' | 'wallet'
2366
+ messageId?: string
2367
+ }
2368
+ ```
2369
+
2370
+ **TransactionalSendError** (interface)
2371
+ ```typescript
2372
+ interface TransactionalSendError {
2373
+ ok: false
2374
+ * Error code. Known values:
2375
+ * - `transactional.contact_not_found`
2376
+ * - `transactional.template_not_found`
2377
+ * - `transactional.no_channel_available`
2378
+ * - `transactional.email_missing`
2379
+ * - `transactional.phone_missing`
2380
+ * - `transactional.no_push_methods`
2381
+ * - `transactional.no_wallet_methods`
2382
+ error: string
2383
+ }
2384
+ ```
2385
+
2336
2386
  **RecipientId** = `string`
2337
2387
 
2338
2388
  **Recipient** = `import('./contact').Contact`
@@ -2341,6 +2391,328 @@ interface SubscriptionsResolveResponse {
2341
2391
 
2342
2392
  **ConsentChannels** = `Partial<Record<BroadcastChannel, boolean>>`
2343
2393
 
2394
+ **TransactionalSendResult** = `// src/types/comms.ts
2395
+ // Communication and notification types for the Smartlinks API
2396
+ import type { IdField } from './common'
2397
+ import type { BroadcastChannel } from './broadcasts'
2398
+
2399
+ /**
2400
+ * Target subject for notifications (product, collection, etc.)
2401
+ */
2402
+ export interface NotificationSubjectTarget {
2403
+ /** Type of target entity */
2404
+ type: 'product' | 'collection' | 'user' | 'batch' | 'proof'
2405
+ /** ID of the target entity */
2406
+ id: string
2407
+ }
2408
+
2409
+
2410
+ // Analytics & logging (communication events)
2411
+
2412
+ export interface CommunicationEvent {
2413
+ orgId: string
2414
+ broadcastId?: string
2415
+ journeyId?: string
2416
+ userId?: string
2417
+ contactId?: string
2418
+ channel?: string
2419
+ timestamp: string
2420
+ eventType: string
2421
+ outcome?: string | null
2422
+ templateId?: string | null
2423
+ [k: string]: any
2424
+ }
2425
+
2426
+ export interface CommsQueryByUser {
2427
+ userId?: string
2428
+ contactId?: string
2429
+ from?: string
2430
+ to?: string
2431
+ limit?: number
2432
+ }
2433
+
2434
+ export type RecipientId = string
2435
+ export interface RecipientWithOutcome { id: string; outcome: string }
2436
+
2437
+ export interface CommsRecipientIdsQuery {
2438
+ broadcastId?: string
2439
+ journeyId?: string
2440
+ journeyStepId?: string
2441
+ idField?: IdField
2442
+ from?: string
2443
+ to?: string
2444
+ limit?: number
2445
+ }
2446
+
2447
+ export interface CommsRecipientsWithoutActionQuery {
2448
+ broadcastId?: string
2449
+ journeyId?: string
2450
+ actionId?: string
2451
+ appId?: string
2452
+ idField?: IdField
2453
+ from?: string
2454
+ to?: string
2455
+ limit?: number
2456
+ }
2457
+
2458
+ export interface CommsRecipientsWithActionQuery {
2459
+ broadcastId?: string
2460
+ journeyId?: string
2461
+ actionId?: string
2462
+ appId?: string
2463
+ outcome?: string
2464
+ idField?: IdField
2465
+ includeOutcome?: boolean
2466
+ from?: string
2467
+ to?: string
2468
+ limit?: number
2469
+ }
2470
+
2471
+ export interface LogCommunicationEventBody {
2472
+ broadcastId?: string
2473
+ journeyId?: string
2474
+ userId?: string
2475
+ contactId?: string
2476
+ channel?: string
2477
+ eventType: string
2478
+ outcome?: string
2479
+ templateId?: string
2480
+ timestamp?: string
2481
+ [k: string]: any
2482
+ }
2483
+
2484
+ export interface LogBulkCommunicationEventsBody {
2485
+ params: { broadcastId?: string; journeyId?: string; [k: string]: any }
2486
+ ids: string[]
2487
+ idField?: IdField
2488
+ }
2489
+
2490
+ export interface AppendResult { success: true }
2491
+ export interface AppendBulkResult { success: true; count: number }
2492
+
2493
+ // Common recipient type used by segments and broadcasts
2494
+ export type Recipient = import('./contact').Contact
2495
+
2496
+ // Shared page response shape for recipient listings
2497
+ export interface RecipientsPage {
2498
+ items: Recipient[]
2499
+ total: number
2500
+ limit: number
2501
+ offset: number
2502
+ note?: string
2503
+ }
2504
+
2505
+ // Web Push (public client registration)
2506
+
2507
+ export interface PushSubscriptionJSON {
2508
+ endpoint: string
2509
+ keys?: {
2510
+ p256dh?: string
2511
+ auth?: string
2512
+ }
2513
+ }
2514
+
2515
+ export interface PushVapidResponse { publicKey: string }
2516
+ export interface PushSubscribeResponse { ok: true; id: string }
2517
+
2518
+ // Public: register a push contact method
2519
+ export interface RegisterPushMethodRequest {
2520
+ contactId: string
2521
+ endpoint: string
2522
+ keys: { p256dh: string; auth: string }
2523
+ meta?: Record<string, any>
2524
+ }
2525
+
2526
+ // Admin Comms Settings
2527
+
2528
+ export interface CommsSettings {
2529
+ unsub?: {
2530
+ requireToken?: boolean
2531
+ /** Secret for token generation; omitted unless includeSecret=true */
2532
+ secret?: string
2533
+ /** Convenience flag indicating a secret is set (masked responses) */
2534
+ hasSecret?: boolean
2535
+ }
2536
+ /** Map of topic keys to topic config */
2537
+ topics?: Record<string, TopicConfig>
2538
+ [k: string]: any
2539
+ }
2540
+
2541
+ export interface TopicConfig {
2542
+ label?: string
2543
+ description?: string
2544
+ /** Optional UI-only grouping labels */
2545
+ labels?: string[]
2546
+ /** Classification for UI and default policy guidance */
2547
+ classification?: 'transactional' | 'marketing'
2548
+ defaults?: {
2549
+ channels?: Partial<Record<BroadcastChannel, boolean>>
2550
+ topics?: Record<string, boolean | undefined>
2551
+ /** Default consent policy when explicit preferences are absent */
2552
+ policy?: 'opt-in' | 'opt-out'
2553
+ /** Per-channel default policy (overrides policy when present) */
2554
+ byChannel?: Partial<Record<BroadcastChannel, 'opt-in' | 'opt-out'>>
2555
+ }
2556
+ rules?: {
2557
+ allowChannels?: BroadcastChannel[]
2558
+ allowUnsubscribe?: boolean
2559
+ required?: boolean
2560
+ }
2561
+ [k: string]: any
2562
+ }
2563
+
2564
+ export interface CommsSettingsGetResponse {
2565
+ ok: true
2566
+ settings: CommsSettings
2567
+ }
2568
+
2569
+ export type CommsSettingsPatchBody = Partial<CommsSettings>
2570
+
2571
+ // Public types listing (array form for public API)
2572
+ export interface CommsPublicTopicsResponse { ok: true; topics: Record<string, TopicConfig> }
2573
+
2574
+ export interface UnsubscribeQuery {
2575
+ contactId: string
2576
+ topic?: string
2577
+ channel?: BroadcastChannel
2578
+ token?: string
2579
+ }
2580
+
2581
+ export interface UnsubscribeResponse { ok: true; applied?: { channels?: Record<string, boolean>; topics?: Record<string, boolean> } }
2582
+
2583
+ // Public consent/preferences/subscribe
2584
+ export type ConsentChannels = Partial<Record<BroadcastChannel, boolean>>
2585
+ type SubjectType = import('./contact').SubjectType
2586
+
2587
+ export interface CommsConsentUpsertRequest {
2588
+ contactId: string
2589
+ channels?: ConsentChannels
2590
+ topics?: Record<string, boolean>
2591
+ topicsByChannel?: Partial<Record<BroadcastChannel, Record<string, boolean>>>
2592
+ }
2593
+
2594
+ export interface CommsPreferencesUpsertRequest {
2595
+ contactId: string
2596
+ subject?: { type: SubjectType; id: string; productId?: string }
2597
+ channels?: ConsentChannels
2598
+ topics?: Record<string, boolean>
2599
+ topicsByChannel?: Partial<Record<BroadcastChannel, Record<string, boolean>>>
2600
+ }
2601
+
2602
+ export interface CommsSubscribeRequest {
2603
+ contactId: string
2604
+ subject: { type: SubjectType; id: string; productId?: string }
2605
+ subscribe: boolean
2606
+ source?: string
2607
+ }
2608
+ export interface CommsSubscribeResponse { ok: true; subscriptionId: string }
2609
+
2610
+ export interface CommsSubscriptionCheckQuery {
2611
+ contactId: string
2612
+ subjectType: SubjectType
2613
+ subjectId: string
2614
+ productId?: string
2615
+ }
2616
+ export interface CommsSubscriptionCheckResponse { ok: true; subscribed: boolean }
2617
+
2618
+ export interface CommsListMethodsQuery {
2619
+ contactId: string
2620
+ type?: BroadcastChannel
2621
+ }
2622
+ export interface CommsListMethodsResponse { ok: true; methods: import('./contact').CommMethod[] }
2623
+
2624
+ export interface RegisterEmailMethodRequest { contactId?: string; email?: string; userId?: string }
2625
+ export interface RegisterSmsMethodRequest { contactId?: string; phone?: string; userId?: string }
2626
+ export interface RegisterMethodResponse { ok: true; contactId: string }
2627
+
2628
+ export interface SubscriptionsResolveRequest {
2629
+ subject: { type: SubjectType; id: string; productId?: string }
2630
+ hints: { userId?: string; pushEndpoint?: string; email?: string; walletObjectId?: string }
2631
+ }
2632
+ export interface SubscriptionsResolveResponse {
2633
+ ok: true
2634
+ subject: { type: SubjectType; id: string; productId?: string }
2635
+ contacts: Array<{
2636
+ contactId: string
2637
+ subscribed: boolean
2638
+ channels?: Partial<Record<BroadcastChannel, boolean>>
2639
+ walletForSubject?: boolean
2640
+ }>
2641
+ anySubscribed: boolean
2642
+ anyMethods: boolean
2643
+ anyWalletForSubject: boolean
2644
+ }
2645
+
2646
+ // Transactional send (single-contact, single-message)
2647
+
2648
+ /**
2649
+ * Send a single message to one contact using a template.
2650
+ * No broadcast record is created; the send is logged directly to the
2651
+ * contact's communication history with sourceType: 'transactional'.
2652
+ *
2653
+ * POST /admin/collection/:collectionId/comm/send
2654
+ */
2655
+ export interface TransactionalSendRequest {
2656
+ /** CRM contact UUID */
2657
+ contactId: string
2658
+ /** Firestore template ID */
2659
+ templateId: string
2660
+ /**
2661
+ * Channel to send on. Defaults to 'preferred', which auto-selects the
2662
+ * contact's best available channel respecting consent, suppression, and
2663
+ * template availability (priority: email → push → sms → wallet).
2664
+ */
2665
+ channel?: 'email' | 'sms' | 'push' | 'wallet' | 'preferred'
2666
+ /** Extra Liquid variables merged into the top-level render context */
2667
+ props?: Record<string, unknown>
2668
+ /** Context objects to hydrate into the Liquid template */
2669
+ include?: {
2670
+ /** Hydrate {{ collection }}. Default: true */
2671
+ collection?: boolean
2672
+ /** Hydrate {{ product }} from this product ID */
2673
+ productId?: string
2674
+ /** Hydrate {{ proof }} (requires productId) */
2675
+ proofId?: string
2676
+ /** Hydrate {{ user }} from contact.userId */
2677
+ user?: boolean
2678
+ /** Hydrate {{ appCase }} from this case UUID */
2679
+ appCase?: string
2680
+ /** Hydrate {{ appThread }} from this thread UUID */
2681
+ appThread?: string
2682
+ /** Hydrate {{ appRecord }} from this record UUID */
2683
+ appRecord?: string
2684
+ }
2685
+ /** Arbitrary label stored on the comms-events row (e.g. 'warranty-step-2') */
2686
+ ref?: string
2687
+ /** App context stored on the comms-events row */
2688
+ appId?: string
2689
+ }
2690
+
2691
+ export interface TransactionalSendResponse {
2692
+ ok: true
2693
+ /** The channel the message was actually sent on */
2694
+ channel: 'email' | 'sms' | 'push' | 'wallet'
2695
+ /** Provider message ID (email/SMS); absent for push/wallet */
2696
+ messageId?: string
2697
+ }
2698
+
2699
+ export interface TransactionalSendError {
2700
+ ok: false
2701
+ /**
2702
+ * Error code. Known values:
2703
+ * - `transactional.contact_not_found`
2704
+ * - `transactional.template_not_found`
2705
+ * - `transactional.no_channel_available`
2706
+ * - `transactional.email_missing`
2707
+ * - `transactional.phone_missing`
2708
+ * - `transactional.no_push_methods`
2709
+ * - `transactional.no_wallet_methods`
2710
+ */
2711
+ error: string
2712
+ }
2713
+
2714
+ export type TransactionalSendResult =`
2715
+
2344
2716
  ### contact
2345
2717
 
2346
2718
  **Contact** (interface)
@@ -2516,6 +2888,16 @@ interface ContactSchemaProperty {
2516
2888
  description?: string
2517
2889
  format?: string
2518
2890
  enum?: string[]
2891
+ * Display labels for `enum` values — parallel array.
2892
+ * `enum[i]` is the stored value; `enumNames[i]` is the display label.
2893
+ * When absent, `enum` values are used as labels.
2894
+ enumNames?: string[]
2895
+ default?: unknown
2896
+ minLength?: number
2897
+ maxLength?: number
2898
+ pattern?: string
2899
+ minimum?: number
2900
+ maximum?: number
2519
2901
  conditions?: FieldCondition[]
2520
2902
  showWhen?: 'all' | 'any'
2521
2903
  }
@@ -2524,9 +2906,17 @@ interface ContactSchemaProperty {
2524
2906
  **ContactUiSchemaEntry** (interface)
2525
2907
  ```typescript
2526
2908
  interface ContactUiSchemaEntry {
2527
- 'ui:disabled'?: true // Field is visible but not editable
2528
- 'ui:placeholder'?: string // Placeholder text
2529
- [key: string]: unknown // Forward-compatible with additional rjsf hints
2909
+ 'ui:disabled'?: true
2910
+ 'ui:placeholder'?: string
2911
+ 'ui:help'?: string
2912
+ 'ui:widget'?: string
2913
+ 'ui:options'?: {
2914
+ rows?: number // textarea: number of visible rows
2915
+ accept?: string // file: accepted MIME types
2916
+ label?: boolean // checkbox: show inline label
2917
+ [key: string]: unknown
2918
+ }
2919
+ [key: string]: unknown
2530
2920
  }
2531
2921
  ```
2532
2922
 
@@ -4934,6 +5324,10 @@ Analytics: Recipients who did not perform an action. POST /admin/collection/:col
4934
5324
  body: CommsRecipientsWithActionQuery) → `Promise<RecipientId[] | RecipientWithOutcome[]>`
4935
5325
  Analytics: Recipients who performed an action, optionally with outcome. POST /admin/collection/:collectionId/comm/query/recipients/with-action
4936
5326
 
5327
+ **sendTransactional**(collectionId: string,
5328
+ body: TransactionalSendRequest) → `Promise<TransactionalSendResult>`
5329
+ Send a single transactional message to one contact using a template. No broadcast record is created. The send is logged to the contact's communication history with sourceType: 'transactional'. POST /admin/collection/:collectionId/comm/send ```typescript const result = await comms.sendTransactional(collectionId, { contactId: 'e4f2a1b0-...', templateId: 'warranty-update', channel: 'preferred', props: { claimRef: 'CLM-0042', decision: 'approved' }, include: { productId: 'prod-abc123', appCase: 'c9d1e2f3-...' }, ref: 'warranty-decision-notification', appId: 'warrantyApp', }) if (result.ok) { console.log(`Sent via ${result.channel}`, result.messageId) } else { console.error('Send failed:', result.error) } ```
5330
+
4937
5331
  **logCommunicationEvent**(collectionId: string,
4938
5332
  body: LogCommunicationEventBody) → `Promise<AppendResult>`
4939
5333
  Logging: Append a single communication event. POST /admin/collection/:collectionId/comm/log