@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,33 @@
1
+ /**
2
+ * `@chatlychat/widget-element` — the Chatly widget as a custom element, and the
3
+ * embed lifecycle every framework wrapper shares.
4
+ *
5
+ * **This entry has no side effects.** Importing it does not define a custom
6
+ * element and does not touch `document`. That is what lets
7
+ * `@chatlychat/widget-react` depend on this package for the lifecycle without
8
+ * registering a tag its consumers never asked for, and it is what makes the
9
+ * package importable from a server bundle.
10
+ *
11
+ * To get `<chatly-widget>`:
12
+ *
13
+ * import '@chatlychat/widget-element/register';
14
+ * // or, to choose the tag name:
15
+ * import { defineChatlyWidget } from '@chatlychat/widget-element';
16
+ * defineChatlyWidget('acme-chat');
17
+ */
18
+ export { controls, startWidget, subscribe, DEFAULT_LOADER_URL, type ChatlyEmbedHandle, } from './embed.js';
19
+ /**
20
+ * Test-only. Resets the module's mount state between tests and reports what
21
+ * it believes is mounted.
22
+ *
23
+ * Exported because `@chatlychat/widget-react`'s tests need it and a workspace
24
+ * package cannot reach past the `exports` map to a deep path. Named with the
25
+ * same `__testing` convention as `apps/realtime/src/gateway.ts` so it reads as
26
+ * what it is. Calling it in production does nothing useful: it forgets the
27
+ * widget without destroying it, which is the leak the refcount exists to
28
+ * prevent.
29
+ */
30
+ export { __testing } from './embed.js';
31
+ export { defineChatlyWidget, CHATLY_WIDGET_TAG, ELEMENT_EVENTS, type ChatlyElementEvent, type ChatlyWidgetElement, } from './element.js';
32
+ export type { ChatlyBehavior, ChatlyCopy, ChatlyEmbedHandlers, ChatlyEmbedOptions, ChatlyEventName, ChatlyIdentity, ChatlyInitOptions, ChatlyMessageEvent, ChatlyQuickLink, ChatlyQuip, ChatlySession, ChatlyTheme, } from './types.js';
33
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EACT,kBAAkB,EAClB,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAC;AACpB;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `@chatlychat/widget-element` — the Chatly widget as a custom element, and the
3
+ * embed lifecycle every framework wrapper shares.
4
+ *
5
+ * **This entry has no side effects.** Importing it does not define a custom
6
+ * element and does not touch `document`. That is what lets
7
+ * `@chatlychat/widget-react` depend on this package for the lifecycle without
8
+ * registering a tag its consumers never asked for, and it is what makes the
9
+ * package importable from a server bundle.
10
+ *
11
+ * To get `<chatly-widget>`:
12
+ *
13
+ * import '@chatlychat/widget-element/register';
14
+ * // or, to choose the tag name:
15
+ * import { defineChatlyWidget } from '@chatlychat/widget-element';
16
+ * defineChatlyWidget('acme-chat');
17
+ */
18
+ export { controls, startWidget, subscribe, DEFAULT_LOADER_URL, } from './embed.js';
19
+ /**
20
+ * Test-only. Resets the module's mount state between tests and reports what
21
+ * it believes is mounted.
22
+ *
23
+ * Exported because `@chatlychat/widget-react`'s tests need it and a workspace
24
+ * package cannot reach past the `exports` map to a deep path. Named with the
25
+ * same `__testing` convention as `apps/realtime/src/gateway.ts` so it reads as
26
+ * what it is. Calling it in production does nothing useful: it forgets the
27
+ * widget without destroying it, which is the leak the refcount exists to
28
+ * prevent.
29
+ */
30
+ export { __testing } from './embed.js';
31
+ export { defineChatlyWidget, CHATLY_WIDGET_TAG, ELEMENT_EVENTS, } from './element.js';
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EACT,kBAAkB,GAEnB,MAAM,YAAY,CAAC;AACpB;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,GAGf,MAAM,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The side-effecting entry: `import '@chatlychat/widget-element/register'`.
3
+ *
4
+ * Separate from `index.ts` on purpose. A package that defines a custom
5
+ * element as a side effect of being imported cannot be used for its types or
6
+ * its helpers without that happening, and it breaks any bundle evaluated on a
7
+ * server. Here the side effect is the whole point, and a consumer opts into it
8
+ * by importing this path.
9
+ */
10
+ import { defineChatlyWidget } from './element.js';
11
+ defineChatlyWidget();
12
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Did the host page actually ask for something different?
3
+ *
4
+ * Every `<chatly-widget>` attribute change and every React re-render arrives
5
+ * here, and the answer decides whether the widget is re-initialised — which
6
+ * destroys and remounts it, closing an open panel. So "the same options
7
+ * spelled differently" has to compare equal.
8
+ *
9
+ * Lifted out of `embed.ts` when that file went over the repo's 650-line
10
+ * ceiling. Pure functions over plain values, which is why they were the right
11
+ * thing to move: nothing here touches the embed's mount state.
12
+ */
13
+ import type { ChatlyInitOptions } from './types.js';
14
+ /**
15
+ * Structural equality, with named exceptions.
16
+ *
17
+ * `JSON.stringify` was the obvious implementation and is wrong twice: key
18
+ * order differs between two literals with the same contents (so every render
19
+ * would look like a change), and `mountTo` can be an Element, which
20
+ * stringifies to `{}` — making two different containers compare equal and a
21
+ * moved mount point silently ignored.
22
+ */
23
+ export declare function sameOptions(a: ChatlyInitOptions, b: ChatlyInitOptions, ignore?: readonly string[]): boolean;
24
+ export declare function sameValue(a: unknown, b: unknown): boolean;
25
+ //# sourceMappingURL=same-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"same-value.d.ts","sourceRoot":"","sources":["../src/same-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,CAAC,EAAE,iBAAiB,EACpB,CAAC,EAAE,iBAAiB,EACpB,MAAM,GAAE,SAAS,MAAM,EAAO,GAC7B,OAAO,CAaT;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAgCzD"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Structural equality, with named exceptions.
3
+ *
4
+ * `JSON.stringify` was the obvious implementation and is wrong twice: key
5
+ * order differs between two literals with the same contents (so every render
6
+ * would look like a change), and `mountTo` can be an Element, which
7
+ * stringifies to `{}` — making two different containers compare equal and a
8
+ * moved mount point silently ignored.
9
+ */
10
+ export function sameOptions(a, b, ignore = []) {
11
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)].filter((k) => !ignore.includes(k)));
12
+ for (const key of keys) {
13
+ // Through `unknown`: an interface with named optional keys does not
14
+ // overlap an index signature, and TypeScript is right to say so — the
15
+ // read below is deliberately dynamic.
16
+ const left = a[key];
17
+ const right = b[key];
18
+ if (!sameValue(left, right)) {
19
+ return false;
20
+ }
21
+ }
22
+ return true;
23
+ }
24
+ export function sameValue(a, b) {
25
+ if (a === b) {
26
+ return true;
27
+ }
28
+ // An absent key and an explicit `undefined` are the same request. React
29
+ // props produce both for the same JSX depending on how they were spread.
30
+ if (a === undefined || b === undefined || a === null || b === null) {
31
+ return false;
32
+ }
33
+ if (typeof a !== 'object' || typeof b !== 'object') {
34
+ return false;
35
+ }
36
+ // A DOM node or a function is compared by identity only — recursing into an
37
+ // Element would walk the host page's entire tree.
38
+ if (isOpaque(a) || isOpaque(b)) {
39
+ return false;
40
+ }
41
+ if (Array.isArray(a) !== Array.isArray(b)) {
42
+ return false;
43
+ }
44
+ if (Array.isArray(a) && Array.isArray(b)) {
45
+ return a.length === b.length && a.every((item, i) => sameValue(item, b[i]));
46
+ }
47
+ const left = a;
48
+ const right = b;
49
+ const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
50
+ for (const key of keys) {
51
+ if (!sameValue(left[key], right[key])) {
52
+ return false;
53
+ }
54
+ }
55
+ return true;
56
+ }
57
+ function isOpaque(value) {
58
+ return typeof Node !== 'undefined' && value instanceof Node;
59
+ }
60
+ //# sourceMappingURL=same-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"same-value.js","sourceRoot":"","sources":["../src/same-value.ts"],"names":[],"mappings":"AAcA;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CACzB,CAAoB,EACpB,CAAoB,EACpB,SAA4B,EAAE;IAE9B,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChG,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,oEAAoE;QACpE,sEAAsE;QACtE,sCAAsC;QACtC,MAAM,IAAI,GAAI,CAAwC,CAAC,GAAG,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAI,CAAwC,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAU,EAAE,CAAU;IAC9C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IACD,wEAAwE;IACxE,yEAAyE;IACzE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,4EAA4E;IAC5E,kDAAkD;IAClD,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,IAAI,GAAG,CAA4B,CAAC;IAC1C,MAAM,KAAK,GAAG,CAA4B,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,OAAO,IAAI,KAAK,WAAW,IAAI,KAAK,YAAY,IAAI,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * The widget's init options, as a dependency-free type.
3
+ *
4
+ * ── Why these are declared again here ───────────────────────────────────
5
+ *
6
+ * The authoritative declaration is `InitOptions` in `apps/widget/src/index.ts`.
7
+ * It cannot be imported: that file is a Preact app entry whose import graph
8
+ * pulls in `preact`, `@preact/signals` and a `?inline` CSS import, and this
9
+ * package ships to a customer's bundler with zero dependencies. The headless
10
+ * SDK makes the same call for the same reason (`packages/sdk-js/src/types.ts`
11
+ * — importing `@livechat/shared` drags zod in, measured at ~11KB gzipped).
12
+ *
13
+ * Two copies of a shape is a drift risk, so it is a CHECKED one:
14
+ * `scripts/check-widget-wrapper-parity.mjs` compares the key sets in this file
15
+ * against the widget's own interfaces and fails the build when either side
16
+ * gains a key the other does not have. Without that gate the failure is
17
+ * silent and one-directional — the widget adds `theme.somethingNew`, a React
18
+ * consumer passes it, and TypeScript rejects a value the widget would have
19
+ * honoured.
20
+ *
21
+ * Nothing here is validated at runtime, and that is deliberate (see
22
+ * `coerceConfig` in `embed.ts` for the one place a boundary exists).
23
+ */
24
+ /** Identity the host page already knows. Mirrors the widget's `WidgetIdentity`. */
25
+ export interface ChatlyIdentity {
26
+ /**
27
+ * Your own stable id for this person. Optional in the type, but it is the
28
+ * only field contacts are matched on — without it every visit creates a new
29
+ * contact.
30
+ */
31
+ externalId?: string;
32
+ email?: string;
33
+ name?: string;
34
+ /**
35
+ * `HMAC-SHA256(<channel IDV secret>, externalId)`, computed by YOUR SERVER.
36
+ * Never in the browser: the secret would be in your page source.
37
+ */
38
+ userHash?: string;
39
+ attributes?: Record<string, unknown>;
40
+ }
41
+ /** Colours, shape, type and launcher art. Mirrors the widget's `WidgetTheme`. */
42
+ export interface ChatlyTheme {
43
+ icons?: Partial<Record<'mic' | 'stop' | 'attachment' | 'check' | 'star', string>>;
44
+ primaryColor?: string;
45
+ primaryContrast?: string;
46
+ background?: string;
47
+ backgroundSubtle?: string;
48
+ foreground?: string;
49
+ foregroundMuted?: string;
50
+ border?: string;
51
+ bubbleAgentBg?: string;
52
+ bubbleAgentFg?: string;
53
+ fontFamily?: string;
54
+ fontSize?: number | string;
55
+ borderRadius?: number | string;
56
+ launcherSize?: number;
57
+ panelWidth?: number;
58
+ panelHeight?: number;
59
+ position?: 'left' | 'right';
60
+ offsetX?: number;
61
+ offsetY?: number;
62
+ headerStyle?: 'gradient' | 'solid' | 'plain';
63
+ headerGradient?: [string, string];
64
+ hideLauncher?: boolean;
65
+ launcherIcon?: string;
66
+ launcherImage?: string;
67
+ launcherPing?: boolean;
68
+ launcherIdleAnimation?: 'none' | 'wiggle' | 'pulse' | 'bounce';
69
+ colorScheme?: 'light' | 'dark' | 'auto';
70
+ dangerColor?: string;
71
+ successColor?: string;
72
+ warningColor?: string;
73
+ hideBranding?: boolean;
74
+ logoUrl?: string;
75
+ agentAvatarUrl?: string;
76
+ }
77
+ /** Rotating micro-copy bound to a selector. Mirrors `WidgetQuip`. */
78
+ export interface ChatlyQuip {
79
+ selector: string;
80
+ lines: string[];
81
+ intervalMs?: number;
82
+ oncePerSession?: boolean;
83
+ }
84
+ /** Behaviour toggles. Mirrors the widget's `WidgetBehavior`. */
85
+ export interface ChatlyBehavior {
86
+ tabs?: Array<'home' | 'messages' | 'help'>;
87
+ defaultTab?: 'home' | 'messages' | 'help';
88
+ autoOpenAfterMs?: number;
89
+ hideOnUrls?: string[];
90
+ helpSearchOnly?: boolean;
91
+ starterPrompts?: string[];
92
+ home?: Array<'start' | 'recent' | 'quickLinks' | 'blocks' | 'helpSearch'>;
93
+ /**
94
+ * A `{ v, blocks }` envelope, the same shape a message carries. `unknown`
95
+ * rather than a block union: the widget validates it at the render boundary
96
+ * precisely so a block type a newer release added does not blank the home
97
+ * screen on an older bundle, and a narrow type here would refuse at compile
98
+ * time the forward compatibility the runtime was built to allow.
99
+ */
100
+ homeBlocks?: unknown;
101
+ draggable?: boolean;
102
+ quips?: ChatlyQuip[];
103
+ confettiClickStreak?: number;
104
+ }
105
+ /** A Home-tab button. Mirrors `WidgetQuickLink`. */
106
+ export interface ChatlyQuickLink {
107
+ label: string;
108
+ href?: string;
109
+ startConversation?: string | {
110
+ initialMessage?: string;
111
+ };
112
+ description?: string;
113
+ icon?: string;
114
+ }
115
+ /** Every string in the panel. Mirrors `WidgetCopy`. */
116
+ export interface ChatlyCopy {
117
+ greeting?: string;
118
+ greetingSubtitle?: string;
119
+ homeStartCta?: string;
120
+ homeStartCtaSubtitle?: string;
121
+ homeRecentTitle?: string;
122
+ homeQuickLinksTitle?: string;
123
+ homeHelpTitle?: string;
124
+ tabHome?: string;
125
+ tabMessages?: string;
126
+ tabHelp?: string;
127
+ messagesEmpty?: string;
128
+ messagesNewCta?: string;
129
+ helpSearchPlaceholder?: string;
130
+ helpEmpty?: string;
131
+ helpNoResults?: string;
132
+ helpStillNeedHelp?: string;
133
+ composerPlaceholder?: string;
134
+ composerSend?: string;
135
+ poweredBy?: string;
136
+ closeAria?: string;
137
+ backAria?: string;
138
+ unavailableMessage?: string;
139
+ unavailableRetry?: string;
140
+ }
141
+ /**
142
+ * Everything `Chatly.init()` accepts, minus `on`.
143
+ *
144
+ * The lifecycle callbacks are deliberately absent: a wrapper has to install
145
+ * ONE stable set of them at boot and fan out to whatever the host most
146
+ * recently passed, or every render with a fresh inline arrow function would
147
+ * look like a changed config and re-initialise the widget. See
148
+ * `ChatlyEmbedHandlers` and the `handlers` box in `embed.ts`.
149
+ */
150
+ export interface ChatlyInitOptions {
151
+ /** Channel public ID. Required. */
152
+ publicId: string;
153
+ apiUrl?: string;
154
+ realtimeUrl?: string;
155
+ visitor?: ChatlyIdentity;
156
+ theme?: ChatlyTheme;
157
+ behavior?: ChatlyBehavior;
158
+ quickLinks?: ChatlyQuickLink[];
159
+ /**
160
+ * Mount inside an element of your own layout instead of floating.
161
+ *
162
+ * Both wrappers set this for you from their own container, so a host rarely
163
+ * passes it directly — in React it is `<ChatlyWidget inline />` and in the
164
+ * custom element it is the `inline` attribute. Passing a selector by hand
165
+ * still works and still carries the widget's refusal behaviour: a selector
166
+ * that matches nothing mounts NOTHING and says so.
167
+ */
168
+ mountTo?: string | Element;
169
+ cssOverrides?: string;
170
+ copy?: ChatlyCopy;
171
+ copyByLocale?: Record<string, ChatlyCopy>;
172
+ }
173
+ /**
174
+ * The widget's event names, as `Chatly.on()` spells them.
175
+ *
176
+ * `ready` is a state rather than a moment — the widget replays the last one
177
+ * to a late subscriber — and both wrappers rely on that, because a React
178
+ * effect or a `connectedCallback` can easily run after the session is up.
179
+ */
180
+ export type ChatlyEventName = 'ready' | 'open' | 'close' | 'message' | 'conversation' | 'identified' | 'reset' | 'action' | 'error';
181
+ /** What a `ready` or `identified` event carries. */
182
+ export interface ChatlySession {
183
+ contactId: string | null;
184
+ workspaceId: string;
185
+ }
186
+ /** What a `message` event carries. */
187
+ export interface ChatlyMessageEvent {
188
+ id: string;
189
+ body: string;
190
+ authorType: string;
191
+ }
192
+ /**
193
+ * Subscribers a wrapper forwards to.
194
+ *
195
+ * Every one is optional and every one is called with whatever the widget
196
+ * emitted — these are not re-typed payloads, they are the widget's own.
197
+ */
198
+ export interface ChatlyEmbedHandlers {
199
+ onReady?: (session: ChatlySession) => void;
200
+ onOpen?: () => void;
201
+ onClose?: () => void;
202
+ onMessage?: (message: ChatlyMessageEvent) => void;
203
+ onConversation?: (detail: unknown) => void;
204
+ onIdentified?: (session: ChatlySession) => void;
205
+ onReset?: (detail: unknown) => void;
206
+ /** A visitor pressed a `host_event` action on a rich block. */
207
+ onAction?: (detail: unknown) => void;
208
+ /**
209
+ * The widget could not do something it was asked to do.
210
+ *
211
+ * Reported rather than thrown. The widget's own `chatly:error` event is the
212
+ * source, and it fires for a refused origin, a dead network and a 5xx —
213
+ * none of which a host page can do anything about by crashing.
214
+ */
215
+ onError?: (detail: unknown) => void;
216
+ }
217
+ /** Where `loader.js` is served from, plus the init options. */
218
+ export interface ChatlyEmbedOptions extends ChatlyInitOptions {
219
+ /**
220
+ * The loader script URL.
221
+ *
222
+ * Defaults to Chatly Cloud's. A SELF-HOSTED deployment must set it: the
223
+ * default points a visitor's browser at our CDN, which for a self-hoster is
224
+ * both wrong and the kind of wrong that still renders a working chat bubble
225
+ * (talking to the wrong API) rather than failing loudly.
226
+ *
227
+ * `GET /v1/channels/:id` returns the right value for your deployment as
228
+ * `embed.loaderUrl`. Use that rather than typing a host.
229
+ */
230
+ loaderUrl?: string;
231
+ /**
232
+ * Set the widget's locale once it is up, via `Chatly.setLocale()`.
233
+ *
234
+ * Not an init option — the widget has none. The strings come from `copy`
235
+ * and `copyByLocale` in the embed, so `locale` picks between bundles YOU
236
+ * supplied; asking for a locale with no bundle warns rather than appearing
237
+ * to work. Changing it does NOT re-initialise the widget.
238
+ */
239
+ locale?: string;
240
+ }
241
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The widget's init options, as a dependency-free type.
3
+ *
4
+ * ── Why these are declared again here ───────────────────────────────────
5
+ *
6
+ * The authoritative declaration is `InitOptions` in `apps/widget/src/index.ts`.
7
+ * It cannot be imported: that file is a Preact app entry whose import graph
8
+ * pulls in `preact`, `@preact/signals` and a `?inline` CSS import, and this
9
+ * package ships to a customer's bundler with zero dependencies. The headless
10
+ * SDK makes the same call for the same reason (`packages/sdk-js/src/types.ts`
11
+ * — importing `@livechat/shared` drags zod in, measured at ~11KB gzipped).
12
+ *
13
+ * Two copies of a shape is a drift risk, so it is a CHECKED one:
14
+ * `scripts/check-widget-wrapper-parity.mjs` compares the key sets in this file
15
+ * against the widget's own interfaces and fails the build when either side
16
+ * gains a key the other does not have. Without that gate the failure is
17
+ * silent and one-directional — the widget adds `theme.somethingNew`, a React
18
+ * consumer passes it, and TypeScript rejects a value the widget would have
19
+ * honoured.
20
+ *
21
+ * Nothing here is validated at runtime, and that is deliberate (see
22
+ * `coerceConfig` in `embed.ts` for the one place a boundary exists).
23
+ */
24
+ export {};
25
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
package/package.json CHANGED
@@ -1,6 +1,70 @@
1
1
  {
2
2
  "name": "@chatlychat/widget-element",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "The Chatly chat widget as a custom element (<chatly-widget>), plus the embed lifecycle framework wrappers share. Zero dependencies.",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/livechat/platform/tree/main/packages/widget-element",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/livechat/platform.git",
10
+ "directory": "packages/widget-element"
11
+ },
12
+ "bugs": "https://github.com/livechat/platform/issues",
13
+ "keywords": [
14
+ "chatly",
15
+ "livechat",
16
+ "chat",
17
+ "widget",
18
+ "custom-element",
19
+ "web-component",
20
+ "support"
21
+ ],
22
+ "author": "LiveChat Platform Engineering",
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js",
31
+ "default": "./dist/index.js"
32
+ },
33
+ "./register": {
34
+ "types": "./dist/register.d.ts",
35
+ "import": "./dist/register.js",
36
+ "default": "./dist/register.js"
37
+ }
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "!dist/**/*.spec.*",
42
+ "README.md",
43
+ "LICENSE",
44
+ "CHANGELOG.md"
45
+ ],
46
+ "sideEffects": [
47
+ "./dist/register.js"
48
+ ],
49
+ "scripts": {
50
+ "build": "tsc -p tsconfig.json",
51
+ "prepublishOnly": "pnpm build",
52
+ "typecheck": "tsc -p tsconfig.json --noEmit",
53
+ "lint": "eslint src --max-warnings=0",
54
+ "test": "vitest run"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public",
58
+ "registry": "https://registry.npmjs.org/",
59
+ "provenance": true
60
+ },
61
+ "engines": {
62
+ "node": ">=18"
63
+ },
64
+ "devDependencies": {
65
+ "@livechat/config": "workspace:*",
66
+ "jsdom": "^30.0.1",
67
+ "typescript": "catalog:",
68
+ "vitest": "catalog:"
69
+ }
70
+ }