@helpai/elements 1.9.0 → 1.10.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/docs/api-reference.md +15 -0
- package/docs/configuration.md +13 -0
- package/docs/frameworks.md +3 -0
- package/docs/security-privacy.md +64 -3
- package/elements-web-component.esm.js +17 -17
- package/elements-web-component.esm.js.map +3 -3
- package/elements.cjs.js +9 -9
- package/elements.cjs.js.map +3 -3
- package/elements.esm.js +9 -9
- package/elements.esm.js.map +3 -3
- package/elements.js +20 -20
- package/elements.js.map +3 -3
- package/index.d.ts +24 -1
- package/index.mjs +3 -3
- package/llms-full.txt +225 -133
- package/llms.txt +19 -18
- package/package.json +1 -1
- package/react.d.ts +24 -1
- package/react.mjs +14 -14
- package/web-component.d.ts +23 -1
- package/web-component.mjs +3 -3
package/docs/api-reference.md
CHANGED
|
@@ -139,6 +139,7 @@ interface ChatWidgetInstance {
|
|
|
139
139
|
|
|
140
140
|
// Lifecycle
|
|
141
141
|
reset(): void; // start over as a new anonymous visitor (on logout)
|
|
142
|
+
login(userToken: UserTokenSource): void; // sign the visitor in as your logged-in user (a signed token, or a function returning one)
|
|
142
143
|
destroy(): void;
|
|
143
144
|
|
|
144
145
|
// Events
|
|
@@ -332,6 +333,20 @@ visitor, their current conversation (draft and queued messages included), prefer
|
|
|
332
333
|
`setUserContext`, then reconnects as a first visit. Listeners added with `on()` stay, and the handle keeps working.
|
|
333
334
|
On `<web-ai-chat>`, also remove a `user-context` attribute you set.
|
|
334
335
|
|
|
336
|
+
### `login(userToken)`
|
|
337
|
+
|
|
338
|
+
Signs the visitor in as your logged-in user. `userToken` is a JWT your server signs with the deployment's secret key,
|
|
339
|
+
or a function returning a fresh one (called again when the server rejects the current token as expired). The widget
|
|
340
|
+
reconnects as that user: their conversations on this browser move to them, and they reach their conversations on any
|
|
341
|
+
device where they're signed in. Call `reset()` when they sign out; switching to another user's token starts over the
|
|
342
|
+
same way. Also `HelpAI('login', userToken)`, `element.login(userToken)` on `<web-ai-chat>` (not an attribute, so the
|
|
343
|
+
token stays out of the DOM), the `userToken` option at `init()`, and `<HelpAI userToken={…} />`. Signing and the
|
|
344
|
+
guarantees: [Security → Verified users](./security-privacy.md#verified-users-usertoken).
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
chat.login(() => fetch('/api/help-ai-token').then((res) => res.text()));
|
|
348
|
+
```
|
|
349
|
+
|
|
335
350
|
---
|
|
336
351
|
|
|
337
352
|
## Events
|
package/docs/configuration.md
CHANGED
|
@@ -102,6 +102,19 @@ Override if you use:
|
|
|
102
102
|
- A custom domain (`your-company.com`).
|
|
103
103
|
- A local dev backend.
|
|
104
104
|
|
|
105
|
+
### `userToken`
|
|
106
|
+
|
|
107
|
+
`string | () => string | Promise<string>` · default: none (anonymous)
|
|
108
|
+
|
|
109
|
+
Signs the visitor in as your logged-in user: a JWT your server signs with the deployment's secret key, or a function
|
|
110
|
+
returning a fresh one. Their conversations then follow them to any device, and the AI gets their name and email as
|
|
111
|
+
verified facts. Runtime-only: not an attribute or `data-*` option, so the token stays out of the page's markup. See
|
|
112
|
+
[Security → Verified users](./security-privacy.md#verified-users-usertoken) for signing it.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
init({ publicKey: 'agent_pk_...', aiAgentDeploymentId: '01900000-0000-7000-8000-000000000000', userToken: () => fetch('/api/help-ai-token').then((res) => res.text()) });
|
|
116
|
+
```
|
|
117
|
+
|
|
105
118
|
### `userContext`
|
|
106
119
|
|
|
107
120
|
`object | undefined`
|
package/docs/frameworks.md
CHANGED
|
@@ -97,6 +97,9 @@ function PricingHelp() {
|
|
|
97
97
|
- **One import path.** The kit carries the whole widget API (`getInstance`, `hook`, the types), so import everything
|
|
98
98
|
from `@helpai/elements/react`; the package's other entries are separate copies with their own widgets.
|
|
99
99
|
- **Two widgets** on one page: give each `<HelpAI widgetId='support' … />` and read it with `useHelpAI('support')`.
|
|
100
|
+
- **Signed-in users:** pass `userToken`, a function that fetches the token your server signs
|
|
101
|
+
([Verified users](./security-privacy.md#verified-users-usertoken)). Keep it stable for one user (a module function, or
|
|
102
|
+
`useCallback` keyed on your user id): a different function signs in afresh, and dropping it signs out.
|
|
100
103
|
|
|
101
104
|
The kit bundles the widget and imports only React from your app, so you don't need Preact installed.
|
|
102
105
|
|
package/docs/security-privacy.md
CHANGED
|
@@ -340,7 +340,8 @@ the pinned version URL (`/v1.2.0/`) supports SRI — the floating URL
|
|
|
340
340
|
## Authentication
|
|
341
341
|
|
|
342
342
|
Browser access is scoped by `aiAgentDeploymentId`; a `publicKey` adds
|
|
343
|
-
workspace authorization.
|
|
343
|
+
workspace authorization. Visitors are anonymous unless your server signs a
|
|
344
|
+
[user token](#verified-users-usertoken) for your logged-in user.
|
|
344
345
|
|
|
345
346
|
### public key (default)
|
|
346
347
|
|
|
@@ -365,6 +366,64 @@ What your public key does NOT grant:
|
|
|
365
366
|
Omit `publicKey` but keep `aiAgentDeploymentId`; the widget connects to
|
|
366
367
|
that public deployment as a guest without an auth header.
|
|
367
368
|
|
|
369
|
+
### Verified users (`userToken`)
|
|
370
|
+
|
|
371
|
+
To show a logged-in user their own conversations on any device, and to let the AI rely on who they are, your
|
|
372
|
+
server signs a short-lived JWT for them with the deployment's **secret key** (on the deployment's Install page;
|
|
373
|
+
never put it in the browser):
|
|
374
|
+
|
|
375
|
+
| Claim | Required | What it is |
|
|
376
|
+
| ------- | -------- | ---------------------------------------------------------- |
|
|
377
|
+
| `sub` | yes | Your own id for the user (a string, up to 255 characters) |
|
|
378
|
+
| `exp` | yes | Expiry, in seconds since the epoch; keep it short (1 hour) |
|
|
379
|
+
| `name` | no | Their name, given to the AI as a verified fact |
|
|
380
|
+
| `email` | no | Their email, given to the AI as a verified fact |
|
|
381
|
+
|
|
382
|
+
Sign it with HS256:
|
|
383
|
+
|
|
384
|
+
```js
|
|
385
|
+
// Node (jose)
|
|
386
|
+
import { SignJWT } from 'jose';
|
|
387
|
+
|
|
388
|
+
const secret = new TextEncoder().encode(process.env.HELPAI_SECRET_KEY);
|
|
389
|
+
const userToken = await new SignJWT({ name: user.name, email: user.email }).setProtectedHeader({ alg: 'HS256' }).setSubject(String(user.id)).setExpirationTime('1h').sign(secret);
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
```python
|
|
393
|
+
# Python (PyJWT)
|
|
394
|
+
import os, time, jwt
|
|
395
|
+
|
|
396
|
+
user_token = jwt.encode({"sub": str(user.id), "exp": int(time.time()) + 3600, "name": user.name, "email": user.email}, os.environ["HELPAI_SECRET_KEY"], algorithm="HS256")
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
```php
|
|
400
|
+
// PHP (firebase/php-jwt)
|
|
401
|
+
use Firebase\JWT\JWT;
|
|
402
|
+
|
|
403
|
+
$userToken = JWT::encode(['sub' => (string) $user->id, 'exp' => time() + 3600, 'name' => $user->name, 'email' => $user->email], getenv('HELPAI_SECRET_KEY'), 'HS256');
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Serve it from an endpoint only your signed-in user can reach, and hand the widget a function that fetches it:
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
const userToken = () => fetch('/api/help-ai-token').then((res) => res.text());
|
|
410
|
+
|
|
411
|
+
init({ publicKey: 'agent_pk_...', aiAgentDeploymentId: '01900000-0000-7000-8000-000000000000', userToken }); // signed in at load
|
|
412
|
+
chat.login(userToken); // or after your sign-in (`HelpAI('login', userToken)`, `<HelpAI userToken={userToken} />`)
|
|
413
|
+
chat.reset(); // on sign-out (`HelpAI('reset')`)
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
- The widget sends the token only to the agent API, as the `x-user-token` header. The function is called when a token
|
|
417
|
+
is first needed and again when the server answers `401 USER_TOKEN_INVALID` (expired or rejected); the request is
|
|
418
|
+
then sent once more. A fixed string can't be refreshed, so an expired one fails until you call `login()` again.
|
|
419
|
+
- A token the server can't verify is refused; it never falls back to an anonymous visitor.
|
|
420
|
+
- Signing in moves the visitor's conversations on that browser to the user. From then on they reach them on any device
|
|
421
|
+
where they're signed in, and nobody else does, the signed-out browser included.
|
|
422
|
+
- Signing out (`reset()`, or dropping the token) or switching to another user starts over as a new visitor: nothing of
|
|
423
|
+
the previous user stays in the browser.
|
|
424
|
+
- Keep the function's identity stable for one user (a module function, or `useCallback` keyed on your user id): a
|
|
425
|
+
different function counts as a different user.
|
|
426
|
+
|
|
368
427
|
### user / page context is NOT auth
|
|
369
428
|
|
|
370
429
|
```ts
|
|
@@ -406,13 +465,13 @@ flowchart TB
|
|
|
406
465
|
direction TB
|
|
407
466
|
B1["Authenticates the HOST's agent deployment<br/>(NOT the end user)"]
|
|
408
467
|
B2["Treats userContext / pageContext as<br/>informational + untrusted"]
|
|
409
|
-
B3["Never registers
|
|
468
|
+
B3["Never registers end users; verifies a signed userToken when the host sends one"]
|
|
410
469
|
end
|
|
411
470
|
|
|
412
471
|
Host -->|"context (untrusted)"| Widget
|
|
413
472
|
Widget -->|"HTTPS/TLS + headers + context field"| Backend
|
|
414
473
|
|
|
415
|
-
note["publicKey + aiAgentDeploymentId auth the host's agent
|
|
474
|
+
note["publicKey + aiAgentDeploymentId auth the host's agent; only a userToken signed by the host's server identifies the end user."]
|
|
416
475
|
Backend -.-> note
|
|
417
476
|
```
|
|
418
477
|
|
|
@@ -430,6 +489,8 @@ and anyone can base64url-decode it. Never put a secret in context.
|
|
|
430
489
|
|
|
431
490
|
- **public keys** — rotate from the dashboard. Old keys are deactivated
|
|
432
491
|
instantly; update your embeds.
|
|
492
|
+
- **secret key** — user tokens signed with a replaced secret key stop verifying, so every verified user is signed out
|
|
493
|
+
until your server signs new ones with the new key.
|
|
433
494
|
|
|
434
495
|
---
|
|
435
496
|
|