@clivly/chat-widget 0.7.2 → 0.7.4

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.
Files changed (2) hide show
  1. package/README.md +202 -93
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,128 +1,199 @@
1
- # @clivly/chat-widget
1
+ # `@clivly/chat-widget`
2
2
 
3
- Embeddable chat widget for Clivly conversations.
3
+ An embeddable chat surface for your app's visitors. Messages land in your Clivly
4
+ workspace under **Conversations**, where your team replies in real time.
4
5
 
5
- ## Install
6
+ > **New here? Start with
7
+ > [Adding the chat widget](../../docs/guides/adding-the-chat-widget.md)** — the
8
+ > canonical end-to-end guide (widget record, session route, embed, operator
9
+ > inbox). This README is the API-level reference for the package's entrypoints.
10
+
11
+ > **Preview-quality surface.** The end-to-end path (SDK session handler,
12
+ > `/widget.js` serving, operator inbox) is implemented and covered by
13
+ > integration tests; treat it as design-partner quality while the conversations
14
+ > UX settles.
15
+
16
+ ## Prerequisites
17
+
18
+ | Requirement | Version / note |
19
+ | --- | --- |
20
+ | Node.js | **≥ 22** |
21
+ | `react` / `react-dom` | **≥ 18** — peer dependencies, for the React entrypoints only. The script-tag build bundles its own |
22
+ | **A backend** | Required. The widget never holds your API key; it calls a route on your origin that does. Static-only sites (plain HTML, WordPress, Webflow) cannot install it |
23
+ | A widget record | Created in the dashboard under **Settings → Chat widget** |
24
+
25
+ ## Installation
6
26
 
7
27
  ```bash
8
28
  npm install @clivly/chat-widget
9
29
  ```
10
30
 
11
- Peer dependencies:
31
+ Published on npm's `latest` tag. Use `@next` only for prerelease testing.
32
+
33
+ The **host-side session route** comes from `clivly/sdk`, not from this package —
34
+ see [Host-side pairing](#host-side-pairing) below. `npx clivly add widget`
35
+ scaffolds it for you.
36
+
37
+ ## Five-minute quick start
12
38
 
13
39
  ```bash
14
- npm install react react-dom
40
+ npx clivly add widget # scaffolds the session route on your backend
41
+ npm install @clivly/chat-widget
15
42
  ```
16
43
 
17
- This package is a Tier 2 surface in
18
- [STABILITY.md](https://github.com/amani-joseph/clivly.com/blob/master/STABILITY.md).
19
- Stable releases publish on npm's `latest` tag. Use `@next` only when you are
20
- testing a prerelease build.
44
+ ```tsx
45
+ import { ChatWidget, createSessionFetcher } from "@clivly/chat-widget";
46
+
47
+ <ChatWidget
48
+ widgetId="support"
49
+ getSession={createSessionFetcher({
50
+ sessionUrl: "/api/clivly/widget/session",
51
+ })}
52
+ />;
53
+ ```
21
54
 
22
- For the end-to-end integration flow, start with:
23
- [Adding the chat widget](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/adding-the-chat-widget.md).
55
+ `widgetId` is the **public slug** you set on the widget record — it is not a
56
+ credential. `sessionUrl` must be the path where you mounted the session route on
57
+ your own origin; `/api/clivly/widget/session` is what `clivly add widget`
58
+ writes.
24
59
 
25
60
  ## Entrypoints
26
61
 
62
+ This package exposes four stable entrypoints with different intended use cases.
63
+
27
64
  ### `@clivly/chat-widget`
28
65
 
29
- Use the package root for React components plus browser-safe helpers.
66
+ Use the package root for app-side integration code.
30
67
 
31
- Exports include:
68
+ It exports:
32
69
 
33
- - `ChatWidget`
34
- - `ChatLauncher`
35
- - `ChatPanel`
36
- - `ConversationView`
37
- - `MessageComposer`
38
- - `PreChatForm`
70
+ - React widget components
39
71
  - `createSessionFetcher()`
40
72
  - `createClivlyTransport()`
41
- - `createWebSocketTransport()`
42
- - `createLoopbackTransport()`
43
- - `mountChatWidget()`
44
- - `mountChatWidgetScript()`
45
- - `autoMountChatWidgetScript()`
73
+ - side-effect-free mount helpers
46
74
 
47
75
  Example:
48
76
 
49
77
  ```ts
50
78
  import {
51
- ChatWidget,
52
- createSessionFetcher,
79
+ createSessionFetcher,
80
+ createClivlyTransport,
81
+ mountChatWidget,
53
82
  } from "@clivly/chat-widget";
83
+
84
+ const getSession = createSessionFetcher({
85
+ sessionUrl: "/api/clivly/widget/session",
86
+ });
54
87
  ```
55
88
 
56
89
  ### `@clivly/chat-widget/browser`
57
90
 
58
- Browser entry that auto-mounts at module evaluation time when `document`
59
- exists. It also exports `mountChatWidget()`, `mountChatWidgetScript()`, and
60
- `autoMountChatWidgetScript()`.
91
+ Use this entry for the browser auto-mount module build.
61
92
 
62
- ### `@clivly/chat-widget/mount`
93
+ This entry:
63
94
 
64
- Use this when you want the mounting helpers without the browser entry's
65
- auto-mount side effect.
95
+ - exports `mountChatWidget()`
96
+ - exports `mountChatWidgetScript()`
97
+ - exports `autoMountChatWidgetScript()`
98
+ - auto-mounts at module evaluation time when `document` exists
66
99
 
67
- ### `@clivly/chat-widget/script`
100
+ This is the module-side equivalent of the script-tag embed behavior.
68
101
 
69
- Maps to the generated global bundle at `dist/widget.global.js` for script-tag or
70
- CDN-style delivery.
102
+ ### `@clivly/chat-widget/mount`
71
103
 
72
- ## React usage
104
+ Use this entry when you want the mount helpers without the browser entry's
105
+ auto-mount side effect.
73
106
 
74
- ```tsx
75
- import { ChatWidget, createSessionFetcher } from "@clivly/chat-widget";
107
+ This is the safest browser/helper entry for host-controlled mounting.
76
108
 
77
- <ChatWidget
78
- widgetId="support"
79
- getSession={createSessionFetcher({
80
- sessionUrl: "/api/clivly/widget/session",
81
- })}
82
- />;
83
- ```
109
+ It exports:
110
+
111
+ - `mountChatWidget()`
112
+ - `mountChatWidgetScript()`
113
+ - `autoMountChatWidgetScript()`
114
+ - `MountChatWidgetOptions`
115
+ - `ChatWidgetMount`
116
+ - `ScriptMountResult`
84
117
 
85
- ## Script-tag usage
118
+ ### `@clivly/chat-widget/script`
86
119
 
87
- ```html
88
- <script
89
- src="https://api.clivly.com/widget.js"
90
- data-widget-id="support"
91
- data-session-url="/api/clivly/widget/session"
92
- defer
93
- ></script>
94
- ```
120
+ This entry maps to the generated global/browser artifact:
95
121
 
96
- Supported attributes:
122
+ - `dist/widget.global.js`
97
123
 
98
- | Attribute | Required | Purpose |
99
- | --- | --- | --- |
100
- | `data-widget-id` | yes | Public widget slug from the Clivly dashboard |
101
- | `data-session-url` | yes | Your backend route that mounts `createChatSessionHandler()` |
102
- | `data-theme` | no | `auto`, `light`, or `dark` |
103
- | `data-socket-url-template` | no | Legacy socket override; usually unnecessary |
124
+ Use it for script-tag delivery, CDN-style consumption, or any future server path
125
+ that serves the bundled widget directly.
104
126
 
105
127
  ## Theming
106
128
 
107
- The widget ships light and dark palettes and follows the host by default.
129
+ The widget ships light and dark palettes and follows the host app by default.
130
+ For integration recipes (Tailwind, next-themes, a custom toggle) see
131
+ [the guide's theming section](../../docs/guides/adding-the-chat-widget.md#5-theming).
108
132
 
109
- `theme` accepts:
133
+ ### `theme`
110
134
 
111
135
  | Value | Behaviour |
112
136
  | --- | --- |
113
- | `"auto"` | Follows `data-theme` on `<html>`, then `dark` / `light` classes on `<html>`, then `prefers-color-scheme` |
114
- | `"light"` / `"dark"` | Pinned theme |
137
+ | `"auto"` *(default)* | Follows the host: `data-theme="dark"`/`"light"` on `<html>`, then a `dark`/`light` class on `<html>`, then `prefers-color-scheme`. Re-resolves live. |
138
+ | `"light"` / `"dark"` | Pinned. Host signals are ignored and nothing is observed. |
139
+
140
+ Set it as a prop (`<ChatWidget theme="dark" />`), as `data-theme` on the script
141
+ tag, or as `theme` in `mountChatWidget()` options. An unrecognised
142
+ `data-theme` value falls back to `"auto"` rather than throwing.
143
+
144
+ `mountChatWidgetScript()` also returns `setTheme(theme)` for hosts whose toggle
145
+ does not touch `<html>`:
146
+
147
+ ```ts
148
+ const { setTheme } = mountChatWidgetScript(script);
149
+ setTheme("dark"); // pin
150
+ setTheme("auto"); // hand control back to the host
151
+ ```
152
+
153
+ The resolved theme is applied as `data-clivly-theme="light|dark"` on the widget
154
+ root, together with `color-scheme`, so native scrollbars, autofill, and the
155
+ caret follow the panel.
156
+
157
+ ### Palette tokens
115
158
 
116
- Set it as a React prop, a script-tag `data-theme`, or through
117
- `mountChatWidget()` options. `mountChatWidgetScript()` also returns
118
- `setTheme(theme)` for hosts with a custom toggle.
159
+ Every colour reads through a CSS custom property. React hosts can override any
160
+ of them inline — inline declarations beat both palette rules, so no specificity
161
+ work is needed:
119
162
 
120
- The resolved theme is written to `data-clivly-theme="light|dark"` on the widget
121
- root.
163
+ ```tsx
164
+ <ChatWidget style={{ "--clivly-chat-panel": "#0b0f19" }} widgetId="support" />
165
+ ```
122
166
 
123
- ## Session bootstrap
167
+ | Token | Light | Dark |
168
+ | --- | --- | --- |
169
+ | `--clivly-chat-accent` | `#185adb` | `#4f8cff` |
170
+ | `--clivly-chat-accent-contrast` | `#ffffff` | `#0b1220` |
171
+ | `--clivly-chat-panel` | `#ffffff` | `#111827` |
172
+ | `--clivly-chat-input` | `transparent` | `#0b1220` |
173
+ | `--clivly-chat-border` | `#d6dde8` | `#2a3546` |
174
+ | `--clivly-chat-text` | `#132238` | `#e8edf5` |
175
+ | `--clivly-chat-muted` | `#60738a` | `#93a2b8` |
176
+ | `--clivly-chat-visitor` | `#ecf3ff` | `#1e3a6b` |
177
+ | `--clivly-chat-operator` | `#f5f7fa` | `#1b2534` |
178
+ | `--clivly-chat-shadow` | `rgba(19, 34, 56, 0.18)` | `rgba(0, 0, 0, 0.5)` |
179
+ | `--clivly-chat-error-bg` | `#fff1f1` | `#2c1618` |
180
+ | `--clivly-chat-error-border` | `#f2c2c2` | `#5c2a2e` |
181
+ | `--clivly-chat-error-text` | `#9f2d2d` | `#ffb4b4` |
182
+
183
+ The widget record's `brandColor` overrides `--clivly-chat-accent` in **both**
184
+ themes — the widget will not silently lighten your brand. If your brand colour
185
+ is very dark it will be low-contrast on the dark panel; pick a lighter accent,
186
+ or override the token per theme in a React host.
187
+
188
+ Deep per-token overrides are not available on the script-tag path: it mounts
189
+ into a Shadow DOM, so host CSS cannot reach the widget's internals. Use
190
+ `brandColor` and the two themes there.
191
+
192
+ ## Session bootstrap shape
193
+
194
+ The widget expects a session bootstrap endpoint that returns a
195
+ `WidgetSessionPayload`.
124
196
 
125
- The widget expects a bootstrap endpoint that returns a `WidgetSessionPayload`.
126
197
  Important fields include:
127
198
 
128
199
  - `token`
@@ -132,21 +203,39 @@ Important fields include:
132
203
  - `messages`
133
204
  - optional `socketUrl`
134
205
 
135
- When `socketUrl` is present, the widget prefers it over reconstructing one from
136
- `socketUrlTemplate`.
206
+ When `socketUrl` is present, the widget prefers it over reconstructing the
207
+ socket URL from a client-side template.
208
+
209
+ ## Transport behavior
137
210
 
138
- ## Transport behaviour
211
+ The package includes:
139
212
 
140
- The default browser mount order is:
213
+ - `createClivlyTransport()` for real Clivly backends
214
+ - `createWebSocketTransport()` for explicit socket wiring
215
+ - `createLoopbackTransport()` for local UI/testing flows
141
216
 
142
- 1. use a caller-provided `createTransport`
217
+ The default browser mount behavior is:
218
+
219
+ 1. use a caller-provided `createTransport` when present
143
220
  2. otherwise prefer `session.socketUrl`
144
- 3. otherwise fall back to `socketUrlTemplate`
221
+ 3. otherwise fall back to `socketUrlTemplate` when provided
222
+
223
+ ## Build outputs
224
+
225
+ The package currently produces:
226
+
227
+ - `dist/index.*`
228
+ - `dist/browser.*`
229
+ - `dist/browser-mount.*`
230
+ - `dist/widget.global.js`
145
231
 
146
- ## Host-side session route
232
+ The `browser` and `browser-mount` outputs are built as standalone entrypoints.
147
233
 
148
- The widget talks to your backend, not directly to Clivly. Mount the session
149
- handler from the SDK on your own origin:
234
+ ## Host-side pairing
235
+
236
+ The host-side session handler is the bridge between a backend holding
237
+ `CLIVLY_SECRET_KEY` and the widget's `sessionUrl`. Import it from `clivly/sdk`,
238
+ which is available from the `clivly` package `clivly init` already installs:
150
239
 
151
240
  ```ts
152
241
  import { createChatSessionHandler } from "clivly/sdk";
@@ -156,22 +245,42 @@ export const POST = createChatSessionHandler({
156
245
  });
157
246
  ```
158
247
 
159
- The current scaffolded/default route path is:
248
+ `@clivly/sdk` exports the same handler if you depend on it directly. Don't import
249
+ from `clivly` (the package root) — that entry is the CLI and is Node-only.
160
250
 
161
- ```text
162
- /api/clivly/widget/session
163
- ```
251
+ Use the handler rather than hand-writing the proxy: it puts `origin` in the
252
+ request body (the backend requires it there, and only falls back to the `Origin`
253
+ header), accepts `visitorToken: null` for a first-time visitor, and turns an
254
+ unreachable Clivly into a JSON `502` instead of a thrown `fetch`.
164
255
 
165
- Use the handler rather than hand-writing the proxy. It forwards `origin`
166
- correctly, accepts `visitorToken: null` for first-time visitors, and returns a
167
- clean JSON `502` when Clivly is unreachable.
256
+ ## Verify the integration
168
257
 
169
- ## More docs
258
+ 1. Load a page that embeds the widget, from an origin in the widget record's
259
+ **allowed origins** list.
260
+ 2. Open the launcher and submit the pre-chat form.
261
+ 3. The conversation should appear in your Clivly workspace under
262
+ **Conversations** within a second or two.
170
263
 
171
- - End-to-end guide:
172
- [Adding the chat widget](https://github.com/amani-joseph/clivly.com/blob/master/docs/guides/adding-the-chat-widget.md)
173
- - Release notes:
174
- [CHANGELOG.md](https://github.com/amani-joseph/clivly.com/blob/master/CHANGELOG.md)
264
+ ## Common errors and troubleshooting
265
+
266
+ | Symptom | Cause | Fix |
267
+ | --- | --- | --- |
268
+ | Widget mounts but every session is `403` | The origin is not in the widget record's allowlist. It is **exact-match**: `https://example.com` does not cover `https://www.example.com` | Add every embedding origin, with scheme, under **Settings → Chat widget** |
269
+ | A brand-new widget refuses everything | An empty origin list permits nothing | Add at least one origin |
270
+ | `503 widget_not_configured` | The Clivly server has no `CLIVLY_WIDGET_TOKEN_SECRET` | Only relevant when self-hosting — set it, or set `CLIVLY_MASTER_KEY` |
271
+ | Session request returns an opaque `400` | The route was hand-written and omits `origin` from the **body**, or rejects `visitorToken: null` | Use `createChatSessionHandler` from `clivly/sdk` |
272
+ | `404` on the session request | `sessionUrl` does not match where you mounted the route | `clivly add widget` writes `/api/clivly/widget/session` — match it, or set `sessionUrl` to your path |
273
+ | Bundle throws on `node:fs` / `node:child_process` | Something imported the `clivly` package root | Import the handler from `clivly/sdk` |
274
+ | A returning visitor starts a fresh thread on another device | By design — conversations resume by opaque `visitorToken` in `localStorage`, never by the (unverified) email | Not a bug; resuming by email would leak a known customer's history |
275
+ | Brand colour looks wrong on the dark panel | `brandColor` overrides `--clivly-chat-accent` in **both** themes | Pick a lighter accent, or override the token per theme in a React host |
276
+ | Deep CSS overrides do nothing on the script-tag embed | It mounts into a Shadow DOM, so host CSS cannot reach it | Use `brandColor` and the two themes there, or switch to the React embed |
277
+
278
+ ## Related documentation
279
+
280
+ - **[Adding the chat widget](../../docs/guides/adding-the-chat-widget.md)** — the canonical end-to-end guide
281
+ - [Connecting to Clivly Cloud](../../docs/guides/connecting-to-clivly-cloud.md) — the overall integration guide
282
+ - [`@clivly/sdk` README](../sdk/README.md) — `createChatSessionHandler` and the rest of the runtime
283
+ - [`clivly` CLI README](../cli/README.md) — `clivly add widget`
175
284
 
176
285
  ## License
177
286
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clivly/chat-widget",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Clivly chat widget — embeddable React and script-tag entrypoints for Clivly conversations.",