@ada-cx/messaging-bridge 1.0.0-setup.0 → 1.0.0-setup.1
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/loader-CVynp73o.js → dist-npm/loader-CL-9BTWS.js} +66 -43
- package/dist-npm/loader-CL-9BTWS.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.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
|
@@ -16,39 +16,39 @@ function R() {
|
|
|
16
16
|
const t = Array.from(s, (i) => i.toString(16).padStart(2, "0"));
|
|
17
17
|
return `${t.slice(0, 4).join("")}-${t.slice(4, 6).join("")}-${t.slice(6, 8).join("")}-${t.slice(8, 10).join("")}-${t.slice(10).join("")}`;
|
|
18
18
|
}
|
|
19
|
-
function
|
|
20
|
-
return new Promise((
|
|
19
|
+
function T(a, s, t, i) {
|
|
20
|
+
return new Promise((d, f) => {
|
|
21
21
|
if (s.isDisposed()) {
|
|
22
|
-
|
|
22
|
+
f(new B());
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
let
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
},
|
|
25
|
+
let m = !1, g = null, p = null;
|
|
26
|
+
const S = (o) => {
|
|
27
|
+
C({ error: o });
|
|
28
|
+
}, C = (o) => {
|
|
29
|
+
m || (m = !0, s.unregister(S), g?.(), p !== null && clearTimeout(p), "value" in o ? d(o.value) : f(o.error));
|
|
30
|
+
}, q = () => {
|
|
31
31
|
const o = t(a.getState());
|
|
32
|
-
o &&
|
|
32
|
+
o && C(o);
|
|
33
33
|
};
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
q(), !m && (s.register(S), g = a.subscribe(q), i?.timeoutMs !== void 0 && (p = setTimeout(() => {
|
|
35
|
+
C({ error: /* @__PURE__ */ new Error(`Bridge operation timed out after ${i.timeoutMs}ms.`) });
|
|
36
36
|
}, i.timeoutMs)));
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
function O(a) {
|
|
40
|
-
function s(i,
|
|
41
|
-
const
|
|
42
|
-
let
|
|
43
|
-
return
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
const
|
|
47
|
-
|
|
40
|
+
function s(i, d, f) {
|
|
41
|
+
const m = f?.equals ?? Object.is;
|
|
42
|
+
let g = i(a.getState());
|
|
43
|
+
return f?.emitInitial === !0 && d(g, void 0), a.subscribe(() => {
|
|
44
|
+
const p = i(a.getState());
|
|
45
|
+
if (m(p, g)) return;
|
|
46
|
+
const S = g;
|
|
47
|
+
g = p, d(p, S);
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
function t(i,
|
|
51
|
-
return s((
|
|
50
|
+
function t(i, d, f) {
|
|
51
|
+
return s((m) => m?.[i], d, f);
|
|
52
52
|
}
|
|
53
53
|
return {
|
|
54
54
|
subscribeKey: t,
|
|
@@ -64,7 +64,7 @@ function A(a) {
|
|
|
64
64
|
sendEvent: (e, ...r) => {
|
|
65
65
|
s || a.sendEvent(e, ...r);
|
|
66
66
|
}
|
|
67
|
-
}, i = /* @__PURE__ */ new Set(),
|
|
67
|
+
}, i = /* @__PURE__ */ new Set(), d = {
|
|
68
68
|
isDisposed: () => s,
|
|
69
69
|
register: (e) => {
|
|
70
70
|
i.add(e);
|
|
@@ -73,63 +73,63 @@ function A(a) {
|
|
|
73
73
|
i.delete(e);
|
|
74
74
|
}
|
|
75
75
|
};
|
|
76
|
-
let
|
|
77
|
-
function
|
|
78
|
-
|
|
76
|
+
let f = "", m = "", g = null, p = null, S = null;
|
|
77
|
+
function C() {
|
|
78
|
+
f = "", m = "", g !== null && (clearTimeout(g), g = null);
|
|
79
79
|
}
|
|
80
|
-
function
|
|
81
|
-
if (
|
|
80
|
+
function q() {
|
|
81
|
+
if (S) return;
|
|
82
82
|
let e = t.getState()?.["chat.conversationId"] ?? null;
|
|
83
|
-
|
|
83
|
+
S = t.subscribe(() => {
|
|
84
84
|
const r = t.getState()?.["chat.conversationId"] ?? null;
|
|
85
|
-
r !== e && (e = r,
|
|
85
|
+
r !== e && (e = r, C(), p = r);
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
function o() {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
cursor:
|
|
92
|
-
...
|
|
89
|
+
g === null && (g = setTimeout(() => {
|
|
90
|
+
g = null, f > m && (m = f, t.sendEvent("chat.messages.read", {
|
|
91
|
+
cursor: f,
|
|
92
|
+
...p ? { conversationId: p } : {}
|
|
93
93
|
}));
|
|
94
94
|
}, L));
|
|
95
95
|
}
|
|
96
96
|
let w = 0;
|
|
97
97
|
const D = {
|
|
98
98
|
sendMessage(e, r) {
|
|
99
|
-
const n = typeof e == "string" ? e.trim() : "",
|
|
100
|
-
let
|
|
99
|
+
const n = typeof e == "string" ? e.trim() : "", h = r?.secret === !0, v = R();
|
|
100
|
+
let y = null, b = null;
|
|
101
101
|
if (n) {
|
|
102
|
-
const
|
|
103
|
-
|
|
102
|
+
const l = t.getState();
|
|
103
|
+
y = l?.["chat.error"] ?? null, b = l?.["chat.error.seq"] ?? null, t.sendEvent("chat.message.send", {
|
|
104
104
|
body: n,
|
|
105
|
-
messageType:
|
|
105
|
+
messageType: h ? "secret" : "text",
|
|
106
106
|
tempMessageUuid: v
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
return {
|
|
110
110
|
tempMessageUuid: v,
|
|
111
|
-
settled(
|
|
112
|
-
return n ?
|
|
113
|
-
},
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
return
|
|
119
|
-
const
|
|
120
|
-
if (typeof
|
|
121
|
-
if (
|
|
122
|
-
|
|
111
|
+
settled(l) {
|
|
112
|
+
return n ? h ? T(t, d, () => {
|
|
113
|
+
}, l) : T(t, d, (c) => {
|
|
114
|
+
const I = (c?.["chat.messages"] ?? []).find((M) => M.clientKey === v);
|
|
115
|
+
if (I) return { value: I };
|
|
116
|
+
const u = c?.["chat.error"] ?? null;
|
|
117
|
+
if (c !== null && "chat.error.clientKey" in c)
|
|
118
|
+
return u !== null && c["chat.error.clientKey"] === v ? { error: new Error(u) } : void 0;
|
|
119
|
+
const E = c?.["chat.error.seq"];
|
|
120
|
+
if (typeof E == "number") {
|
|
121
|
+
if (b === null) {
|
|
122
|
+
b = E;
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
|
-
return
|
|
125
|
+
return u !== null && E !== b ? { error: new Error(u) } : void 0;
|
|
126
126
|
}
|
|
127
|
-
if (
|
|
128
|
-
|
|
127
|
+
if (u === null) {
|
|
128
|
+
y = null;
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
|
-
if (
|
|
132
|
-
},
|
|
131
|
+
if (u !== y) return { error: new Error(u) };
|
|
132
|
+
}, l) : Promise.reject(/* @__PURE__ */ new Error("sendMessage requires a non-empty body."));
|
|
133
133
|
}
|
|
134
134
|
};
|
|
135
135
|
},
|
|
@@ -177,30 +177,30 @@ function A(a) {
|
|
|
177
177
|
submitCapture(e) {
|
|
178
178
|
const r = t.getState()?.["conversation.stateData.capture"];
|
|
179
179
|
if (!r) return { settled: () => Promise.reject(/* @__PURE__ */ new Error("No capture field is active.")) };
|
|
180
|
-
const n = r.dataId,
|
|
180
|
+
const n = r.dataId, h = R();
|
|
181
181
|
t.sendEvent("capture.submit", {
|
|
182
182
|
value: e,
|
|
183
183
|
dataId: n,
|
|
184
|
-
submitId:
|
|
184
|
+
submitId: h
|
|
185
185
|
});
|
|
186
186
|
let v = !1;
|
|
187
|
-
return { settled: (
|
|
188
|
-
const
|
|
189
|
-
if (!
|
|
190
|
-
const
|
|
191
|
-
if (
|
|
187
|
+
return { settled: (y) => T(t, d, (b) => {
|
|
188
|
+
const l = b?.["conversation.stateData.capture"] ?? null;
|
|
189
|
+
if (!l || l.dataId !== n) return { value: { ok: !0 } };
|
|
190
|
+
const c = l.lastSubmitFailure;
|
|
191
|
+
if (c && c.submitId === h) return { value: {
|
|
192
192
|
ok: !1,
|
|
193
|
-
message:
|
|
193
|
+
message: c.message
|
|
194
194
|
} };
|
|
195
|
-
if (
|
|
195
|
+
if (l.isSubmitting === !0) {
|
|
196
196
|
v = !0;
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
|
-
if (v) return
|
|
199
|
+
if (v) return l.validationErrorMessage ? { value: {
|
|
200
200
|
ok: !1,
|
|
201
|
-
message:
|
|
201
|
+
message: l.validationErrorMessage
|
|
202
202
|
} } : { value: { ok: !0 } };
|
|
203
|
-
},
|
|
203
|
+
}, y) };
|
|
204
204
|
},
|
|
205
205
|
cancelCapture(e) {
|
|
206
206
|
const r = t.getState()?.["conversation.stateData.capture"];
|
|
@@ -224,9 +224,9 @@ function A(a) {
|
|
|
224
224
|
},
|
|
225
225
|
markRead(e, r) {
|
|
226
226
|
if (typeof e != "string" || e === "") return;
|
|
227
|
-
|
|
227
|
+
q();
|
|
228
228
|
const n = r?.conversationId ?? t.getState()?.["chat.conversationId"] ?? null;
|
|
229
|
-
n !==
|
|
229
|
+
n !== p && (C(), p = n), e > f && (f = e, o());
|
|
230
230
|
},
|
|
231
231
|
loadOlderMessages() {
|
|
232
232
|
const e = t.getState();
|
|
@@ -240,37 +240,37 @@ function A(a) {
|
|
|
240
240
|
});
|
|
241
241
|
},
|
|
242
242
|
submitCsat(e, r) {
|
|
243
|
-
const { surveyType: n, partial:
|
|
244
|
-
let
|
|
243
|
+
const { surveyType: n, partial: h, conversationId: v } = r, y = t.getState()?.["csat.submitSuccess.seq"] ?? 0;
|
|
244
|
+
let b = t.getState()?.["csat.submitError"] ?? null, l = t.getState()?.["csat.submitError.seq"] ?? null;
|
|
245
245
|
t.sendEvent("csat.submit", {
|
|
246
246
|
data: e,
|
|
247
247
|
surveyType: n,
|
|
248
|
-
...
|
|
248
|
+
...h !== void 0 ? { partial: h } : {},
|
|
249
249
|
...v != null ? { conversationId: v } : {}
|
|
250
250
|
});
|
|
251
|
-
const
|
|
252
|
-
return { settled: (
|
|
253
|
-
if ((
|
|
254
|
-
const
|
|
255
|
-
if (typeof
|
|
256
|
-
if (
|
|
257
|
-
|
|
251
|
+
const c = (I) => v == null || (I ?? null) === v;
|
|
252
|
+
return { settled: (I) => T(t, d, (u) => {
|
|
253
|
+
if ((u?.["csat.submitSuccess.seq"] ?? 0) > y && u?.["csat.submitSuccess.surveyType"] === n && c(u?.["csat.submitSuccess.conversationId"])) return { value: { ok: !0 } };
|
|
254
|
+
const E = u?.["csat.submitError"] ?? null, M = u?.["csat.submitError.seq"];
|
|
255
|
+
if (typeof M == "number") {
|
|
256
|
+
if (l === null) {
|
|
257
|
+
l = M;
|
|
258
258
|
return;
|
|
259
259
|
}
|
|
260
|
-
return
|
|
260
|
+
return E !== null && M !== l && u?.["csat.submitErrorSurveyType"] === n && c(u?.["csat.submitErrorConversationId"]) ? { value: {
|
|
261
261
|
ok: !1,
|
|
262
|
-
message:
|
|
262
|
+
message: E
|
|
263
263
|
} } : void 0;
|
|
264
264
|
}
|
|
265
|
-
if (
|
|
266
|
-
|
|
265
|
+
if (E === null) {
|
|
266
|
+
b = null;
|
|
267
267
|
return;
|
|
268
268
|
}
|
|
269
|
-
if (
|
|
269
|
+
if (E !== b && u?.["csat.submitErrorSurveyType"] === n && c(u?.["csat.submitErrorConversationId"])) return { value: {
|
|
270
270
|
ok: !1,
|
|
271
|
-
message:
|
|
271
|
+
message: E
|
|
272
272
|
} };
|
|
273
|
-
},
|
|
273
|
+
}, I) };
|
|
274
274
|
},
|
|
275
275
|
trackCsatShown(e, r) {
|
|
276
276
|
t.sendEvent("csat.shown", {
|
|
@@ -280,7 +280,7 @@ function A(a) {
|
|
|
280
280
|
},
|
|
281
281
|
checkEndChatEligibility(e) {
|
|
282
282
|
const r = t.getState()?.["csat.endChatEligibility.seq"] ?? 0;
|
|
283
|
-
return t.sendEvent("csat.checkEndChatEligibility"),
|
|
283
|
+
return t.sendEvent("csat.checkEndChatEligibility"), T(t, d, (n) => {
|
|
284
284
|
if (!((n?.["csat.endChatEligibility.seq"] ?? 0) <= r))
|
|
285
285
|
return { value: {
|
|
286
286
|
eligible: n?.["csat.endChatEligible"] ?? null,
|
|
@@ -327,7 +327,7 @@ function A(a) {
|
|
|
327
327
|
},
|
|
328
328
|
emailTranscript(e, r) {
|
|
329
329
|
const n = typeof e == "string" ? e.trim() : "";
|
|
330
|
-
return n ? (t.sendEvent("settings.transcript.email.send", { email: n }), k("transcript.email.status", r)) : Promise.reject(/* @__PURE__ */ new Error("emailTranscript requires a non-empty email."));
|
|
330
|
+
return n ? (t.sendEvent("settings.transcript.email.send", { email: n }), k("transcript.email.status", r, n)) : Promise.reject(/* @__PURE__ */ new Error("emailTranscript requires a non-empty email."));
|
|
331
331
|
},
|
|
332
332
|
downloadTranscript(e) {
|
|
333
333
|
return t.sendEvent("settings.transcript.download.request"), k("transcript.download.status", e);
|
|
@@ -371,22 +371,29 @@ function A(a) {
|
|
|
371
371
|
});
|
|
372
372
|
}
|
|
373
373
|
};
|
|
374
|
-
function k(e, r) {
|
|
375
|
-
const
|
|
376
|
-
let
|
|
377
|
-
return
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (
|
|
381
|
-
|
|
374
|
+
function k(e, r, n) {
|
|
375
|
+
const h = `${e}.seq`;
|
|
376
|
+
let v = t.getState()?.[e] ?? "idle", y = t.getState()?.[h] ?? null, b = t.getState()?.["transcript.email.conflict.seq"] ?? null;
|
|
377
|
+
return T(t, d, (l) => {
|
|
378
|
+
if (n !== void 0) {
|
|
379
|
+
const E = l?.["transcript.email.conflict.seq"];
|
|
380
|
+
if (typeof E == "number") {
|
|
381
|
+
if (b === null) b = E;
|
|
382
|
+
else if (E !== b && l?.["transcript.email.conflict.email"] === n) return { error: /* @__PURE__ */ new Error("emailTranscript was rejected: a request for a different address is already in flight. The in-flight email still completes with its own outcome.") };
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const c = l?.[e] ?? "idle", I = l?.[h];
|
|
386
|
+
if (typeof I == "number") {
|
|
387
|
+
if (y === null) {
|
|
388
|
+
y = I;
|
|
382
389
|
return;
|
|
383
390
|
}
|
|
384
|
-
return
|
|
391
|
+
return I === y ? void 0 : c === "success" ? { value: void 0 } : c === "error" ? { error: /* @__PURE__ */ new Error(`${e} reported an error.`) } : void 0;
|
|
385
392
|
}
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
388
|
-
if (
|
|
389
|
-
if (
|
|
393
|
+
const u = v;
|
|
394
|
+
if (v = c, u === "pending") {
|
|
395
|
+
if (c === "success") return { value: void 0 };
|
|
396
|
+
if (c === "error") return { error: /* @__PURE__ */ new Error(`${e} reported an error.`) };
|
|
390
397
|
}
|
|
391
398
|
}, r);
|
|
392
399
|
}
|
|
@@ -394,7 +401,7 @@ function A(a) {
|
|
|
394
401
|
operations: D,
|
|
395
402
|
dispose() {
|
|
396
403
|
if (!s) {
|
|
397
|
-
s = !0,
|
|
404
|
+
s = !0, C(), S?.(), S = null;
|
|
398
405
|
for (const e of [...i]) e(new B());
|
|
399
406
|
i.clear();
|
|
400
407
|
}
|
|
@@ -403,58 +410,58 @@ function A(a) {
|
|
|
403
410
|
}
|
|
404
411
|
function U(a = null) {
|
|
405
412
|
let s = a, t = !1;
|
|
406
|
-
const i = /* @__PURE__ */ new Set(),
|
|
407
|
-
function
|
|
413
|
+
const i = /* @__PURE__ */ new Set(), d = [];
|
|
414
|
+
function f() {
|
|
408
415
|
for (const o of [...i]) try {
|
|
409
416
|
o();
|
|
410
417
|
} catch (w) {
|
|
411
418
|
console.error("[AdaMessaging] Bridge subscriber threw:", w);
|
|
412
419
|
}
|
|
413
420
|
}
|
|
414
|
-
function
|
|
421
|
+
function m() {
|
|
415
422
|
return s;
|
|
416
423
|
}
|
|
417
|
-
function
|
|
424
|
+
function g(o) {
|
|
418
425
|
return i.add(o), () => {
|
|
419
426
|
i.delete(o);
|
|
420
427
|
};
|
|
421
428
|
}
|
|
422
|
-
function
|
|
423
|
-
t ||
|
|
429
|
+
function p(o, ...w) {
|
|
430
|
+
t || d.push({
|
|
424
431
|
event: o,
|
|
425
432
|
payload: w[0]
|
|
426
433
|
});
|
|
427
434
|
}
|
|
428
|
-
const
|
|
429
|
-
getState:
|
|
430
|
-
subscribe:
|
|
431
|
-
sendEvent:
|
|
432
|
-
},
|
|
435
|
+
const S = {
|
|
436
|
+
getState: m,
|
|
437
|
+
subscribe: g,
|
|
438
|
+
sendEvent: p
|
|
439
|
+
}, C = O(S), q = A(S);
|
|
433
440
|
return {
|
|
434
|
-
getState:
|
|
435
|
-
subscribe:
|
|
436
|
-
sendEvent:
|
|
437
|
-
subscribeKey:
|
|
438
|
-
select:
|
|
439
|
-
operations:
|
|
441
|
+
getState: m,
|
|
442
|
+
subscribe: g,
|
|
443
|
+
sendEvent: p,
|
|
444
|
+
subscribeKey: C.subscribeKey,
|
|
445
|
+
select: C.select,
|
|
446
|
+
operations: q.operations,
|
|
440
447
|
destroy() {
|
|
441
|
-
t = !0,
|
|
448
|
+
t = !0, q.dispose(), s = null, i.clear();
|
|
442
449
|
},
|
|
443
450
|
setState(o) {
|
|
444
|
-
s = o,
|
|
451
|
+
s = o, f();
|
|
445
452
|
},
|
|
446
453
|
updateState(o) {
|
|
447
454
|
s = {
|
|
448
455
|
"chat.error.clientKey": null,
|
|
449
456
|
...s ?? {},
|
|
450
457
|
...o
|
|
451
|
-
},
|
|
458
|
+
}, f();
|
|
452
459
|
},
|
|
453
460
|
get sentEvents() {
|
|
454
|
-
return [...
|
|
461
|
+
return [...d];
|
|
455
462
|
},
|
|
456
463
|
clearSentEvents() {
|
|
457
|
-
|
|
464
|
+
d.length = 0;
|
|
458
465
|
},
|
|
459
466
|
get subscriberCount() {
|
|
460
467
|
return i.size;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../../src/contract/operations.ts","../../src/npm/testing.ts"],"sourcesContent":["import type {\n\tAppDisplayState,\n\tAppEvents,\n\tCsatSubmitData,\n\tMessage,\n\tOptionItem,\n\tQuickReply,\n} from \"./types\";\n\n/**\n * `client.operations` — typed helpers over the raw event/state contract,\n * mined from Ada's reference app so custom apps inherit its validated\n * behavior (debounces, guards, correlation) instead of reimplementing it.\n *\n * Implementation note: the npm test mock and CDN runtime share this module.\n * The mock reuses it over its own in-memory host so mocked handles resolve\n * from scripted state, but the published tarball never carries transport\n * logic — every helper here speaks through `sendEvent`/`subscribe` alone.\n */\n\n/** Debounce window for {@link BridgeOperations.markRead} reports. */\nconst READ_REPORT_DEBOUNCE_MS = 400;\n/** Default {@link BridgeOperations.startNewConversation} cooldown. */\nconst START_NEW_CONVERSATION_COOLDOWN_MS = 5_000;\n\n/**\n * The minimal client surface the operations layer builds on. Satisfied by the\n * real `BridgeClient` and by the npm test mock.\n */\nexport interface BridgeOperationsHost {\n\tgetState(): AppDisplayState | null;\n\tsubscribe(callback: () => void): () => void;\n\tsendEvent<K extends keyof AppEvents>(\n\t\tevent: K,\n\t\t...args: AppEvents[K] extends undefined ? [] : [payload: AppEvents[K]]\n\t): void;\n}\n\n/** Outcome of a correlated submit: accepted, or rejected with a message. */\nexport type OperationResult = { ok: true } | { ok: false; message: string };\n\nexport interface SettleOptions {\n\t/** Reject with an `Error` if the operation has not settled in time. */\n\ttimeoutMs?: number;\n}\n\n/**\n * Rejection every in-flight `settled()` promise receives when the client is\n * destroyed, so teardown is the layer's bound of last resort even without a\n * `timeoutMs`. The class identity does not survive the npm/CDN module split,\n * so detect it by `error.name === \"BridgeClientDestroyedError\"` (or via\n * {@link BridgeClientDestroyedError.is}), never by `instanceof` alone.\n */\nexport class BridgeClientDestroyedError extends Error {\n\tconstructor(message = \"The bridge client was destroyed.\") {\n\t\tsuper(message);\n\t\tthis.name = \"BridgeClientDestroyedError\";\n\t}\n\n\tstatic is(error: unknown): error is BridgeClientDestroyedError {\n\t\treturn (\n\t\t\terror instanceof Error && error.name === \"BridgeClientDestroyedError\"\n\t\t);\n\t}\n}\n\nexport interface SendHandle {\n\t/**\n\t * The uuid put on the wire as `tempMessageUuid`. Core seeds the optimistic\n\t * message's `clientKey` from it, so the sent message is findable in\n\t * `chat.messages` by `clientKey === tempMessageUuid`.\n\t */\n\treadonly tempMessageUuid: string;\n\t/**\n\t * Resolves with the message once it appears in `chat.messages` (the\n\t * optimistic row; the durable server echo keeps the same `clientKey`).\n\t * Rejects when core reports THIS send's error before the row appears —\n\t * rate limit, over-length, session not ready, dispatch failure —\n\t * correlated exactly on `chat.error.clientKey` matching the minted\n\t * `tempMessageUuid`, so an unrelated failure in the same window never\n\t * falsely rejects a delivered send. On a core document that predates\n\t * `chat.error.clientKey`, falls back to the positional\n\t * `chat.error.seq`-advance detection, and before that to `chat.error`\n\t * text transitions. A secret send NEVER resolves — core deliberately\n\t * writes no transcript row for it — so pass `timeoutMs` or skip\n\t * `settled()` for secret sends. Destroying the client rejects every\n\t * pending `settled()` with a {@link BridgeClientDestroyedError}.\n\t */\n\tsettled(opts?: SettleOptions): Promise<Message>;\n}\n\nexport interface CaptureHandle {\n\t/**\n\t * Resolves on the verdict for THIS capture submit: `{ ok: true }` when the\n\t * value was accepted (core removes the capture block), or\n\t * `{ ok: false, message }` when it was rejected — a server validation\n\t * rejection (observed on the `isSubmitting` falling edge, with the\n\t * validation error text), or a failure/drop core stamps on the capture's\n\t * `lastSubmitFailure` keyed to this submit's own minted `submitId` (no\n\t * session to round-trip, value over the length cap, transport failure, a\n\t * duplicate submit while one is in flight, a host-driven reset). The\n\t * correlation is exact: the handle never reads the global `chat.error`,\n\t * so an unrelated failure in the same window can never masquerade as this\n\t * capture's verdict. On a core document that predates `lastSubmitFailure`,\n\t * those failures are not capture-attributable at all and the handle stays\n\t * pending — pass `timeoutMs` when targeting older cores.\n\t */\n\tsettled(opts?: SettleOptions): Promise<OperationResult>;\n}\n\nexport interface CsatSubmitHandle {\n\t/**\n\t * Resolves when core reports this survey's outcome, correlated on the\n\t * success seq advance x surveyType x conversationId triple (and the\n\t * mirror-image error triple). A `partial` submit reports no terminal\n\t * outcome, so `settled()` on one only settles via `timeoutMs`.\n\t */\n\tsettled(opts?: SettleOptions): Promise<OperationResult>;\n}\n\nexport interface FileUploadHandle {\n\t/** The minted upload id sent with `file.upload.start`. */\n\treadonly uploadId: string;\n\t/**\n\t * Re-send the EXACT same `{ file, uploadId }` pair. Core correlates the\n\t * retry to the failed attempt by that pair, so a fresh pair would orphan\n\t * the original error state.\n\t */\n\tretry(): void;\n\t/** Dismiss a reported upload error (`file.uploadError`). */\n\tdismissError(): void;\n}\n\nexport interface EndChatEligibilityResult {\n\t/** `csat.endChatEligible` at the moment the answer arrived. */\n\teligible: boolean | null;\n\t/** Which survey End Chat should present, when eligible. */\n\tsurveyTarget: \"bot\" | \"agent\" | null;\n}\n\nexport interface ObserveOptions<T> {\n\t/** Change detector; defaults to `Object.is`. */\n\tequals?: (a: T, b: T) => boolean;\n\t/** Also invoke the callback immediately with the current value. */\n\temitInitial?: boolean;\n}\n\n/**\n * Typed helpers over the bridge event/state contract. Obtain via\n * `client.operations`. Fire-and-forget helpers return `void`; correlated\n * helpers return a handle or Promise that settles from state transitions\n * (there is no request/response channel — core answers through state).\n */\nexport interface BridgeOperations {\n\t/**\n\t * Send a chat message. The body is trimmed; an empty result sends nothing\n\t * (the returned handle then rejects). `secret: true` sends a masked\n\t * message: the raw body never enters the transcript and the handle never\n\t * resolves. While `ui.secretMessage.isOpen` is true you likely want\n\t * `secret: true` to match the composer's mode.\n\t */\n\tsendMessage(body: string, opts?: { secret?: boolean }): SendHandle;\n\t/** Retry a failed send by message id (see {@link canRetryMessage}). */\n\tretryMessage(messageId: string): void;\n\t/**\n\t * Whether the retry affordance should show for a message: a `text`\n\t * message core marked `isRetryable`, no disconnected Zendesk SDK, and the\n\t * message belongs to the current conversation (or predates stamping).\n\t */\n\tcanRetryMessage(message: Message): boolean;\n\n\t/** Answer a quick-reply chip. Pass the chip and its message id verbatim. */\n\tselectQuickReply(reply: QuickReply, messageId: string): void;\n\t/** Answer an options block. The label falls back to the option id. */\n\tselectOption(option: OptionItem, messageId: string): void;\n\t/**\n\t * Submit the active selectable list (`conversation.stateData.listSelection`\n\t * supplies the `dataId`). No-op when no list selection is active.\n\t */\n\tsubmitListSelection(selectedIds: string[]): void;\n\t/**\n\t * Cancel the active selectable list. Uses the block's own cancel response\n\t * and label (`label` overrides the visible label). No-op when no list\n\t * selection is active or it has no cancel response.\n\t */\n\tcancelListSelection(label?: string): void;\n\t/**\n\t * Submit the active capture field (`conversation.stateData.capture`\n\t * supplies the `dataId`). Each call mints its own `submitId`, so the\n\t * handle settles only on ITS OWN submit's verdict or failure — a second\n\t * submit sent while one is in flight is dropped by core and its handle\n\t * resolves `{ ok: false }` on its own terms rather than inheriting the\n\t * in-flight submit's verdict.\n\t */\n\tsubmitCapture(value: string): CaptureHandle;\n\t/**\n\t * Cancel the active capture field. `label` overrides the block's own\n\t * cancel label. No-op when no capture is active or it has no cancel\n\t * response.\n\t */\n\tcancelCapture(label?: string): void;\n\n\t/** React to a bot message with a thumbs vote. */\n\taddReaction(messageId: string, reaction: 1 | -1): void;\n\t/**\n\t * Report that the user activated a `link` message. Core resolves the\n\t * stored message for tracking and, with `navigateInHost`, validated\n\t * same-tab host navigation.\n\t */\n\treportLinkClick(messageId: string, opts?: { navigateInHost?: boolean }): void;\n\n\t/**\n\t * Advance the persisted read watermark. Reports are debounced 400 ms, the\n\t * watermark is a monotonic lexical max over `_id` cursor strings (calling\n\t * with an older cursor never lowers it), and the accumulator resets when\n\t * `chat.conversationId` changes so a pending cursor from conversation A\n\t * can never commit against B. Call with `message.cursor` for each message\n\t * that scrolls into view; messages stamped with a DIFFERENT\n\t * `conversationId` must be excluded by the caller (the transcript\n\t * preserves the previous conversation's rows).\n\t */\n\tmarkRead(cursor: string, opts?: { conversationId?: string }): void;\n\n\t/**\n\t * Request an older page of history. No-op unless `chat.canLoadMore` is\n\t * true and no load is already in flight.\n\t */\n\tloadOlderMessages(): void;\n\t/**\n\t * Invoke `callback` each time restored/baseline history (re)loads\n\t * (`chat.recentMessagesLoadSeq` advances) — the one-shot trigger for\n\t * \"scroll to the bottom of restored history\" and for seeding an unread\n\t * divider. Returns an unsubscribe function.\n\t */\n\tonHistoryLoaded(callback: (seq: number) => void): () => void;\n\n\t/**\n\t * Submit a CSAT survey. Pass `conversationId: message.conversationId` for\n\t * a survey rendered IN the transcript (the row can outlive its\n\t * conversation); omit it — or pass `null`, which is treated as omitted on\n\t * the wire and in correlation — for End Chat / proactive flows, where\n\t * core resolves the conversation itself.\n\t */\n\tsubmitCsat(\n\t\tdata: CsatSubmitData,\n\t\topts: {\n\t\t\tsurveyType: string;\n\t\t\tpartial?: boolean;\n\t\t\tconversationId?: string | null;\n\t\t},\n\t): CsatSubmitHandle;\n\t/** Analytics: report that a survey was displayed. Fire-and-forget. */\n\ttrackCsatShown(surveyType: string, conversationId?: string | null): void;\n\n\t/**\n\t * Ask core whether End Chat should present a survey. Correlated by\n\t * latching `csat.endChatEligibility.seq` and resolving when it advances\n\t * (there is no request id; a `ready -> ready` re-check changes no other\n\t * observable state).\n\t */\n\tcheckEndChatEligibility(\n\t\topts?: SettleOptions,\n\t): Promise<EndChatEligibilityResult>;\n\t/** End the chat without presenting a survey. */\n\tskipCsatAndEndChat(): void;\n\t/**\n\t * Start a new conversation. Applies a local cooldown (default 5 s) that\n\t * swallows rapid re-clicks; returns `false` while cooling down.\n\t */\n\tstartNewConversation(opts?: { cooldownMs?: number }): boolean;\n\t/** Reset the app frame's conversation state. */\n\tresetApp(): void;\n\n\t/**\n\t * Report a content-free composer-changed edge (drives live-agent typing\n\t * indicators). The event is payload-free by contract — composer text must\n\t * never cross the frame boundary — and this helper suppresses it entirely\n\t * in secret mode (pass `secret: true`, or leave it to the\n\t * `ui.secretMessage.isOpen` state check): even a content-free typing edge\n\t * is a signal about the secret being typed.\n\t */\n\tnotifyComposerChanged(opts?: { secret?: boolean }): void;\n\t/** Open or close the masked (secret) composer mode. */\n\ttoggleSecretMessage(open: boolean): void;\n\n\t/**\n\t * Start a live-agent file upload. Mints and retains the `{ file,\n\t * uploadId }` pair so `retry()` replays exactly it. Progress and errors\n\t * land on `file.isUploading`, `file.transfer`, and `file.uploadError`\n\t * (core can report an error without ever setting `isUploading`).\n\t */\n\tstartFileUpload(file: File): FileUploadHandle;\n\n\t/** Change the conversation language (BCP 47 tag the bot offers). */\n\tsetLanguage(language: string): void;\n\t/**\n\t * Email the transcript. Resolves/rejects when `transcript.email.status`\n\t * reaches `success | error` with its `.seq` advanced past this call's\n\t * baseline — a request core drops without ever broadcasting `pending`\n\t * (a host-driven reset in progress) still rejects. On a core document\n\t * that predates the seq, falls back to the `pending -> terminal` edge.\n\t * The email is trimmed; an empty result rejects immediately without\n\t * sending (core drops an empty email silently, so nothing would ever\n\t * settle it). The request is single-flight and address-aware: a call for\n\t * the SAME address as an in-flight request joins it and settles on its\n\t * verdict; a call for a DIFFERENT address is rejected address-matched on\n\t * `transcript.email.conflict.*` — ONLY the conflicting call's promise\n\t * rejects, while the in-flight request still completes, writes the final\n\t * status, and settles its own handle with the true outcome (a rejection\n\t * here never means the in-flight email was not sent). On a core document\n\t * that predates the conflict channel, a conflicting call settles on the\n\t * in-flight verdict instead.\n\t */\n\temailTranscript(email: string, opts?: SettleOptions): Promise<void>;\n\t/**\n\t * Download the transcript. Same settle contract as\n\t * {@link BridgeOperations.emailTranscript}, on\n\t * `transcript.download.status`.\n\t */\n\tdownloadTranscript(opts?: SettleOptions): Promise<void>;\n\t/** Toggle the new-message alert sound. */\n\tsetAlertSound(enabled: boolean): void;\n\t/**\n\t * Ask the HOST page to request Web Notification permission (permission is\n\t * per-origin, so the widget frame's own value is not the governing one).\n\t * Result lands on `chatter.notificationPermission`.\n\t */\n\trequestNotificationPermission(): void;\n\t/** Set the user's in-widget theme override. */\n\tsetTheme(theme: \"light\" | \"dark\" | \"auto\"): void;\n\t/** Set the user's in-widget text-size override. */\n\tsetTextSize(size: \"small\" | \"default\" | \"large\"): void;\n\n\t/** The header close affordance (ends the chat when `endChat.canEnd`). */\n\tclose(): void;\n\t/** Minimize the widget. */\n\tminimize(): void;\n\t/** Dismiss the visible toast. */\n\tdismissToast(): void;\n\t/**\n\t * Clear `chat.error` in core. Clear core state rather than hiding the\n\t * error locally, or the session's second error renders nothing.\n\t */\n\tdismissError(): void;\n\t/** Ask the SDK host to expand or restore the app's viewport surface. */\n\tsetHostViewportExpanded(expanded: boolean): void;\n\t/** Retry after a response outage banner. */\n\tretryAfterOutage(): void;\n\t/**\n\t * Report a fatal app error to core (renders the fallback UI and reports\n\t * telemetry). Callable from anywhere with a client reference — including\n\t * a class error boundary outside any React provider.\n\t */\n\treportAppError(error: unknown, componentStack?: string): void;\n}\n\nfunction mintUuid(): string {\n\tconst cryptoObj = typeof crypto === \"undefined\" ? undefined : crypto;\n\tif (typeof cryptoObj?.randomUUID === \"function\") {\n\t\treturn cryptoObj.randomUUID();\n\t}\n\tconst bytes = new Uint8Array(16);\n\tif (typeof cryptoObj?.getRandomValues === \"function\") {\n\t\tcryptoObj.getRandomValues(bytes);\n\t} else {\n\t\tfor (let index = 0; index < bytes.length; index += 1) {\n\t\t\tbytes[index] = Math.floor(Math.random() * 256);\n\t\t}\n\t}\n\t// RFC 4122 version/variant bits so core's uuid-shape validation accepts it.\n\tbytes[6] = ((bytes[6] as number) & 0x0f) | 0x40;\n\tbytes[8] = ((bytes[8] as number) & 0x3f) | 0x80;\n\tconst hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n\treturn `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex\n\t\t.slice(6, 8)\n\t\t.join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10).join(\"\")}`;\n}\n\ntype Outcome<T> = { value: T } | { error: Error };\n\n/**\n * The disposal hooks a settle promise registers with, so `dispose()` can\n * reject every in-flight `settled()` with a typed\n * {@link BridgeClientDestroyedError} — the layer's bound of last resort when\n * no `timeoutMs` was passed.\n */\ninterface SettleLifecycle {\n\tisDisposed(): boolean;\n\tregister(abort: (error: Error) => void): void;\n\tunregister(abort: (error: Error) => void): void;\n}\n\n/**\n * Settle a promise from state transitions: `inspect` runs once immediately\n * and then on every state update until it returns an outcome. `timeoutMs`\n * bounds the wait; without it an operation whose answer never arrives keeps\n * its subscription until it settles or the client is destroyed, which\n * rejects it with a {@link BridgeClientDestroyedError}.\n */\nfunction settleFromState<T>(\n\thost: BridgeOperationsHost,\n\tlifecycle: SettleLifecycle,\n\tinspect: (state: AppDisplayState | null) => Outcome<T> | undefined,\n\topts?: SettleOptions,\n): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tif (lifecycle.isDisposed()) {\n\t\t\treject(new BridgeClientDestroyedError());\n\t\t\treturn;\n\t\t}\n\t\tlet done = false;\n\t\tlet unsubscribe: (() => void) | null = null;\n\t\tlet timer: ReturnType<typeof setTimeout> | null = null;\n\t\tconst abort = (error: Error): void => {\n\t\t\tfinish({ error });\n\t\t};\n\t\tconst finish = (outcome: Outcome<T>): void => {\n\t\t\tif (done) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone = true;\n\t\t\tlifecycle.unregister(abort);\n\t\t\tunsubscribe?.();\n\t\t\tif (timer !== null) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\tif (\"value\" in outcome) {\n\t\t\t\tresolve(outcome.value);\n\t\t\t} else {\n\t\t\t\treject(outcome.error);\n\t\t\t}\n\t\t};\n\t\tconst run = (): void => {\n\t\t\tconst outcome = inspect(host.getState());\n\t\t\tif (outcome) {\n\t\t\t\tfinish(outcome);\n\t\t\t}\n\t\t};\n\t\trun();\n\t\tif (done) {\n\t\t\treturn;\n\t\t}\n\t\tlifecycle.register(abort);\n\t\tunsubscribe = host.subscribe(run);\n\t\tif (opts?.timeoutMs !== undefined) {\n\t\t\ttimer = setTimeout(() => {\n\t\t\t\tfinish({\n\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t`Bridge operation timed out after ${opts.timeoutMs}ms.`,\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t}, opts.timeoutMs);\n\t\t}\n\t});\n}\n\ninterface StateObservation {\n\tsubscribeKey<K extends keyof AppDisplayState>(\n\t\tkey: K,\n\t\tcallback: (\n\t\t\tvalue: AppDisplayState[K] | undefined,\n\t\t\tprevious: AppDisplayState[K] | undefined,\n\t\t) => void,\n\t\topts?: ObserveOptions<AppDisplayState[K] | undefined>,\n\t): () => void;\n\tselect<T>(\n\t\tselector: (state: AppDisplayState | null) => T,\n\t\tcallback: (value: T, previous: T | undefined) => void,\n\t\topts?: ObserveOptions<T>,\n\t): () => void;\n}\n\n/**\n * Build the `subscribeKey`/`select` observation primitives over a host.\n * `Object.is` is a sound default equality for `subscribeKey`: state crosses\n * the frame boundary by structured clone, so the real client restores each\n * structurally unchanged key's previous reference before notifying (the test\n * mock shares references in memory to begin with). For `select`, whose\n * selector typically MINTS a new object per call, pass a custom `equals`\n * (or select a primitive/signature string) when projecting objects.\n */\nexport function createStateObservation(\n\thost: BridgeOperationsHost,\n): StateObservation {\n\tfunction select<T>(\n\t\tselector: (state: AppDisplayState | null) => T,\n\t\tcallback: (value: T, previous: T | undefined) => void,\n\t\topts?: ObserveOptions<T>,\n\t): () => void {\n\t\tconst equals = opts?.equals ?? Object.is;\n\t\tlet previous = selector(host.getState());\n\t\tif (opts?.emitInitial === true) {\n\t\t\tcallback(previous, undefined);\n\t\t}\n\t\treturn host.subscribe(() => {\n\t\t\tconst next = selector(host.getState());\n\t\t\tif (equals(next, previous)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst before = previous;\n\t\t\tprevious = next;\n\t\t\tcallback(next, before);\n\t\t});\n\t}\n\n\tfunction subscribeKey<K extends keyof AppDisplayState>(\n\t\tkey: K,\n\t\tcallback: (\n\t\t\tvalue: AppDisplayState[K] | undefined,\n\t\t\tprevious: AppDisplayState[K] | undefined,\n\t\t) => void,\n\t\topts?: ObserveOptions<AppDisplayState[K] | undefined>,\n\t): () => void {\n\t\treturn select((state) => state?.[key], callback, opts);\n\t}\n\n\treturn { subscribeKey, select };\n}\n\nexport interface BridgeOperationsBundle {\n\toperations: BridgeOperations;\n\t/** Release the layer's own subscriptions and timers (client teardown). */\n\tdispose(): void;\n}\n\nexport function createBridgeOperations(\n\trawHost: BridgeOperationsHost,\n): BridgeOperationsBundle {\n\tlet disposed = false;\n\n\t// Disposal must actually stop the layer: after `dispose()` no helper may\n\t// send another event or take a new subscription (the client's transport\n\t// is gone). Guarding the host once covers every helper below.\n\tconst host: BridgeOperationsHost = {\n\t\tgetState: () => rawHost.getState(),\n\t\tsubscribe: (callback) =>\n\t\t\tdisposed\n\t\t\t\t? () => {\n\t\t\t\t\t\t// nothing was subscribed\n\t\t\t\t\t}\n\t\t\t\t: rawHost.subscribe(callback),\n\t\tsendEvent: (event, ...args) => {\n\t\t\tif (!disposed) {\n\t\t\t\trawHost.sendEvent(event, ...args);\n\t\t\t}\n\t\t},\n\t};\n\n\tconst liveSettleAborts = new Set<(error: Error) => void>();\n\tconst lifecycle: SettleLifecycle = {\n\t\tisDisposed: () => disposed,\n\t\tregister: (abort) => {\n\t\t\tliveSettleAborts.add(abort);\n\t\t},\n\t\tunregister: (abort) => {\n\t\t\tliveSettleAborts.delete(abort);\n\t\t},\n\t};\n\n\t// markRead accumulator (mirrors the reference app's useReadTracking).\n\tlet readMax = \"\";\n\tlet readReported = \"\";\n\tlet readTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet readConversationId: string | null = null;\n\tlet readResetUnsubscribe: (() => void) | null = null;\n\n\tfunction resetReadAccumulator(): void {\n\t\treadMax = \"\";\n\t\treadReported = \"\";\n\t\tif (readTimer !== null) {\n\t\t\tclearTimeout(readTimer);\n\t\t\treadTimer = null;\n\t\t}\n\t}\n\n\t// Cursor spaces are per conversation: when the pin changes, drop the\n\t// accumulator AND any pending debounced report so a cursor collected in\n\t// conversation A can never be committed against B.\n\tfunction ensureReadResetSubscription(): void {\n\t\tif (readResetUnsubscribe) {\n\t\t\treturn;\n\t\t}\n\t\tlet previousPin = host.getState()?.[\"chat.conversationId\"] ?? null;\n\t\treadResetUnsubscribe = host.subscribe(() => {\n\t\t\tconst pin = host.getState()?.[\"chat.conversationId\"] ?? null;\n\t\t\tif (pin !== previousPin) {\n\t\t\t\tpreviousPin = pin;\n\t\t\t\tresetReadAccumulator();\n\t\t\t\treadConversationId = pin;\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction scheduleReadReport(): void {\n\t\tif (readTimer !== null) {\n\t\t\treturn;\n\t\t}\n\t\treadTimer = setTimeout(() => {\n\t\t\treadTimer = null;\n\t\t\tif (readMax > readReported) {\n\t\t\t\treadReported = readMax;\n\t\t\t\thost.sendEvent(\"chat.messages.read\", {\n\t\t\t\t\tcursor: readMax,\n\t\t\t\t\t...(readConversationId ? { conversationId: readConversationId } : {}),\n\t\t\t\t});\n\t\t\t}\n\t\t}, READ_REPORT_DEBOUNCE_MS);\n\t}\n\n\tlet newConversationBlockedUntil = 0;\n\n\tconst operations: BridgeOperations = {\n\t\tsendMessage(body, opts) {\n\t\t\tconst trimmed = typeof body === \"string\" ? body.trim() : \"\";\n\t\t\tconst secret = opts?.secret === true;\n\t\t\tconst tempMessageUuid = mintUuid();\n\t\t\tlet errorBaseline: string | null = null;\n\t\t\tlet errorSeqBaseline: number | null = null;\n\t\t\tif (trimmed) {\n\t\t\t\tconst preSend = host.getState();\n\t\t\t\terrorBaseline = preSend?.[\"chat.error\"] ?? null;\n\t\t\t\terrorSeqBaseline = preSend?.[\"chat.error.seq\"] ?? null;\n\t\t\t\thost.sendEvent(\"chat.message.send\", {\n\t\t\t\t\tbody: trimmed,\n\t\t\t\t\tmessageType: secret ? \"secret\" : \"text\",\n\t\t\t\t\ttempMessageUuid,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttempMessageUuid,\n\t\t\t\tsettled(settleOpts) {\n\t\t\t\t\tif (!trimmed) {\n\t\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\t\tnew Error(\"sendMessage requires a non-empty body.\"),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (secret) {\n\t\t\t\t\t\t// No optimistic row exists for a secret send by design, so\n\t\t\t\t\t\t// there is nothing to resolve with. Time-bound or skip; the\n\t\t\t\t\t\t// wait is still bounded by client destroy.\n\t\t\t\t\t\treturn settleFromState<Message>(\n\t\t\t\t\t\t\thost,\n\t\t\t\t\t\t\tlifecycle,\n\t\t\t\t\t\t\t() => undefined,\n\t\t\t\t\t\t\tsettleOpts,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn settleFromState<Message>(\n\t\t\t\t\t\thost,\n\t\t\t\t\t\tlifecycle,\n\t\t\t\t\t\t(state) => {\n\t\t\t\t\t\t\tconst messages = state?.[\"chat.messages\"] ?? [];\n\t\t\t\t\t\t\tconst match = messages.find(\n\t\t\t\t\t\t\t\t(message) => message.clientKey === tempMessageUuid,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\t\treturn { value: match };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst error = state?.[\"chat.error\"] ?? null;\n\t\t\t\t\t\t\t// A core that stamps `chat.error.clientKey` (always present,\n\t\t\t\t\t\t\t// null when unattributed) attributes every pre-row send\n\t\t\t\t\t\t\t// failure to the send's own key, so the correlation is exact:\n\t\t\t\t\t\t\t// only THIS send's error rejects, and an unrelated failure\n\t\t\t\t\t\t\t// landing between the send and its optimistic row (the seq\n\t\t\t\t\t\t\t// fallback's false-rejection window) is ignored.\n\t\t\t\t\t\t\tif (state !== null && \"chat.error.clientKey\" in state) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t\t\t\tstate[\"chat.error.clientKey\"] === tempMessageUuid\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\treturn { error: new Error(error) };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst errorSeq = state?.[\"chat.error.seq\"];\n\t\t\t\t\t\t\tif (typeof errorSeq === \"number\") {\n\t\t\t\t\t\t\t\tif (errorSeqBaseline === null) {\n\t\t\t\t\t\t\t\t\t// The send raced state hydration (no state yet when the\n\t\t\t\t\t\t\t\t\t// baseline was captured): latch the first observed seq\n\t\t\t\t\t\t\t\t\t// and treat the current error as pre-existing.\n\t\t\t\t\t\t\t\t\terrorSeqBaseline = errorSeq;\n\t\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// The seq advances on EVERY error set — including a repeat\n\t\t\t\t\t\t\t\t// of the identical text, which the fallback below cannot\n\t\t\t\t\t\t\t\t// see. `!==` rather than `>`, so a counter restarted by a\n\t\t\t\t\t\t\t\t// full core reset still rejects.\n\t\t\t\t\t\t\t\tif (error !== null && errorSeq !== errorSeqBaseline) {\n\t\t\t\t\t\t\t\t\treturn { error: new Error(error) };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Core document predates chat.error.seq: fall back to text\n\t\t\t\t\t\t\t// transitions (a repeated identical error is invisible here).\n\t\t\t\t\t\t\tif (error === null) {\n\t\t\t\t\t\t\t\terrorBaseline = null;\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (error !== errorBaseline) {\n\t\t\t\t\t\t\t\treturn { error: new Error(error) };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsettleOpts,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\tretryMessage(messageId) {\n\t\t\thost.sendEvent(\"chat.message.retry\", {\n\t\t\t\tmessage: { id: messageId, type: \"text\" },\n\t\t\t});\n\t\t},\n\n\t\tcanRetryMessage(message) {\n\t\t\tconst state = host.getState();\n\t\t\treturn (\n\t\t\t\tmessage.type === \"text\" &&\n\t\t\t\tmessage.isRetryable === true &&\n\t\t\t\tstate?.[\"zendesk.sdk.disconnected\"] !== true &&\n\t\t\t\t(message.conversationId == null ||\n\t\t\t\t\tmessage.conversationId === (state?.[\"chat.conversationId\"] ?? null))\n\t\t\t);\n\t\t},\n\n\t\tselectQuickReply(reply, messageId) {\n\t\t\thost.sendEvent(\"chat.quickReply.select\", {\n\t\t\t\tlabel: reply.label,\n\t\t\t\ttarget: reply.target,\n\t\t\t\tbuttonType: reply.buttonType,\n\t\t\t\t...(reply.value !== undefined ? { value: reply.value } : {}),\n\t\t\t\tmessageId,\n\t\t\t});\n\t\t},\n\n\t\tselectOption(option, messageId) {\n\t\t\thost.sendEvent(\"chat.option.select\", {\n\t\t\t\toptionId: option.id,\n\t\t\t\toptionLabel: option.label || option.id,\n\t\t\t\tmessageId,\n\t\t\t});\n\t\t},\n\n\t\tsubmitListSelection(selectedIds) {\n\t\t\tconst listSelection =\n\t\t\t\thost.getState()?.[\"conversation.stateData.listSelection\"];\n\t\t\tif (!listSelection) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thost.sendEvent(\"chat.selectableList.submit\", {\n\t\t\t\tselectedIds,\n\t\t\t\tdataId: listSelection.dataId,\n\t\t\t});\n\t\t},\n\n\t\tcancelListSelection(label) {\n\t\t\tconst listSelection =\n\t\t\t\thost.getState()?.[\"conversation.stateData.listSelection\"];\n\t\t\t// Core drops a cancel without a response id, so don't send one.\n\t\t\tif (!listSelection?.cancelCaptureResponseId) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thost.sendEvent(\"listSelection.cancel\", {\n\t\t\t\tcancelResponseId: listSelection.cancelCaptureResponseId,\n\t\t\t\tcancelLabel: label ?? listSelection.cancelCaptureLabel,\n\t\t\t\tdataId: listSelection.dataId,\n\t\t\t});\n\t\t},\n\n\t\tsubmitCapture(value) {\n\t\t\tconst capture = host.getState()?.[\"conversation.stateData.capture\"];\n\t\t\tif (!capture) {\n\t\t\t\treturn {\n\t\t\t\t\tsettled: () =>\n\t\t\t\t\t\tPromise.reject(new Error(\"No capture field is active.\")),\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst dataId = capture.dataId;\n\t\t\tconst submitId = mintUuid();\n\t\t\thost.sendEvent(\"capture.submit\", { value, dataId, submitId });\n\t\t\t// The verdict rides the capture object itself: `isSubmitting` is\n\t\t\t// core-owned, flips true while the submit is in flight, and the\n\t\t\t// falling edge carries `validationErrorMessage`; an ACCEPTED value\n\t\t\t// removes the whole object (or replaces it with the next block).\n\t\t\t// Every failure or drop WITHOUT a server validation verdict — a\n\t\t\t// pre-flight drop that raises and settles `isSubmitting` inside one\n\t\t\t// broadcast batch, a transport failure, a duplicate submit dropped\n\t\t\t// while another is in flight — lands on `lastSubmitFailure` keyed\n\t\t\t// with this call's own `submitId`, so the correlation is exact and\n\t\t\t// the global `chat.error` is never consulted.\n\t\t\tlet sawSubmitting = false;\n\t\t\treturn {\n\t\t\t\tsettled: (settleOpts) =>\n\t\t\t\t\tsettleFromState<OperationResult>(\n\t\t\t\t\t\thost,\n\t\t\t\t\t\tlifecycle,\n\t\t\t\t\t\t(state) => {\n\t\t\t\t\t\t\tconst current = state?.[\"conversation.stateData.capture\"] ?? null;\n\t\t\t\t\t\t\tif (!current || current.dataId !== dataId) {\n\t\t\t\t\t\t\t\treturn { value: { ok: true } };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Keyed failure BEFORE the in-flight latch: a duplicate\n\t\t\t\t\t\t\t// submit's drop is stamped while the OTHER submit still holds\n\t\t\t\t\t\t\t// `isSubmitting`, and latching that flag here would make this\n\t\t\t\t\t\t\t// handle inherit the other submit's verdict.\n\t\t\t\t\t\t\tconst failure = current.lastSubmitFailure;\n\t\t\t\t\t\t\tif (failure && failure.submitId === submitId) {\n\t\t\t\t\t\t\t\treturn { value: { ok: false, message: failure.message } };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (current.isSubmitting === true) {\n\t\t\t\t\t\t\t\tsawSubmitting = true;\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (sawSubmitting) {\n\t\t\t\t\t\t\t\treturn current.validationErrorMessage\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\t\t\t\t\t\tmessage: current.validationErrorMessage,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: { value: { ok: true } };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsettleOpts,\n\t\t\t\t\t),\n\t\t\t};\n\t\t},\n\n\t\tcancelCapture(label) {\n\t\t\tconst capture = host.getState()?.[\"conversation.stateData.capture\"];\n\t\t\tif (!capture?.cancelCaptureResponseId) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thost.sendEvent(\"capture.cancel\", {\n\t\t\t\tcancelResponseId: capture.cancelCaptureResponseId,\n\t\t\t\tcancelLabel: label ?? capture.cancelCaptureLabel,\n\t\t\t\tdataId: capture.dataId,\n\t\t\t});\n\t\t},\n\n\t\taddReaction(messageId, reaction) {\n\t\t\thost.sendEvent(\"chat.message.reaction.add\", { messageId, reaction });\n\t\t},\n\n\t\treportLinkClick(messageId, opts) {\n\t\t\thost.sendEvent(\"chat.link.click\", {\n\t\t\t\tmessageId,\n\t\t\t\t...(opts?.navigateInHost !== undefined\n\t\t\t\t\t? { navigateInHost: opts.navigateInHost }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t},\n\n\t\tmarkRead(cursor, opts) {\n\t\t\tif (typeof cursor !== \"string\" || cursor === \"\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tensureReadResetSubscription();\n\t\t\tconst conversationId =\n\t\t\t\topts?.conversationId ??\n\t\t\t\thost.getState()?.[\"chat.conversationId\"] ??\n\t\t\t\tnull;\n\t\t\tif (conversationId !== readConversationId) {\n\t\t\t\tresetReadAccumulator();\n\t\t\t\treadConversationId = conversationId;\n\t\t\t}\n\t\t\tif (cursor > readMax) {\n\t\t\t\treadMax = cursor;\n\t\t\t\tscheduleReadReport();\n\t\t\t}\n\t\t},\n\n\t\tloadOlderMessages() {\n\t\t\tconst state = host.getState();\n\t\t\tif (\n\t\t\t\tstate?.[\"chat.canLoadMore\"] !== true ||\n\t\t\t\tstate[\"chat.loadingPreviousMessages\"] === true\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thost.sendEvent(\"chat.logs.loadMore\");\n\t\t},\n\n\t\tonHistoryLoaded(callback) {\n\t\t\tlet previous = host.getState()?.[\"chat.recentMessagesLoadSeq\"] ?? 0;\n\t\t\treturn host.subscribe(() => {\n\t\t\t\tconst seq = host.getState()?.[\"chat.recentMessagesLoadSeq\"] ?? 0;\n\t\t\t\tif (seq > previous) {\n\t\t\t\t\tprevious = seq;\n\t\t\t\t\tcallback(seq);\n\t\t\t\t} else if (seq < previous) {\n\t\t\t\t\t// Returned to 0 on a chat clear; re-arm without firing.\n\t\t\t\t\tprevious = seq;\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tsubmitCsat(data, opts) {\n\t\t\tconst { surveyType, partial, conversationId } = opts;\n\t\t\tconst baselineSeq = host.getState()?.[\"csat.submitSuccess.seq\"] ?? 0;\n\t\t\tlet errorBaseline = host.getState()?.[\"csat.submitError\"] ?? null;\n\t\t\tlet errorSeqBaseline = host.getState()?.[\"csat.submitError.seq\"] ?? null;\n\t\t\t// `null` means \"omitted\" on the wire AND in correlation: core's\n\t\t\t// resolver treats a falsy id as absent and reports the SESSION's id\n\t\t\t// back, so a null-scoped predicate could never match it and the\n\t\t\t// handle would hang on a fully successful submit.\n\t\t\thost.sendEvent(\"csat.submit\", {\n\t\t\t\tdata,\n\t\t\t\tsurveyType,\n\t\t\t\t...(partial !== undefined ? { partial } : {}),\n\t\t\t\t...(conversationId != null ? { conversationId } : {}),\n\t\t\t});\n\t\t\t// When the caller omitted conversationId (End Chat / proactive),\n\t\t\t// core resolves the conversation itself, so match on the type +\n\t\t\t// seq alone; a caller-scoped survey matches its exact conversation.\n\t\t\tconst matchesConversation = (\n\t\t\t\tcandidate: string | null | undefined,\n\t\t\t): boolean =>\n\t\t\t\tconversationId == null || (candidate ?? null) === conversationId;\n\t\t\treturn {\n\t\t\t\tsettled: (settleOpts) =>\n\t\t\t\t\tsettleFromState<OperationResult>(\n\t\t\t\t\t\thost,\n\t\t\t\t\t\tlifecycle,\n\t\t\t\t\t\t(state) => {\n\t\t\t\t\t\t\tconst seq = state?.[\"csat.submitSuccess.seq\"] ?? 0;\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tseq > baselineSeq &&\n\t\t\t\t\t\t\t\tstate?.[\"csat.submitSuccess.surveyType\"] === surveyType &&\n\t\t\t\t\t\t\t\tmatchesConversation(\n\t\t\t\t\t\t\t\t\tstate?.[\"csat.submitSuccess.conversationId\"],\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\treturn { value: { ok: true } };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst error = state?.[\"csat.submitError\"] ?? null;\n\t\t\t\t\t\t\tconst errorSeq = state?.[\"csat.submitError.seq\"];\n\t\t\t\t\t\t\tif (typeof errorSeq === \"number\") {\n\t\t\t\t\t\t\t\t// The seq advances on EVERY error set — including a repeat\n\t\t\t\t\t\t\t\t// of the identical text (the same submit dropped twice at a\n\t\t\t\t\t\t\t\t// core gate), which the text transition below cannot see.\n\t\t\t\t\t\t\t\tif (errorSeqBaseline === null) {\n\t\t\t\t\t\t\t\t\t// The submit raced state hydration: latch the first\n\t\t\t\t\t\t\t\t\t// observed seq and treat the current error as\n\t\t\t\t\t\t\t\t\t// pre-existing.\n\t\t\t\t\t\t\t\t\terrorSeqBaseline = errorSeq;\n\t\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\terror !== null &&\n\t\t\t\t\t\t\t\t\terrorSeq !== errorSeqBaseline &&\n\t\t\t\t\t\t\t\t\tstate?.[\"csat.submitErrorSurveyType\"] === surveyType &&\n\t\t\t\t\t\t\t\t\tmatchesConversation(state?.[\"csat.submitErrorConversationId\"])\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\treturn { value: { ok: false, message: error } };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Core document predates csat.submitError.seq: fall back to\n\t\t\t\t\t\t\t// text transitions.\n\t\t\t\t\t\t\tif (error === null) {\n\t\t\t\t\t\t\t\t// Core clears the error at the start of every\n\t\t\t\t\t\t\t\t// non-partial submit; from here any error is ours.\n\t\t\t\t\t\t\t\terrorBaseline = null;\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\terror !== errorBaseline &&\n\t\t\t\t\t\t\t\tstate?.[\"csat.submitErrorSurveyType\"] === surveyType &&\n\t\t\t\t\t\t\t\tmatchesConversation(state?.[\"csat.submitErrorConversationId\"])\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\treturn { value: { ok: false, message: error } };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsettleOpts,\n\t\t\t\t\t),\n\t\t\t};\n\t\t},\n\n\t\ttrackCsatShown(surveyType, conversationId) {\n\t\t\thost.sendEvent(\"csat.shown\", {\n\t\t\t\tsurveyType,\n\t\t\t\t...(conversationId != null ? { conversationId } : {}),\n\t\t\t});\n\t\t},\n\n\t\tcheckEndChatEligibility(opts) {\n\t\t\tconst baselineSeq = host.getState()?.[\"csat.endChatEligibility.seq\"] ?? 0;\n\t\t\thost.sendEvent(\"csat.checkEndChatEligibility\");\n\t\t\treturn settleFromState<EndChatEligibilityResult>(\n\t\t\t\thost,\n\t\t\t\tlifecycle,\n\t\t\t\t(state) => {\n\t\t\t\t\tconst seq = state?.[\"csat.endChatEligibility.seq\"] ?? 0;\n\t\t\t\t\tif (seq <= baselineSeq) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\teligible: state?.[\"csat.endChatEligible\"] ?? null,\n\t\t\t\t\t\t\tsurveyTarget: state?.[\"csat.endChatSurveyTarget\"] ?? null,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\topts,\n\t\t\t);\n\t\t},\n\n\t\tskipCsatAndEndChat() {\n\t\t\thost.sendEvent(\"endChat.skipCsat\");\n\t\t},\n\n\t\tstartNewConversation(opts) {\n\t\t\tconst now = Date.now();\n\t\t\tif (now < newConversationBlockedUntil) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tnewConversationBlockedUntil =\n\t\t\t\tnow + (opts?.cooldownMs ?? START_NEW_CONVERSATION_COOLDOWN_MS);\n\t\t\thost.sendEvent(\"app.startNewConversation\");\n\t\t\treturn true;\n\t\t},\n\n\t\tresetApp() {\n\t\t\thost.sendEvent(\"app.reset\");\n\t\t},\n\n\t\tnotifyComposerChanged(opts) {\n\t\t\t// Even a content-free typing edge is a signal that a secret is\n\t\t\t// being typed, so it stays suppressed at the source.\n\t\t\tif (\n\t\t\t\topts?.secret === true ||\n\t\t\t\thost.getState()?.[\"ui.secretMessage.isOpen\"] === true\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thost.sendEvent(\"ui.composer.textChanged\");\n\t\t},\n\n\t\ttoggleSecretMessage(open) {\n\t\t\thost.sendEvent(\"ui.secretMessage.toggle\", { open });\n\t\t},\n\n\t\tstartFileUpload(file) {\n\t\t\tconst uploadId = mintUuid();\n\t\t\thost.sendEvent(\"file.upload.start\", { file, uploadId });\n\t\t\treturn {\n\t\t\t\tuploadId,\n\t\t\t\tretry() {\n\t\t\t\t\thost.sendEvent(\"file.upload.retry\", { file, uploadId });\n\t\t\t\t},\n\t\t\t\tdismissError() {\n\t\t\t\t\thost.sendEvent(\"file.upload.errorDismiss\");\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\tsetLanguage(language) {\n\t\t\thost.sendEvent(\"settings.language.change\", { language });\n\t\t},\n\n\t\temailTranscript(email, opts) {\n\t\t\t// Core drops an empty email silently — no status transition ever —\n\t\t\t// so validate here and reject immediately instead of hanging.\n\t\t\tconst trimmed = typeof email === \"string\" ? email.trim() : \"\";\n\t\t\tif (!trimmed) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tnew Error(\"emailTranscript requires a non-empty email.\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\thost.sendEvent(\"settings.transcript.email.send\", { email: trimmed });\n\t\t\treturn transcriptSettled(\"transcript.email.status\", opts, trimmed);\n\t\t},\n\n\t\tdownloadTranscript(opts) {\n\t\t\thost.sendEvent(\"settings.transcript.download.request\");\n\t\t\treturn transcriptSettled(\"transcript.download.status\", opts);\n\t\t},\n\n\t\tsetAlertSound(enabled) {\n\t\t\thost.sendEvent(\"settings.alertSound.toggle\", { enabled });\n\t\t},\n\n\t\trequestNotificationPermission() {\n\t\t\thost.sendEvent(\"settings.notifications.requestPermission\");\n\t\t},\n\n\t\tsetTheme(theme) {\n\t\t\thost.sendEvent(\"appearance.setTheme\", { theme });\n\t\t},\n\n\t\tsetTextSize(size) {\n\t\t\thost.sendEvent(\"appearance.setTextSize\", { textSize: size });\n\t\t},\n\n\t\tclose() {\n\t\t\thost.sendEvent(\"ui.closeButton.click\");\n\t\t},\n\n\t\tminimize() {\n\t\t\thost.sendEvent(\"ui.minimizeButton.click\");\n\t\t},\n\n\t\tdismissToast() {\n\t\t\thost.sendEvent(\"ui.toast.dismiss\");\n\t\t},\n\n\t\tdismissError() {\n\t\t\thost.sendEvent(\"chat.error.dismiss\");\n\t\t},\n\n\t\tsetHostViewportExpanded(expanded) {\n\t\t\thost.sendEvent(\"ui.hostViewport.set\", { expanded });\n\t\t},\n\n\t\tretryAfterOutage() {\n\t\t\thost.sendEvent(\"outage.retry\");\n\t\t},\n\n\t\treportAppError(error, componentStack) {\n\t\t\tconst err = error instanceof Error ? error : null;\n\t\t\thost.sendEvent(\"app.error.report\", {\n\t\t\t\tmessage: err?.message ?? String(error),\n\t\t\t\tstack: err?.stack ?? \"\",\n\t\t\t\tcomponentStack: componentStack ?? \"\",\n\t\t\t});\n\t\t},\n\t};\n\n\tfunction transcriptSettled(\n\t\tkey: \"transcript.email.status\" | \"transcript.download.status\",\n\t\topts?: SettleOptions,\n\t\t// Email only: reject THIS call when core rejects a conflicting request\n\t\t// for exactly this address on `transcript.email.conflict.*` — the\n\t\t// shared status channel never carries the conflict, so the in-flight\n\t\t// caller settles on its own verdict.\n\t\tconflictEmail?: string,\n\t): Promise<void> {\n\t\tconst seqKey = `${key}.seq` as\n\t\t\t| \"transcript.email.status.seq\"\n\t\t\t| \"transcript.download.status.seq\";\n\t\tlet previous = host.getState()?.[key] ?? \"idle\";\n\t\tlet seqBaseline = host.getState()?.[seqKey] ?? null;\n\t\tlet conflictSeqBaseline =\n\t\t\thost.getState()?.[\"transcript.email.conflict.seq\"] ?? null;\n\t\treturn settleFromState<void>(\n\t\t\thost,\n\t\t\tlifecycle,\n\t\t\t(state) => {\n\t\t\t\tif (conflictEmail !== undefined) {\n\t\t\t\t\tconst conflictSeq = state?.[\"transcript.email.conflict.seq\"];\n\t\t\t\t\tif (typeof conflictSeq === \"number\") {\n\t\t\t\t\t\tif (conflictSeqBaseline === null) {\n\t\t\t\t\t\t\t// The request raced state hydration: latch the first\n\t\t\t\t\t\t\t// observed seq, mirroring the status-seq baseline below.\n\t\t\t\t\t\t\t// Residual: if that first snapshot already carries THIS\n\t\t\t\t\t\t\t// call's own conflict, the reject branch never fires and\n\t\t\t\t\t\t\t// the handle falls through to the shared-status\n\t\t\t\t\t\t\t// correlation — the same bounded degradation as the\n\t\t\t\t\t\t\t// documented old-core (no conflict keys) skew. Not\n\t\t\t\t\t\t\t// closable from here: with no pre-call baseline, a\n\t\t\t\t\t\t\t// matching-address conflict in the first snapshot is\n\t\t\t\t\t\t\t// indistinguishable from a pre-existing one, and\n\t\t\t\t\t\t\t// treating it as ours would false-reject.\n\t\t\t\t\t\t\tconflictSeqBaseline = conflictSeq;\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\tconflictSeq !== conflictSeqBaseline &&\n\t\t\t\t\t\t\tstate?.[\"transcript.email.conflict.email\"] === conflictEmail\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\t\t\"emailTranscript was rejected: a request for a different \" +\n\t\t\t\t\t\t\t\t\t\t\"address is already in flight. The in-flight email \" +\n\t\t\t\t\t\t\t\t\t\t\"still completes with its own outcome.\",\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst status = state?.[key] ?? \"idle\";\n\t\t\t\tconst seq = state?.[seqKey];\n\t\t\t\tif (typeof seq === \"number\") {\n\t\t\t\t\t// The seq advances on every status write, so a request core\n\t\t\t\t\t// drops straight to a terminal status (never `pending` in a\n\t\t\t\t\t// broadcast snapshot) and a repeat of the previous terminal\n\t\t\t\t\t// status both stay observable.\n\t\t\t\t\tif (seqBaseline === null) {\n\t\t\t\t\t\t// The request raced state hydration: latch the first observed\n\t\t\t\t\t\t// seq and treat the current status as pre-existing.\n\t\t\t\t\t\tseqBaseline = seq;\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tif (seq === seqBaseline) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tif (status === \"success\") {\n\t\t\t\t\t\treturn { value: undefined };\n\t\t\t\t\t}\n\t\t\t\t\tif (status === \"error\") {\n\t\t\t\t\t\treturn { error: new Error(`${key} reported an error.`) };\n\t\t\t\t\t}\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\t// Core document predates the seq key: fall back to the\n\t\t\t\t// pending -> terminal edge.\n\t\t\t\tconst was = previous;\n\t\t\t\tprevious = status;\n\t\t\t\tif (was !== \"pending\") {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tif (status === \"success\") {\n\t\t\t\t\treturn { value: undefined };\n\t\t\t\t}\n\t\t\t\tif (status === \"error\") {\n\t\t\t\t\treturn { error: new Error(`${key} reported an error.`) };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\topts,\n\t\t);\n\t}\n\n\treturn {\n\t\toperations,\n\t\tdispose() {\n\t\t\tif (disposed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdisposed = true;\n\t\t\tresetReadAccumulator();\n\t\t\treadResetUnsubscribe?.();\n\t\t\treadResetUnsubscribe = null;\n\t\t\t// Reject every in-flight settled() promise: the transport is gone,\n\t\t\t// so no state transition can ever answer it. Snapshot first — each\n\t\t\t// abort unregisters itself from the live set.\n\t\t\tfor (const abort of [...liveSettleAborts]) {\n\t\t\t\tabort(new BridgeClientDestroyedError());\n\t\t\t}\n\t\t\tliveSettleAborts.clear();\n\t\t},\n\t};\n}\n","import type { BridgeClient } from \"../contract/bridge-client\";\nimport {\n\tcreateBridgeOperations,\n\tcreateStateObservation,\n} from \"../contract/operations\";\nimport type { AppDisplayState, AppEvents } from \"../contract/types\";\n\n/** One recorded `sendEvent` call. */\nexport interface SentBridgeEvent<K extends keyof AppEvents = keyof AppEvents> {\n\tevent: K;\n\tpayload: AppEvents[K] | undefined;\n}\n\n/**\n * A scriptable, in-memory {@link BridgeClient} for unit tests.\n *\n * No postMessage, no origin checks, no network: tests drive state through\n * `setState`/`updateState` and assert on the events the component under test\n * sent through `sentEvents`. The `operations`, `subscribeKey`, and `select`\n * surfaces are the REAL implementations running over this in-memory state:\n * every operation records its events in `sentEvents`, and a correlated\n * handle (`sendMessage().settled()`, `submitCsat().settled()`, ...) resolves\n * when the test scripts the answering state transition via `updateState`.\n */\nexport interface MockBridgeClient extends BridgeClient {\n\t/** Replace the state snapshot and notify subscribers. */\n\tsetState(state: AppDisplayState | null): void;\n\t/**\n\t * Shallow-merge a partial snapshot over the current state (or over an empty\n\t * object when no state is set) and notify subscribers. Seeds\n\t * `\"chat.error.clientKey\": null` when the key is absent — production core\n\t * always publishes it (null when no keyed send owns the error), and\n\t * `operations` send handles take the keyed correlation path only when it is\n\t * present. Script a `chat.error` fixture with the send's `tempMessageUuid`\n\t * as `chat.error.clientKey` to reject that handle; use `setState` to script\n\t * an older core document without the key.\n\t */\n\tupdateState(partial: Partial<AppDisplayState>): void;\n\t/**\n\t * Every event sent through the client, in order. Each read returns a fresh\n\t * copy, so a captured array survives `clearSentEvents()`.\n\t */\n\treadonly sentEvents: readonly SentBridgeEvent[];\n\t/** Forget recorded events without touching state or subscribers. */\n\tclearSentEvents(): void;\n\t/** Number of active subscribers. */\n\treadonly subscriberCount: number;\n\t/** True once `destroy()` has been called. */\n\treadonly destroyed: boolean;\n}\n\n/**\n * Create a {@link MockBridgeClient}, optionally seeded with an initial state\n * snapshot. Mirrors the real client's teardown semantics: after `destroy()`,\n * state is `null`, subscribers are cleared, `sendEvent` is a no-op, and every\n * in-flight `operations` `settled()` promise rejects with a\n * `BridgeClientDestroyedError`. Notification also mirrors the real client:\n * a throwing subscriber is caught and logged, never aborting the pass.\n *\n * The derivation helpers (`filterDisplayable`, `groupMessages`, `messageKey`,\n * `selectUnread`, ...) are runtime-only: this package types them on\n * `MessagingBridgeModule` but ships no implementation, so there is no mock\n * module to destructure them from. In unit tests, inject them into the code\n * under test (plain function parameters or props); to exercise the real\n * implementations, load the module with `loadMessagingBridge()` in an\n * integration test. Do not re-implement them — a copy drifts from the\n * runtime's edge cases.\n */\nexport function createMockBridgeClient(\n\tinitialState: AppDisplayState | null = null,\n): MockBridgeClient {\n\tlet state = initialState;\n\tlet destroyed = false;\n\tconst subscribers = new Set<() => void>();\n\tconst sentEvents: SentBridgeEvent[] = [];\n\n\tfunction notify(): void {\n\t\t// Mirrors the real client's notify(): one throwing subscriber must not\n\t\t// abort the pass (a settled() promise resolved from a later subscriber\n\t\t// would otherwise hang) or skip subscribers that unsubscribe mid-pass.\n\t\tfor (const callback of [...subscribers]) {\n\t\t\ttry {\n\t\t\t\tcallback();\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(\"[AdaMessaging] Bridge subscriber threw:\", err);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getState(): AppDisplayState | null {\n\t\treturn state;\n\t}\n\n\tfunction subscribe(callback: () => void): () => void {\n\t\tsubscribers.add(callback);\n\t\treturn () => {\n\t\t\tsubscribers.delete(callback);\n\t\t};\n\t}\n\n\tfunction sendEvent<K extends keyof AppEvents>(\n\t\tevent: K,\n\t\t...args: AppEvents[K] extends undefined ? [] : [payload: AppEvents[K]]\n\t): void {\n\t\tif (destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tsentEvents.push({ event, payload: args[0] });\n\t}\n\n\tconst host = { getState, subscribe, sendEvent };\n\tconst observation = createStateObservation(host);\n\tconst operationsBundle = createBridgeOperations(host);\n\n\treturn {\n\t\tgetState,\n\t\tsubscribe,\n\t\tsendEvent,\n\t\tsubscribeKey: observation.subscribeKey,\n\t\tselect: observation.select,\n\t\toperations: operationsBundle.operations,\n\n\t\tdestroy(): void {\n\t\t\tdestroyed = true;\n\t\t\toperationsBundle.dispose();\n\t\t\tstate = null;\n\t\t\tsubscribers.clear();\n\t\t},\n\n\t\tsetState(next: AppDisplayState | null): void {\n\t\t\tstate = next;\n\t\t\tnotify();\n\t\t},\n\n\t\tupdateState(partial: Partial<AppDisplayState>): void {\n\t\t\t// Production core always publishes `chat.error.clientKey` (null when\n\t\t\t// unattributed), and `operations` feature-detects on its presence.\n\t\t\t// Seed it so a scripted failure exercises the keyed path production\n\t\t\t// takes; override it in `partial` (or use setState) to script an\n\t\t\t// older core document.\n\t\t\tstate = {\n\t\t\t\t\"chat.error.clientKey\": null,\n\t\t\t\t...(state ?? {}),\n\t\t\t\t...partial,\n\t\t\t} as AppDisplayState;\n\t\t\tnotify();\n\t\t},\n\n\t\tget sentEvents(): readonly SentBridgeEvent[] {\n\t\t\treturn [...sentEvents];\n\t\t},\n\n\t\tclearSentEvents(): void {\n\t\t\tsentEvents.length = 0;\n\t\t},\n\n\t\tget subscriberCount(): number {\n\t\t\treturn subscribers.size;\n\t\t},\n\n\t\tget destroyed(): boolean {\n\t\t\treturn destroyed;\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|