@burdenoff/website-sdk 2026.1028.1 → 2026.1031.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.
Files changed (52) hide show
  1. package/README.md +159 -1
  2. package/dist/avatar-live/index.d.mts +11 -0
  3. package/dist/avatar-live/index.d.ts +11 -0
  4. package/dist/avatar-live/index.js +120 -0
  5. package/dist/avatar-live/index.js.map +1 -0
  6. package/dist/avatar-live/index.mjs +118 -0
  7. package/dist/avatar-live/index.mjs.map +1 -0
  8. package/dist/avatar-live-view/index.d.mts +42 -0
  9. package/dist/avatar-live-view/index.d.ts +42 -0
  10. package/dist/avatar-live-view/index.js +1422 -0
  11. package/dist/avatar-live-view/index.js.map +1 -0
  12. package/dist/avatar-live-view/index.mjs +1420 -0
  13. package/dist/avatar-live-view/index.mjs.map +1 -0
  14. package/dist/components/contact.js +9 -3
  15. package/dist/components/contact.js.map +1 -1
  16. package/dist/components/contact.mjs +9 -3
  17. package/dist/components/contact.mjs.map +1 -1
  18. package/dist/components/explore.d.mts +2 -2
  19. package/dist/components/explore.d.ts +2 -2
  20. package/dist/components/explore.js +11 -4
  21. package/dist/components/explore.js.map +1 -1
  22. package/dist/components/explore.mjs +11 -4
  23. package/dist/components/explore.mjs.map +1 -1
  24. package/dist/components/partners.js +9 -3
  25. package/dist/components/partners.js.map +1 -1
  26. package/dist/components/partners.mjs +9 -3
  27. package/dist/components/partners.mjs.map +1 -1
  28. package/dist/{explore-BEgq1_0O.d.mts → explore-DUTNYUOm.d.mts} +1 -1
  29. package/dist/{explore-CHiP9u-4.d.ts → explore-DjQE7Xia.d.ts} +1 -1
  30. package/dist/explore-avatar-live-config-B171o1Yo.d.ts +283 -0
  31. package/dist/explore-avatar-live-config-BGsGwbcq.d.mts +283 -0
  32. package/dist/{explore-types-_9UJu6EA.d.mts → explore-types-Bb2Ih3d8.d.mts} +1 -1
  33. package/dist/{explore-types-_9UJu6EA.d.ts → explore-types-Bb2Ih3d8.d.ts} +1 -1
  34. package/dist/hooks/index.d.mts +3 -2
  35. package/dist/hooks/index.d.ts +3 -2
  36. package/dist/hooks/index.js +6 -1
  37. package/dist/hooks/index.js.map +1 -1
  38. package/dist/hooks/index.mjs +6 -1
  39. package/dist/hooks/index.mjs.map +1 -1
  40. package/dist/index.d.mts +16 -253
  41. package/dist/index.d.ts +16 -253
  42. package/dist/index.js +225 -41
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +225 -41
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/types-CndbmBK-.d.mts +68 -0
  47. package/dist/types-CndbmBK-.d.ts +68 -0
  48. package/dist/{use-progressive-reveal-C0hkdu_i.d.ts → use-explore-chat-DunjG-3p.d.ts} +10 -36
  49. package/dist/{use-progressive-reveal-BFPWbEXy.d.mts → use-explore-chat-zRuoAin6.d.mts} +10 -36
  50. package/dist/use-progressive-reveal-ppicEgzZ.d.mts +35 -0
  51. package/dist/use-progressive-reveal-ppicEgzZ.d.ts +35 -0
  52. package/package.json +15 -3
@@ -0,0 +1,68 @@
1
+ /**
2
+ * BOFF-9797. The shapes shared by the site-wide assistant panel (the package root) and the live avatar's sub-path
3
+ * (`@burdenoff/website-sdk/avatar-live`).
4
+ *
5
+ * Types only, on purpose: the root imports this file for its types and nothing else, so the root bundle never carries
6
+ * any of the sub-path's code or its media library. The panel reaches the sub-path only through the loader its host
7
+ * passes in (`live.load`), and only after the visitor has agreed to start.
8
+ */
9
+ /** What the receive-only room tells the panel. */
10
+ type ReceiveOnlyEvent =
11
+ /** One of the speaker's tracks (the avatar worker's video or audio) is subscribed and attached. */
12
+ {
13
+ type: "speaker-track";
14
+ kind: "video" | "audio";
15
+ }
16
+ /** The avatar worker left the room: the session is over on the server's side. */
17
+ | {
18
+ type: "speaker-left";
19
+ }
20
+ /**
21
+ * Whether the browser is holding back sound or video until the visitor taps (Safari and iOS, mostly). While `true`,
22
+ * the panel offers "Tap to turn on sound", which calls `enablePlayback` from that tap.
23
+ */
24
+ | {
25
+ type: "playback-blocked";
26
+ blocked: boolean;
27
+ }
28
+ /**
29
+ * The room connection closed without the panel asking. `byServer` when the server closed it (the room was deleted
30
+ * or closed, or this viewer removed); otherwise the connection was lost.
31
+ */
32
+ | {
33
+ type: "disconnected";
34
+ byServer: boolean;
35
+ };
36
+ interface ReceiveOnlyJoinOptions {
37
+ /** The room server: `join.livekitUrl` from the create answer. Only a `wss:` URL is accepted. */
38
+ url: string;
39
+ /** `join.participantToken` from the create answer: subscribe-only and short-lived. Never logged. */
40
+ token: string;
41
+ /** `join.workerIdentity` from the create answer: the one participant whose video and audio are subscribed. */
42
+ workerIdentity: string;
43
+ /** Where the speaker's video plays. */
44
+ video: HTMLVideoElement;
45
+ /** Where the speaker's voice plays. */
46
+ audio: HTMLAudioElement;
47
+ /** Called for every {@link ReceiveOnlyEvent}. */
48
+ onEvent: (event: ReceiveOnlyEvent) => void;
49
+ }
50
+ /** A joined room. */
51
+ interface ReceiveOnlySession {
52
+ /**
53
+ * Resume what the browser held back (`playback-blocked`). Call it from the visitor's tap or click: browsers allow
54
+ * sound only from a gesture.
55
+ */
56
+ enablePlayback: () => Promise<void>;
57
+ /** Leave the room and detach the speaker's tracks. Safe to call more than once. */
58
+ leave: () => Promise<void>;
59
+ }
60
+ /**
61
+ * What `live.load` resolves to: the `@burdenoff/website-sdk/avatar-live` module, whose `joinReceiveOnly` joins a room
62
+ * that can only watch and listen.
63
+ */
64
+ interface AvatarLiveModule {
65
+ joinReceiveOnly: (options: ReceiveOnlyJoinOptions) => Promise<ReceiveOnlySession>;
66
+ }
67
+
68
+ export type { AvatarLiveModule as A, ReceiveOnlyJoinOptions as R, ReceiveOnlySession as a, ReceiveOnlyEvent as b };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * BOFF-9797. The shapes shared by the site-wide assistant panel (the package root) and the live avatar's sub-path
3
+ * (`@burdenoff/website-sdk/avatar-live`).
4
+ *
5
+ * Types only, on purpose: the root imports this file for its types and nothing else, so the root bundle never carries
6
+ * any of the sub-path's code or its media library. The panel reaches the sub-path only through the loader its host
7
+ * passes in (`live.load`), and only after the visitor has agreed to start.
8
+ */
9
+ /** What the receive-only room tells the panel. */
10
+ type ReceiveOnlyEvent =
11
+ /** One of the speaker's tracks (the avatar worker's video or audio) is subscribed and attached. */
12
+ {
13
+ type: "speaker-track";
14
+ kind: "video" | "audio";
15
+ }
16
+ /** The avatar worker left the room: the session is over on the server's side. */
17
+ | {
18
+ type: "speaker-left";
19
+ }
20
+ /**
21
+ * Whether the browser is holding back sound or video until the visitor taps (Safari and iOS, mostly). While `true`,
22
+ * the panel offers "Tap to turn on sound", which calls `enablePlayback` from that tap.
23
+ */
24
+ | {
25
+ type: "playback-blocked";
26
+ blocked: boolean;
27
+ }
28
+ /**
29
+ * The room connection closed without the panel asking. `byServer` when the server closed it (the room was deleted
30
+ * or closed, or this viewer removed); otherwise the connection was lost.
31
+ */
32
+ | {
33
+ type: "disconnected";
34
+ byServer: boolean;
35
+ };
36
+ interface ReceiveOnlyJoinOptions {
37
+ /** The room server: `join.livekitUrl` from the create answer. Only a `wss:` URL is accepted. */
38
+ url: string;
39
+ /** `join.participantToken` from the create answer: subscribe-only and short-lived. Never logged. */
40
+ token: string;
41
+ /** `join.workerIdentity` from the create answer: the one participant whose video and audio are subscribed. */
42
+ workerIdentity: string;
43
+ /** Where the speaker's video plays. */
44
+ video: HTMLVideoElement;
45
+ /** Where the speaker's voice plays. */
46
+ audio: HTMLAudioElement;
47
+ /** Called for every {@link ReceiveOnlyEvent}. */
48
+ onEvent: (event: ReceiveOnlyEvent) => void;
49
+ }
50
+ /** A joined room. */
51
+ interface ReceiveOnlySession {
52
+ /**
53
+ * Resume what the browser held back (`playback-blocked`). Call it from the visitor's tap or click: browsers allow
54
+ * sound only from a gesture.
55
+ */
56
+ enablePlayback: () => Promise<void>;
57
+ /** Leave the room and detach the speaker's tracks. Safe to call more than once. */
58
+ leave: () => Promise<void>;
59
+ }
60
+ /**
61
+ * What `live.load` resolves to: the `@burdenoff/website-sdk/avatar-live` module, whose `joinReceiveOnly` joins a room
62
+ * that can only watch and listen.
63
+ */
64
+ interface AvatarLiveModule {
65
+ joinReceiveOnly: (options: ReceiveOnlyJoinOptions) => Promise<ReceiveOnlySession>;
66
+ }
67
+
68
+ export type { AvatarLiveModule as A, ReceiveOnlyJoinOptions as R, ReceiveOnlySession as a, ReceiveOnlyEvent as b };
@@ -1,4 +1,4 @@
1
- import { b as ExploreCatalog, c as ExploreMessage, d as ExploreFeedbackRating, e as ExploreFeedbackReason, f as ExploreLimits } from './explore-types-_9UJu6EA.js';
1
+ import { E as ExploreCatalog, a as ExploreMessage, b as ExploreFeedbackRating, c as ExploreFeedbackReason, d as ExploreLimits } from './explore-types-Bb2Ih3d8.js';
2
2
 
3
3
  /** What travels on the wire — mirrors `ExploreAttachmentInput`. */
4
4
  interface ExploreAttachmentPayload {
@@ -207,6 +207,14 @@ interface UseExploreChatResult {
207
207
  */
208
208
  isSharedView: boolean;
209
209
  canSend: boolean;
210
+ /**
211
+ * BOFF-9797. This visitor's conversation token as it stands at the call, or null (no conversation yet, or a
212
+ * read-only shared view, whose `?c=` secret is not a conversation token).
213
+ *
214
+ * A function rather than a field on purpose: nothing renders, serialises or logs it with the rest of this object.
215
+ * The live avatar reads it once, into the body of its create request, which is the only place it goes.
216
+ */
217
+ getConversationToken: () => string | null;
210
218
  }
211
219
  /** Fallback limits, mirroring the server defaults in CONTRACT.md §3. */
212
220
  declare const FALLBACK_EXPLORE_LIMITS: ExploreLimits;
@@ -235,38 +243,4 @@ interface ArchivedExploreConversation {
235
243
  }
236
244
  declare function useExploreChat(options?: UseExploreChatOptions): UseExploreChatResult;
237
245
 
238
- /**
239
- * Stop whatever this SDK is reading aloud, from outside a component.
240
- *
241
- * A no-op when nothing of ours is speaking — deliberately, rather than calling
242
- * `speechSynthesis.cancel()` unconditionally, which would also silence a host page that is
243
- * using the same queue for its own reasons.
244
- */
245
- declare function stopSpeaking(): void;
246
- interface UseSpeechOutputOptions {
247
- /** BCP-47 tag to read in. Omit to let the platform pick its default voice. */
248
- lang?: string;
249
- }
250
- interface UseSpeechOutputResult {
251
- /**
252
- * False when this browser has no synthesiser, or has one that was asked to speak and did
253
- * not. Render no control at all when it is false — see the note at the top of the file.
254
- */
255
- supported: boolean;
256
- speaking: boolean;
257
- speak: (text: string) => void;
258
- stop: () => void;
259
- toggle: (text: string) => void;
260
- }
261
- declare function useSpeechOutput({ lang, }?: UseSpeechOutputOptions): UseSpeechOutputResult;
262
-
263
- /**
264
- * The part of `text` that is currently on screen.
265
- *
266
- * @param text everything that has arrived so far — `content` once the turn completes,
267
- * `partialContent` while it runs.
268
- * @param settled true once the turn is COMPLETED or FAILED and `text` will not grow again.
269
- */
270
- declare function useProgressiveReveal(text: string, settled: boolean): string;
271
-
272
- export { DEFAULT_EXPLORE_EXAMPLE_PROMPTS as D, type ExploreChatError as E, FALLBACK_EXPLORE_LIMITS as F, type StagedAttachment as S, type UseExploreChatOptions as U, type ExploreChatErrorKind as a, type ExploreChatPhase as b, type ExploreEscalateOutcome as c, type ExploreEscalateResult as d, type UseExploreChatResult as e, type UseSpeechOutputOptions as f, type UseSpeechOutputResult as g, classifyExploreError as h, useProgressiveReveal as i, useSpeechOutput as j, stopSpeaking as s, useExploreChat as u };
246
+ export { DEFAULT_EXPLORE_EXAMPLE_PROMPTS as D, type ExploreChatError as E, FALLBACK_EXPLORE_LIMITS as F, type StagedAttachment as S, type UseExploreChatOptions as U, type ExploreChatErrorKind as a, type ExploreChatPhase as b, type ExploreEscalateOutcome as c, type ExploreEscalateResult as d, type UseExploreChatResult as e, classifyExploreError as f, useExploreChat as u };
@@ -1,4 +1,4 @@
1
- import { b as ExploreCatalog, c as ExploreMessage, d as ExploreFeedbackRating, e as ExploreFeedbackReason, f as ExploreLimits } from './explore-types-_9UJu6EA.mjs';
1
+ import { E as ExploreCatalog, a as ExploreMessage, b as ExploreFeedbackRating, c as ExploreFeedbackReason, d as ExploreLimits } from './explore-types-Bb2Ih3d8.mjs';
2
2
 
3
3
  /** What travels on the wire — mirrors `ExploreAttachmentInput`. */
4
4
  interface ExploreAttachmentPayload {
@@ -207,6 +207,14 @@ interface UseExploreChatResult {
207
207
  */
208
208
  isSharedView: boolean;
209
209
  canSend: boolean;
210
+ /**
211
+ * BOFF-9797. This visitor's conversation token as it stands at the call, or null (no conversation yet, or a
212
+ * read-only shared view, whose `?c=` secret is not a conversation token).
213
+ *
214
+ * A function rather than a field on purpose: nothing renders, serialises or logs it with the rest of this object.
215
+ * The live avatar reads it once, into the body of its create request, which is the only place it goes.
216
+ */
217
+ getConversationToken: () => string | null;
210
218
  }
211
219
  /** Fallback limits, mirroring the server defaults in CONTRACT.md §3. */
212
220
  declare const FALLBACK_EXPLORE_LIMITS: ExploreLimits;
@@ -235,38 +243,4 @@ interface ArchivedExploreConversation {
235
243
  }
236
244
  declare function useExploreChat(options?: UseExploreChatOptions): UseExploreChatResult;
237
245
 
238
- /**
239
- * Stop whatever this SDK is reading aloud, from outside a component.
240
- *
241
- * A no-op when nothing of ours is speaking — deliberately, rather than calling
242
- * `speechSynthesis.cancel()` unconditionally, which would also silence a host page that is
243
- * using the same queue for its own reasons.
244
- */
245
- declare function stopSpeaking(): void;
246
- interface UseSpeechOutputOptions {
247
- /** BCP-47 tag to read in. Omit to let the platform pick its default voice. */
248
- lang?: string;
249
- }
250
- interface UseSpeechOutputResult {
251
- /**
252
- * False when this browser has no synthesiser, or has one that was asked to speak and did
253
- * not. Render no control at all when it is false — see the note at the top of the file.
254
- */
255
- supported: boolean;
256
- speaking: boolean;
257
- speak: (text: string) => void;
258
- stop: () => void;
259
- toggle: (text: string) => void;
260
- }
261
- declare function useSpeechOutput({ lang, }?: UseSpeechOutputOptions): UseSpeechOutputResult;
262
-
263
- /**
264
- * The part of `text` that is currently on screen.
265
- *
266
- * @param text everything that has arrived so far — `content` once the turn completes,
267
- * `partialContent` while it runs.
268
- * @param settled true once the turn is COMPLETED or FAILED and `text` will not grow again.
269
- */
270
- declare function useProgressiveReveal(text: string, settled: boolean): string;
271
-
272
- export { DEFAULT_EXPLORE_EXAMPLE_PROMPTS as D, type ExploreChatError as E, FALLBACK_EXPLORE_LIMITS as F, type StagedAttachment as S, type UseExploreChatOptions as U, type ExploreChatErrorKind as a, type ExploreChatPhase as b, type ExploreEscalateOutcome as c, type ExploreEscalateResult as d, type UseExploreChatResult as e, type UseSpeechOutputOptions as f, type UseSpeechOutputResult as g, classifyExploreError as h, useProgressiveReveal as i, useSpeechOutput as j, stopSpeaking as s, useExploreChat as u };
246
+ export { DEFAULT_EXPLORE_EXAMPLE_PROMPTS as D, type ExploreChatError as E, FALLBACK_EXPLORE_LIMITS as F, type StagedAttachment as S, type UseExploreChatOptions as U, type ExploreChatErrorKind as a, type ExploreChatPhase as b, type ExploreEscalateOutcome as c, type ExploreEscalateResult as d, type UseExploreChatResult as e, classifyExploreError as f, useExploreChat as u };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Stop whatever this SDK is reading aloud, from outside a component.
3
+ *
4
+ * A no-op when nothing of ours is speaking — deliberately, rather than calling
5
+ * `speechSynthesis.cancel()` unconditionally, which would also silence a host page that is
6
+ * using the same queue for its own reasons.
7
+ */
8
+ declare function stopSpeaking(): void;
9
+ interface UseSpeechOutputOptions {
10
+ /** BCP-47 tag to read in. Omit to let the platform pick its default voice. */
11
+ lang?: string;
12
+ }
13
+ interface UseSpeechOutputResult {
14
+ /**
15
+ * False when this browser has no synthesiser, or has one that was asked to speak and did
16
+ * not. Render no control at all when it is false — see the note at the top of the file.
17
+ */
18
+ supported: boolean;
19
+ speaking: boolean;
20
+ speak: (text: string) => void;
21
+ stop: () => void;
22
+ toggle: (text: string) => void;
23
+ }
24
+ declare function useSpeechOutput({ lang, }?: UseSpeechOutputOptions): UseSpeechOutputResult;
25
+
26
+ /**
27
+ * The part of `text` that is currently on screen.
28
+ *
29
+ * @param text everything that has arrived so far — `content` once the turn completes,
30
+ * `partialContent` while it runs.
31
+ * @param settled true once the turn is COMPLETED or FAILED and `text` will not grow again.
32
+ */
33
+ declare function useProgressiveReveal(text: string, settled: boolean): string;
34
+
35
+ export { type UseSpeechOutputOptions as U, type UseSpeechOutputResult as a, useSpeechOutput as b, stopSpeaking as s, useProgressiveReveal as u };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Stop whatever this SDK is reading aloud, from outside a component.
3
+ *
4
+ * A no-op when nothing of ours is speaking — deliberately, rather than calling
5
+ * `speechSynthesis.cancel()` unconditionally, which would also silence a host page that is
6
+ * using the same queue for its own reasons.
7
+ */
8
+ declare function stopSpeaking(): void;
9
+ interface UseSpeechOutputOptions {
10
+ /** BCP-47 tag to read in. Omit to let the platform pick its default voice. */
11
+ lang?: string;
12
+ }
13
+ interface UseSpeechOutputResult {
14
+ /**
15
+ * False when this browser has no synthesiser, or has one that was asked to speak and did
16
+ * not. Render no control at all when it is false — see the note at the top of the file.
17
+ */
18
+ supported: boolean;
19
+ speaking: boolean;
20
+ speak: (text: string) => void;
21
+ stop: () => void;
22
+ toggle: (text: string) => void;
23
+ }
24
+ declare function useSpeechOutput({ lang, }?: UseSpeechOutputOptions): UseSpeechOutputResult;
25
+
26
+ /**
27
+ * The part of `text` that is currently on screen.
28
+ *
29
+ * @param text everything that has arrived so far — `content` once the turn completes,
30
+ * `partialContent` while it runs.
31
+ * @param settled true once the turn is COMPLETED or FAILED and `text` will not grow again.
32
+ */
33
+ declare function useProgressiveReveal(text: string, settled: boolean): string;
34
+
35
+ export { type UseSpeechOutputOptions as U, type UseSpeechOutputResult as a, useSpeechOutput as b, stopSpeaking as s, useProgressiveReveal as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/website-sdk",
3
- "version": "2026.1028.1",
3
+ "version": "2026.1031.1",
4
4
  "description": "Shared SDK for Burdenoff product websites - reusable React components, utilities, and configurations",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -56,6 +56,11 @@
56
56
  "import": "./dist/store/index.mjs",
57
57
  "require": "./dist/store/index.js"
58
58
  },
59
+ "./avatar-live": {
60
+ "types": "./dist/avatar-live/index.d.ts",
61
+ "import": "./dist/avatar-live/index.mjs",
62
+ "require": "./dist/avatar-live/index.js"
63
+ },
59
64
  "./comparison": {
60
65
  "types": "./dist/comparison/index.d.ts",
61
66
  "import": "./dist/comparison/index.mjs",
@@ -68,7 +73,7 @@
68
73
  "LICENSE"
69
74
  ],
70
75
  "scripts": {
71
- "build": "tsup",
76
+ "build": "tsup && node scripts/validate-avatar-live.mjs",
72
77
  "dev": "tsup --watch",
73
78
  "lint": "eslint . --ext .ts,.tsx",
74
79
  "lint:ci": "eslint src --max-warnings 0",
@@ -120,7 +125,13 @@
120
125
  "react-hook-form": ">=7.0.0",
121
126
  "sonner": ">=1.0.0",
122
127
  "tailwind-merge": ">=2.0.0",
123
- "zod": ">=3.0.0"
128
+ "zod": ">=3.0.0",
129
+ "livekit-client": "^2.22.3"
130
+ },
131
+ "peerDependenciesMeta": {
132
+ "livekit-client": {
133
+ "optional": true
134
+ }
124
135
  },
125
136
  "dependencies": {
126
137
  "isomorphic-dompurify": "^2.36.0",
@@ -152,6 +163,7 @@
152
163
  "eslint-plugin-react-hooks": "^5.2.0",
153
164
  "globals": "^16.5.0",
154
165
  "jsdom": "^24.1.3",
166
+ "livekit-client": "2.22.3",
155
167
  "lucide-react": "^0.462.0",
156
168
  "prettier": "^3.9.6",
157
169
  "react": "^18.3.1",