@ada-cx/messaging-bridge 1.0.0-setup.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.
@@ -0,0 +1,160 @@
1
+ //#region \0@oxc-project+runtime@0.122.0/helpers/typeof.js
2
+ function _typeof(o) {
3
+ "@babel/helpers - typeof";
4
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
5
+ return typeof o;
6
+ } : function(o) {
7
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
8
+ }, _typeof(o);
9
+ }
10
+ //#endregion
11
+ //#region \0@oxc-project+runtime@0.122.0/helpers/toPrimitive.js
12
+ function toPrimitive(t, r) {
13
+ if ("object" != _typeof(t) || !t) return t;
14
+ var e = t[Symbol.toPrimitive];
15
+ if (void 0 !== e) {
16
+ var i = e.call(t, r || "default");
17
+ if ("object" != _typeof(i)) return i;
18
+ throw new TypeError("@@toPrimitive must return a primitive value.");
19
+ }
20
+ return ("string" === r ? String : Number)(t);
21
+ }
22
+ //#endregion
23
+ //#region \0@oxc-project+runtime@0.122.0/helpers/toPropertyKey.js
24
+ function toPropertyKey(t) {
25
+ var i = toPrimitive(t, "string");
26
+ return "symbol" == _typeof(i) ? i : i + "";
27
+ }
28
+ //#endregion
29
+ //#region \0@oxc-project+runtime@0.122.0/helpers/defineProperty.js
30
+ function _defineProperty(e, r, t) {
31
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
32
+ value: t,
33
+ enumerable: !0,
34
+ configurable: !0,
35
+ writable: !0
36
+ }) : e[r] = t, e;
37
+ }
38
+ //#endregion
39
+ //#region src/loader.ts
40
+ var DEFAULT_CDN_BASE = "https://messaging-assets.ada.support";
41
+ var BRIDGE_ASSET_PATH = "/bridge.js";
42
+ var PINNED_BRIDGE_ENTRY_PATH = "bridge/bridge.js";
43
+ var PINNED_BUILD_SHA_PATTERN = /^[0-9a-f]{40}$/;
44
+ var UNSTAMPED_BUILD_SHA_PATTERN = /^0{40}$/;
45
+ /**
46
+ * Typed failure raised by {@link loadMessagingBridge} and
47
+ * {@link resolveBridgeCdnUrl}. Mirrors the sdk loader's
48
+ * `MessagingSdkLoadError` so both loaders share one error contract.
49
+ */
50
+ var MessagingBridgeLoadError = class extends Error {
51
+ constructor(message, code, cause) {
52
+ super(message);
53
+ _defineProperty(this, "code", void 0);
54
+ this.name = "MessagingBridgeLoadError";
55
+ this.code = code;
56
+ if (cause !== void 0) this.cause = cause;
57
+ }
58
+ };
59
+ var defaultImportModule = (url) => import(
60
+ /* webpackIgnore: true */
61
+ /* @vite-ignore */
62
+ url
63
+ );
64
+ var inFlightByImporter = /* @__PURE__ */ new WeakMap();
65
+ var LOOPBACK_HOSTS = new Set([
66
+ "localhost",
67
+ "127.0.0.1",
68
+ "[::1]",
69
+ "::1"
70
+ ]);
71
+ function isLoopbackHostname(hostname) {
72
+ const normalized = hostname.trim().toLowerCase();
73
+ return LOOPBACK_HOSTS.has(normalized) || normalized.endsWith(".localhost");
74
+ }
75
+ function resolvePinnedBuildSha(pinBuildSha) {
76
+ const sha = pinBuildSha.trim().toLowerCase();
77
+ if (!PINNED_BUILD_SHA_PATTERN.test(sha)) throw new MessagingBridgeLoadError(`The pinBuildSha option must be a full 40-character hex git SHA: "${pinBuildSha}".`, "invalid_build_sha");
78
+ if (UNSTAMPED_BUILD_SHA_PATTERN.test(sha)) throw new MessagingBridgeLoadError("The pinBuildSha option is the unstamped CDN_BUILD_SHA placeholder. Only the published npm package carries a stamped SHA; a repository or local build cannot pin a CDN build.", "unstamped_build_sha");
79
+ return sha;
80
+ }
81
+ /**
82
+ * Resolve the full bridge asset URL for the given options: trailing slashes
83
+ * are stripped from `cdnBase` and `/bridge.js` is appended — or, with
84
+ * `pinBuildSha`, `/<sha>/bridge/bridge.js` for that build's immutable copy.
85
+ *
86
+ * The runtime this URL serves carries the bridge's security logic (origin
87
+ * derivation, the TOFU origin lock, the hydration TTL), so a cleartext
88
+ * transport would let an on-path attacker replace it wholesale: `https:` is
89
+ * required, with a loopback-only `http:` exception for local development.
90
+ *
91
+ * @throws {MessagingBridgeLoadError} with code `invalid_cdn_base` when
92
+ * `cdnBase` does not form a valid URL under that policy, `invalid_build_sha`
93
+ * when `pinBuildSha` is not a full 40-hex git SHA, or `unstamped_build_sha`
94
+ * when it is the unstamped placeholder.
95
+ */
96
+ function resolveBridgeCdnUrl(options) {
97
+ const base = (options?.cdnBase ?? DEFAULT_CDN_BASE).trim().replace(/\/+$/, "");
98
+ const assetPath = options?.pinBuildSha === void 0 ? BRIDGE_ASSET_PATH : `/${resolvePinnedBuildSha(options.pinBuildSha)}/${PINNED_BRIDGE_ENTRY_PATH}`;
99
+ let url;
100
+ try {
101
+ url = new URL(`${base}${assetPath}`);
102
+ } catch (cause) {
103
+ throw new MessagingBridgeLoadError(`The cdnBase option is not a valid URL: "${base}".`, "invalid_cdn_base", cause);
104
+ }
105
+ const isHttps = url.protocol === "https:";
106
+ const isLoopbackHttp = url.protocol === "http:" && isLoopbackHostname(url.hostname);
107
+ if (!isHttps && !isLoopbackHttp) throw new MessagingBridgeLoadError(`The cdnBase option must use https (plain http is allowed only for loopback hosts): "${base}".`, "invalid_cdn_base");
108
+ return url.toString();
109
+ }
110
+ function isMessagingBridgeModule(value) {
111
+ return typeof value === "object" && value !== null && typeof value.createBridgeClient === "function";
112
+ }
113
+ async function importBridgeModule(url, importModule) {
114
+ let loaded;
115
+ try {
116
+ loaded = await importModule(url);
117
+ } catch (cause) {
118
+ throw new MessagingBridgeLoadError(`The Ada bridge runtime failed to load from ${url}.`, "bridge_import_failed", cause);
119
+ }
120
+ if (!isMessagingBridgeModule(loaded)) throw new MessagingBridgeLoadError(`The module at ${url} does not export createBridgeClient; it is not an Ada bridge build.`, "bridge_module_invalid");
121
+ return loaded;
122
+ }
123
+ /**
124
+ * Load the Ada bridge runtime from the CDN.
125
+ *
126
+ * The returned promise is memoized per resolved URL: concurrent and repeated
127
+ * calls with the same `cdnBase` share one in-flight import. A failed load is
128
+ * evicted from the memo so a later call can retry. Rejections are always
129
+ * {@link MessagingBridgeLoadError}.
130
+ *
131
+ * @example
132
+ * const { createBridgeClient, STATE } = await loadMessagingBridge();
133
+ */
134
+ function loadMessagingBridge(options = {}) {
135
+ const importModule = options.importModule ?? defaultImportModule;
136
+ let url;
137
+ try {
138
+ url = resolveBridgeCdnUrl(options);
139
+ } catch (error) {
140
+ return Promise.reject(error);
141
+ }
142
+ let inFlight = inFlightByImporter.get(importModule);
143
+ if (!inFlight) {
144
+ inFlight = /* @__PURE__ */ new Map();
145
+ inFlightByImporter.set(importModule, inFlight);
146
+ }
147
+ const existing = inFlight.get(url);
148
+ if (existing) return existing;
149
+ const cache = inFlight;
150
+ const pending = importBridgeModule(url, importModule);
151
+ cache.set(url, pending);
152
+ pending.catch(() => {
153
+ if (cache.get(url) === pending) cache.delete(url);
154
+ });
155
+ return pending;
156
+ }
157
+ //#endregion
158
+ export { loadMessagingBridge as n, resolveBridgeCdnUrl as r, MessagingBridgeLoadError as t };
159
+
160
+ //# sourceMappingURL=loader-CVynp73o.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-CVynp73o.js","names":[],"sources":["../src/loader.ts"],"sourcesContent":["import type { BridgeClient, createBridgeClient } from \"./bridge-client\";\nimport type {\n\tfilterDisplayable,\n\tfindFirstUnread,\n\tgroupMessages,\n\tisAgentTyping,\n\tisConnectivityLost,\n\tisHistoricalRow,\n\tmessageKey,\n\tresolveBotName,\n\tselectUnread,\n} from \"./derive\";\nimport type { STATE } from \"./state-keys\";\n\nconst DEFAULT_CDN_BASE = \"https://messaging-assets.ada.support\";\nconst BRIDGE_ASSET_PATH = \"/bridge.js\";\n\n// The CDN pipeline uploads each main commit's bridge runtime as an immutable\n// SHA-rooted copy (`<cdnBase>/<sha>/bridge/bridge.js`); the mutable root\n// `bridge.js` is the loader fence's copy of one of those. A pin bypasses the\n// root asset and imports one immutable copy directly.\nconst PINNED_BRIDGE_ENTRY_PATH = \"bridge/bridge.js\";\n\n// Strict on purpose: the pin is interpolated into a CDN path, so only a full\n// lowercase 40-hex git SHA may pass (mirrors the sdk loader's boundary).\nconst PINNED_BUILD_SHA_PATTERN = /^[0-9a-f]{40}$/;\nconst UNSTAMPED_BUILD_SHA_PATTERN = /^0{40}$/;\n\n/** Why a {@link MessagingBridgeLoadError} was raised. */\nexport type MessagingBridgeLoadErrorCode =\n\t/**\n\t * The `cdnBase` option is not a valid `https:` URL (plain `http:` is\n\t * allowed only for loopback hosts).\n\t */\n\t| \"invalid_cdn_base\"\n\t/** The `pinBuildSha` option is not a full 40-character hex git SHA. */\n\t| \"invalid_build_sha\"\n\t/**\n\t * The `pinBuildSha` option is the unstamped 40-zero placeholder: this\n\t * copy of the package was built from the repository, not published, so\n\t * its `CDN_BUILD_SHA` names no CDN build.\n\t */\n\t| \"unstamped_build_sha\"\n\t/** The dynamic import of the CDN asset failed (network, CSP, 404). */\n\t| \"bridge_import_failed\"\n\t/** The imported module does not expose the Ada bridge surface. */\n\t| \"bridge_module_invalid\";\n\n/**\n * Typed failure raised by {@link loadMessagingBridge} and\n * {@link resolveBridgeCdnUrl}. Mirrors the sdk loader's\n * `MessagingSdkLoadError` so both loaders share one error contract.\n */\nexport class MessagingBridgeLoadError extends Error {\n\treadonly code: MessagingBridgeLoadErrorCode;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tcode: MessagingBridgeLoadErrorCode,\n\t\tcause?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"MessagingBridgeLoadError\";\n\t\tthis.code = code;\n\t\tif (cause !== undefined) {\n\t\t\tthis.cause = cause;\n\t\t}\n\t}\n}\n\n/**\n * The module shape served at `<cdnBase>/bridge.js`.\n *\n * The npm package never carries this runtime — it always resolves from Ada's\n * CDN so security-bearing logic (origin derivation, the TOFU origin lock, the\n * hydration TTL) stays patchable by Ada without a customer release.\n */\nexport interface MessagingBridgeModule {\n\t/**\n\t * Create a {@link BridgeClient} connected to the parent core frame.\n\t * Declared as `typeof` the runtime symbol so the published type cannot\n\t * drift from the CDN implementation (pinned by types-drift.test.ts).\n\t */\n\tcreateBridgeClient: typeof createBridgeClient;\n\t/** Typed constants for all bridge state keys. */\n\tSTATE: typeof STATE;\n\t// Pure derivation helpers (src/derive.ts) — logic mined from Ada's\n\t// reference app, distributed with the runtime so it stays Ada-patchable.\n\t// Older cached bridge.js builds may predate them: feature-detect before\n\t// depending on one in code that must tolerate a stale CDN cache.\n\t/** Stable message identity across the stream-final and optimistic-durable id swaps. */\n\tmessageKey: typeof messageKey;\n\t/** Whether a row belongs to a conversation the chatter has left. */\n\tisHistoricalRow: typeof isHistoricalRow;\n\t/** First unread bot/agent message past the persisted read watermark. */\n\tfindFirstUnread: typeof findFirstUnread;\n\t/** Unread divider anchor + count derived from state. */\n\tselectUnread: typeof selectUnread;\n\t/** Per-index date-divider and sender-run grouping decisions. */\n\tgroupMessages: typeof groupMessages;\n\t/** The messages a transcript should actually render. */\n\tfilterDisplayable: typeof filterDisplayable;\n\t/** Bot display name: `config.botName`, else `config.handle`, else \"Ada\". */\n\tresolveBotName: typeof resolveBotName;\n\t/** Someone is composing a reply (core's typing verdict + active agent). */\n\tisAgentTyping: typeof isAgentTyping;\n\t/** Core's connectivity verdict — never substitute `navigator.onLine`. */\n\tisConnectivityLost: typeof isConnectivityLost;\n}\n\ntype ImportBridgeModule = (url: string) => Promise<unknown>;\n\n/**\n * Options for {@link loadMessagingBridge}.\n */\nexport interface LoadMessagingBridgeOptions {\n\t/**\n\t * Origin the bridge runtime is loaded from. Must be an `https:` URL;\n\t * plain `http:` is accepted only for loopback hosts (`localhost`,\n\t * `127.0.0.1`, `[::1]`, `*.localhost`) during local development.\n\t * Defaults to Ada's production asset host\n\t * (`https://messaging-assets.ada.support`). Override only for staging\n\t * validation against a non-production asset host.\n\t */\n\tcdnBase?: string;\n\t/**\n\t * Full 40-character git commit SHA of a deployed CDN build. When set, the\n\t * loader skips the mutable root `bridge.js` and imports that build's\n\t * immutable copy (`<cdnBase>/<sha>/bridge/bridge.js`) directly. Pass the\n\t * package's `CDN_BUILD_SHA` export to pin the build associated with this\n\t * npm version. NOT recommended for production: a pinned runtime misses\n\t * Ada's fixes and the loader-fence rollout, and may predate core/server\n\t * contract changes. Composes with `cdnBase` for staged validation.\n\t */\n\tpinBuildSha?: string;\n\t/**\n\t * Import seam for unit tests. Defaults to a native dynamic `import()` of\n\t * the resolved asset URL.\n\t */\n\timportModule?: ImportBridgeModule;\n}\n\n// Both annotations are load-bearing: bundlers rewrite bare dynamic imports,\n// and this specifier must reach the browser untouched so the runtime always\n// resolves from Ada's CDN. The npm build for this entry is unminified so the\n// annotations survive into the published output.\nconst defaultImportModule: ImportBridgeModule = (url) =>\n\timport(/* webpackIgnore: true */ /* @vite-ignore */ url);\n\n// Keyed by import seam so production memoizes on the module-level default\n// while each injected test seam gets an isolated cache.\nconst inFlightByImporter = new WeakMap<\n\tImportBridgeModule,\n\tMap<string, Promise<MessagingBridgeModule>>\n>();\n\n// Mirrors the loopback semantics of the shared `isLoopbackHost` /\n// `validateMessagingEndpoint` (shared/utils/src/url.ts). Inlined because the\n// published loader must stay dependency-free; keep the host set in sync.\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\", \"::1\"]);\n\nfunction isLoopbackHostname(hostname: string): boolean {\n\tconst normalized = hostname.trim().toLowerCase();\n\t// `*.localhost` resolves to the loopback interface and is \"potentially\n\t// trustworthy\" per the Secure Contexts spec; no production host ends in\n\t// `.localhost`.\n\treturn LOOPBACK_HOSTS.has(normalized) || normalized.endsWith(\".localhost\");\n}\n\nfunction resolvePinnedBuildSha(pinBuildSha: string): string {\n\tconst sha = pinBuildSha.trim().toLowerCase();\n\tif (!PINNED_BUILD_SHA_PATTERN.test(sha)) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t`The pinBuildSha option must be a full 40-character hex git SHA: \"${pinBuildSha}\".`,\n\t\t\t\"invalid_build_sha\",\n\t\t);\n\t}\n\tif (UNSTAMPED_BUILD_SHA_PATTERN.test(sha)) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t\"The pinBuildSha option is the unstamped CDN_BUILD_SHA placeholder. Only the published npm package carries a stamped SHA; a repository or local build cannot pin a CDN build.\",\n\t\t\t\"unstamped_build_sha\",\n\t\t);\n\t}\n\treturn sha;\n}\n\n/**\n * Resolve the full bridge asset URL for the given options: trailing slashes\n * are stripped from `cdnBase` and `/bridge.js` is appended — or, with\n * `pinBuildSha`, `/<sha>/bridge/bridge.js` for that build's immutable copy.\n *\n * The runtime this URL serves carries the bridge's security logic (origin\n * derivation, the TOFU origin lock, the hydration TTL), so a cleartext\n * transport would let an on-path attacker replace it wholesale: `https:` is\n * required, with a loopback-only `http:` exception for local development.\n *\n * @throws {MessagingBridgeLoadError} with code `invalid_cdn_base` when\n * `cdnBase` does not form a valid URL under that policy, `invalid_build_sha`\n * when `pinBuildSha` is not a full 40-hex git SHA, or `unstamped_build_sha`\n * when it is the unstamped placeholder.\n */\nexport function resolveBridgeCdnUrl(\n\toptions?: Pick<LoadMessagingBridgeOptions, \"cdnBase\" | \"pinBuildSha\">,\n): string {\n\tconst base = (options?.cdnBase ?? DEFAULT_CDN_BASE)\n\t\t.trim()\n\t\t.replace(/\\/+$/, \"\");\n\tconst assetPath =\n\t\toptions?.pinBuildSha === undefined\n\t\t\t? BRIDGE_ASSET_PATH\n\t\t\t: `/${resolvePinnedBuildSha(options.pinBuildSha)}/${PINNED_BRIDGE_ENTRY_PATH}`;\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(`${base}${assetPath}`);\n\t} catch (cause) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t`The cdnBase option is not a valid URL: \"${base}\".`,\n\t\t\t\"invalid_cdn_base\",\n\t\t\tcause,\n\t\t);\n\t}\n\tconst isHttps = url.protocol === \"https:\";\n\tconst isLoopbackHttp =\n\t\turl.protocol === \"http:\" && isLoopbackHostname(url.hostname);\n\tif (!isHttps && !isLoopbackHttp) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t`The cdnBase option must use https (plain http is allowed only for loopback hosts): \"${base}\".`,\n\t\t\t\"invalid_cdn_base\",\n\t\t);\n\t}\n\treturn url.toString();\n}\n\nfunction isMessagingBridgeModule(\n\tvalue: unknown,\n): value is MessagingBridgeModule {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\ttypeof (value as Record<string, unknown>).createBridgeClient === \"function\"\n\t);\n}\n\nasync function importBridgeModule(\n\turl: string,\n\timportModule: ImportBridgeModule,\n): Promise<MessagingBridgeModule> {\n\tlet loaded: unknown;\n\ttry {\n\t\tloaded = await importModule(url);\n\t} catch (cause) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t`The Ada bridge runtime failed to load from ${url}.`,\n\t\t\t\"bridge_import_failed\",\n\t\t\tcause,\n\t\t);\n\t}\n\tif (!isMessagingBridgeModule(loaded)) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t`The module at ${url} does not export createBridgeClient; it is not an Ada bridge build.`,\n\t\t\t\"bridge_module_invalid\",\n\t\t);\n\t}\n\treturn loaded;\n}\n\n/**\n * Load the Ada bridge runtime from the CDN.\n *\n * The returned promise is memoized per resolved URL: concurrent and repeated\n * calls with the same `cdnBase` share one in-flight import. A failed load is\n * evicted from the memo so a later call can retry. Rejections are always\n * {@link MessagingBridgeLoadError}.\n *\n * @example\n * const { createBridgeClient, STATE } = await loadMessagingBridge();\n */\nexport function loadMessagingBridge(\n\toptions: LoadMessagingBridgeOptions = {},\n): Promise<MessagingBridgeModule> {\n\tconst importModule = options.importModule ?? defaultImportModule;\n\tlet url: string;\n\ttry {\n\t\turl = resolveBridgeCdnUrl(options);\n\t} catch (error) {\n\t\treturn Promise.reject(error);\n\t}\n\n\tlet inFlight = inFlightByImporter.get(importModule);\n\tif (!inFlight) {\n\t\tinFlight = new Map();\n\t\tinFlightByImporter.set(importModule, inFlight);\n\t}\n\tconst existing = inFlight.get(url);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\tconst cache = inFlight;\n\tconst pending = importBridgeModule(url, importModule);\n\tcache.set(url, pending);\n\tpending.catch(() => {\n\t\tif (cache.get(url) === pending) {\n\t\t\tcache.delete(url);\n\t\t}\n\t});\n\treturn pending;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAM1B,IAAM,2BAA2B;AAIjC,IAAM,2BAA2B;AACjC,IAAM,8BAA8B;;;;;;AA2BpC,IAAa,2BAAb,cAA8C,MAAM;CAGnD,YACC,SACA,MACA,OACC;AACD,QAAM,QAAQ;wBAPf,QAAA,KAAA,EAAS;AAQR,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,MAAI,UAAU,KAAA,EACb,MAAK,QAAQ;;;AAiFhB,IAAM,uBAA2C,QAChD;;;CAAoD;;AAIrD,IAAM,qCAAqB,IAAI,SAG5B;AAKH,IAAM,iBAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAS;CAAM,CAAC;AAE1E,SAAS,mBAAmB,UAA2B;CACtD,MAAM,aAAa,SAAS,MAAM,CAAC,aAAa;AAIhD,QAAO,eAAe,IAAI,WAAW,IAAI,WAAW,SAAS,aAAa;;AAG3E,SAAS,sBAAsB,aAA6B;CAC3D,MAAM,MAAM,YAAY,MAAM,CAAC,aAAa;AAC5C,KAAI,CAAC,yBAAyB,KAAK,IAAI,CACtC,OAAM,IAAI,yBACT,oEAAoE,YAAY,KAChF,oBACA;AAEF,KAAI,4BAA4B,KAAK,IAAI,CACxC,OAAM,IAAI,yBACT,gLACA,sBACA;AAEF,QAAO;;;;;;;;;;;;;;;;;AAkBR,SAAgB,oBACf,SACS;CACT,MAAM,QAAQ,SAAS,WAAW,kBAChC,MAAM,CACN,QAAQ,QAAQ,GAAG;CACrB,MAAM,YACL,SAAS,gBAAgB,KAAA,IACtB,oBACA,IAAI,sBAAsB,QAAQ,YAAY,CAAC,GAAG;CACtD,IAAI;AACJ,KAAI;AACH,QAAM,IAAI,IAAI,GAAG,OAAO,YAAY;UAC5B,OAAO;AACf,QAAM,IAAI,yBACT,2CAA2C,KAAK,KAChD,oBACA,MACA;;CAEF,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,iBACL,IAAI,aAAa,WAAW,mBAAmB,IAAI,SAAS;AAC7D,KAAI,CAAC,WAAW,CAAC,eAChB,OAAM,IAAI,yBACT,uFAAuF,KAAK,KAC5F,mBACA;AAEF,QAAO,IAAI,UAAU;;AAGtB,SAAS,wBACR,OACiC;AACjC,QACC,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAkC,uBAAuB;;AAInE,eAAe,mBACd,KACA,cACiC;CACjC,IAAI;AACJ,KAAI;AACH,WAAS,MAAM,aAAa,IAAI;UACxB,OAAO;AACf,QAAM,IAAI,yBACT,8CAA8C,IAAI,IAClD,wBACA,MACA;;AAEF,KAAI,CAAC,wBAAwB,OAAO,CACnC,OAAM,IAAI,yBACT,iBAAiB,IAAI,sEACrB,wBACA;AAEF,QAAO;;;;;;;;;;;;;AAcR,SAAgB,oBACf,UAAsC,EAAE,EACP;CACjC,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,IAAI;AACJ,KAAI;AACH,QAAM,oBAAoB,QAAQ;UAC1B,OAAO;AACf,SAAO,QAAQ,OAAO,MAAM;;CAG7B,IAAI,WAAW,mBAAmB,IAAI,aAAa;AACnD,KAAI,CAAC,UAAU;AACd,6BAAW,IAAI,KAAK;AACpB,qBAAmB,IAAI,cAAc,SAAS;;CAE/C,MAAM,WAAW,SAAS,IAAI,IAAI;AAClC,KAAI,SACH,QAAO;CAGR,MAAM,QAAQ;CACd,MAAM,UAAU,mBAAmB,KAAK,aAAa;AACrD,OAAM,IAAI,KAAK,QAAQ;AACvB,SAAQ,YAAY;AACnB,MAAI,MAAM,IAAI,IAAI,KAAK,QACtB,OAAM,OAAO,IAAI;GAEjB;AACF,QAAO"}
@@ -0,0 +1,125 @@
1
+ import type { createBridgeClient } from "./bridge-client.js";
2
+ import type { filterDisplayable, findFirstUnread, groupMessages, isAgentTyping, isConnectivityLost, isHistoricalRow, messageKey, resolveBotName, selectUnread } from "./derive.js";
3
+ import type { STATE } from "./state-keys.js";
4
+ /** Why a {@link MessagingBridgeLoadError} was raised. */
5
+ export type MessagingBridgeLoadErrorCode =
6
+ /**
7
+ * The `cdnBase` option is not a valid `https:` URL (plain `http:` is
8
+ * allowed only for loopback hosts).
9
+ */
10
+ "invalid_cdn_base"
11
+ /** The `pinBuildSha` option is not a full 40-character hex git SHA. */
12
+ | "invalid_build_sha"
13
+ /**
14
+ * The `pinBuildSha` option is the unstamped 40-zero placeholder: this
15
+ * copy of the package was built from the repository, not published, so
16
+ * its `CDN_BUILD_SHA` names no CDN build.
17
+ */
18
+ | "unstamped_build_sha"
19
+ /** The dynamic import of the CDN asset failed (network, CSP, 404). */
20
+ | "bridge_import_failed"
21
+ /** The imported module does not expose the Ada bridge surface. */
22
+ | "bridge_module_invalid";
23
+ /**
24
+ * Typed failure raised by {@link loadMessagingBridge} and
25
+ * {@link resolveBridgeCdnUrl}. Mirrors the sdk loader's
26
+ * `MessagingSdkLoadError` so both loaders share one error contract.
27
+ */
28
+ export declare class MessagingBridgeLoadError extends Error {
29
+ readonly code: MessagingBridgeLoadErrorCode;
30
+ constructor(message: string, code: MessagingBridgeLoadErrorCode, cause?: unknown);
31
+ }
32
+ /**
33
+ * The module shape served at `<cdnBase>/bridge.js`.
34
+ *
35
+ * The npm package never carries this runtime — it always resolves from Ada's
36
+ * CDN so security-bearing logic (origin derivation, the TOFU origin lock, the
37
+ * hydration TTL) stays patchable by Ada without a customer release.
38
+ */
39
+ export interface MessagingBridgeModule {
40
+ /**
41
+ * Create a {@link BridgeClient} connected to the parent core frame.
42
+ * Declared as `typeof` the runtime symbol so the published type cannot
43
+ * drift from the CDN implementation (pinned by types-drift.test.ts).
44
+ */
45
+ createBridgeClient: typeof createBridgeClient;
46
+ /** Typed constants for all bridge state keys. */
47
+ STATE: typeof STATE;
48
+ /** Stable message identity across the stream-final and optimistic-durable id swaps. */
49
+ messageKey: typeof messageKey;
50
+ /** Whether a row belongs to a conversation the chatter has left. */
51
+ isHistoricalRow: typeof isHistoricalRow;
52
+ /** First unread bot/agent message past the persisted read watermark. */
53
+ findFirstUnread: typeof findFirstUnread;
54
+ /** Unread divider anchor + count derived from state. */
55
+ selectUnread: typeof selectUnread;
56
+ /** Per-index date-divider and sender-run grouping decisions. */
57
+ groupMessages: typeof groupMessages;
58
+ /** The messages a transcript should actually render. */
59
+ filterDisplayable: typeof filterDisplayable;
60
+ /** Bot display name: `config.botName`, else `config.handle`, else "Ada". */
61
+ resolveBotName: typeof resolveBotName;
62
+ /** Someone is composing a reply (core's typing verdict + active agent). */
63
+ isAgentTyping: typeof isAgentTyping;
64
+ /** Core's connectivity verdict — never substitute `navigator.onLine`. */
65
+ isConnectivityLost: typeof isConnectivityLost;
66
+ }
67
+ type ImportBridgeModule = (url: string) => Promise<unknown>;
68
+ /**
69
+ * Options for {@link loadMessagingBridge}.
70
+ */
71
+ export interface LoadMessagingBridgeOptions {
72
+ /**
73
+ * Origin the bridge runtime is loaded from. Must be an `https:` URL;
74
+ * plain `http:` is accepted only for loopback hosts (`localhost`,
75
+ * `127.0.0.1`, `[::1]`, `*.localhost`) during local development.
76
+ * Defaults to Ada's production asset host
77
+ * (`https://messaging-assets.ada.support`). Override only for staging
78
+ * validation against a non-production asset host.
79
+ */
80
+ cdnBase?: string;
81
+ /**
82
+ * Full 40-character git commit SHA of a deployed CDN build. When set, the
83
+ * loader skips the mutable root `bridge.js` and imports that build's
84
+ * immutable copy (`<cdnBase>/<sha>/bridge/bridge.js`) directly. Pass the
85
+ * package's `CDN_BUILD_SHA` export to pin the build associated with this
86
+ * npm version. NOT recommended for production: a pinned runtime misses
87
+ * Ada's fixes and the loader-fence rollout, and may predate core/server
88
+ * contract changes. Composes with `cdnBase` for staged validation.
89
+ */
90
+ pinBuildSha?: string;
91
+ /**
92
+ * Import seam for unit tests. Defaults to a native dynamic `import()` of
93
+ * the resolved asset URL.
94
+ */
95
+ importModule?: ImportBridgeModule;
96
+ }
97
+ /**
98
+ * Resolve the full bridge asset URL for the given options: trailing slashes
99
+ * are stripped from `cdnBase` and `/bridge.js` is appended — or, with
100
+ * `pinBuildSha`, `/<sha>/bridge/bridge.js` for that build's immutable copy.
101
+ *
102
+ * The runtime this URL serves carries the bridge's security logic (origin
103
+ * derivation, the TOFU origin lock, the hydration TTL), so a cleartext
104
+ * transport would let an on-path attacker replace it wholesale: `https:` is
105
+ * required, with a loopback-only `http:` exception for local development.
106
+ *
107
+ * @throws {MessagingBridgeLoadError} with code `invalid_cdn_base` when
108
+ * `cdnBase` does not form a valid URL under that policy, `invalid_build_sha`
109
+ * when `pinBuildSha` is not a full 40-hex git SHA, or `unstamped_build_sha`
110
+ * when it is the unstamped placeholder.
111
+ */
112
+ export declare function resolveBridgeCdnUrl(options?: Pick<LoadMessagingBridgeOptions, "cdnBase" | "pinBuildSha">): string;
113
+ /**
114
+ * Load the Ada bridge runtime from the CDN.
115
+ *
116
+ * The returned promise is memoized per resolved URL: concurrent and repeated
117
+ * calls with the same `cdnBase` share one in-flight import. A failed load is
118
+ * evicted from the memo so a later call can retry. Rejections are always
119
+ * {@link MessagingBridgeLoadError}.
120
+ *
121
+ * @example
122
+ * const { createBridgeClient, STATE } = await loadMessagingBridge();
123
+ */
124
+ export declare function loadMessagingBridge(options?: LoadMessagingBridgeOptions): Promise<MessagingBridgeModule>;
125
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@ada-cx/messaging-bridge` — published npm entry.
3
+ *
4
+ * Carries only TypeScript types and the thin CDN loader. The bridge runtime
5
+ * (`createBridgeClient`, `STATE`) always resolves from Ada's CDN via
6
+ * `loadMessagingBridge()` so Ada can patch security-bearing logic without a
7
+ * customer release. Never add runtime implementation to this entry.
8
+ */
9
+ export type { FileUploadErrorData, FileUploadErrorReason, } from "./shared-utils/index.js";
10
+ export type { BridgeClient } from "./bridge-client.js";
11
+ export { CDN_BUILD_SHA, isCdnBuildShaStamped } from "./build-info.js";
12
+ export type { MessageGroupingEntry, UnreadSelection } from "./derive.js";
13
+ export type { LoadMessagingBridgeOptions, MessagingBridgeLoadErrorCode, MessagingBridgeModule, } from "./loader.js";
14
+ export { loadMessagingBridge, MessagingBridgeLoadError, resolveBridgeCdnUrl, } from "./loader.js";
15
+ export type { BridgeClientDestroyedError, BridgeOperations, BridgeOperationsHost, CaptureHandle, CsatSubmitHandle, EndChatEligibilityResult, FileUploadHandle, ObserveOptions, OperationResult, SendHandle, SettleOptions, } from "./operations.js";
16
+ export type { StateKey } from "./state-keys.js";
17
+ export type { AppDisplayState, AppEvents, CaptureData, CsatMessage, CsatScaleType, DownloadableMessage, FallbackUiConfig, LinkMessage, ListSelectionData, LiveChatStateData, Message, NotificationPermissionMessage, OptionItem, OptionsMessage, PictureMessage, PresenceMessage, QueueBotBlockMessage, QuickRepliesMessage, QuickReply, SdkPlatform, SeamlessOAuthMessage, SelectableListItem, SelectableListMessage, SignInMessage, TextMessage, VideoMessage, WidgetMessage, } from "./types.js";
@@ -0,0 +1,28 @@
1
+ import { n as loadMessagingBridge, r as resolveBridgeCdnUrl, t as MessagingBridgeLoadError } from "./loader-CVynp73o.js";
2
+ //#region src/build-info.ts
3
+ var GIT_SHA_PATTERN = /^[0-9a-f]{40}$/;
4
+ var UNSTAMPED_SHA_PATTERN = /^0{40}$/;
5
+ /**
6
+ * Git commit SHA of the monorepo commit this npm version was published from.
7
+ * The CDN pipeline deploys each main commit's bridge runtime under an
8
+ * immutable SHA root, so this value names the CDN build associated with this
9
+ * npm version. Pass it as the `pinBuildSha` loader option to load exactly
10
+ * that runtime build — not recommended for production (see the README).
11
+ *
12
+ * In the repository, and in any locally built copy, the value is the
13
+ * unstamped 40-zero placeholder ({@link isCdnBuildShaStamped} returns
14
+ * `false`); only published tarballs carry a real SHA.
15
+ */
16
+ var CDN_BUILD_SHA = "0000000000000000000000000000000000000000";
17
+ /**
18
+ * Whether `sha` (default {@link CDN_BUILD_SHA}) is a stamped full git commit
19
+ * SHA rather than the unstamped repo placeholder.
20
+ */
21
+ function isCdnBuildShaStamped(sha = CDN_BUILD_SHA) {
22
+ const normalized = sha.trim().toLowerCase();
23
+ return GIT_SHA_PATTERN.test(normalized) && !UNSTAMPED_SHA_PATTERN.test(normalized);
24
+ }
25
+ //#endregion
26
+ export { CDN_BUILD_SHA, MessagingBridgeLoadError, isCdnBuildShaStamped, loadMessagingBridge, resolveBridgeCdnUrl };
27
+
28
+ //# sourceMappingURL=npm-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-index.js","names":[],"sources":["../src/build-info.ts"],"sourcesContent":["// The repo copy carries the 40-zero placeholder; the publish workflow\n// (.github/workflows/messaging-publish-web-packages.yml) stamps the real\n// commit SHA into the built packages/bridge/dist output via\n// scripts/stamp-cdn-build-sha.mjs and verifies the packed tarball before\n// `npm publish`. Keep the placeholder as a single 40-zero string literal:\n// the stamp is a same-length text replacement, so source maps stay valid.\nconst GIT_SHA_PATTERN = /^[0-9a-f]{40}$/;\nconst UNSTAMPED_SHA_PATTERN = /^0{40}$/;\n\n/**\n * Git commit SHA of the monorepo commit this npm version was published from.\n * The CDN pipeline deploys each main commit's bridge runtime under an\n * immutable SHA root, so this value names the CDN build associated with this\n * npm version. Pass it as the `pinBuildSha` loader option to load exactly\n * that runtime build — not recommended for production (see the README).\n *\n * In the repository, and in any locally built copy, the value is the\n * unstamped 40-zero placeholder ({@link isCdnBuildShaStamped} returns\n * `false`); only published tarballs carry a real SHA.\n */\nexport const CDN_BUILD_SHA: string = \"0000000000000000000000000000000000000000\";\n\n/**\n * Whether `sha` (default {@link CDN_BUILD_SHA}) is a stamped full git commit\n * SHA rather than the unstamped repo placeholder.\n */\nexport function isCdnBuildShaStamped(sha: string = CDN_BUILD_SHA): boolean {\n\tconst normalized = sha.trim().toLowerCase();\n\treturn (\n\t\tGIT_SHA_PATTERN.test(normalized) && !UNSTAMPED_SHA_PATTERN.test(normalized)\n\t);\n}\n"],"mappings":";;AAMA,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;;;;;;;;;;;;AAa9B,IAAa,gBAAwB;;;;;AAMrC,SAAgB,qBAAqB,MAAc,eAAwB;CAC1E,MAAM,aAAa,IAAI,MAAM,CAAC,aAAa;AAC3C,QACC,gBAAgB,KAAK,WAAW,IAAI,CAAC,sBAAsB,KAAK,WAAW"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `@ada-cx/messaging-bridge/react` — published npm entry.
3
+ *
4
+ * Trivial delegation only: the provider and hooks accept a `BridgeClient`
5
+ * created by the CDN-loaded runtime. Never import `createBridgeClient` here —
6
+ * the security-bearing runtime must not reach the npm tarball.
7
+ */
8
+ export type { BridgeClient } from "./bridge-client.js";
9
+ export type { LoadedBridgeProviderProps } from "./bridge-react.js";
10
+ export { BridgeProvider, createBridgeProvider, useBridgeClient, useBridgeState, useBridgeStateKey, } from "./bridge-react.js";
11
+ export type { LoadMessagingBridgeOptions, MessagingBridgeLoadErrorCode, MessagingBridgeModule, } from "./loader.js";
12
+ export { loadMessagingBridge, MessagingBridgeLoadError, resolveBridgeCdnUrl, } from "./loader.js";
13
+ export type { AppDisplayState, AppEvents } from "./types.js";
@@ -0,0 +1,113 @@
1
+ import { n as loadMessagingBridge, r as resolveBridgeCdnUrl, t as MessagingBridgeLoadError } from "./loader-CVynp73o.js";
2
+ import { createContext, useCallback, useContext, useEffect, useRef, useState, useSyncExternalStore } from "react";
3
+ import { Fragment, jsx } from "react/jsx-runtime";
4
+ //#region src/bridge-react.tsx
5
+ var BridgeContext = createContext(null);
6
+ /**
7
+ * Provide a {@link BridgeClient} to the React tree.
8
+ *
9
+ * Pure delegation: the caller owns the client lifecycle. The provider does not
10
+ * create, initialize, or destroy the client — obtain one from the CDN module
11
+ * returned by `loadMessagingBridge()` (or use {@link createBridgeProvider} to
12
+ * have loading, `app.initialize`, and teardown handled for you).
13
+ */
14
+ function BridgeProvider({ client, children }) {
15
+ return /* @__PURE__ */ jsx(BridgeContext.Provider, {
16
+ value: client,
17
+ children
18
+ });
19
+ }
20
+ /** The active {@link BridgeClient}. Throws outside a `BridgeProvider`. */
21
+ function useBridgeClient() {
22
+ const client = useContext(BridgeContext);
23
+ if (!client) throw new Error("useBridgeClient must be used within a BridgeProvider");
24
+ return client;
25
+ }
26
+ /**
27
+ * The full display-state snapshot, or `null` before the first
28
+ * `core.state.update`. Re-renders on every state change.
29
+ */
30
+ function useBridgeState() {
31
+ const client = useBridgeClient();
32
+ const subscribe = useCallback((callback) => client.subscribe(callback), [client]);
33
+ const getSnapshot = useCallback(() => client.getState(), [client]);
34
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
35
+ }
36
+ /**
37
+ * Returns a single typed value from the bridge state, or `null` when the state
38
+ * is not yet available. Provides full TypeScript autocomplete for the key names
39
+ * and returns the exact type declared in AppDisplayState.
40
+ *
41
+ * Re-renders only when THIS key's value changes (delegating to the client's
42
+ * `subscribeKey`), not on every state update the way `useBridgeState` does.
43
+ */
44
+ function useBridgeStateKey(key) {
45
+ const client = useBridgeClient();
46
+ const subscribe = useCallback((onStoreChange) => typeof client.subscribeKey === "function" ? client.subscribeKey(key, onStoreChange) : client.subscribe(onStoreChange), [client, key]);
47
+ const getSnapshot = useCallback(() => {
48
+ const state = client.getState();
49
+ if (state === null) return null;
50
+ const value = state[key];
51
+ return value !== void 0 ? value : null;
52
+ }, [client, key]);
53
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
54
+ }
55
+ /**
56
+ * Build a provider component that loads the bridge runtime from the CDN,
57
+ * creates a client, sends the required `app.initialize` handshake, and
58
+ * destroys the client on unmount.
59
+ *
60
+ * The returned component renders `fallback` (default: nothing) until the
61
+ * runtime has loaded, then renders `children` inside a {@link BridgeProvider}.
62
+ * When the load fails it renders `errorFallback` (default: `fallback`) and
63
+ * reports the error through `onError` (default: `console.error`).
64
+ *
65
+ * @example
66
+ * const AdaBridgeProvider = createBridgeProvider();
67
+ * root.render(<AdaBridgeProvider><MyChatUi /></AdaBridgeProvider>);
68
+ */
69
+ function createBridgeProvider(load = loadMessagingBridge) {
70
+ return function LoadedBridgeProvider({ children, fallback, errorFallback, onError }) {
71
+ const [client, setClient] = useState(null);
72
+ const [failed, setFailed] = useState(false);
73
+ const onErrorRef = useRef(onError);
74
+ useEffect(() => {
75
+ onErrorRef.current = onError;
76
+ });
77
+ useEffect(() => {
78
+ let disposed = false;
79
+ let created = null;
80
+ load().then((mod) => {
81
+ if (disposed) return;
82
+ created = mod.createBridgeClient();
83
+ created.sendEvent("app.initialize");
84
+ setClient(created);
85
+ }).catch((error) => {
86
+ if (disposed) return;
87
+ setFailed(true);
88
+ const handler = onErrorRef.current;
89
+ if (handler) {
90
+ handler(error);
91
+ return;
92
+ }
93
+ console.error("[AdaMessaging] Failed to load the bridge runtime:", error);
94
+ });
95
+ return () => {
96
+ disposed = true;
97
+ created?.destroy();
98
+ };
99
+ }, []);
100
+ if (!client) {
101
+ if (failed) return /* @__PURE__ */ jsx(Fragment, { children: errorFallback ?? fallback ?? null });
102
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback ?? null });
103
+ }
104
+ return /* @__PURE__ */ jsx(BridgeProvider, {
105
+ client,
106
+ children
107
+ });
108
+ };
109
+ }
110
+ //#endregion
111
+ export { BridgeProvider, MessagingBridgeLoadError, createBridgeProvider, loadMessagingBridge, resolveBridgeCdnUrl, useBridgeClient, useBridgeState, useBridgeStateKey };
112
+
113
+ //# sourceMappingURL=npm-react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-react.js","names":[],"sources":["../src/bridge-react.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\nimport type { BridgeClient } from \"./bridge-client\";\nimport type { MessagingBridgeModule } from \"./loader\";\nimport { loadMessagingBridge } from \"./loader\";\nimport type { AppDisplayState } from \"./types\";\n\nexport const BridgeContext = createContext<BridgeClient | null>(null);\n\n/**\n * Provide a {@link BridgeClient} to the React tree.\n *\n * Pure delegation: the caller owns the client lifecycle. The provider does not\n * create, initialize, or destroy the client — obtain one from the CDN module\n * returned by `loadMessagingBridge()` (or use {@link createBridgeProvider} to\n * have loading, `app.initialize`, and teardown handled for you).\n */\nexport function BridgeProvider({\n\tclient,\n\tchildren,\n}: {\n\tclient: BridgeClient;\n\tchildren: React.ReactNode;\n}): React.JSX.Element {\n\treturn (\n\t\t<BridgeContext.Provider value={client}>{children}</BridgeContext.Provider>\n\t);\n}\n\n/** The active {@link BridgeClient}. Throws outside a `BridgeProvider`. */\nexport function useBridgeClient(): BridgeClient {\n\tconst client = useContext(BridgeContext);\n\tif (!client) {\n\t\tthrow new Error(\"useBridgeClient must be used within a BridgeProvider\");\n\t}\n\treturn client;\n}\n\n/**\n * The full display-state snapshot, or `null` before the first\n * `core.state.update`. Re-renders on every state change.\n */\nexport function useBridgeState(): AppDisplayState | null {\n\tconst client = useBridgeClient();\n\tconst subscribe = useCallback(\n\t\t(callback: () => void) => client.subscribe(callback),\n\t\t[client],\n\t);\n\tconst getSnapshot = useCallback(() => client.getState(), [client]);\n\n\treturn useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Returns a single typed value from the bridge state, or `null` when the state\n * is not yet available. Provides full TypeScript autocomplete for the key names\n * and returns the exact type declared in AppDisplayState.\n *\n * Re-renders only when THIS key's value changes (delegating to the client's\n * `subscribeKey`), not on every state update the way `useBridgeState` does.\n */\nexport function useBridgeStateKey<K extends keyof AppDisplayState>(\n\tkey: K,\n): AppDisplayState[K] | null {\n\tconst client = useBridgeClient();\n\tconst subscribe = useCallback(\n\t\t(onStoreChange: () => void) =>\n\t\t\t// A stale-cached CDN runtime (or a hand-rolled client) may predate\n\t\t\t// subscribeKey; fall back to the full-state subscription — the\n\t\t\t// snapshot comparison below still skips the re-render.\n\t\t\ttypeof client.subscribeKey === \"function\"\n\t\t\t\t? client.subscribeKey(key, onStoreChange)\n\t\t\t\t: client.subscribe(onStoreChange),\n\t\t[client, key],\n\t);\n\tconst getSnapshot = useCallback((): AppDisplayState[K] | null => {\n\t\tconst state = client.getState();\n\t\tif (state === null) {\n\t\t\treturn null;\n\t\t}\n\t\tconst value = state[key];\n\t\treturn value !== undefined ? value : null;\n\t}, [client, key]);\n\n\treturn useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport interface LoadedBridgeProviderProps {\n\tchildren: React.ReactNode;\n\t/** Rendered while the bridge runtime is loading. Defaults to nothing. */\n\tfallback?: React.ReactNode;\n\t/**\n\t * Rendered when the runtime fails to load (network, CSP, 404). Defaults\n\t * to `fallback`, so without it a failure looks like loading forever.\n\t */\n\terrorFallback?: React.ReactNode;\n\t/**\n\t * Called when the runtime fails to load, with the rejection — a\n\t * {@link MessagingBridgeLoadError} for every loader-detected failure.\n\t * When omitted, the failure is logged with `console.error`.\n\t */\n\tonError?: (error: unknown) => void;\n}\n\n/**\n * Build a provider component that loads the bridge runtime from the CDN,\n * creates a client, sends the required `app.initialize` handshake, and\n * destroys the client on unmount.\n *\n * The returned component renders `fallback` (default: nothing) until the\n * runtime has loaded, then renders `children` inside a {@link BridgeProvider}.\n * When the load fails it renders `errorFallback` (default: `fallback`) and\n * reports the error through `onError` (default: `console.error`).\n *\n * @example\n * const AdaBridgeProvider = createBridgeProvider();\n * root.render(<AdaBridgeProvider><MyChatUi /></AdaBridgeProvider>);\n */\nexport function createBridgeProvider(\n\tload: () => Promise<MessagingBridgeModule> = loadMessagingBridge,\n): (props: LoadedBridgeProviderProps) => React.JSX.Element {\n\treturn function LoadedBridgeProvider({\n\t\tchildren,\n\t\tfallback,\n\t\terrorFallback,\n\t\tonError,\n\t}: LoadedBridgeProviderProps): React.JSX.Element {\n\t\tconst [client, setClient] = useState<BridgeClient | null>(null);\n\t\tconst [failed, setFailed] = useState(false);\n\t\t// Ref so a new onError identity does not re-trigger the load effect.\n\t\tconst onErrorRef = useRef(onError);\n\t\tuseEffect(() => {\n\t\t\tonErrorRef.current = onError;\n\t\t});\n\n\t\tuseEffect(() => {\n\t\t\tlet disposed = false;\n\t\t\tlet created: BridgeClient | null = null;\n\t\t\tload()\n\t\t\t\t.then((mod) => {\n\t\t\t\t\tif (disposed) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcreated = mod.createBridgeClient();\n\t\t\t\t\tcreated.sendEvent(\"app.initialize\");\n\t\t\t\t\tsetClient(created);\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tif (disposed) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsetFailed(true);\n\t\t\t\t\tconst handler = onErrorRef.current;\n\t\t\t\t\tif (handler) {\n\t\t\t\t\t\thandler(error);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\"[AdaMessaging] Failed to load the bridge runtime:\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\treturn () => {\n\t\t\t\tdisposed = true;\n\t\t\t\tcreated?.destroy();\n\t\t\t};\n\t\t}, []);\n\n\t\tif (!client) {\n\t\t\tif (failed) {\n\t\t\t\treturn <>{errorFallback ?? fallback ?? null}</>;\n\t\t\t}\n\t\t\treturn <>{fallback ?? null}</>;\n\t\t}\n\t\treturn <BridgeProvider client={client}>{children}</BridgeProvider>;\n\t};\n}\n"],"mappings":";;;;AAcA,IAAa,gBAAgB,cAAmC,KAAK;;;;;;;;;AAUrE,SAAgB,eAAe,EAC9B,QACA,YAIqB;AACrB,QACC,oBAAC,cAAc,UAAf;EAAwB,OAAO;EAAS;EAAkC,CAAA;;;AAK5E,SAAgB,kBAAgC;CAC/C,MAAM,SAAS,WAAW,cAAc;AACxC,KAAI,CAAC,OACJ,OAAM,IAAI,MAAM,uDAAuD;AAExE,QAAO;;;;;;AAOR,SAAgB,iBAAyC;CACxD,MAAM,SAAS,iBAAiB;CAChC,MAAM,YAAY,aAChB,aAAyB,OAAO,UAAU,SAAS,EACpD,CAAC,OAAO,CACR;CACD,MAAM,cAAc,kBAAkB,OAAO,UAAU,EAAE,CAAC,OAAO,CAAC;AAElE,QAAO,qBAAqB,WAAW,aAAa,YAAY;;;;;;;;;;AAWjE,SAAgB,kBACf,KAC4B;CAC5B,MAAM,SAAS,iBAAiB;CAChC,MAAM,YAAY,aAChB,kBAIA,OAAO,OAAO,iBAAiB,aAC5B,OAAO,aAAa,KAAK,cAAc,GACvC,OAAO,UAAU,cAAc,EACnC,CAAC,QAAQ,IAAI,CACb;CACD,MAAM,cAAc,kBAA6C;EAChE,MAAM,QAAQ,OAAO,UAAU;AAC/B,MAAI,UAAU,KACb,QAAO;EAER,MAAM,QAAQ,MAAM;AACpB,SAAO,UAAU,KAAA,IAAY,QAAQ;IACnC,CAAC,QAAQ,IAAI,CAAC;AAEjB,QAAO,qBAAqB,WAAW,aAAa,YAAY;;;;;;;;;;;;;;;;AAkCjE,SAAgB,qBACf,OAA6C,qBACa;AAC1D,QAAO,SAAS,qBAAqB,EACpC,UACA,UACA,eACA,WACgD;EAChD,MAAM,CAAC,QAAQ,aAAa,SAA8B,KAAK;EAC/D,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;EAE3C,MAAM,aAAa,OAAO,QAAQ;AAClC,kBAAgB;AACf,cAAW,UAAU;IACpB;AAEF,kBAAgB;GACf,IAAI,WAAW;GACf,IAAI,UAA+B;AACnC,SAAM,CACJ,MAAM,QAAQ;AACd,QAAI,SACH;AAED,cAAU,IAAI,oBAAoB;AAClC,YAAQ,UAAU,iBAAiB;AACnC,cAAU,QAAQ;KACjB,CACD,OAAO,UAAU;AACjB,QAAI,SACH;AAED,cAAU,KAAK;IACf,MAAM,UAAU,WAAW;AAC3B,QAAI,SAAS;AACZ,aAAQ,MAAM;AACd;;AAED,YAAQ,MACP,qDACA,MACA;KACA;AACH,gBAAa;AACZ,eAAW;AACX,aAAS,SAAS;;KAEjB,EAAE,CAAC;AAEN,MAAI,CAAC,QAAQ;AACZ,OAAI,OACH,QAAO,oBAAA,UAAA,EAAA,UAAG,iBAAiB,YAAY,MAAQ,CAAA;AAEhD,UAAO,oBAAA,UAAA,EAAA,UAAG,YAAY,MAAQ,CAAA;;AAE/B,SAAO,oBAAC,gBAAD;GAAwB;GAAS;GAA0B,CAAA"}