@cusuai/web-sdk 0.2.1 → 0.3.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/README.md +33 -56
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ npm install @cusuai/web-sdk
|
|
|
20
20
|
- Dictation via `/v1/transcribe` (Bearer public key)
|
|
21
21
|
- `identify` for logged-in customers (optional HMAC signature from your backend)
|
|
22
22
|
- Locales: English (`en`), Bulgarian (`bg`), Czech (`cs`), Slovak (`sk`), Spanish (`es`), German (`de`), Estonian (`et`), French (`fr`), Polish (`pl`), Hungarian (`hu`), Italian (`it`), Lithuanian (`lt`), Latvian (`lv`), Dutch (`nl`), Norwegian Bokmål (`no`), Portuguese (`pt`), Danish (`da`), Slovenian (`sl`), Croatian (`hr`), Romanian (`ro`), Swedish (`sv`), and Finnish (`fi`); chrome follows group language from boot, or page/`config.locale` when reply locale is `auto`
|
|
23
|
-
- Published builds: **ES module** (`dist/index.js`) + **IIFE** (`
|
|
23
|
+
- Published builds: **ES module** (`dist/index.js`) + **IIFE** script tag on the Zerops CDN (`widget/<version>/cusu.js`, global `Cusu`)
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
@@ -84,12 +84,12 @@ import Cusu from '@cusuai/web-sdk';
|
|
|
84
84
|
|
|
85
85
|
Types ship with the package (`dist/index.d.ts`).
|
|
86
86
|
|
|
87
|
-
### Script tag (
|
|
87
|
+
### Script tag (Shopify, Shoptet, plain HTML)
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
No package manager. Paste this before `</body>` in the theme (`theme.liquid` on Shopify). Pin the version — `latest` can stay cached for up to 30 days.
|
|
90
90
|
|
|
91
91
|
```html
|
|
92
|
-
<script src="https://cdn.
|
|
92
|
+
<script src="https://storage.cdn.zerops.app/4gfpg-widgetcdn/widget/0.2.0/cusu.js"></script>
|
|
93
93
|
<script>
|
|
94
94
|
Cusu.initialize({
|
|
95
95
|
group: 'grp_…',
|
|
@@ -98,7 +98,7 @@ After install (or from your CDN of the published `dist/`):
|
|
|
98
98
|
</script>
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
The
|
|
101
|
+
The script exposes a global `Cusu` with the same API as the default export. The shop origin must be on the public key's allowed origins. Layout, cache, and how a release publishes the file: [docs/widget-cdn.md](./docs/widget-cdn.md).
|
|
102
102
|
|
|
103
103
|
---
|
|
104
104
|
|
|
@@ -181,73 +181,50 @@ Cusu.identify('user_123', {
|
|
|
181
181
|
|
|
182
182
|
### Signed identify (recommended in production)
|
|
183
183
|
|
|
184
|
-
When the group has an identify secret (`isk_…`), unsigned `identify` is **rejected**. Sign on your **backend** only.
|
|
184
|
+
When the group has an identify secret (`isk_…`), unsigned `identify` is **rejected**. Sign on your **backend** only — use [`@cusuai/node`](https://github.com/cusuai/cusu-node-sdk) `identifySign` (do not put `isk_…` in the browser).
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
```text
|
|
190
|
-
v1\n{visitorId}\n{externalId}\n{signedAt}\n{name}\n{email}\n{phone}\n{gender}
|
|
186
|
+
```bash
|
|
187
|
+
npm install @cusuai/node
|
|
191
188
|
```
|
|
192
189
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
**Node.js example** (Express / any backend):
|
|
190
|
+
```ts
|
|
191
|
+
import { identifySign } from '@cusuai/node';
|
|
197
192
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
function signIdentify(secret, { visitorId, externalId, signedAt, name, email, phone, gender }) {
|
|
202
|
-
const canonical = [
|
|
203
|
-
'v1',
|
|
204
|
-
visitorId,
|
|
205
|
-
externalId,
|
|
206
|
-
String(signedAt),
|
|
207
|
-
name ?? '',
|
|
208
|
-
email ?? '',
|
|
209
|
-
phone ?? '',
|
|
210
|
-
gender ?? ''
|
|
211
|
-
].join('\n');
|
|
212
|
-
return createHmac('sha256', secret).update(canonical, 'utf8').digest('hex');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// POST /api/cusu-identify
|
|
193
|
+
// POST /api/cusu-identify — body: { visitorId } from the browser (cusu_vid cookie).
|
|
194
|
+
// Take externalId + traits from your authenticated session / DB.
|
|
216
195
|
app.post('/api/cusu-identify', (req, res) => {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
gender: traits.gender
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
res.json({ ...traits, signedAt, signature });
|
|
196
|
+
const visitorId = String(req.body.visitorId ?? '').trim();
|
|
197
|
+
res.json(
|
|
198
|
+
identifySign({
|
|
199
|
+
isk: process.env.CUSU_IDENTIFY_SECRET!,
|
|
200
|
+
visitorId,
|
|
201
|
+
externalId: req.user.id,
|
|
202
|
+
traits: {
|
|
203
|
+
name: req.user.name,
|
|
204
|
+
email: req.user.email,
|
|
205
|
+
gender: req.user.gender
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
);
|
|
234
209
|
});
|
|
235
210
|
```
|
|
236
211
|
|
|
237
212
|
Browser:
|
|
238
213
|
|
|
239
214
|
```js
|
|
215
|
+
const visitorId = document.cookie
|
|
216
|
+
.split('; ')
|
|
217
|
+
.find((row) => row.startsWith('cusu_vid='))
|
|
218
|
+
?.split('=')[1];
|
|
219
|
+
|
|
240
220
|
const identity = await fetch('/api/cusu-identify', {
|
|
241
221
|
method: 'POST',
|
|
242
222
|
headers: { 'content-type': 'application/json' },
|
|
243
223
|
credentials: 'same-origin',
|
|
244
|
-
body: JSON.stringify({
|
|
245
|
-
externalId: 'user_123',
|
|
246
|
-
traits: { name: 'Jane Doe', email: 'jane@shop.test', gender: 'female' }
|
|
247
|
-
})
|
|
224
|
+
body: JSON.stringify({ visitorId })
|
|
248
225
|
}).then((r) => r.json());
|
|
249
226
|
|
|
250
|
-
Cusu.identify(
|
|
227
|
+
Cusu.identify(identity.externalId, identity);
|
|
251
228
|
```
|
|
252
229
|
|
|
253
230
|
On **logout**, call `reset()` before the next `identify`. `destroy()` + `initialize()` is not enough: the same `cusu_vid` cookie and local conversation list would keep the previous customer's threads. After `identify`, the SDK replaces local history with that customer's threads from the server.
|
|
@@ -256,7 +233,7 @@ On **logout**, call `reset()` before the next `identify`. `destroy()` + `initial
|
|
|
256
233
|
Cusu.reset();
|
|
257
234
|
```
|
|
258
235
|
|
|
259
|
-
Full protocol notes: [docs/protocol.md](./docs/protocol.md). Integrator security checklist: [SECURITY.md](./SECURITY.md).
|
|
236
|
+
Package docs: [cusuai/cusu-node-sdk](https://github.com/cusuai/cusu-node-sdk). Full protocol notes: [docs/protocol.md](./docs/protocol.md). Integrator security checklist: [SECURITY.md](./SECURITY.md).
|
|
260
237
|
|
|
261
238
|
---
|
|
262
239
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cusuai/web-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Framework-agnostic Cusu customer chat widget (Shadow DOM, ES + IIFE).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,13 +44,14 @@
|
|
|
44
44
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
45
45
|
"lint": "biome check .",
|
|
46
46
|
"format": "biome check --write .",
|
|
47
|
-
"test": "bun test src",
|
|
47
|
+
"test": "bun test src scripts",
|
|
48
48
|
"test:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=lcov src",
|
|
49
49
|
"test:coverage:check": "bun run scripts/check-coverage.ts --write-badge",
|
|
50
50
|
"audit": "bun audit --audit-level=moderate",
|
|
51
51
|
"ci": "bun run lint && bun run check && bun run test:coverage && bun run test:coverage:check && bun run build && bun run audit"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"@aws-sdk/client-s3": "^3.1139.0",
|
|
54
55
|
"@biomejs/biome": "^2.5.12",
|
|
55
56
|
"@inlang/paraglide-js": "^2.25.0",
|
|
56
57
|
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|