@chatlychat/widget-element 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,122 @@
1
+ import type { ChatlyEmbedHandlers, ChatlyEmbedOptions, ChatlyEventName, ChatlyIdentity } from './types.js';
2
+ /** Chatly Cloud. A self-hosted deployment MUST override this — see the type. */
3
+ export declare const DEFAULT_LOADER_URL = "https://widget.chatlychat.com/loader.js";
4
+ export interface ChatlyEmbedHandle {
5
+ /**
6
+ * Re-apply props. Cheap when nothing material changed — which is the common
7
+ * case, because a parent re-render produces new object literals with the
8
+ * same contents.
9
+ */
10
+ update: (options: ChatlyEmbedOptions, handlers?: ChatlyEmbedHandlers) => void;
11
+ /** Give up this claim. The widget is torn down when the last one goes. */
12
+ stop: () => void;
13
+ }
14
+ /**
15
+ * Mount the widget, or join the one that is already mounted.
16
+ *
17
+ * `claim` is any object identity — a component instance, an element, a
18
+ * `{}` — and it is what `stop()` releases. Two claims from the same owner are
19
+ * one claim, which is what makes a React effect that re-runs idempotent.
20
+ */
21
+ export declare function startWidget(claim: object, options: ChatlyEmbedOptions, handlers?: ChatlyEmbedHandlers): ChatlyEmbedHandle;
22
+ /**
23
+ * The widget's post-boot methods, typed.
24
+ *
25
+ * This is `ChatlyApi` minus `init`/`destroy` — see the header for why those
26
+ * two are not here — and it invents NOTHING: every method below exists on
27
+ * `window.Chatly`, and `apps/widget/src/public-api.spec.ts` pins which ones do
28
+ * (including a test for the two the widget deliberately does not offer).
29
+ * `scripts/check-widget-wrapper-parity.mjs` fails the build if this object and
30
+ * that interface drift.
31
+ *
32
+ * Every call returns `void`, including the two the widget returns a promise
33
+ * from. The call may be QUEUED — the bundle has not necessarily arrived — and
34
+ * there is nothing to await in that state. `onIdentified` is how you learn
35
+ * that an `identify` landed; `onError` is how you learn it did not.
36
+ */
37
+ export declare const controls: {
38
+ readonly open: (tab?: "home" | "messages" | "help") => void;
39
+ readonly close: () => void;
40
+ readonly toggle: (next?: "open" | "close" | boolean) => void;
41
+ readonly identify: (identity: ChatlyIdentity) => void;
42
+ readonly setUser: (externalId: string, attributes?: Record<string, unknown>) => void;
43
+ readonly setCustomAttributes: (attributes: Record<string, unknown>) => void;
44
+ readonly deleteCustomAttribute: (key: string) => void;
45
+ readonly setLabel: (label: string) => void;
46
+ readonly removeLabel: (label: string) => void;
47
+ readonly setLocale: (locale: string) => void;
48
+ readonly track: (name: string, properties?: Record<string, unknown>) => void;
49
+ readonly registerPushToken: (platform: "apns" | "fcm" | "web-push", token: string, appVersion?: string) => void;
50
+ readonly reset: () => void;
51
+ /**
52
+ * Open the panel ON a conversation, optionally routed and pre-filled.
53
+ *
54
+ * `botSlug` is published by the widget as the unsigned context claim
55
+ * `context.unverified.bot`, which an operator keys a bot route on — there
56
+ * is no "start with bot X" endpoint. A visitor can therefore forge it,
57
+ * which is fine for "ask the shopping agent rather than support" and not
58
+ * fine if the two assistants differ in what they may reach.
59
+ */
60
+ readonly startConversation: (request?: {
61
+ botSlug?: string;
62
+ initialMessage?: string;
63
+ }) => void;
64
+ /**
65
+ * Tell the widget what this page claims about the visitor.
66
+ *
67
+ * `audience` is UNSIGNED — it lands in `context.unverified.audience` and
68
+ * the visitor can set it themselves, because the widget is on their page.
69
+ * `contextToken` is a JWT your SERVER signs with the channel's
70
+ * identity-verification secret, and only its claims reach
71
+ * `context.verified.*`, which is the bag a privilege decision may rest on.
72
+ */
73
+ readonly setContext: (input: {
74
+ audience?: string;
75
+ context?: Record<string, string | number | boolean>;
76
+ page?: {
77
+ path?: string;
78
+ url?: string;
79
+ };
80
+ contextToken?: string;
81
+ }) => void;
82
+ /**
83
+ * Report what your page did with a `host_event`, back into the thread.
84
+ *
85
+ * Pass back the `messageId` and `actionId` the `action` event handed you.
86
+ * Reporting the same action twice replaces the first result rather than
87
+ * stacking, so your own retry logic leaves one line.
88
+ */
89
+ readonly reportAction: (input: {
90
+ messageId: string;
91
+ actionId: string;
92
+ status: "done" | "failed";
93
+ text?: string;
94
+ blocks?: unknown;
95
+ data?: Record<string, unknown>;
96
+ }) => void;
97
+ };
98
+ /**
99
+ * Subscribe to one widget event, and get the unsubscribe back.
100
+ *
101
+ * Not on `controls`, because `controls` mirrors the methods you can call and
102
+ * this is a pair you must not get wrong: `Chatly.off` only removes a handler
103
+ * it can match by identity, so a consumer who built a fresh closure for `on`
104
+ * and another for `off` leaks a subscriber on every mount. Handing back the
105
+ * exact unsubscribe removes the chance.
106
+ *
107
+ * Survives a re-init: the widget's subscriber registry is module-scoped and
108
+ * `init()` does not clear it.
109
+ */
110
+ export declare function subscribe(event: ChatlyEventName, handler: (detail: unknown) => void): () => void;
111
+ /** Test-only window into the module's state. Not part of the public surface. */
112
+ export declare const __testing: {
113
+ reset(): void;
114
+ claimCount(): number;
115
+ isMounted(): boolean;
116
+ };
117
+ /**
118
+ * Re-exported because it was part of this module's surface before the split
119
+ * and `same-value.spec.ts` imports it from here.
120
+ */
121
+ export { sameValue } from './same-value.js';
122
+ //# sourceMappingURL=embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,cAAc,EAIf,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,4CAA4C,CAAC;AAwD5E,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,MAAM,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC9E,0EAA0E;IAC1E,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,GAAE,mBAAwB,GACjC,iBAAiB,CA+CnB;AA+TD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ;0BACN,MAAM,GAAG,UAAU,GAAG,MAAM,KAAG,IAAI;0BACrC,IAAI;6BACC,MAAM,GAAG,OAAO,GAAG,OAAO,KAAG,IAAI;kCAC5B,cAAc,KAAG,IAAI;mCACpB,MAAM,eAAe,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;+CAEvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;0CAEnC,MAAM,KAAG,IAAI;+BACxB,MAAM,KAAG,IAAI;kCACV,MAAM,KAAG,IAAI;iCACd,MAAM,KAAG,IAAI;2BACnB,MAAM,eAAe,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;2CAGrD,MAAM,GAAG,KAAK,GAAG,UAAU,SAC9B,MAAM,eACA,MAAM,KAClB,IAAI;0BACI,IAAI;IACf;;;;;;;;OAQG;2CAC2B;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,KAAG,IAAI;IAElF;;;;;;;;OAQG;iCACiB;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACvC,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,KAAG,IAAI;IACR;;;;;;OAMG;mCACmB;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,KAAG,IAAI;CACA,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAUhG;AAED,gFAAgF;AAChF,eAAO,MAAM,SAAS;aACX,IAAI;kBAQC,MAAM;iBAGP,OAAO;CAGrB,CAAC;AAEF;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/embed.js ADDED
@@ -0,0 +1,493 @@
1
+ /**
2
+ * One widget, many claimants — the lifecycle both wrappers share.
3
+ *
4
+ * ── What problem this solves ────────────────────────────────────────────
5
+ *
6
+ * `window.Chatly` is a SINGLETON. `init()` destroys whatever is mounted and
7
+ * mounts again; `destroy()` removes it outright. A framework wrapper is the
8
+ * opposite shape: components mount, unmount, re-render with new props, and in
9
+ * React 18 StrictMode every effect runs mount → cleanup → mount again before
10
+ * the user has done anything at all.
11
+ *
12
+ * Handing that directly to `init`/`destroy` produces three bugs, all of which
13
+ * look like the widget being flaky rather than the wrapper being wrong:
14
+ *
15
+ * 1. **StrictMode double-boot.** mount/cleanup/mount with a naive effect is
16
+ * init → destroy → init: two `POST /v1/widget/init` round trips, two
17
+ * sessions minted, and a launcher that visibly appears, vanishes and
18
+ * reappears in development.
19
+ * 2. **A leak on unmount.** An effect with no cleanup leaves the widget in
20
+ * the DOM after its component is gone — it survives route changes it
21
+ * should not, holds its socket, and a later mount `init`s a second one
22
+ * on top.
23
+ * 3. **Re-init on every render.** Comparing props by reference re-inits
24
+ * whenever a parent re-renders with a fresh `theme={{…}}` literal or a
25
+ * new inline `onMessage` arrow. The visitor's open panel closes mid
26
+ * sentence.
27
+ *
28
+ * So: a reference count with a DEFERRED teardown, a structural comparison of
29
+ * the options, and ONE stable set of event forwarders installed at boot that
30
+ * fan out to whatever each claimant most recently passed.
31
+ *
32
+ * ── Deliberately not exported ───────────────────────────────────────────
33
+ *
34
+ * `init` and `destroy` are absent from `controls`. A host that calls them
35
+ * behind this module's back desynchronises the count — the widget is gone and
36
+ * the wrapper still believes it is mounted, so the next unmount is a no-op and
37
+ * the next mount does nothing. Mount with a wrapper or mount with the snippet;
38
+ * not both.
39
+ */
40
+ import { sameOptions, sameValue } from './same-value.js';
41
+ /** Chatly Cloud. A self-hosted deployment MUST override this — see the type. */
42
+ export const DEFAULT_LOADER_URL = 'https://widget.chatlychat.com/loader.js';
43
+ function embedWindow() {
44
+ // Guarded rather than assumed: this module is imported by a React component
45
+ // that may be rendered on a server, and `startWidget` is the only thing that
46
+ // must be browser-only. A null here is a clear refusal instead of a
47
+ // ReferenceError inside someone's SSR build.
48
+ return typeof window === 'undefined' ? null : window;
49
+ }
50
+ let state = null;
51
+ /** True once THIS module injected a loader script, so it never injects twice. */
52
+ let injectedLoader = false;
53
+ /**
54
+ * Mount the widget, or join the one that is already mounted.
55
+ *
56
+ * `claim` is any object identity — a component instance, an element, a
57
+ * `{}` — and it is what `stop()` releases. Two claims from the same owner are
58
+ * one claim, which is what makes a React effect that re-runs idempotent.
59
+ */
60
+ export function startWidget(claim, options, handlers = {}) {
61
+ const handle = {
62
+ update: (next, nextHandlers) => applyUpdate(claim, next, nextHandlers ?? {}),
63
+ stop: () => release(claim),
64
+ };
65
+ if (embedWindow() === null) {
66
+ // Server-side. Return a handle whose methods are inert rather than
67
+ // throwing: a component that renders on the server and hydrates in the
68
+ // browser calls this from an effect, and an effect never runs on the
69
+ // server — but a defensive caller should not have to know that.
70
+ return handle;
71
+ }
72
+ if (typeof options.publicId !== 'string' || options.publicId.length === 0) {
73
+ // The loader's own message for the same mistake, so an embedder searching
74
+ // for it finds one answer rather than two.
75
+ console.warn('[Chatly] missing publicId — widget not started');
76
+ return handle;
77
+ }
78
+ if (state !== null) {
79
+ if (state.teardown !== null) {
80
+ /*
81
+ * A teardown was scheduled and a mount came back before it ran. This is
82
+ * StrictMode's cleanup/re-mount pair, and a route change that swaps
83
+ * which component owns the widget lands here too. Cancelling it is the
84
+ * whole point: the visitor's session, open panel and scroll position
85
+ * survive something that was never a real unmount.
86
+ */
87
+ clearTimeout(state.teardown);
88
+ state.teardown = null;
89
+ }
90
+ warnOnConflict(state, options);
91
+ state.claims.set(claim, { options, handlers });
92
+ reconcile();
93
+ return handle;
94
+ }
95
+ state = {
96
+ claims: new Map([[claim, { options, handlers }]]),
97
+ active: options,
98
+ loaderUrl: options.loaderUrl ?? DEFAULT_LOADER_URL,
99
+ teardown: null,
100
+ };
101
+ boot(state);
102
+ return handle;
103
+ }
104
+ /** Warned once per page: two mounted widgets asking for different things. */
105
+ let warnedConflict = false;
106
+ /**
107
+ * A second claim with different options.
108
+ *
109
+ * There is one `window.Chatly`, so the second set cannot be honoured — the
110
+ * first mount's configuration stays in force and the second component's
111
+ * handlers still fire. Silence here would be the worst outcome: a developer
112
+ * who renders `<ChatlyWidget>` in two layouts sees one of their two themes
113
+ * applied, at random, with nothing to search for.
114
+ */
115
+ function warnOnConflict(mount, options) {
116
+ if (warnedConflict) {
117
+ return;
118
+ }
119
+ const owner = mount.claims.values().next().value;
120
+ if (owner === undefined || sameOptions(initOptionsFor(owner.options), initOptionsFor(options))) {
121
+ return;
122
+ }
123
+ warnedConflict = true;
124
+ console.warn('[Chatly] a second widget was mounted with different options. There is only one ' +
125
+ 'widget per page, so the FIRST mount owns the configuration — the second one is ' +
126
+ 'ignored (its event handlers still fire). Render one <ChatlyWidget>, high in the ' +
127
+ 'tree, and use useChatly() elsewhere.');
128
+ }
129
+ /** Install the shim, subscribe, queue the init, and fetch the loader. */
130
+ function boot(mount) {
131
+ const w = embedWindow();
132
+ if (w === null) {
133
+ return;
134
+ }
135
+ /*
136
+ * Was there a `window.Chatly` before us?
137
+ *
138
+ * If so the host page pasted the snippet as well, its loader is already on
139
+ * its way, and injecting a second script tag would fetch the bundle twice.
140
+ * We still queue our own `init`, which the loader prefers over its own —
141
+ * see `apps/widget-loader/src/loader.ts`.
142
+ */
143
+ const preexisting = typeof w.Chatly === 'function';
144
+ const bundleAlreadyLoaded = typeof w.Chatly?.init === 'function';
145
+ const shim = w.Chatly ??
146
+ Object.assign(function queue(...args) {
147
+ (shim.q = shim.q ?? []).push(args);
148
+ }, {});
149
+ w.Chatly = shim;
150
+ // The loader reads these off the shim at script-evaluation time. `publicId`
151
+ // in particular: without it the loader refuses to fetch the bundle at all.
152
+ shim.publicId = mount.active.publicId;
153
+ if (mount.active.apiUrl !== undefined) {
154
+ shim.apiUrl = mount.active.apiUrl;
155
+ }
156
+ // Subscribe BEFORE init so nothing emitted during boot is missed. `ready`
157
+ // would survive a late subscription (the widget replays the last one) but
158
+ // `open`, `message` and `error` are moments and would not.
159
+ for (const [event, forward] of FORWARDERS) {
160
+ shim('on', event, forward);
161
+ }
162
+ shim('init', initOptionsFor(mount.active));
163
+ if (mount.active.locale !== undefined) {
164
+ shim('setLocale', mount.active.locale);
165
+ }
166
+ if (bundleAlreadyLoaded || preexisting || injectedLoader) {
167
+ return;
168
+ }
169
+ injectLoader(mount.loaderUrl);
170
+ }
171
+ /** The options the widget's own `init` gets — ours, minus our own extras. */
172
+ function initOptionsFor(options) {
173
+ // `loaderUrl` and `locale` are this package's, not the widget's. Passing
174
+ // them through would be harmless today and a collision the day the widget
175
+ // adds a key of the same name, so they are stripped rather than ignored.
176
+ const { loaderUrl: _loaderUrl, locale: _locale, ...init } = options;
177
+ return init;
178
+ }
179
+ function injectLoader(loaderUrl) {
180
+ injectedLoader = true;
181
+ /*
182
+ * The DOM is the real source of truth, not `injectedLoader`.
183
+ *
184
+ * A dev-server hot reload re-evaluates this module — resetting the flag —
185
+ * while the page keeps the script tag it already appended. Checking the
186
+ * marker attribute means a reload does not stack a second loader (and a
187
+ * second bundle fetch) onto a page that already has one.
188
+ */
189
+ if (document.querySelector('script[data-chatly-loader]') !== null) {
190
+ return;
191
+ }
192
+ const script = document.createElement('script');
193
+ script.async = true;
194
+ script.src = loaderUrl;
195
+ script.setAttribute('data-chatly-loader', '');
196
+ script.onerror = () => {
197
+ // The loader has the same message for the bundle it fetches. A script that
198
+ // never loads is otherwise completely silent: an ad blocker, a CSP missing
199
+ // the widget origin, or a typo'd `loaderUrl` all produce an empty page
200
+ // corner and an empty console.
201
+ console.warn(`[Chatly] widget loader failed to load from ${loaderUrl}`);
202
+ };
203
+ document.head.appendChild(script);
204
+ }
205
+ /** Dispatch through the callable form, which works queued or live. */
206
+ function dispatch(method, ...args) {
207
+ const w = embedWindow();
208
+ const chatly = w?.Chatly;
209
+ if (typeof chatly !== 'function') {
210
+ // Not an exception: a header button wired to `open()` on a page where no
211
+ // widget is mounted is a configuration mistake, not a reason to break the
212
+ // host page's click handler.
213
+ console.warn(`[Chatly] ${method}() ignored — no widget is mounted. ` +
214
+ 'Mount <ChatlyWidget> (or <chatly-widget>) before calling it.');
215
+ return;
216
+ }
217
+ chatly(method, ...args);
218
+ }
219
+ /**
220
+ * Apply a claim's new props.
221
+ *
222
+ * Three outcomes, and which one you get is the whole contract:
223
+ *
224
+ * - `visitor` changed → `identify()`. No re-init, no lost panel state.
225
+ * - `locale` changed → `setLocale()`. Same.
226
+ * - anything else changed → `init()` again, which DESTROYS and re-mounts.
227
+ * The conversation is server-side so no history is lost, but an open
228
+ * panel closes. That is the honest cost of a widget with no `setTheme`,
229
+ * and it is documented in both READMEs rather than hidden behind a
230
+ * silently-ignored prop.
231
+ */
232
+ function applyUpdate(claim, options, handlers) {
233
+ if (state === null) {
234
+ // Updating something that was never started. Start it, so a component
235
+ // whose effect order put the update first still ends up mounted.
236
+ startWidget(claim, options, handlers);
237
+ return;
238
+ }
239
+ state.claims.set(claim, { options, handlers });
240
+ reconcile();
241
+ }
242
+ /** Bring the live widget in line with the owning claim's options. */
243
+ function reconcile() {
244
+ if (state === null) {
245
+ return;
246
+ }
247
+ const owner = state.claims.values().next().value;
248
+ if (owner === undefined) {
249
+ return;
250
+ }
251
+ const next = owner.options;
252
+ const active = state.active;
253
+ const wantedLoader = next.loaderUrl ?? DEFAULT_LOADER_URL;
254
+ if (wantedLoader !== state.loaderUrl) {
255
+ /*
256
+ * The bundle is already fetched and `window.Chatly` already installed, so
257
+ * there is no honest way to honour this: pointing the running widget at
258
+ * another deployment would need a page reload. Refused loudly rather than
259
+ * applied halfway — the alternative is a widget talking to the host it was
260
+ * loaded from while the props say otherwise.
261
+ */
262
+ console.warn(`[Chatly] loaderUrl changed from ${state.loaderUrl} to ${wantedLoader} after the ` +
263
+ 'widget loaded. A different deployment needs a page reload; the running widget ' +
264
+ 'is unchanged.');
265
+ }
266
+ const initChanged = !sameOptions(initOptionsFor(active), initOptionsFor(next), ['visitor']);
267
+ if (initChanged) {
268
+ state.active = next;
269
+ for (const [event, forward] of FORWARDERS) {
270
+ // `init` destroys and re-mounts. The widget's subscriber registry is
271
+ // module-scoped and survives that, so re-subscribing would double every
272
+ // callback — hence `off` first, with the same function identity, which
273
+ // is why the forwarders are module constants.
274
+ dispatch('off', event, forward);
275
+ dispatch('on', event, forward);
276
+ }
277
+ dispatch('init', initOptionsFor(next));
278
+ if (next.locale !== undefined) {
279
+ dispatch('setLocale', next.locale);
280
+ }
281
+ return;
282
+ }
283
+ if (!sameValue(active.visitor, next.visitor)) {
284
+ state.active = { ...state.active, visitor: next.visitor };
285
+ identifyOrReset(next.visitor);
286
+ }
287
+ if (active.locale !== next.locale) {
288
+ state.active = { ...state.active, locale: next.locale };
289
+ if (next.locale !== undefined) {
290
+ dispatch('setLocale', next.locale);
291
+ }
292
+ // Going from a locale back to `undefined` is left alone deliberately:
293
+ // there is no "unset locale" call, and `setLocale('')` would warn about a
294
+ // missing bundle. The last explicit locale stays in force.
295
+ }
296
+ }
297
+ /**
298
+ * The visitor prop changed. Sign in, or sign out.
299
+ *
300
+ * A host that renders `visitor={user ?? undefined}` is describing a sign-OUT
301
+ * when it goes away, and `identify(undefined)` is not a thing. `reset()` is:
302
+ * it forgets this visitor and boots a fresh anonymous session, and it drops
303
+ * the identity permanently so the re-boot cannot resurrect the person who
304
+ * just left.
305
+ */
306
+ function identifyOrReset(visitor) {
307
+ if (visitor === undefined) {
308
+ dispatch('reset');
309
+ return;
310
+ }
311
+ dispatch('identify', visitor);
312
+ }
313
+ /**
314
+ * Drop a claim, and tear down when it was the last one.
315
+ *
316
+ * The teardown is a TASK, not a microtask and not immediate. StrictMode's
317
+ * cleanup runs synchronously before the second mount, so a microtask would be
318
+ * enough for it — but an SPA route change that unmounts one layout and mounts
319
+ * another is not guaranteed to be in the same microtask, and treating that as
320
+ * a real teardown is a visible re-boot for the visitor.
321
+ */
322
+ function release(claim) {
323
+ if (state === null) {
324
+ return;
325
+ }
326
+ state.claims.delete(claim);
327
+ if (state.claims.size > 0) {
328
+ reconcile();
329
+ return;
330
+ }
331
+ if (state.teardown !== null) {
332
+ return;
333
+ }
334
+ state.teardown = setTimeout(() => {
335
+ if (state === null || state.claims.size > 0) {
336
+ return;
337
+ }
338
+ for (const [event, forward] of FORWARDERS) {
339
+ dispatch('off', event, forward);
340
+ }
341
+ dispatch('destroy');
342
+ state = null;
343
+ }, 0);
344
+ }
345
+ /**
346
+ * One forwarder per event, created once at module scope.
347
+ *
348
+ * Identity matters twice: `off` only removes a handler it can match, and a
349
+ * re-init re-subscribes. A closure created per boot would leak a subscriber
350
+ * on every mount/unmount cycle and fire every callback N times after N
351
+ * mounts — the kind of bug that only shows up after a few route changes.
352
+ */
353
+ const FORWARDERS = [
354
+ // The two asserted payloads are the widget's own — `SessionSnapshot` for
355
+ // ready/identified, `{ id, body, authorType }` for message — mirrored in
356
+ // `types.ts` and held there by the parity gate. The rest stay `unknown`
357
+ // because the widget's own types do: re-typing them here would be inventing
358
+ // a contract rather than forwarding one.
359
+ ['ready', (d) => fanOut((h) => h.onReady?.(d))],
360
+ ['open', () => fanOut((h) => h.onOpen?.())],
361
+ ['close', () => fanOut((h) => h.onClose?.())],
362
+ ['message', (d) => fanOut((h) => h.onMessage?.(d))],
363
+ ['conversation', (d) => fanOut((h) => h.onConversation?.(d))],
364
+ ['identified', (d) => fanOut((h) => h.onIdentified?.(d))],
365
+ ['reset', (d) => fanOut((h) => h.onReset?.(d))],
366
+ ['action', (d) => fanOut((h) => h.onAction?.(d))],
367
+ ['error', (d) => fanOut((h) => h.onError?.(d))],
368
+ ];
369
+ /**
370
+ * Call one handler on every current claim.
371
+ *
372
+ * Every claim, not just the owner: a page may render the widget in a layout
373
+ * and a `useChatly`-driven badge elsewhere, and both asked to be told. A
374
+ * throwing subscriber must not stop the others, nor reach the widget — which
375
+ * already guards its own dispatch for the same reason.
376
+ */
377
+ function fanOut(call) {
378
+ if (state === null) {
379
+ return;
380
+ }
381
+ for (const { handlers } of [...state.claims.values()]) {
382
+ try {
383
+ call(handlers);
384
+ }
385
+ catch (err) {
386
+ console.warn('[Chatly] an event handler threw', err);
387
+ }
388
+ }
389
+ }
390
+ /**
391
+ * The widget's post-boot methods, typed.
392
+ *
393
+ * This is `ChatlyApi` minus `init`/`destroy` — see the header for why those
394
+ * two are not here — and it invents NOTHING: every method below exists on
395
+ * `window.Chatly`, and `apps/widget/src/public-api.spec.ts` pins which ones do
396
+ * (including a test for the two the widget deliberately does not offer).
397
+ * `scripts/check-widget-wrapper-parity.mjs` fails the build if this object and
398
+ * that interface drift.
399
+ *
400
+ * Every call returns `void`, including the two the widget returns a promise
401
+ * from. The call may be QUEUED — the bundle has not necessarily arrived — and
402
+ * there is nothing to await in that state. `onIdentified` is how you learn
403
+ * that an `identify` landed; `onError` is how you learn it did not.
404
+ */
405
+ export const controls = {
406
+ open: (tab) => dispatch('open', tab),
407
+ close: () => dispatch('close'),
408
+ toggle: (next) => dispatch('toggle', next),
409
+ identify: (identity) => dispatch('identify', identity),
410
+ setUser: (externalId, attributes) => dispatch('setUser', externalId, attributes),
411
+ setCustomAttributes: (attributes) => dispatch('setCustomAttributes', attributes),
412
+ deleteCustomAttribute: (key) => dispatch('deleteCustomAttribute', key),
413
+ setLabel: (label) => dispatch('setLabel', label),
414
+ removeLabel: (label) => dispatch('removeLabel', label),
415
+ setLocale: (locale) => dispatch('setLocale', locale),
416
+ track: (name, properties) => dispatch('track', name, properties),
417
+ registerPushToken: (platform, token, appVersion) => dispatch('registerPushToken', platform, token, appVersion),
418
+ reset: () => dispatch('reset'),
419
+ /**
420
+ * Open the panel ON a conversation, optionally routed and pre-filled.
421
+ *
422
+ * `botSlug` is published by the widget as the unsigned context claim
423
+ * `context.unverified.bot`, which an operator keys a bot route on — there
424
+ * is no "start with bot X" endpoint. A visitor can therefore forge it,
425
+ * which is fine for "ask the shopping agent rather than support" and not
426
+ * fine if the two assistants differ in what they may reach.
427
+ */
428
+ startConversation: (request) => dispatch('startConversation', request),
429
+ /**
430
+ * Tell the widget what this page claims about the visitor.
431
+ *
432
+ * `audience` is UNSIGNED — it lands in `context.unverified.audience` and
433
+ * the visitor can set it themselves, because the widget is on their page.
434
+ * `contextToken` is a JWT your SERVER signs with the channel's
435
+ * identity-verification secret, and only its claims reach
436
+ * `context.verified.*`, which is the bag a privilege decision may rest on.
437
+ */
438
+ setContext: (input) => dispatch('setContext', input),
439
+ /**
440
+ * Report what your page did with a `host_event`, back into the thread.
441
+ *
442
+ * Pass back the `messageId` and `actionId` the `action` event handed you.
443
+ * Reporting the same action twice replaces the first result rather than
444
+ * stacking, so your own retry logic leaves one line.
445
+ */
446
+ reportAction: (input) => dispatch('reportAction', input),
447
+ };
448
+ /**
449
+ * Subscribe to one widget event, and get the unsubscribe back.
450
+ *
451
+ * Not on `controls`, because `controls` mirrors the methods you can call and
452
+ * this is a pair you must not get wrong: `Chatly.off` only removes a handler
453
+ * it can match by identity, so a consumer who built a fresh closure for `on`
454
+ * and another for `off` leaks a subscriber on every mount. Handing back the
455
+ * exact unsubscribe removes the chance.
456
+ *
457
+ * Survives a re-init: the widget's subscriber registry is module-scoped and
458
+ * `init()` does not clear it.
459
+ */
460
+ export function subscribe(event, handler) {
461
+ dispatch('on', event, handler);
462
+ let off = false;
463
+ return () => {
464
+ if (off) {
465
+ return;
466
+ }
467
+ off = true;
468
+ dispatch('off', event, handler);
469
+ };
470
+ }
471
+ /** Test-only window into the module's state. Not part of the public surface. */
472
+ export const __testing = {
473
+ reset() {
474
+ if (state !== null && state.teardown !== null) {
475
+ clearTimeout(state.teardown);
476
+ }
477
+ state = null;
478
+ injectedLoader = false;
479
+ warnedConflict = false;
480
+ },
481
+ claimCount() {
482
+ return state?.claims.size ?? 0;
483
+ },
484
+ isMounted() {
485
+ return state !== null;
486
+ },
487
+ };
488
+ /**
489
+ * Re-exported because it was part of this module's surface before the split
490
+ * and `same-value.spec.ts` imports it from here.
491
+ */
492
+ export { sameValue } from './same-value.js';
493
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"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"}