@stackable-labs/sdk-extension-contracts 2.30.0 → 3.0.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/index.d.ts +420 -37
- package/dist/index.js +66 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -468,6 +468,396 @@ declare const IDENTITY_CLAIM_MAX_STRING_VALUE_LEN = 256;
|
|
|
468
468
|
*/
|
|
469
469
|
type ExtendIdentityHandler = (claims: IdentityBaseClaims) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
470
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Messaging Contract — all messaging-domain types (events + send capability).
|
|
473
|
+
*/
|
|
474
|
+
|
|
475
|
+
/** Messaging context — conversation and app identifiers. */
|
|
476
|
+
interface MessagingContext {
|
|
477
|
+
conversationId?: string | null;
|
|
478
|
+
appId?: string | null;
|
|
479
|
+
}
|
|
480
|
+
/** Messaging event subscription types — 'postback' for all, 'postback:<actionName>' for specific */
|
|
481
|
+
type MessagingEventType = 'postback' | `postback:${string}`;
|
|
482
|
+
/** Normalized postback event payload */
|
|
483
|
+
interface MessagingPostbackEvent {
|
|
484
|
+
eventName: 'postback';
|
|
485
|
+
data: {
|
|
486
|
+
/**
|
|
487
|
+
* The postback button's display text (Zendesk-specific).
|
|
488
|
+
* NOTE: This is NOT an event system field — `eventType` and `eventName` are our event system
|
|
489
|
+
* conventions. `actionName` is a domain-specific payload field identifying which button was
|
|
490
|
+
* clicked, and lives inside `data` alongside other Zendesk messaging fields.
|
|
491
|
+
*/
|
|
492
|
+
actionName: string;
|
|
493
|
+
conversationId: string;
|
|
494
|
+
timestamp: ISOTimestamp;
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
/** Union of all messaging events (extensible for future event types) */
|
|
498
|
+
type MessagingEvent = MessagingPostbackEvent;
|
|
499
|
+
/** Handler type for useMessagingEvent — use with useCallback for memoized handlers */
|
|
500
|
+
type MessagingEventHandler = (event: MessagingEvent) => void;
|
|
501
|
+
/**
|
|
502
|
+
* Primitives allowed as values in metadata (both message-level and action-level).
|
|
503
|
+
* Sunco rejects nested objects/arrays at the wire layer; total metadata capped at 4KB.
|
|
504
|
+
*/
|
|
505
|
+
type ActionMetadataValue = string | number | boolean | null;
|
|
506
|
+
/**
|
|
507
|
+
* Format of a message body. Drives which Sunco wire field the host populates:
|
|
508
|
+
* - 'text' → Sunco `content.text` (plain — default; max 4096 chars)
|
|
509
|
+
* - 'markdown' → Sunco `content.markdownText` (server-converts to htmlText)
|
|
510
|
+
* - 'html' → Sunco `content.htmlText` (max 4096 chars; mutex with markdownText)
|
|
511
|
+
*
|
|
512
|
+
* Sunco auto-converts markdown/html to plain text for channels that don't support
|
|
513
|
+
* rich text — graceful cross-channel fallback.
|
|
514
|
+
*/
|
|
515
|
+
type TextFormat = 'text' | 'markdown' | 'html';
|
|
516
|
+
/** Common base — fields available on EVERY message kind. */
|
|
517
|
+
interface BaseMessagePayload {
|
|
518
|
+
/**
|
|
519
|
+
* When true, disables the user's chat input while this is the most recent
|
|
520
|
+
* message in the conversation. Useful for guided / forced-button-response flows.
|
|
521
|
+
* Maps to Sunco `content.blockChatInput`.
|
|
522
|
+
*/
|
|
523
|
+
disableUserInput?: boolean;
|
|
524
|
+
/**
|
|
525
|
+
* Caller-supplied metadata. Merged with host-injected `stackable.*` block
|
|
526
|
+
* (extensionId / capabilityCallId / instanceId — non-overridable by extensions).
|
|
527
|
+
* Values are primitives; total ≤4KB. Doesn't render in the Messenger widget.
|
|
528
|
+
*/
|
|
529
|
+
metadata?: Record<string, ActionMetadataValue>;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Mixin for message kinds that support a text body + format. Extended by
|
|
533
|
+
* text (required override), and future image/file/carousel (optional caption).
|
|
534
|
+
*/
|
|
535
|
+
interface TextEnabledPayload {
|
|
536
|
+
body?: string;
|
|
537
|
+
bodyFormat?: TextFormat;
|
|
538
|
+
}
|
|
539
|
+
/** Common base for all action types — shared label + per-action metadata. */
|
|
540
|
+
interface BaseAction {
|
|
541
|
+
label: string;
|
|
542
|
+
/** Optional flat metadata attached to this action. Primitives only; 4KB cap total. */
|
|
543
|
+
metadata?: Record<string, ActionMetadataValue>;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Reply action — clicking inserts a visible user-reply bubble carrying `payload`
|
|
547
|
+
* back to the conversation, as if the user typed it.
|
|
548
|
+
*
|
|
549
|
+
* MUTUALLY EXCLUSIVE — a `reply` action cannot appear in the same `actions[]`
|
|
550
|
+
* array as any other action type. Sunco returns 400 if mixed. The host validates
|
|
551
|
+
* pre-flight and surfaces `invalid_message` to the extension.
|
|
552
|
+
*/
|
|
553
|
+
interface ReplyAction extends BaseAction {
|
|
554
|
+
type: 'reply';
|
|
555
|
+
/** Opaque string. Sunco rejects non-string payloads. For structured data, use `metadata`. */
|
|
556
|
+
payload: string;
|
|
557
|
+
/** Optional icon URL rendered next to the reply pill. */
|
|
558
|
+
iconUrl?: string;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Link action — clicking opens `url` in a new tab/window. No bubble inserted.
|
|
562
|
+
* Freely mixable with other non-reply action types.
|
|
563
|
+
*/
|
|
564
|
+
interface LinkAction extends BaseAction {
|
|
565
|
+
type: 'link';
|
|
566
|
+
url: string;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Postback action — clicking fires a server-side `conversation:postback` webhook
|
|
570
|
+
* to the Stackable backend with the full `payload` + any `metadata`. NO visible
|
|
571
|
+
* bubble inserted. Extensions receive postback events via declared event handlers
|
|
572
|
+
* (see `events:messaging` permission). Freely mixable with other non-reply types.
|
|
573
|
+
*/
|
|
574
|
+
interface PostbackAction extends BaseAction {
|
|
575
|
+
type: 'postback';
|
|
576
|
+
/** Opaque string. Sunco rejects non-string payloads. For structured data, use `metadata`. */
|
|
577
|
+
payload: string;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Location-request action — prompts the user to share their device location.
|
|
581
|
+
* Response arrives as a separate `location`-type message inbound to the conversation.
|
|
582
|
+
* Freely mixable with other non-reply action types.
|
|
583
|
+
*/
|
|
584
|
+
interface LocationRequestAction extends BaseAction {
|
|
585
|
+
type: 'locationRequest';
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Union of message-level action types. Used as the type of `actions` on
|
|
589
|
+
* top-level message payloads. For carousel and list ITEMS (future), see
|
|
590
|
+
* `MessageItemAction` (a subset that excludes `reply` and `locationRequest`).
|
|
591
|
+
*/
|
|
592
|
+
type MessageAction = ReplyAction | LinkAction | PostbackAction | LocationRequestAction;
|
|
593
|
+
/**
|
|
594
|
+
* Subset of action types valid inside future carousel/list items. Sunco's
|
|
595
|
+
* `actionSubset` schema excludes `reply` and `locationRequest`. Surfaced as a
|
|
596
|
+
* separate type so the SDK compile-time prevents using them where Sunco doesn't.
|
|
597
|
+
*/
|
|
598
|
+
type MessageItemAction = LinkAction | PostbackAction;
|
|
599
|
+
/**
|
|
600
|
+
* Text message — plain text body with optional in-message actions.
|
|
601
|
+
*
|
|
602
|
+
* Inherits from:
|
|
603
|
+
* - BaseMessagePayload → disableUserInput, metadata
|
|
604
|
+
* - TextEnabledPayload → body (narrowed to REQUIRED here), bodyFormat
|
|
605
|
+
*/
|
|
606
|
+
interface SendTextMessagePayload extends BaseMessagePayload, TextEnabledPayload {
|
|
607
|
+
kind: 'text';
|
|
608
|
+
/**
|
|
609
|
+
* Body text — THE message itself for the `text` kind. Required.
|
|
610
|
+
* Narrows the optional `body` from TextEnabledPayload to required for this kind.
|
|
611
|
+
* Sunco caps at 4096 chars (across all of text/htmlText/markdownText).
|
|
612
|
+
*/
|
|
613
|
+
body: string;
|
|
614
|
+
/**
|
|
615
|
+
* Optional in-message actions. Reply actions are mutex with all other types
|
|
616
|
+
* (host validates and surfaces `invalid_message`). Practical max ~10 per message.
|
|
617
|
+
*/
|
|
618
|
+
actions?: MessageAction[];
|
|
619
|
+
/**
|
|
620
|
+
* Echoed payload from a prior `reply` action click. Set by the host on inbound
|
|
621
|
+
* messages; not generally set by extension authors on outbound. Maps to Sunco
|
|
622
|
+
* `textMessage.payload`.
|
|
623
|
+
*/
|
|
624
|
+
payload?: string;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Image message — embedded image with optional caption + action buttons.
|
|
628
|
+
* Use for product photos, screenshots, visual help / troubleshooting.
|
|
629
|
+
*
|
|
630
|
+
* Inherits from:
|
|
631
|
+
* - BaseMessagePayload → disableUserInput, metadata
|
|
632
|
+
* - TextEnabledPayload → body (optional caption alongside the image), bodyFormat
|
|
633
|
+
*
|
|
634
|
+
* Spec note: Sunco `imageMessage.mediaUrl` has no explicit maxLength in the OpenAPI
|
|
635
|
+
* spec. `altText` is OPTIONAL — Sunco defaults it to the URL's filename if omitted.
|
|
636
|
+
*/
|
|
637
|
+
interface SendImageMessagePayload extends BaseMessagePayload, TextEnabledPayload {
|
|
638
|
+
kind: 'image';
|
|
639
|
+
/** Public URL or pre-signed URL. Must respond with Content-Type `image/*`. */
|
|
640
|
+
url: string;
|
|
641
|
+
/**
|
|
642
|
+
* Optional accessibility label, max 128 chars. If omitted, Sunco populates
|
|
643
|
+
* from the URL's filename.
|
|
644
|
+
*/
|
|
645
|
+
altText?: string;
|
|
646
|
+
/** Optional in-message actions. Reply-mutex rule applies (see ReplyAction). */
|
|
647
|
+
actions?: MessageAction[];
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* File message — embedded file attachment (PDF, document, etc.) with optional
|
|
651
|
+
* caption. Use for return labels, receipts, NDAs, referral docs, warranty paperwork.
|
|
652
|
+
*
|
|
653
|
+
* Inherits from:
|
|
654
|
+
* - BaseMessagePayload → disableUserInput, metadata
|
|
655
|
+
* - TextEnabledPayload → body (optional caption alongside the file), bodyFormat
|
|
656
|
+
*
|
|
657
|
+
* Spec note: file messages have NO actions field (Sunco fileMessage schema doesn't
|
|
658
|
+
* support them). `altText` optional, defaults to filename. `mediaSize` + `mediaType`
|
|
659
|
+
* are readonly server-set fields.
|
|
660
|
+
*/
|
|
661
|
+
interface SendFileMessagePayload extends BaseMessagePayload, TextEnabledPayload {
|
|
662
|
+
kind: 'file';
|
|
663
|
+
/** Public URL or pre-signed URL. Content-Type drives how Sunco renders the attachment. */
|
|
664
|
+
url: string;
|
|
665
|
+
/**
|
|
666
|
+
* Optional accessibility label, max 128 chars. If omitted, Sunco populates
|
|
667
|
+
* from the URL's filename.
|
|
668
|
+
*/
|
|
669
|
+
altText?: string;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Shared item shape used by carousel payloads (and reserved for future list
|
|
673
|
+
* support if/when the Zendesk Messenger Widget adds rendering — see note on
|
|
674
|
+
* SendMessagePayload below). Maps to Sunco's single `item` schema.
|
|
675
|
+
*
|
|
676
|
+
* Spec note: `actions` is REQUIRED with min 1 / max 3 entries, all from the
|
|
677
|
+
* `MessageItemAction` subset (no reply, no locationRequest). The tuple-rest
|
|
678
|
+
* type enforces ≥1 at compile time; max 3 is host-validated.
|
|
679
|
+
*/
|
|
680
|
+
interface MessageItem {
|
|
681
|
+
/** Required, 1-128 chars. */
|
|
682
|
+
title: string;
|
|
683
|
+
/** Optional, max 128 chars. */
|
|
684
|
+
description?: string;
|
|
685
|
+
/** Optional image URL, max 2048 chars. */
|
|
686
|
+
imageUrl?: string;
|
|
687
|
+
/** Optional accessibility label, max 128 chars. */
|
|
688
|
+
altText?: string;
|
|
689
|
+
/** Display size for the item's image. Maps to Sunco `item.size`. */
|
|
690
|
+
imageSize?: 'compact' | 'large';
|
|
691
|
+
/** REQUIRED 1-3 actions per item. Subset only — no reply, no locationRequest. */
|
|
692
|
+
actions: [MessageItemAction, ...MessageItemAction[]];
|
|
693
|
+
/** Optional flat metadata, primitives only, 4KB cap. */
|
|
694
|
+
metadata?: Record<string, ActionMetadataValue>;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Carousel message — horizontally scrolling cards. THE conversational-commerce
|
|
698
|
+
* primitive: product recommendations, size/color pickers, search results with
|
|
699
|
+
* images, multi-option selection.
|
|
700
|
+
*
|
|
701
|
+
* Inherits from BaseMessagePayload only — Sunco `carouselMessage` has no
|
|
702
|
+
* settable text body (its `text` field is a readonly server-set fallback for
|
|
703
|
+
* channels that don't render carousels). Use a separate text message before
|
|
704
|
+
* the carousel if you need an intro.
|
|
705
|
+
*
|
|
706
|
+
* Spec note: NO message-level `actions` field — Sunco carouselMessage doesn't
|
|
707
|
+
* define one. Actions live per-card on `items[].actions`. `items` REQUIRED,
|
|
708
|
+
* min 1, max 10.
|
|
709
|
+
*/
|
|
710
|
+
interface SendCarouselMessagePayload extends BaseMessagePayload {
|
|
711
|
+
kind: 'carousel';
|
|
712
|
+
/** 1-10 cards. Host validates the cap. */
|
|
713
|
+
items: MessageItem[];
|
|
714
|
+
/** Optional carousel-level display tweaks. */
|
|
715
|
+
displaySettings?: {
|
|
716
|
+
/**
|
|
717
|
+
* How carousel images render. `horizontal` (default) or `square`. Only
|
|
718
|
+
* supported by Facebook Messenger, Web Messenger, Android SDK, iOS SDK;
|
|
719
|
+
* other channels ignore.
|
|
720
|
+
*/
|
|
721
|
+
imageAspectRatio?: 'horizontal' | 'square';
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Payload for messaging.send capability — discriminated by `kind`.
|
|
726
|
+
*/
|
|
727
|
+
type SendMessagePayload = SendTextMessagePayload | SendImageMessagePayload | SendFileMessagePayload | SendCarouselMessagePayload;
|
|
728
|
+
/** Discriminator literals — one per supported kind. */
|
|
729
|
+
type MessagePayloadKind = SendMessagePayload['kind'];
|
|
730
|
+
/**
|
|
731
|
+
* Canonical example payloads — one per kind. Single source of truth for the
|
|
732
|
+
* developer-docs cookbook generator. `satisfies` makes TypeScript verify every
|
|
733
|
+
* example is a valid `SendMessagePayload` AND that every kind has an entry, so
|
|
734
|
+
* adding a new kind (or renaming/removing a field) breaks the build until the
|
|
735
|
+
* example is updated alongside the type.
|
|
736
|
+
*/
|
|
737
|
+
declare const MESSAGING_SEND_EXAMPLES: {
|
|
738
|
+
readonly text: {
|
|
739
|
+
readonly kind: "text";
|
|
740
|
+
readonly body: "Order approved ✓";
|
|
741
|
+
readonly actions: [{
|
|
742
|
+
readonly type: "reply";
|
|
743
|
+
readonly label: "Got it";
|
|
744
|
+
readonly payload: "ACK";
|
|
745
|
+
}, {
|
|
746
|
+
readonly type: "reply";
|
|
747
|
+
readonly label: "Show details";
|
|
748
|
+
readonly payload: "DETAILS";
|
|
749
|
+
}];
|
|
750
|
+
};
|
|
751
|
+
readonly image: {
|
|
752
|
+
readonly kind: "image";
|
|
753
|
+
readonly url: "https://cdn.example.com/products/widget-blue.jpg";
|
|
754
|
+
readonly altText: "Blue widget — model A24";
|
|
755
|
+
readonly body: "Here is the product you asked about:";
|
|
756
|
+
readonly actions: [{
|
|
757
|
+
readonly type: "link";
|
|
758
|
+
readonly label: "View on site";
|
|
759
|
+
readonly url: "https://example.com/p/widget-a24";
|
|
760
|
+
}];
|
|
761
|
+
};
|
|
762
|
+
readonly file: {
|
|
763
|
+
readonly kind: "file";
|
|
764
|
+
readonly url: "https://cdn.example.com/receipts/order-12345.pdf";
|
|
765
|
+
readonly altText: "Receipt for order #12345";
|
|
766
|
+
readonly body: "Your receipt is attached.";
|
|
767
|
+
};
|
|
768
|
+
readonly carousel: {
|
|
769
|
+
readonly kind: "carousel";
|
|
770
|
+
readonly items: [{
|
|
771
|
+
readonly title: "Widget A24 — Blue";
|
|
772
|
+
readonly description: "In stock — ships in 1-2 days";
|
|
773
|
+
readonly imageUrl: "https://cdn.example.com/products/widget-blue.jpg";
|
|
774
|
+
readonly actions: [{
|
|
775
|
+
readonly type: "link";
|
|
776
|
+
readonly label: "View";
|
|
777
|
+
readonly url: "https://example.com/p/widget-a24-blue";
|
|
778
|
+
}, {
|
|
779
|
+
readonly type: "postback";
|
|
780
|
+
readonly label: "Add to cart";
|
|
781
|
+
readonly payload: "add_to_cart:widget-a24-blue";
|
|
782
|
+
}];
|
|
783
|
+
}, {
|
|
784
|
+
readonly title: "Widget A24 — Red";
|
|
785
|
+
readonly description: "Limited stock";
|
|
786
|
+
readonly imageUrl: "https://cdn.example.com/products/widget-red.jpg";
|
|
787
|
+
readonly actions: [{
|
|
788
|
+
readonly type: "link";
|
|
789
|
+
readonly label: "View";
|
|
790
|
+
readonly url: "https://example.com/p/widget-a24-red";
|
|
791
|
+
}, {
|
|
792
|
+
readonly type: "postback";
|
|
793
|
+
readonly label: "Add to cart";
|
|
794
|
+
readonly payload: "add_to_cart:widget-a24-red";
|
|
795
|
+
}];
|
|
796
|
+
}];
|
|
797
|
+
readonly displaySettings: {
|
|
798
|
+
readonly imageAspectRatio: "horizontal";
|
|
799
|
+
};
|
|
800
|
+
};
|
|
801
|
+
};
|
|
802
|
+
/**
|
|
803
|
+
* Canonical example actions — one per action type. Single source of truth for
|
|
804
|
+
* the developer-docs cookbook generator. The mapped-type satisfies clause
|
|
805
|
+
* forces each entry to be the SPECIFIC narrowed action (reply must have a
|
|
806
|
+
* payload; locationRequest must not; etc.) AND that every action type
|
|
807
|
+
* literal has an entry, so adding/removing/renaming an action breaks the
|
|
808
|
+
* build until the example is updated alongside the type.
|
|
809
|
+
*/
|
|
810
|
+
declare const MESSAGING_ACTION_EXAMPLES: {
|
|
811
|
+
readonly reply: {
|
|
812
|
+
readonly type: "reply";
|
|
813
|
+
readonly label: "Got it";
|
|
814
|
+
readonly payload: "ACK";
|
|
815
|
+
};
|
|
816
|
+
readonly link: {
|
|
817
|
+
readonly type: "link";
|
|
818
|
+
readonly label: "View on site";
|
|
819
|
+
readonly url: "https://example.com/p/widget-a24";
|
|
820
|
+
};
|
|
821
|
+
readonly postback: {
|
|
822
|
+
readonly type: "postback";
|
|
823
|
+
readonly label: "Add to cart";
|
|
824
|
+
readonly payload: "add_to_cart:widget-a24";
|
|
825
|
+
};
|
|
826
|
+
readonly locationRequest: {
|
|
827
|
+
readonly type: "locationRequest";
|
|
828
|
+
readonly label: "Share location";
|
|
829
|
+
};
|
|
830
|
+
};
|
|
831
|
+
/**
|
|
832
|
+
* Response from messaging.send — minimum surface for extensions to correlate
|
|
833
|
+
* with their own UI. Full Sunco response shape intentionally not surfaced.
|
|
834
|
+
*/
|
|
835
|
+
interface SendMessageResponse {
|
|
836
|
+
messageId: string;
|
|
837
|
+
/** ISO 8601 — when Sunco persisted the message. */
|
|
838
|
+
receivedAt: string;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Codes that the extension author can meaningfully react to in UI. These are
|
|
842
|
+
* the only codes that surface via the `useMessaging` hook's `state.error` and
|
|
843
|
+
* cause `send()` to throw. End-users can act on each (retry, fix payload,
|
|
844
|
+
* back off rate-limit, retry transient upstream issue). The wider
|
|
845
|
+
* `SendMessageErrorCode` includes host-handled codes that the SDK swallows.
|
|
846
|
+
*/
|
|
847
|
+
type SendMessageActionableErrorCode = 'invalid_message' | 'rate_limited' | 'upstream_error';
|
|
848
|
+
/**
|
|
849
|
+
* Full wire taxonomy returned by the host's `messaging.send` capability.
|
|
850
|
+
* Superset of `SendMessageActionableErrorCode` plus host-handled codes that
|
|
851
|
+
* the SDK does NOT surface to extension state:
|
|
852
|
+
* - `no_conversation`: framework logs `console.info`; extension can pre-empt via `useContextData().messaging?.conversationId`
|
|
853
|
+
* - `reauth_required`: framework logs `console.warn`; server flips `messagingDisconnected:true` → admin dashboard surfaces Reconnect UI
|
|
854
|
+
* - `forbidden`: framework logs `console.warn`; extension manifest/permission misconfig — admin/dev resolves
|
|
855
|
+
*
|
|
856
|
+
* Lowercase snake_case to match the existing convention (e.g.
|
|
857
|
+
* `reauth_required` on the reconnect endpoint).
|
|
858
|
+
*/
|
|
859
|
+
type SendMessageErrorCode = SendMessageActionableErrorCode | 'no_conversation' | 'reauth_required' | 'forbidden';
|
|
860
|
+
|
|
471
861
|
/**
|
|
472
862
|
* Capabilities Contract
|
|
473
863
|
* Defines the host-mediated APIs that extensions can call via RPC.
|
|
@@ -552,11 +942,6 @@ interface ActionInvokePayload {
|
|
|
552
942
|
action: InvokeAction;
|
|
553
943
|
payload?: Record<string, unknown>;
|
|
554
944
|
}
|
|
555
|
-
/** Messaging context — conversation and app identifiers */
|
|
556
|
-
interface MessagingContext {
|
|
557
|
-
conversationId?: string | null;
|
|
558
|
-
appId?: string | null;
|
|
559
|
-
}
|
|
560
945
|
/** Context returned by context.read capability */
|
|
561
946
|
interface ContextData {
|
|
562
947
|
customerId?: string;
|
|
@@ -606,36 +991,12 @@ type CapabilityCall = {
|
|
|
606
991
|
} | {
|
|
607
992
|
type: 'identity.extend';
|
|
608
993
|
payload: IdentityExtendPayload;
|
|
994
|
+
} | {
|
|
995
|
+
type: 'messaging.send';
|
|
996
|
+
payload: SendMessagePayload;
|
|
609
997
|
};
|
|
610
998
|
type CapabilityType = CapabilityCall['type'];
|
|
611
999
|
|
|
612
|
-
/**
|
|
613
|
-
* Messaging Contract
|
|
614
|
-
* Types for the messaging event system (postback buttons, etc.).
|
|
615
|
-
*/
|
|
616
|
-
|
|
617
|
-
/** Messaging event subscription types — 'postback' for all, 'postback:<actionName>' for specific */
|
|
618
|
-
type MessagingEventType = 'postback' | `postback:${string}`;
|
|
619
|
-
/** Normalized postback event payload */
|
|
620
|
-
interface MessagingPostbackEvent {
|
|
621
|
-
eventName: 'postback';
|
|
622
|
-
data: {
|
|
623
|
-
/**
|
|
624
|
-
* The postback button's display text (Zendesk-specific).
|
|
625
|
-
* NOTE: This is NOT an event system field — `eventType` and `eventName` are our event system
|
|
626
|
-
* conventions. `actionName` is a domain-specific payload field identifying which button was
|
|
627
|
-
* clicked, and lives inside `data` alongside other Zendesk messaging fields.
|
|
628
|
-
*/
|
|
629
|
-
actionName: string;
|
|
630
|
-
conversationId: string;
|
|
631
|
-
timestamp: ISOTimestamp;
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
/** Union of all messaging events (extensible for future event types) */
|
|
635
|
-
type MessagingEvent = MessagingPostbackEvent;
|
|
636
|
-
/** Handler type for useMessagingEvent — use with useCallback for memoized handlers */
|
|
637
|
-
type MessagingEventHandler = (event: MessagingEvent) => void;
|
|
638
|
-
|
|
639
1000
|
/**
|
|
640
1001
|
* Activity Event Contract
|
|
641
1002
|
* Types for the activity event system (host-to-extension push events).
|
|
@@ -690,6 +1051,7 @@ interface InstanceConfig {
|
|
|
690
1051
|
identityProvider?: string;
|
|
691
1052
|
messagingIntegrationId?: string;
|
|
692
1053
|
messagingAppId?: string;
|
|
1054
|
+
messagingDisplayName?: string;
|
|
693
1055
|
} & Record<string, unknown>;
|
|
694
1056
|
secrets?: {
|
|
695
1057
|
identityKey?: string;
|
|
@@ -731,7 +1093,7 @@ interface InstanceOption {
|
|
|
731
1093
|
* Extensions declare required permissions in their manifest.
|
|
732
1094
|
* Host enforces: capability calls must be a subset of granted permissions.
|
|
733
1095
|
*/
|
|
734
|
-
declare const PERMISSIONS: readonly ["context:read", "data:query", "data:fetch", "actions:toast", "actions:invoke", "identity:extend", "events:identity", "events:messaging", "events:activity"];
|
|
1096
|
+
declare const PERMISSIONS: readonly ["context:read", "data:query", "data:fetch", "actions:toast", "actions:invoke", "messaging:send", "identity:extend", "events:identity", "events:messaging", "events:activity"];
|
|
735
1097
|
type Permission = (typeof PERMISSIONS)[number];
|
|
736
1098
|
/**
|
|
737
1099
|
* Maps capability types (dot notation, used in code) to the permission
|
|
@@ -744,20 +1106,38 @@ declare const CAPABILITY_PERMISSION_MAP: {
|
|
|
744
1106
|
readonly 'actions.toast': "actions:toast";
|
|
745
1107
|
readonly 'actions.invoke': "actions:invoke";
|
|
746
1108
|
readonly 'identity.extend': "identity:extend";
|
|
1109
|
+
readonly 'messaging.send': "messaging:send";
|
|
747
1110
|
};
|
|
748
1111
|
/** Capability key type — dot-notation API names (e.g., 'data.query', 'actions.toast') */
|
|
749
1112
|
type Capability = keyof typeof CAPABILITY_PERMISSION_MAP;
|
|
750
1113
|
/**
|
|
751
|
-
* Maps event
|
|
752
|
-
*
|
|
1114
|
+
* Maps event-hook names to the permission required to subscribe via that hook.
|
|
1115
|
+
* Use this when iterating event hooks specifically (e.g., docs that talk about
|
|
1116
|
+
* the manifest `events` array, drift guardrails over `## events:*` doc sections).
|
|
1117
|
+
* For broader "any hook → permission" detection, use HOOK_PERMISSION_MAP below.
|
|
753
1118
|
*/
|
|
754
1119
|
declare const EVENT_HOOK_PERMISSION_MAP: {
|
|
755
1120
|
readonly useIdentityEvent: "events:identity";
|
|
756
1121
|
readonly useMessagingEvent: "events:messaging";
|
|
757
1122
|
readonly useActivityEvent: "events:activity";
|
|
758
1123
|
};
|
|
759
|
-
/** Event-hook key type — hook names
|
|
1124
|
+
/** Event-hook key type — hook names that subscribe to host events. */
|
|
760
1125
|
type EventHook = keyof typeof EVENT_HOOK_PERMISSION_MAP;
|
|
1126
|
+
/**
|
|
1127
|
+
* Maps React hook names (as used in source code) to the permission required to
|
|
1128
|
+
* use that hook. Covers event hooks AND non-event hooks (useExtendIdentity,
|
|
1129
|
+
* useMessaging) so static analysis can detect the full author-facing surface.
|
|
1130
|
+
* Composed from EVENT_HOOK_PERMISSION_MAP + the non-event additions.
|
|
1131
|
+
*/
|
|
1132
|
+
declare const HOOK_PERMISSION_MAP: {
|
|
1133
|
+
readonly useMessaging: "messaging:send";
|
|
1134
|
+
readonly useExtendIdentity: "identity:extend";
|
|
1135
|
+
readonly useIdentityEvent: "events:identity";
|
|
1136
|
+
readonly useMessagingEvent: "events:messaging";
|
|
1137
|
+
readonly useActivityEvent: "events:activity";
|
|
1138
|
+
};
|
|
1139
|
+
/** Hook key type — React hook names (e.g., 'useIdentityEvent', 'useMessaging'). */
|
|
1140
|
+
type Hook = keyof typeof HOOK_PERMISSION_MAP;
|
|
761
1141
|
|
|
762
1142
|
/**
|
|
763
1143
|
* Extension Manifest Schema
|
|
@@ -908,6 +1288,9 @@ type HostToSandboxMessage = {
|
|
|
908
1288
|
} | {
|
|
909
1289
|
type: 'surface-lifecycle';
|
|
910
1290
|
data: SurfaceLifecycleMessage;
|
|
1291
|
+
} | {
|
|
1292
|
+
type: 'messaging-lifecycle';
|
|
1293
|
+
enabled: boolean;
|
|
911
1294
|
} | {
|
|
912
1295
|
type: 'extension-encryption-key';
|
|
913
1296
|
encryptionKey: string;
|
|
@@ -1166,4 +1549,4 @@ interface Order {
|
|
|
1166
1549
|
declare const TEMPLATE_FLAVORS: readonly ["minimal", "starter", "kitchen-sink"];
|
|
1167
1550
|
type TemplateFlavor = typeof TEMPLATE_FLAVORS[number];
|
|
1168
1551
|
|
|
1169
|
-
export { ACTIVITY_EVENT, ALLOWED_ICONS, type ActionInvokePayload, type ActionPayloadMap, type ActivityEvent, type ActivityEventHandler, type ActivityEventType, type Address, type AllowedIconName, type ApiError, type ApiRequest, type ApiResponse, CAPABILITY_PERMISSION_MAP, type Capability, type CapabilityCall, type CapabilityRequest, type CapabilityResponse, type CapabilityType, type ContextData, type ConversationField, type ConversationTags, type Customer, type DataField, type DataFieldType, EVENT_HOOK_PERMISSION_MAP, type EncryptedPayload, type EventDomain, type EventHook, type EventType, type ExtendIdentityHandler, type ExtendIdentityRequest, type ExtendIdentityResponse, type ExtensionGroup, type ExtensionManifest, type ExtensionRegistryEntry, type FetchRequest, type FetchRequestInit, type FetchResponse, type HostToSandboxMessage, IDENTITY_CLAIMS_MAX_KEYS, IDENTITY_CLAIM_KEY_PATTERN, IDENTITY_CLAIM_MAX_STRING_VALUE_LEN, IDENTITY_EVENT, INVOKE_ACTION, type IdentityBaseClaims, type IdentityEvent, type IdentityEventType, type IdentityExtendPayload, type IdentityExtendResponse, type IdentityState, type InstanceConfig, type InstanceOption, type InvokeAction, type MarketplaceExtension, type MessagingContext, type MessagingEvent, type MessagingEventHandler, type MessagingEventType, type MessagingPostbackEvent, type MessengerCommand, type NamedEntity, type NewConversationPayload, type Order, type OrderAction, type OrderItem, type OrderStatus, type OrderStatuses, PERMISSIONS, type Permission, type Price, RESERVED_CONTEXT_KEYS, RESERVED_IDENTITY_CLAIM_KEYS, type ReservedContextKey, STANDARD_IDENTITY_CLAIM_KEYS, SURFACE_TARGET, type SandboxToHostMessage, type Shipment, type SurfaceContext, type SurfaceLifecycleMessage, type SurfaceTarget, TEMPLATE_FLAVORS, type Target, type TemplateFlavor, type Theme, type ToastPayload, type UITag, type UITagCategory, UI_TAGS, UI_TAG_ATTRIBUTES, UI_TAG_ATTRIBUTE_VALUES, UI_TAG_CATEGORIES, UI_TAG_CHILDREN, UI_TAG_CHILD_ONLY, UI_TAG_COMPOUND, UI_TAG_DEFINITIONS, UI_TAG_SELF_CLOSING, type UserIdentity, type WellKnownActivityEvent, type WidgetAction, tagToComponentName };
|
|
1552
|
+
export { ACTIVITY_EVENT, ALLOWED_ICONS, type ActionInvokePayload, type ActionMetadataValue, type ActionPayloadMap, type ActivityEvent, type ActivityEventHandler, type ActivityEventType, type Address, type AllowedIconName, type ApiError, type ApiRequest, type ApiResponse, type BaseAction, type BaseMessagePayload, CAPABILITY_PERMISSION_MAP, type Capability, type CapabilityCall, type CapabilityRequest, type CapabilityResponse, type CapabilityType, type ContextData, type ConversationField, type ConversationTags, type Customer, type DataField, type DataFieldType, EVENT_HOOK_PERMISSION_MAP, type EncryptedPayload, type EventDomain, type EventHook, type EventType, type ExtendIdentityHandler, type ExtendIdentityRequest, type ExtendIdentityResponse, type ExtensionGroup, type ExtensionManifest, type ExtensionRegistryEntry, type FetchRequest, type FetchRequestInit, type FetchResponse, HOOK_PERMISSION_MAP, type Hook, type HostToSandboxMessage, IDENTITY_CLAIMS_MAX_KEYS, IDENTITY_CLAIM_KEY_PATTERN, IDENTITY_CLAIM_MAX_STRING_VALUE_LEN, IDENTITY_EVENT, INVOKE_ACTION, type IdentityBaseClaims, type IdentityEvent, type IdentityEventType, type IdentityExtendPayload, type IdentityExtendResponse, type IdentityState, type InstanceConfig, type InstanceOption, type InvokeAction, type LinkAction, type LocationRequestAction, MESSAGING_ACTION_EXAMPLES, MESSAGING_SEND_EXAMPLES, type MarketplaceExtension, type MessageAction, type MessageItem, type MessageItemAction, type MessagePayloadKind, type MessagingContext, type MessagingEvent, type MessagingEventHandler, type MessagingEventType, type MessagingPostbackEvent, type MessengerCommand, type NamedEntity, type NewConversationPayload, type Order, type OrderAction, type OrderItem, type OrderStatus, type OrderStatuses, PERMISSIONS, type Permission, type PostbackAction, type Price, RESERVED_CONTEXT_KEYS, RESERVED_IDENTITY_CLAIM_KEYS, type ReplyAction, type ReservedContextKey, STANDARD_IDENTITY_CLAIM_KEYS, SURFACE_TARGET, type SandboxToHostMessage, type SendCarouselMessagePayload, type SendFileMessagePayload, type SendImageMessagePayload, type SendMessageActionableErrorCode, type SendMessageErrorCode, type SendMessagePayload, type SendMessageResponse, type SendTextMessagePayload, type Shipment, type SurfaceContext, type SurfaceLifecycleMessage, type SurfaceTarget, TEMPLATE_FLAVORS, type Target, type TemplateFlavor, type TextEnabledPayload, type TextFormat, type Theme, type ToastPayload, type UITag, type UITagCategory, UI_TAGS, UI_TAG_ATTRIBUTES, UI_TAG_ATTRIBUTE_VALUES, UI_TAG_CATEGORIES, UI_TAG_CHILDREN, UI_TAG_CHILD_ONLY, UI_TAG_COMPOUND, UI_TAG_DEFINITIONS, UI_TAG_SELF_CLOSING, type UserIdentity, type WellKnownActivityEvent, type WidgetAction, tagToComponentName };
|
package/dist/index.js
CHANGED
|
@@ -427,6 +427,63 @@ var IDENTITY_CLAIM_KEY_PATTERN = /^[a-z_][a-z0-9_]{0,63}$/;
|
|
|
427
427
|
var IDENTITY_CLAIMS_MAX_KEYS = 20;
|
|
428
428
|
var IDENTITY_CLAIM_MAX_STRING_VALUE_LEN = 256;
|
|
429
429
|
|
|
430
|
+
// src/messaging.ts
|
|
431
|
+
var MESSAGING_SEND_EXAMPLES = {
|
|
432
|
+
text: {
|
|
433
|
+
kind: "text",
|
|
434
|
+
body: "Order approved \u2713",
|
|
435
|
+
actions: [
|
|
436
|
+
{ type: "reply", label: "Got it", payload: "ACK" },
|
|
437
|
+
{ type: "reply", label: "Show details", payload: "DETAILS" }
|
|
438
|
+
]
|
|
439
|
+
},
|
|
440
|
+
image: {
|
|
441
|
+
kind: "image",
|
|
442
|
+
url: "https://cdn.example.com/products/widget-blue.jpg",
|
|
443
|
+
altText: "Blue widget \u2014 model A24",
|
|
444
|
+
body: "Here is the product you asked about:",
|
|
445
|
+
actions: [
|
|
446
|
+
{ type: "link", label: "View on site", url: "https://example.com/p/widget-a24" }
|
|
447
|
+
]
|
|
448
|
+
},
|
|
449
|
+
file: {
|
|
450
|
+
kind: "file",
|
|
451
|
+
url: "https://cdn.example.com/receipts/order-12345.pdf",
|
|
452
|
+
altText: "Receipt for order #12345",
|
|
453
|
+
body: "Your receipt is attached."
|
|
454
|
+
},
|
|
455
|
+
carousel: {
|
|
456
|
+
kind: "carousel",
|
|
457
|
+
items: [
|
|
458
|
+
{
|
|
459
|
+
title: "Widget A24 \u2014 Blue",
|
|
460
|
+
description: "In stock \u2014 ships in 1-2 days",
|
|
461
|
+
imageUrl: "https://cdn.example.com/products/widget-blue.jpg",
|
|
462
|
+
actions: [
|
|
463
|
+
{ type: "link", label: "View", url: "https://example.com/p/widget-a24-blue" },
|
|
464
|
+
{ type: "postback", label: "Add to cart", payload: "add_to_cart:widget-a24-blue" }
|
|
465
|
+
]
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
title: "Widget A24 \u2014 Red",
|
|
469
|
+
description: "Limited stock",
|
|
470
|
+
imageUrl: "https://cdn.example.com/products/widget-red.jpg",
|
|
471
|
+
actions: [
|
|
472
|
+
{ type: "link", label: "View", url: "https://example.com/p/widget-a24-red" },
|
|
473
|
+
{ type: "postback", label: "Add to cart", payload: "add_to_cart:widget-a24-red" }
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
],
|
|
477
|
+
displaySettings: { imageAspectRatio: "horizontal" }
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var MESSAGING_ACTION_EXAMPLES = {
|
|
481
|
+
reply: { type: "reply", label: "Got it", payload: "ACK" },
|
|
482
|
+
link: { type: "link", label: "View on site", url: "https://example.com/p/widget-a24" },
|
|
483
|
+
postback: { type: "postback", label: "Add to cart", payload: "add_to_cart:widget-a24" },
|
|
484
|
+
locationRequest: { type: "locationRequest", label: "Share location" }
|
|
485
|
+
};
|
|
486
|
+
|
|
430
487
|
// src/activity.ts
|
|
431
488
|
var ACTIVITY_EVENT = {
|
|
432
489
|
CLICK: "click",
|
|
@@ -445,6 +502,7 @@ var PERMISSIONS = [
|
|
|
445
502
|
"data:fetch",
|
|
446
503
|
"actions:toast",
|
|
447
504
|
"actions:invoke",
|
|
505
|
+
"messaging:send",
|
|
448
506
|
"identity:extend",
|
|
449
507
|
"events:identity",
|
|
450
508
|
"events:messaging",
|
|
@@ -456,13 +514,19 @@ var CAPABILITY_PERMISSION_MAP = {
|
|
|
456
514
|
"data.fetch": "data:fetch",
|
|
457
515
|
"actions.toast": "actions:toast",
|
|
458
516
|
"actions.invoke": "actions:invoke",
|
|
459
|
-
"identity.extend": "identity:extend"
|
|
517
|
+
"identity.extend": "identity:extend",
|
|
518
|
+
"messaging.send": "messaging:send"
|
|
460
519
|
};
|
|
461
520
|
var EVENT_HOOK_PERMISSION_MAP = {
|
|
462
521
|
useIdentityEvent: "events:identity",
|
|
463
522
|
useMessagingEvent: "events:messaging",
|
|
464
523
|
useActivityEvent: "events:activity"
|
|
465
524
|
};
|
|
525
|
+
var HOOK_PERMISSION_MAP = {
|
|
526
|
+
...EVENT_HOOK_PERMISSION_MAP,
|
|
527
|
+
useMessaging: "messaging:send",
|
|
528
|
+
useExtendIdentity: "identity:extend"
|
|
529
|
+
};
|
|
466
530
|
|
|
467
531
|
// src/manifest.ts
|
|
468
532
|
var SURFACE_TARGET = {
|
|
@@ -475,4 +539,4 @@ var SURFACE_TARGET = {
|
|
|
475
539
|
// src/scaffold.ts
|
|
476
540
|
var TEMPLATE_FLAVORS = ["minimal", "starter", "kitchen-sink"];
|
|
477
541
|
|
|
478
|
-
export { ACTIVITY_EVENT, ALLOWED_ICONS, CAPABILITY_PERMISSION_MAP, EVENT_HOOK_PERMISSION_MAP, EXTENSION_CATEGORY, EXTENSION_VISIBILITY, IDENTITY_CLAIMS_MAX_KEYS, IDENTITY_CLAIM_KEY_PATTERN, IDENTITY_CLAIM_MAX_STRING_VALUE_LEN, IDENTITY_EVENT, INVOKE_ACTION, PERMISSIONS, RESERVED_CONTEXT_KEYS, RESERVED_IDENTITY_CLAIM_KEYS, STANDARD_IDENTITY_CLAIM_KEYS, SURFACE_TARGET, TEMPLATE_FLAVORS, UI_TAGS, UI_TAG_ATTRIBUTES, UI_TAG_ATTRIBUTE_VALUES, UI_TAG_CATEGORIES, UI_TAG_CHILDREN, UI_TAG_CHILD_ONLY, UI_TAG_COMPOUND, UI_TAG_DEFINITIONS, UI_TAG_SELF_CLOSING, asClerkOrgId, asClerkUserId, asISOTimestamp, tagToComponentName };
|
|
542
|
+
export { ACTIVITY_EVENT, ALLOWED_ICONS, CAPABILITY_PERMISSION_MAP, EVENT_HOOK_PERMISSION_MAP, EXTENSION_CATEGORY, EXTENSION_VISIBILITY, HOOK_PERMISSION_MAP, IDENTITY_CLAIMS_MAX_KEYS, IDENTITY_CLAIM_KEY_PATTERN, IDENTITY_CLAIM_MAX_STRING_VALUE_LEN, IDENTITY_EVENT, INVOKE_ACTION, MESSAGING_ACTION_EXAMPLES, MESSAGING_SEND_EXAMPLES, PERMISSIONS, RESERVED_CONTEXT_KEYS, RESERVED_IDENTITY_CLAIM_KEYS, STANDARD_IDENTITY_CLAIM_KEYS, SURFACE_TARGET, TEMPLATE_FLAVORS, UI_TAGS, UI_TAG_ATTRIBUTES, UI_TAG_ATTRIBUTE_VALUES, UI_TAG_CATEGORIES, UI_TAG_CHILDREN, UI_TAG_CHILD_ONLY, UI_TAG_COMPOUND, UI_TAG_DEFINITIONS, UI_TAG_SELF_CLOSING, asClerkOrgId, asClerkUserId, asISOTimestamp, tagToComponentName };
|