@kavchat/widget 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 maxsave
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,163 @@
1
- # Temporary Holding Version
1
+ # Kavchat web widget
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The embeddable chat that your visitors see on your website. It loads the bot you published in the
4
+ Kavchat dashboard and runs the whole conversation in the browser with the shared `@kavchat/core` engine.
5
+ No LLM, no third-party requests, about 19 KB gzip.
6
+
7
+ ## Install
8
+
9
+ Paste this before `</body>`:
10
+
11
+ ```html
12
+ <script src="https://cdn.kavchat.com/v1/kavchat.js" data-key="pk_live_..." async></script>
13
+ ```
14
+
15
+ The public key (`pk_live_...`) is safe to put in a page. Never put the secret key (`sk_live_...`) in a page.
16
+
17
+ ### Attributes
18
+
19
+ | Attribute | Default | Description |
20
+ |---|---|---|
21
+ | `data-key` | (required) | Your public key. |
22
+ | `data-api` | `https://api.kavchat.com` | API base URL. |
23
+ | `data-locale` | the browser language | Language of the widget chrome (buttons, form, notices): `he`, `en`, `ar`, `ru`, `es`, `fr`, `de`, `pt`, `it`, `tr`. If the language has no translation, the bot locale is used. The script content is always shown as you wrote it. `he` and `ar` render right to left. |
24
+ | `data-user-token` | none | Identity token for a signed-in user (see below). |
25
+ | `data-user-name` | none | Shown in the greeting (`{name}`) and prefilled in the contact form. |
26
+ | `data-open` | `false` | `"true"` opens the chat as soon as it loads. |
27
+
28
+ ## JavaScript API
29
+
30
+ The script installs `window.Kavchat`:
31
+
32
+ ```js
33
+ Kavchat.init({
34
+ publicKey: 'pk_live_...',
35
+ apiBase: 'https://api.kavchat.com', // optional
36
+ locale: 'he', // optional
37
+ userToken: '<identity JWT>', // optional
38
+ userName: 'Dana', // optional
39
+ open: false, // optional
40
+ onScreen(screen, targetId) {}, // optional: "screen" buttons in your scripts
41
+ screens: [ // optional: shown as a dropdown in the dashboard editor
42
+ { id: 'orders', label: 'My orders' },
43
+ { id: 'product', label: 'Product page', needsTarget: true },
44
+ ],
45
+ onEvent(event) {}, // optional: ready, unavailable, open, close, effect, ticket
46
+ });
47
+ Kavchat.open();
48
+ Kavchat.close();
49
+ Kavchat.toggle();
50
+ Kavchat.setUser({ token: '<identity JWT>', name: 'Dana' }); // on login; setUser(null) on logout
51
+ Kavchat.destroy();
52
+ ```
53
+
54
+ `init` is not needed when the script tag has `data-key`. Calling `init` again replaces the running widget.
55
+
56
+ ### Calling the API before the script loads
57
+
58
+ The script tag is `async`, so your code may run first. Create a queue, push calls into it, and the
59
+ widget runs them in order when it loads (`init` always runs first; options from `init` are merged over
60
+ the script tag attributes):
61
+
62
+ ```html
63
+ <script>
64
+ window.Kavchat = window.Kavchat || { q: [] };
65
+ Kavchat.q.push(['init', { publicKey: 'pk_live_...', onScreen: function (s, id) { location.href = '/' + s + '/' + id; } }]);
66
+ Kavchat.q.push(['setUser', { token: '<identity JWT>', name: 'Dana' }]);
67
+ </script>
68
+ <script src="https://cdn.kavchat.com/v1/kavchat.js" async></script>
69
+ ```
70
+
71
+ Each entry is `[methodName, ...args]`. After the script has loaded, `Kavchat.q.push(...)` still works
72
+ and runs the call immediately, so the same code works in both cases.
73
+
74
+ ### Events
75
+
76
+ `onEvent` receives one of:
77
+
78
+ | `type` | Fields | When |
79
+ |---|---|---|
80
+ | `ready` | `version`, `offline` | The bot loaded (from the network, or from the saved copy when offline). |
81
+ | `unavailable` | `reason?` (`'quota'`) | The bot is off, limited to testers, or over quota. Nothing is shown. |
82
+ | `open`, `close` | | The panel opened or closed. |
83
+ | `effect` | `effect` | A button asked for the contact form, a link or a screen. |
84
+ | `ticket` | `id`, `number` | A contact request was created. |
85
+
86
+ ### Script actions
87
+
88
+ * **Contact**: opens the contact form inside the chat. The conversation transcript is attached to the request.
89
+ * **Link**: opens `https:` and `tel:` links in a new tab (`rel="noopener noreferrer"`). Other schemes are ignored.
90
+ * **Screen**: calls your `onScreen(screen, targetId)`. Without it the button does nothing on the web.
91
+
92
+ ### Screens
93
+
94
+ Declare the screens (or pages) a script button may open with the `screens` option. The widget registers them with
95
+ Kavchat only when the list changes, or once a week, and never blocks the page if that fails. The dashboard editor then
96
+ offers them in a dropdown with their readable names, asks for an item id when `needsTarget` is true, and warns about
97
+ buttons that point to a screen you did not declare. `id` must match `^[A-Za-z0-9_.-]{1,40}$`, `label` is up to 60
98
+ characters, at most 100 screens.
99
+
100
+ ## Identifying your users
101
+
102
+ To tag sessions and tickets with your own user id, or to show the bot only to testers, sign a JWT on
103
+ your backend and pass it as `data-user-token` or `userToken`:
104
+
105
+ * algorithm `HS256`, key = your secret key (the full `sk_live_...` string, as UTF-8 bytes)
106
+ * claims: `sub` (your user id, required), `exp` (required, at most 30 days ahead),
107
+ optional `phone`, `name`, `email`
108
+
109
+ The widget sends it as `Authorization: Bearer <token>` on every call. Signed-in users may open a
110
+ request without leaving an email or phone. Full details are in the API reference
111
+ (`server/openapi.yaml`, section "Identifying your users").
112
+
113
+ ## Content Security Policy
114
+
115
+ If your site sends a CSP header, allow:
116
+
117
+ ```
118
+ script-src https://cdn.kavchat.com;
119
+ connect-src https://api.kavchat.com;
120
+ ```
121
+
122
+ Add `img-src https:` (or your image hosts) if your scripts or avatar use images. The widget injects
123
+ its styles into its own Shadow DOM `<style>` element; if your CSP restricts `style-src`, it needs
124
+ `'unsafe-inline'` for that element.
125
+
126
+ ## How it behaves
127
+
128
+ * **Isolation**: everything renders inside a Shadow DOM. Your CSS does not reach the widget and the widget's CSS does not reach your page.
129
+ * **Caching**: the published bot is saved in `localStorage` per public key with its ETag. Each load sends `If-None-Match`; when nothing changed the server answers 304. When the network is down the saved copy is used and a notice is shown.
130
+ * **Sessions**: a random session id is kept in `sessionStorage`, so moving between pages keeps the same conversation.
131
+ * **Analytics**: the conversation path is reported about 2 seconds after each action, and on page hide with `fetch(..., { keepalive: true })`.
132
+ * **Free plan**: the "Powered by Kavchat" badge is shown unless your plan removes branding.
133
+ * **Accessibility**: the panel is a labelled dialog, focus moves into it and back, Esc closes it, buttons are real buttons, new bot messages are announced, and motion is reduced when the visitor asks for it.
134
+
135
+ ## AI answers (Premium)
136
+
137
+ There is nothing to configure on your site. When AI answers are turned on in the dashboard (on your own
138
+ AI provider key), a typed question that no script matches is sent to `POST /v1/client/{publicKey}/ai/answer`,
139
+ and the chat shows a typing indicator while it waits (up to 20 seconds). The answer is shown as plain text
140
+ (`textContent`, no links or HTML) with a small "AI answer" label in the UI language, followed by a button for
141
+ the suggested script when there is one, and "Talk to our team". If there is no answer, or the request fails,
142
+ times out or is rate limited, the chat shows the regular "no match" reply. Unanswered questions are reported
143
+ to `/events` exactly as before, and AI answers are kept in the saved conversation.
144
+
145
+ ## npm
146
+
147
+ ```js
148
+ import { createWidget } from '@kavchat/widget';
149
+
150
+ const widget = createWidget({ publicKey: 'pk_live_...' });
151
+ await widget.ready;
152
+ widget.open();
153
+ ```
154
+
155
+ ## Development
156
+
157
+ ```bash
158
+ yarn build # dist/kavchat.js (IIFE for the CDN) and dist/index.mjs (ESM)
159
+ yarn test # vitest + jsdom
160
+ yarn tsc --noEmit
161
+ ```
162
+
163
+ Open `demo/index.html` in a browser after building. It mocks the API inside the page, in Hebrew and English.