@ada-cx/messaging-bridge 1.0.0-setup.0 → 1.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/README.md +49 -50
- package/{dist → dist-npm/contract}/bridge-client.d.ts +5 -5
- package/{dist → dist-npm/contract}/derive.d.ts +4 -5
- package/{dist → dist-npm/contract}/operations.d.ts +9 -1
- package/{dist → dist-npm/contract}/state-keys.d.ts +1 -1
- package/{dist → dist-npm/contract}/types.d.ts +12 -2
- package/dist-npm/loader-CfCnvaTU.js +197 -0
- package/dist-npm/loader-CfCnvaTU.js.map +1 -0
- package/{dist → dist-npm/npm}/bridge-react.d.ts +2 -2
- package/{dist/npm-index.d.ts → dist-npm/npm/index.d.ts} +6 -7
- package/dist-npm/npm/index.js +2 -0
- package/dist-npm/npm/loader.d.ts +76 -0
- package/{dist/npm-react.d.ts → dist-npm/npm/react.d.ts} +2 -2
- package/{dist/npm-react.js → dist-npm/npm/react.js} +4 -4
- package/dist-npm/npm/react.js.map +1 -0
- package/{dist → dist-npm/npm}/testing.d.ts +11 -2
- package/{dist → dist-npm/npm}/testing.js +132 -125
- package/dist-npm/npm/testing.js.map +1 -0
- package/package.json +26 -28
- package/dist/build-info.d.ts +0 -17
- package/dist/loader-CVynp73o.js +0 -160
- package/dist/loader-CVynp73o.js.map +0 -1
- package/dist/loader.d.ts +0 -125
- package/dist/npm-index.js +0 -28
- package/dist/npm-index.js.map +0 -1
- package/dist/npm-react.js.map +0 -1
- package/dist/testing.js.map +0 -1
- /package/{dist → dist-npm}/shared-utils/csat-settings.d.ts +0 -0
- /package/{dist → dist-npm}/shared-utils/file-upload.d.ts +0 -0
- /package/{dist → dist-npm}/shared-utils/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -2,18 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
Build your own chat UI (a "custom app") on Ada Messaging's bridge contract.
|
|
4
4
|
|
|
5
|
-
This package carries TypeScript types, test mocks, and a thin loader.
|
|
6
|
-
|
|
7
|
-
`
|
|
8
|
-
|
|
5
|
+
This package carries TypeScript types, test mocks, and a thin loader.
|
|
6
|
+
|
|
7
|
+
Ada core stamps its build identifier into your app frame's `window.name`. The loader uses it to load the matching bridge runtime.
|
|
8
|
+
|
|
9
|
+
Your installed package never contains the runtime. Ada can update runtime security logic through a coordinated core release.
|
|
9
10
|
|
|
10
11
|
## Requirements
|
|
11
12
|
|
|
12
13
|
- Your custom app runs inside an iframe that Ada's core frame mounts. The
|
|
13
14
|
core frame is served from Ada's asset host, and it sits inside the page
|
|
14
15
|
that embeds the widget. Both origins are in your app's ancestor chain.
|
|
15
|
-
- You point the Web SDK at your app with its `appUrl` setting.
|
|
16
|
-
|
|
16
|
+
- You point the Web SDK at your app with its `appUrl` setting.
|
|
17
|
+
- Your app's origin must be in your handle's **Allowed websites** list. Add
|
|
18
|
+
it in your Ada dashboard, under **Channels** > **Chat**. Until the list
|
|
19
|
+
allows your origin, a configured `appUrl` is dropped with a console
|
|
20
|
+
warning and Ada's default app mounts (with `appUrlFallback: false` the
|
|
21
|
+
activation fails instead). An entry that carries a path, query, or
|
|
22
|
+
fragment does not authorize a custom app. Add the bare origin as its own
|
|
23
|
+
entry. Local development needs no entry when both your app and the
|
|
24
|
+
embedding page run on loopback hosts.
|
|
17
25
|
- If your app's responses send no `X-Frame-Options` header and no CSP
|
|
18
26
|
`frame-ancestors` directive, browsers permit framing, and no server change
|
|
19
27
|
is needed. If your app restricts framing, `frame-ancestors` must allow
|
|
@@ -155,64 +163,47 @@ anchors.
|
|
|
155
163
|
|
|
156
164
|
| Option | Default | Purpose |
|
|
157
165
|
| --- | --- | --- |
|
|
158
|
-
| `cdnBase` | `https://messaging-assets.ada.support` | Asset origin for
|
|
159
|
-
|
|
166
|
+
| `cdnBase` | `https://messaging-assets.ada.support` | Asset origin for immutable bridge builds. It must use HTTPS. Plain HTTP works only for loopback development. Override it only when your Ada team directs you to during a joint validation. |
|
|
167
|
+
|
|
168
|
+
### Frame-only asset URL resolution
|
|
169
|
+
|
|
170
|
+
`resolveBridgeCdnUrl()` returns the bridge asset URL selected for the current custom app frame.
|
|
171
|
+
It uses the same validation as `loadMessagingBridge()`.
|
|
172
|
+
|
|
173
|
+
This helper is frame-only. It throws a `MessagingBridgeLoadError` outside an Ada-mounted custom app frame.
|
|
174
|
+
Call it after your app starts inside that frame. Do not evaluate it at module scope in code that also runs elsewhere.
|
|
160
175
|
|
|
161
176
|
Errors: `loadMessagingBridge` rejects with a `MessagingBridgeLoadError`. Its
|
|
162
177
|
`code` property identifies the failure:
|
|
163
178
|
|
|
164
179
|
| Code | Meaning |
|
|
165
180
|
| --- | --- |
|
|
166
|
-
| `invalid_cdn_base` | The `cdnBase` option
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
181
|
+
| `invalid_cdn_base` | The `cdnBase` option violates the HTTPS or loopback HTTP policy. |
|
|
182
|
+
| `missing_build_sha` | The frame's `window.name` carries no core build marker, or the mounting core predates build-marker delivery. |
|
|
183
|
+
| `invalid_build_sha` | The frame-name marker matches no accepted build identifier form. |
|
|
184
|
+
| `dev_marker_not_loopback` | The frame uses the `dev` marker with a non-loopback asset host. |
|
|
169
185
|
| `bridge_import_failed` | The asset failed to load (network, CSP, 404). |
|
|
170
186
|
| `bridge_module_invalid` | The loaded module is not an Ada bridge build. |
|
|
171
187
|
|
|
172
|
-
###
|
|
188
|
+
### Matching the core build
|
|
173
189
|
|
|
174
|
-
|
|
175
|
-
monorepo commit this npm version was published from. Ada deploys each
|
|
176
|
-
commit's bridge runtime as an immutable SHA-rooted copy on the CDN. The
|
|
177
|
-
value therefore names the CDN build associated with this npm version.
|
|
190
|
+
Ada core mounts your frame with `window.name` set to `ada-custom-app:<build identifier>` before your app code runs. Your URL and its fragment mount untouched, so hash routes keep working.
|
|
178
191
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`<cdnBase>/<sha>/bridge/bridge.js
|
|
192
|
+
| Marker | Meaning | Resolved asset |
|
|
193
|
+
| --- | --- | --- |
|
|
194
|
+
| A bare 40-character hexadecimal SHA | An immutable production build. | `<cdnBase>/<sha>/bridge/bridge.js` |
|
|
195
|
+
| Lowercase `pr-<N>` | An Ada-internal preview build. | `<cdnBase>/pr-<N>/bridge/bridge.js` |
|
|
196
|
+
| `dev` | An Ada-internal local core build. Customer pages never receive this marker. | `<cdnBase>/bridge/bridge.js` on loopback only. |
|
|
182
197
|
|
|
183
|
-
|
|
184
|
-
import {
|
|
185
|
-
CDN_BUILD_SHA,
|
|
186
|
-
isCdnBuildShaStamped,
|
|
187
|
-
loadMessagingBridge,
|
|
188
|
-
} from "@ada-cx/messaging-bridge";
|
|
189
|
-
|
|
190
|
-
if (isCdnBuildShaStamped()) {
|
|
191
|
-
await loadMessagingBridge({ pinBuildSha: CDN_BUILD_SHA });
|
|
192
|
-
}
|
|
193
|
-
```
|
|
198
|
+
The loader accepts only these marker shapes. It never accepts a URL or path from the frame name.
|
|
194
199
|
|
|
195
|
-
|
|
196
|
-
fixes and the loader-fence rollout. A pinned runtime can also predate later
|
|
197
|
-
core or server contract changes and stop working. Use a pin only to debug an
|
|
198
|
-
issue, to validate a staged build, or to reproduce a report against a known
|
|
199
|
-
runtime.
|
|
200
|
+
The loader snapshots `window.name` when your app first evaluates the package, through either entry: `@ada-cx/messaging-bridge` or `@ada-cx/messaging-bridge/react`. Keep that import in a module your page evaluates at startup. A route-level code split evaluates too late. Code that runs first, for example a library that uses `window.name`, could overwrite the name. If the route that renders `AdaBridgeProvider` is lazily loaded, add a bare `import "@ada-cx/messaging-bridge";` to your entry module. The loader keeps the snapshot value if code overwrites `window.name` later.
|
|
200
201
|
|
|
201
|
-
|
|
202
|
-
build. The loader rejects any other value with the `invalid_build_sha` error
|
|
203
|
-
code. Only published packages carry a real SHA. In the repository, and in a
|
|
204
|
-
locally built copy, `CDN_BUILD_SHA` is a 40-zero placeholder and
|
|
205
|
-
`isCdnBuildShaStamped()` returns `false`. The loader rejects the placeholder
|
|
206
|
-
with the `unstamped_build_sha` error code.
|
|
202
|
+
Do not persist or replay the frame-name marker. Core supplies the authoritative value for every frame load.
|
|
207
203
|
|
|
208
|
-
The
|
|
209
|
-
the first minutes after a release, a pin can fail with
|
|
210
|
-
`bridge_import_failed` until the deploy completes. If the deploy of that
|
|
211
|
-
commit failed, the pinned build never exists. The unpinned default is
|
|
212
|
-
unaffected in both cases.
|
|
204
|
+
Do not set or change `window.name`. The loader fails closed when your page runs outside an Ada-mounted custom app frame.
|
|
213
205
|
|
|
214
|
-
`
|
|
215
|
-
asset host you pass.
|
|
206
|
+
The `dev` marker and PR preview aliases are Ada-internal workflows. Local Ada core builds stamp `ada-custom-app:dev`, which works only with a loopback `cdnBase`. An Ada preview core selects its matching preview bridge automatically. You do not need a `cdnBase` override for a joint validation when the page loads `sdk.js` from the production asset root. A preview alias against an asset host that lacks the preview fails closed.
|
|
216
207
|
|
|
217
208
|
## React
|
|
218
209
|
|
|
@@ -241,6 +232,13 @@ function MyChatUi() {
|
|
|
241
232
|
}
|
|
242
233
|
```
|
|
243
234
|
|
|
235
|
+
If your app lazily loads the route that renders `AdaBridgeProvider`, add a
|
|
236
|
+
bare `import "@ada-cx/messaging-bridge";` to your entry module. The loader
|
|
237
|
+
then snapshots the frame name at startup, before other code can overwrite
|
|
238
|
+
`window.name`. A statically imported `createBridgeProvider` already evaluates
|
|
239
|
+
the loader through a used binding; the bare import matters only when that
|
|
240
|
+
import itself lives in a lazily loaded chunk.
|
|
241
|
+
|
|
244
242
|
The provider accepts two more props for load failures. `errorFallback`
|
|
245
243
|
renders when the runtime fails to load. `onError` receives the
|
|
246
244
|
`MessagingBridgeLoadError`. Without them, the provider logs the error and
|
|
@@ -312,8 +310,9 @@ await handle.settled();
|
|
|
312
310
|
pinned to your first document, so your app must not navigate or reload its
|
|
313
311
|
own frame. A navigation disconnects the bridge permanently.
|
|
314
312
|
- The runtime detects the custom-app frame by the frame name core sets
|
|
315
|
-
(`ada-custom-app
|
|
316
|
-
change `window.name` inside your app
|
|
313
|
+
(`ada-custom-app:<build identifier>`), which also selects the bridge
|
|
314
|
+
build the loader imports. Do not change `window.name` inside your app
|
|
315
|
+
document.
|
|
317
316
|
- The custom-app frame keeps your real origin, so your own cookies and
|
|
318
317
|
storage work inside it. Browsers partition third-party storage by the
|
|
319
318
|
embedding site. Cookies need `Partitioned; Secure; SameSite=None`.
|
|
@@ -50,11 +50,11 @@ export interface BridgeClient {
|
|
|
50
50
|
/**
|
|
51
51
|
* Create a {@link BridgeClient} bound to the parent core frame.
|
|
52
52
|
*
|
|
53
|
-
* Declaration only
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
53
|
+
* Declaration only: the implementation lives in this package's private
|
|
54
|
+
* runtime source and ships exclusively as the CDN asset `bridge.js`.
|
|
55
|
+
* Obtain it through `loadMessagingBridge()`. The runtime compiles against
|
|
56
|
+
* this signature (`MessagingBridgeModule` is pinned both ways by
|
|
57
|
+
* `runtime/cdn-contract.ts`), so the published
|
|
58
58
|
* type can never drift from the CDN implementation.
|
|
59
59
|
*
|
|
60
60
|
* Security model: the core origin is derived from `document.referrer` when
|
|
@@ -5,11 +5,10 @@ import type { AppDisplayState, Message } from "./types.js";
|
|
|
5
5
|
* so a custom app does not have to rediscover the edge cases the hard way.
|
|
6
6
|
* No DOM, no client: every helper is a pure function of state or messages.
|
|
7
7
|
*
|
|
8
|
-
* Declarations only
|
|
9
|
-
* the
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `cdn-contract.ts`), so the published types cannot drift from the CDN
|
|
8
|
+
* Declarations only: the implementations live in `src/runtime` and ship
|
|
9
|
+
* exclusively on the CDN runtime, typed on `MessagingBridgeModule`. The
|
|
10
|
+
* runtime compiles against these signatures (pinned both ways by
|
|
11
|
+
* `runtime/cdn-contract.ts`), so the published types cannot drift from the CDN
|
|
13
12
|
* implementation.
|
|
14
13
|
*/
|
|
15
14
|
/**
|
|
@@ -257,7 +257,15 @@ export interface BridgeOperations {
|
|
|
257
257
|
* that predates the seq, falls back to the `pending -> terminal` edge.
|
|
258
258
|
* The email is trimmed; an empty result rejects immediately without
|
|
259
259
|
* sending (core drops an empty email silently, so nothing would ever
|
|
260
|
-
* settle it).
|
|
260
|
+
* settle it). The request is single-flight and address-aware: a call for
|
|
261
|
+
* the SAME address as an in-flight request joins it and settles on its
|
|
262
|
+
* verdict; a call for a DIFFERENT address is rejected address-matched on
|
|
263
|
+
* `transcript.email.conflict.*` — ONLY the conflicting call's promise
|
|
264
|
+
* rejects, while the in-flight request still completes, writes the final
|
|
265
|
+
* status, and settles its own handle with the true outcome (a rejection
|
|
266
|
+
* here never means the in-flight email was not sent). On a core document
|
|
267
|
+
* that predates the conflict channel, a conflicting call settles on the
|
|
268
|
+
* in-flight verdict instead.
|
|
261
269
|
*/
|
|
262
270
|
emailTranscript(email: string, opts?: SettleOptions): Promise<void>;
|
|
263
271
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { CsatFeedbackOption, CsatSurveySettings, FileUploadErrorData } from "
|
|
1
|
+
import type { CsatFeedbackOption, CsatSurveySettings, FileUploadErrorData } from "../shared-utils/index.js";
|
|
2
2
|
/**
|
|
3
|
-
* Bridge
|
|
3
|
+
* Bridge contract definitions describing the state and events that flow between
|
|
4
4
|
* the messaging core frame and the display layer (app or native WebView).
|
|
5
5
|
*
|
|
6
6
|
* These types are the source of truth for the `@ada-cx/messaging-bridge`
|
|
@@ -374,6 +374,16 @@ export interface AppDisplayState {
|
|
|
374
374
|
* edge never appears — correlate on this advancing to a terminal status
|
|
375
375
|
* instead. Optional: absent on a core document that predates it. */
|
|
376
376
|
"transcript.email.status.seq"?: number;
|
|
377
|
+
/** The trimmed address of the most recently rejected CONFLICTING email
|
|
378
|
+
* request — an `emailTranscript` for a DIFFERENT address while one was in
|
|
379
|
+
* flight. Its own channel: `emailTranscript` rejects on this advancing
|
|
380
|
+
* with ITS address, so only the conflicting caller rejects while the
|
|
381
|
+
* in-flight request settles on its own status. Optional: absent on a core
|
|
382
|
+
* document that predates it (there a conflicting caller settles on the
|
|
383
|
+
* in-flight verdict instead). */
|
|
384
|
+
"transcript.email.conflict.email"?: string | null;
|
|
385
|
+
/** Advances on every `transcript.email.conflict.email` write. */
|
|
386
|
+
"transcript.email.conflict.seq"?: number;
|
|
377
387
|
/** Same lifecycle as `transcript.email.status`, for
|
|
378
388
|
* `settings.transcript.download.request`. */
|
|
379
389
|
"transcript.download.status": "idle" | "pending" | "success" | "error";
|
|
@@ -0,0 +1,197 @@
|
|
|
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/npm/loader.ts
|
|
40
|
+
var DEFAULT_CDN_BASE = "https://messaging-assets.ada.support";
|
|
41
|
+
var CUSTOM_APP_FRAME_NAME = "ada-custom-app";
|
|
42
|
+
var BRIDGE_ENTRY_PATH = "bridge/bridge.js";
|
|
43
|
+
var DEV_BUILD_MARKER = "dev";
|
|
44
|
+
var PINNED_BUILD_SHA_PATTERN = /^[0-9a-f]{40}$/i;
|
|
45
|
+
var PR_BUILD_ALIAS_PATTERN = /^pr-\d+$/;
|
|
46
|
+
/** Typed failure raised by {@link loadMessagingBridge}. */
|
|
47
|
+
var MessagingBridgeLoadError = class extends Error {
|
|
48
|
+
constructor(message, code, cause) {
|
|
49
|
+
super(message);
|
|
50
|
+
_defineProperty(this, "code", void 0);
|
|
51
|
+
this.name = "MessagingBridgeLoadError";
|
|
52
|
+
this.code = code;
|
|
53
|
+
if (cause !== void 0) this.cause = cause;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var defaultImportModule = (url) => import(
|
|
57
|
+
/* webpackIgnore: true */
|
|
58
|
+
/* @vite-ignore */
|
|
59
|
+
url
|
|
60
|
+
);
|
|
61
|
+
var inFlightByImporter = /* @__PURE__ */ new WeakMap();
|
|
62
|
+
var LOOPBACK_HOSTS = new Set([
|
|
63
|
+
"localhost",
|
|
64
|
+
"127.0.0.1",
|
|
65
|
+
"[::1]",
|
|
66
|
+
"::1"
|
|
67
|
+
]);
|
|
68
|
+
function isLoopbackHostname(hostname) {
|
|
69
|
+
const normalized = hostname.trim().toLowerCase();
|
|
70
|
+
return LOOPBACK_HOSTS.has(normalized) || normalized.endsWith(".localhost");
|
|
71
|
+
}
|
|
72
|
+
function trimTrailingSlashes(value) {
|
|
73
|
+
let end = value.length;
|
|
74
|
+
while (end > 0 && value[end - 1] === "/") end -= 1;
|
|
75
|
+
return value.slice(0, end);
|
|
76
|
+
}
|
|
77
|
+
function bridgeFrameOnlyMessage(message) {
|
|
78
|
+
return `${message} The bridge only runs inside an Ada-mounted custom-app frame.`;
|
|
79
|
+
}
|
|
80
|
+
var FRAME_NAME_MARKER_PREFIX = `${CUSTOM_APP_FRAME_NAME}:`;
|
|
81
|
+
function frameNameCarriesBuild(name) {
|
|
82
|
+
return name.startsWith(FRAME_NAME_MARKER_PREFIX);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Read the build marker core stamps into the frame's `window.name`
|
|
86
|
+
* (`ada-custom-app:<marker>`). The name is Ada-owned for this frame, so the
|
|
87
|
+
* marker never touches customer-owned URL state such as a hash route.
|
|
88
|
+
*/
|
|
89
|
+
function resolveBridgeBuildFromFrameName(name) {
|
|
90
|
+
if (name === CUSTOM_APP_FRAME_NAME) throw new MessagingBridgeLoadError("The mounting Ada core predates build-marker delivery, so it cannot select a versioned bridge. The Ada core rollout must include the marker-stamping core before the npm bridge can load.", "missing_build_sha");
|
|
91
|
+
if (!frameNameCarriesBuild(name)) throw new MessagingBridgeLoadError(`${bridgeFrameOnlyMessage("This document was not mounted by an Ada core frame: window.name carries no ada-custom-app build marker.")} If this frame is Ada-mounted, make sure @ada-cx/messaging-bridge (or its /react entry) is imported from a module your page evaluates at startup — a lazily loaded chunk evaluates after customer code could overwrite window.name.`, "missing_build_sha");
|
|
92
|
+
const value = name.slice(FRAME_NAME_MARKER_PREFIX.length);
|
|
93
|
+
if (value === DEV_BUILD_MARKER) return { kind: "dev" };
|
|
94
|
+
if (PR_BUILD_ALIAS_PATTERN.test(value)) return {
|
|
95
|
+
kind: "alias",
|
|
96
|
+
identifier: value
|
|
97
|
+
};
|
|
98
|
+
if (!PINNED_BUILD_SHA_PATTERN.test(value)) throw new MessagingBridgeLoadError(bridgeFrameOnlyMessage(`The window.name build marker must be exactly a bare 40-character hex git SHA or a lowercase pr-<N> alias. URLs and paths are not allowed: "${value}".`), "invalid_build_sha");
|
|
99
|
+
return {
|
|
100
|
+
kind: "sha",
|
|
101
|
+
identifier: value.toLowerCase()
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
var initialFrameName = typeof window === "undefined" ? "" : window.name;
|
|
105
|
+
var initialFrameNameHasBuild = frameNameCarriesBuild(initialFrameName);
|
|
106
|
+
function currentFrameName() {
|
|
107
|
+
if (initialFrameNameHasBuild) return initialFrameName;
|
|
108
|
+
return typeof window === "undefined" ? "" : window.name;
|
|
109
|
+
}
|
|
110
|
+
function resolveCdnBase(cdnBase) {
|
|
111
|
+
const base = trimTrailingSlashes((cdnBase ?? DEFAULT_CDN_BASE).trim());
|
|
112
|
+
let url;
|
|
113
|
+
try {
|
|
114
|
+
url = new URL(base);
|
|
115
|
+
} catch (cause) {
|
|
116
|
+
throw new MessagingBridgeLoadError(`The cdnBase option is not a valid URL: "${base}".`, "invalid_cdn_base", cause);
|
|
117
|
+
}
|
|
118
|
+
const isHttps = url.protocol === "https:";
|
|
119
|
+
const isLoopbackHttp = url.protocol === "http:" && isLoopbackHostname(url.hostname);
|
|
120
|
+
if (!isHttps && !isLoopbackHttp) throw new MessagingBridgeLoadError(`The cdnBase option must use https (plain http is allowed only for loopback hosts): "${base}".`, "invalid_cdn_base");
|
|
121
|
+
return {
|
|
122
|
+
base,
|
|
123
|
+
hostname: url.hostname
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Resolve the bridge asset URL from this frame's name marker and the CDN
|
|
128
|
+
* base. Production builds always resolve the immutable SHA-rooted asset.
|
|
129
|
+
* PR aliases stay under the configured CDN base. A production-base alias that
|
|
130
|
+
* does not exist fails closed through the normal bridge import error.
|
|
131
|
+
* Local development resolves `/bridge/bridge.js` only on a loopback base.
|
|
132
|
+
*/
|
|
133
|
+
function resolveBridgeCdnUrl(options) {
|
|
134
|
+
const build = resolveBridgeBuildFromFrameName(currentFrameName());
|
|
135
|
+
const { base, hostname } = resolveCdnBase(options?.cdnBase);
|
|
136
|
+
if (build.kind === "dev" && !isLoopbackHostname(hostname)) throw new MessagingBridgeLoadError(bridgeFrameOnlyMessage(`The ${FRAME_NAME_MARKER_PREFIX}${DEV_BUILD_MARKER} frame-name marker requires a loopback cdnBase.`), "dev_marker_not_loopback");
|
|
137
|
+
const assetPath = build.kind === "dev" ? `/${BRIDGE_ENTRY_PATH}` : `/${build.identifier}/${BRIDGE_ENTRY_PATH}`;
|
|
138
|
+
return new URL(`${base}${assetPath}`).toString();
|
|
139
|
+
}
|
|
140
|
+
var REQUIRED_BRIDGE_FUNCTION_EXPORTS = [
|
|
141
|
+
"createBridgeClient",
|
|
142
|
+
"messageKey",
|
|
143
|
+
"isHistoricalRow",
|
|
144
|
+
"findFirstUnread",
|
|
145
|
+
"selectUnread",
|
|
146
|
+
"groupMessages",
|
|
147
|
+
"filterDisplayable",
|
|
148
|
+
"resolveBotName",
|
|
149
|
+
"isAgentTyping",
|
|
150
|
+
"isConnectivityLost"
|
|
151
|
+
];
|
|
152
|
+
function isMessagingBridgeModule(value) {
|
|
153
|
+
if (typeof value !== "object" || value === null) return false;
|
|
154
|
+
const candidate = value;
|
|
155
|
+
return candidate.STATE != null && REQUIRED_BRIDGE_FUNCTION_EXPORTS.every((key) => typeof candidate[key] === "function");
|
|
156
|
+
}
|
|
157
|
+
async function importBridgeModule(url, importModule) {
|
|
158
|
+
let loaded;
|
|
159
|
+
try {
|
|
160
|
+
loaded = await importModule(url);
|
|
161
|
+
} catch (cause) {
|
|
162
|
+
throw new MessagingBridgeLoadError(`The Ada bridge runtime failed to load from ${url}.`, "bridge_import_failed", cause);
|
|
163
|
+
}
|
|
164
|
+
if (!isMessagingBridgeModule(loaded)) throw new MessagingBridgeLoadError(`The module at ${url} does not expose the full Ada bridge surface; it is not a complete Ada bridge build.`, "bridge_module_invalid");
|
|
165
|
+
return loaded;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Load the bridge runtime that matches the mounting core frame. Loads are
|
|
169
|
+
* memoized per resolved URL and importer. A failed load is evicted for retry.
|
|
170
|
+
*/
|
|
171
|
+
function loadMessagingBridge(options = {}) {
|
|
172
|
+
const importModule = options.importModule ?? defaultImportModule;
|
|
173
|
+
let url;
|
|
174
|
+
try {
|
|
175
|
+
url = resolveBridgeCdnUrl(options);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
return Promise.reject(error);
|
|
178
|
+
}
|
|
179
|
+
let inFlight = inFlightByImporter.get(importModule);
|
|
180
|
+
if (!inFlight) {
|
|
181
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
182
|
+
inFlightByImporter.set(importModule, inFlight);
|
|
183
|
+
}
|
|
184
|
+
const existing = inFlight.get(url);
|
|
185
|
+
if (existing) return existing;
|
|
186
|
+
const cache = inFlight;
|
|
187
|
+
const pending = importBridgeModule(url, importModule);
|
|
188
|
+
cache.set(url, pending);
|
|
189
|
+
pending.catch(() => {
|
|
190
|
+
if (cache.get(url) === pending) cache.delete(url);
|
|
191
|
+
});
|
|
192
|
+
return pending;
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
195
|
+
export { loadMessagingBridge as n, resolveBridgeCdnUrl as r, MessagingBridgeLoadError as t };
|
|
196
|
+
|
|
197
|
+
//# sourceMappingURL=loader-CfCnvaTU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-CfCnvaTU.js","names":[],"sources":["../src/npm/loader.ts"],"sourcesContent":["import type { createBridgeClient } from \"../contract/bridge-client\";\nimport type {\n\tfilterDisplayable,\n\tfindFirstUnread,\n\tgroupMessages,\n\tisAgentTyping,\n\tisConnectivityLost,\n\tisHistoricalRow,\n\tmessageKey,\n\tresolveBotName,\n\tselectUnread,\n} from \"../contract/derive\";\nimport type { STATE } from \"../contract/state-keys\";\n\nconst DEFAULT_CDN_BASE = \"https://messaging-assets.ada.support\";\n// Keep aligned with packages/core/src/app-bridge.ts; pinned by\n// scripts/core-html-contract.test.mjs.\nconst CUSTOM_APP_FRAME_NAME = \"ada-custom-app\";\nconst BRIDGE_ENTRY_PATH = \"bridge/bridge.js\";\nconst DEV_BUILD_MARKER = \"dev\";\n\n// Only canonical build identifiers may become part of an executable asset URL.\nconst PINNED_BUILD_SHA_PATTERN = /^[0-9a-f]{40}$/i;\n// Deliberately narrower than scripts/sdk.js parseVersionOverride (7-40 hex,\n// case-insensitive): deployed keys are always lowercase `pr-<N>`, and a short\n// SHA never names an uploaded tree, so the narrower grammar loses no reachable\n// build while keeping the executable-path grammar minimal.\nconst PR_BUILD_ALIAS_PATTERN = /^pr-\\d+$/;\n\n/** Why a {@link MessagingBridgeLoadError} was raised. */\nexport type MessagingBridgeLoadErrorCode =\n\t/** The `cdnBase` option violates the HTTPS or loopback HTTP policy. */\n\t| \"invalid_cdn_base\"\n\t/** The frame's `window.name` carries no core build marker. */\n\t| \"missing_build_sha\"\n\t/** The frame-name marker is not a supported bare build identifier. */\n\t| \"invalid_build_sha\"\n\t/** The `dev` marker was paired with a non-loopback CDN base. */\n\t| \"dev_marker_not_loopback\"\n\t/** The dynamic import of the CDN asset failed. */\n\t| \"bridge_import_failed\"\n\t/** The imported module does not expose the Ada bridge surface. */\n\t| \"bridge_module_invalid\";\n\n/** Typed failure raised by {@link loadMessagingBridge}. */\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/** The module shape served by the SHA-matched bridge CDN asset. */\nexport interface MessagingBridgeModule {\n\tcreateBridgeClient: typeof createBridgeClient;\n\tSTATE: typeof STATE;\n\tmessageKey: typeof messageKey;\n\tisHistoricalRow: typeof isHistoricalRow;\n\tfindFirstUnread: typeof findFirstUnread;\n\tselectUnread: typeof selectUnread;\n\tgroupMessages: typeof groupMessages;\n\tfilterDisplayable: typeof filterDisplayable;\n\tresolveBotName: typeof resolveBotName;\n\tisAgentTyping: typeof isAgentTyping;\n\tisConnectivityLost: typeof isConnectivityLost;\n}\n\ntype ImportBridgeModule = (url: string) => Promise<unknown>;\n\n/** Options for {@link loadMessagingBridge}. */\nexport interface LoadMessagingBridgeOptions {\n\t/**\n\t * Asset base for staged validation. It must use HTTPS. Plain HTTP is\n\t * accepted only for loopback hosts.\n\t */\n\tcdnBase?: string;\n\t/** Import seam for unit tests. */\n\timportModule?: ImportBridgeModule;\n}\n\n// Both annotations are load-bearing. Customer bundlers must leave the\n// browser-resolved CDN URL untouched.\nconst defaultImportModule: ImportBridgeModule = (url) =>\n\timport(/* webpackIgnore: true */ /* @vite-ignore */ url);\n\nconst inFlightByImporter = new WeakMap<\n\tImportBridgeModule,\n\tMap<string, Promise<MessagingBridgeModule>>\n>();\n\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\treturn LOOPBACK_HOSTS.has(normalized) || normalized.endsWith(\".localhost\");\n}\n\nfunction trimTrailingSlashes(value: string): string {\n\tlet end = value.length;\n\twhile (end > 0 && value[end - 1] === \"/\") {\n\t\tend -= 1;\n\t}\n\treturn value.slice(0, end);\n}\n\ntype BridgeBuild =\n\t| { kind: \"sha\"; identifier: string }\n\t| { kind: \"alias\"; identifier: string }\n\t| { kind: \"dev\" };\n\nfunction bridgeFrameOnlyMessage(message: string): string {\n\treturn `${message} The bridge only runs inside an Ada-mounted custom-app frame.`;\n}\n\nconst FRAME_NAME_MARKER_PREFIX = `${CUSTOM_APP_FRAME_NAME}:`;\n\nfunction frameNameCarriesBuild(name: string): boolean {\n\treturn name.startsWith(FRAME_NAME_MARKER_PREFIX);\n}\n\n/**\n * Read the build marker core stamps into the frame's `window.name`\n * (`ada-custom-app:<marker>`). The name is Ada-owned for this frame, so the\n * marker never touches customer-owned URL state such as a hash route.\n */\nexport function resolveBridgeBuildFromFrameName(name: string): BridgeBuild {\n\tif (name === CUSTOM_APP_FRAME_NAME) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t\"The mounting Ada core predates build-marker delivery, so it cannot select a versioned bridge. The Ada core rollout must include the marker-stamping core before the npm bridge can load.\",\n\t\t\t\"missing_build_sha\",\n\t\t);\n\t}\n\tif (!frameNameCarriesBuild(name)) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\t`${bridgeFrameOnlyMessage(\n\t\t\t\t\"This document was not mounted by an Ada core frame: window.name carries no ada-custom-app build marker.\",\n\t\t\t)} If this frame is Ada-mounted, make sure @ada-cx/messaging-bridge (or its /react entry) is imported from a module your page evaluates at startup — a lazily loaded chunk evaluates after customer code could overwrite window.name.`,\n\t\t\t\"missing_build_sha\",\n\t\t);\n\t}\n\tconst value = name.slice(FRAME_NAME_MARKER_PREFIX.length);\n\tif (value === DEV_BUILD_MARKER) {\n\t\treturn { kind: \"dev\" };\n\t}\n\tif (PR_BUILD_ALIAS_PATTERN.test(value)) {\n\t\treturn { kind: \"alias\", identifier: value };\n\t}\n\tif (!PINNED_BUILD_SHA_PATTERN.test(value)) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\tbridgeFrameOnlyMessage(\n\t\t\t\t`The window.name build marker must be exactly a bare 40-character hex git SHA or a lowercase pr-<N> alias. URLs and paths are not allowed: \"${value}\".`,\n\t\t\t),\n\t\t\t\"invalid_build_sha\",\n\t\t);\n\t}\n\treturn { kind: \"sha\", identifier: value.toLowerCase() };\n}\n\n// Latch window.name at module evaluation: core stamps the marker on the\n// frame element before the document loads, and customer code — for example a\n// library that uses window.name as a storage channel — could overwrite it\n// after boot. The latch therefore only holds when this package is imported\n// from the page's entry module rather than a lazily loaded chunk — the\n// boundary README_NPM.md documents and the snapshot tests in loader.test.ts\n// pin.\nconst initialFrameName = typeof window === \"undefined\" ? \"\" : window.name;\nconst initialFrameNameHasBuild = frameNameCarriesBuild(initialFrameName);\n\nfunction currentFrameName(): string {\n\tif (initialFrameNameHasBuild) {\n\t\treturn initialFrameName;\n\t}\n\treturn typeof window === \"undefined\" ? \"\" : window.name;\n}\n\nfunction resolveCdnBase(cdnBase: string | undefined): {\n\tbase: string;\n\thostname: string;\n} {\n\tconst base = trimTrailingSlashes((cdnBase ?? DEFAULT_CDN_BASE).trim());\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(base);\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 { base, hostname: url.hostname };\n}\n\n/**\n * Resolve the bridge asset URL from this frame's name marker and the CDN\n * base. Production builds always resolve the immutable SHA-rooted asset.\n * PR aliases stay under the configured CDN base. A production-base alias that\n * does not exist fails closed through the normal bridge import error.\n * Local development resolves `/bridge/bridge.js` only on a loopback base.\n */\nexport function resolveBridgeCdnUrl(\n\toptions?: Pick<LoadMessagingBridgeOptions, \"cdnBase\">,\n): string {\n\tconst build = resolveBridgeBuildFromFrameName(currentFrameName());\n\tconst { base, hostname } = resolveCdnBase(options?.cdnBase);\n\tif (build.kind === \"dev\" && !isLoopbackHostname(hostname)) {\n\t\tthrow new MessagingBridgeLoadError(\n\t\t\tbridgeFrameOnlyMessage(\n\t\t\t\t`The ${FRAME_NAME_MARKER_PREFIX}${DEV_BUILD_MARKER} frame-name marker requires a loopback cdnBase.`,\n\t\t\t),\n\t\t\t\"dev_marker_not_loopback\",\n\t\t);\n\t}\n\tconst assetPath =\n\t\tbuild.kind === \"dev\"\n\t\t\t? `/${BRIDGE_ENTRY_PATH}`\n\t\t\t: `/${build.identifier}/${BRIDGE_ENTRY_PATH}`;\n\treturn new URL(`${base}${assetPath}`).toString();\n}\n\n// A partial CDN module (mid-deploy, or a rolled-back build missing a newer\n// export) must fail here as a typed bridge_module_invalid error, not later as\n// a TypeError on the first missing call — so every export is checked. The\n// `satisfies` clause rejects names that are not interface members; the\n// exhaustiveness type below is what forces this list to grow with it.\nconst REQUIRED_BRIDGE_FUNCTION_EXPORTS = [\n\t\"createBridgeClient\",\n\t\"messageKey\",\n\t\"isHistoricalRow\",\n\t\"findFirstUnread\",\n\t\"selectUnread\",\n\t\"groupMessages\",\n\t\"filterDisplayable\",\n\t\"resolveBotName\",\n\t\"isAgentTyping\",\n\t\"isConnectivityLost\",\n] as const satisfies readonly (keyof MessagingBridgeModule)[];\n\ntype MissingRequiredBridgeExport = Exclude<\n\tkeyof MessagingBridgeModule,\n\t(typeof REQUIRED_BRIDGE_FUNCTION_EXPORTS)[number] | \"STATE\"\n>;\n// Compile-time exhaustiveness: adding a MessagingBridgeModule member without\n// listing it in REQUIRED_BRIDGE_FUNCTION_EXPORTS (or checking it explicitly,\n// like STATE) makes the Exclude non-`never`, so the `true` assignment below\n// stops compiling.\ntype AllBridgeExportsListed = MissingRequiredBridgeExport extends never\n\t? true\n\t: never;\nconst _allBridgeExportsListed: AllBridgeExportsListed = true;\nvoid _allBridgeExportsListed;\n\nfunction isMessagingBridgeModule(\n\tvalue: unknown,\n): value is MessagingBridgeModule {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\t// STATE is a constant object, not a function, so it gets a presence check.\n\treturn (\n\t\tcandidate.STATE != null &&\n\t\tREQUIRED_BRIDGE_FUNCTION_EXPORTS.every(\n\t\t\t(key) => typeof candidate[key] === \"function\",\n\t\t)\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 expose the full Ada bridge surface; it is not a complete Ada bridge build.`,\n\t\t\t\"bridge_module_invalid\",\n\t\t);\n\t}\n\treturn loaded;\n}\n\n/**\n * Load the bridge runtime that matches the mounting core frame. Loads are\n * memoized per resolved URL and importer. A failed load is evicted for retry.\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":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { BridgeClient } from "
|
|
1
|
+
import type { BridgeClient } from "../contract/bridge-client.js";
|
|
2
|
+
import type { AppDisplayState } from "../contract/types.js";
|
|
2
3
|
import type { MessagingBridgeModule } from "./loader.js";
|
|
3
|
-
import type { AppDisplayState } from "./types.js";
|
|
4
4
|
export declare const BridgeContext: import("react").Context<BridgeClient | null>;
|
|
5
5
|
/**
|
|
6
6
|
* Provide a {@link BridgeClient} to the React tree.
|
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
* `loadMessagingBridge()` so Ada can patch security-bearing logic without a
|
|
7
7
|
* customer release. Never add runtime implementation to this entry.
|
|
8
8
|
*/
|
|
9
|
-
export type { FileUploadErrorData, FileUploadErrorReason, } from "
|
|
10
|
-
export type { BridgeClient } from "
|
|
11
|
-
export {
|
|
12
|
-
export type {
|
|
9
|
+
export type { FileUploadErrorData, FileUploadErrorReason, } from "../shared-utils/index.js";
|
|
10
|
+
export type { BridgeClient } from "../contract/bridge-client.js";
|
|
11
|
+
export type { MessageGroupingEntry, UnreadSelection } from "../contract/derive.js";
|
|
12
|
+
export type { BridgeClientDestroyedError, BridgeOperations, BridgeOperationsHost, CaptureHandle, CsatSubmitHandle, EndChatEligibilityResult, FileUploadHandle, ObserveOptions, OperationResult, SendHandle, SettleOptions, } from "../contract/operations.js";
|
|
13
|
+
export type { StateKey } from "../contract/state-keys.js";
|
|
14
|
+
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 "../contract/types.js";
|
|
13
15
|
export type { LoadMessagingBridgeOptions, MessagingBridgeLoadErrorCode, MessagingBridgeModule, } from "./loader.js";
|
|
14
16
|
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,76 @@
|
|
|
1
|
+
import type { createBridgeClient } from "../contract/bridge-client.js";
|
|
2
|
+
import type { filterDisplayable, findFirstUnread, groupMessages, isAgentTyping, isConnectivityLost, isHistoricalRow, messageKey, resolveBotName, selectUnread } from "../contract/derive.js";
|
|
3
|
+
import type { STATE } from "../contract/state-keys.js";
|
|
4
|
+
/** Why a {@link MessagingBridgeLoadError} was raised. */
|
|
5
|
+
export type MessagingBridgeLoadErrorCode =
|
|
6
|
+
/** The `cdnBase` option violates the HTTPS or loopback HTTP policy. */
|
|
7
|
+
"invalid_cdn_base"
|
|
8
|
+
/** The frame's `window.name` carries no core build marker. */
|
|
9
|
+
| "missing_build_sha"
|
|
10
|
+
/** The frame-name marker is not a supported bare build identifier. */
|
|
11
|
+
| "invalid_build_sha"
|
|
12
|
+
/** The `dev` marker was paired with a non-loopback CDN base. */
|
|
13
|
+
| "dev_marker_not_loopback"
|
|
14
|
+
/** The dynamic import of the CDN asset failed. */
|
|
15
|
+
| "bridge_import_failed"
|
|
16
|
+
/** The imported module does not expose the Ada bridge surface. */
|
|
17
|
+
| "bridge_module_invalid";
|
|
18
|
+
/** Typed failure raised by {@link loadMessagingBridge}. */
|
|
19
|
+
export declare class MessagingBridgeLoadError extends Error {
|
|
20
|
+
readonly code: MessagingBridgeLoadErrorCode;
|
|
21
|
+
constructor(message: string, code: MessagingBridgeLoadErrorCode, cause?: unknown);
|
|
22
|
+
}
|
|
23
|
+
/** The module shape served by the SHA-matched bridge CDN asset. */
|
|
24
|
+
export interface MessagingBridgeModule {
|
|
25
|
+
createBridgeClient: typeof createBridgeClient;
|
|
26
|
+
STATE: typeof STATE;
|
|
27
|
+
messageKey: typeof messageKey;
|
|
28
|
+
isHistoricalRow: typeof isHistoricalRow;
|
|
29
|
+
findFirstUnread: typeof findFirstUnread;
|
|
30
|
+
selectUnread: typeof selectUnread;
|
|
31
|
+
groupMessages: typeof groupMessages;
|
|
32
|
+
filterDisplayable: typeof filterDisplayable;
|
|
33
|
+
resolveBotName: typeof resolveBotName;
|
|
34
|
+
isAgentTyping: typeof isAgentTyping;
|
|
35
|
+
isConnectivityLost: typeof isConnectivityLost;
|
|
36
|
+
}
|
|
37
|
+
type ImportBridgeModule = (url: string) => Promise<unknown>;
|
|
38
|
+
/** Options for {@link loadMessagingBridge}. */
|
|
39
|
+
export interface LoadMessagingBridgeOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Asset base for staged validation. It must use HTTPS. Plain HTTP is
|
|
42
|
+
* accepted only for loopback hosts.
|
|
43
|
+
*/
|
|
44
|
+
cdnBase?: string;
|
|
45
|
+
/** Import seam for unit tests. */
|
|
46
|
+
importModule?: ImportBridgeModule;
|
|
47
|
+
}
|
|
48
|
+
type BridgeBuild = {
|
|
49
|
+
kind: "sha";
|
|
50
|
+
identifier: string;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "alias";
|
|
53
|
+
identifier: string;
|
|
54
|
+
} | {
|
|
55
|
+
kind: "dev";
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Read the build marker core stamps into the frame's `window.name`
|
|
59
|
+
* (`ada-custom-app:<marker>`). The name is Ada-owned for this frame, so the
|
|
60
|
+
* marker never touches customer-owned URL state such as a hash route.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveBridgeBuildFromFrameName(name: string): BridgeBuild;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the bridge asset URL from this frame's name marker and the CDN
|
|
65
|
+
* base. Production builds always resolve the immutable SHA-rooted asset.
|
|
66
|
+
* PR aliases stay under the configured CDN base. A production-base alias that
|
|
67
|
+
* does not exist fails closed through the normal bridge import error.
|
|
68
|
+
* Local development resolves `/bridge/bridge.js` only on a loopback base.
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveBridgeCdnUrl(options?: Pick<LoadMessagingBridgeOptions, "cdnBase">): string;
|
|
71
|
+
/**
|
|
72
|
+
* Load the bridge runtime that matches the mounting core frame. Loads are
|
|
73
|
+
* memoized per resolved URL and importer. A failed load is evicted for retry.
|
|
74
|
+
*/
|
|
75
|
+
export declare function loadMessagingBridge(options?: LoadMessagingBridgeOptions): Promise<MessagingBridgeModule>;
|
|
76
|
+
export {};
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* created by the CDN-loaded runtime. Never import `createBridgeClient` here —
|
|
6
6
|
* the security-bearing runtime must not reach the npm tarball.
|
|
7
7
|
*/
|
|
8
|
-
export type { BridgeClient } from "
|
|
8
|
+
export type { BridgeClient } from "../contract/bridge-client.js";
|
|
9
|
+
export type { AppDisplayState, AppEvents } from "../contract/types.js";
|
|
9
10
|
export type { LoadedBridgeProviderProps } from "./bridge-react.js";
|
|
10
11
|
export { BridgeProvider, createBridgeProvider, useBridgeClient, useBridgeState, useBridgeStateKey, } from "./bridge-react.js";
|
|
11
12
|
export type { LoadMessagingBridgeOptions, MessagingBridgeLoadErrorCode, MessagingBridgeModule, } from "./loader.js";
|
|
12
13
|
export { loadMessagingBridge, MessagingBridgeLoadError, resolveBridgeCdnUrl, } from "./loader.js";
|
|
13
|
-
export type { AppDisplayState, AppEvents } from "./types.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as loadMessagingBridge, r as resolveBridgeCdnUrl, t as MessagingBridgeLoadError } from "
|
|
1
|
+
import { n as loadMessagingBridge, r as resolveBridgeCdnUrl, t as MessagingBridgeLoadError } from "../loader-CfCnvaTU.js";
|
|
2
2
|
import { createContext, useCallback, useContext, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
4
|
-
//#region src/bridge-react.tsx
|
|
4
|
+
//#region src/npm/bridge-react.tsx
|
|
5
5
|
var BridgeContext = createContext(null);
|
|
6
6
|
/**
|
|
7
7
|
* Provide a {@link BridgeClient} to the React tree.
|
|
@@ -43,7 +43,7 @@ function useBridgeState() {
|
|
|
43
43
|
*/
|
|
44
44
|
function useBridgeStateKey(key) {
|
|
45
45
|
const client = useBridgeClient();
|
|
46
|
-
const subscribe = useCallback((onStoreChange) =>
|
|
46
|
+
const subscribe = useCallback((onStoreChange) => client.subscribeKey(key, onStoreChange), [client, key]);
|
|
47
47
|
const getSnapshot = useCallback(() => {
|
|
48
48
|
const state = client.getState();
|
|
49
49
|
if (state === null) return null;
|
|
@@ -110,4 +110,4 @@ function createBridgeProvider(load = loadMessagingBridge) {
|
|
|
110
110
|
//#endregion
|
|
111
111
|
export { BridgeProvider, MessagingBridgeLoadError, createBridgeProvider, loadMessagingBridge, resolveBridgeCdnUrl, useBridgeClient, useBridgeState, useBridgeStateKey };
|
|
112
112
|
|
|
113
|
-
//# sourceMappingURL=
|
|
113
|
+
//# sourceMappingURL=react.js.map
|