@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.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +180 -2
- package/dist/element.d.ts +66 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +333 -0
- package/dist/element.js.map +1 -0
- package/dist/embed.d.ts +122 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +493 -0
- package/dist/embed.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +12 -0
- package/dist/register.js.map +1 -0
- package/dist/same-value.d.ts +25 -0
- package/dist/same-value.d.ts.map +1 -0
- package/dist/same-value.js +60 -0
- package/dist/same-value.js.map +1 -0
- package/dist/types.d.ts +241 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/package.json +68 -4
package/dist/embed.d.ts
ADDED
|
@@ -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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"}
|