@burdenoff/website-sdk 2026.1027.1 → 2026.1029.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 (60) hide show
  1. package/README.md +186 -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/comparison/index.d.mts +83 -0
  15. package/dist/comparison/index.d.ts +83 -0
  16. package/dist/comparison/index.js +116 -0
  17. package/dist/comparison/index.js.map +1 -0
  18. package/dist/comparison/index.mjs +109 -0
  19. package/dist/comparison/index.mjs.map +1 -0
  20. package/dist/components/explore.d.mts +2 -2
  21. package/dist/components/explore.d.ts +2 -2
  22. package/dist/components/explore.js +11 -4
  23. package/dist/components/explore.js.map +1 -1
  24. package/dist/components/explore.mjs +11 -4
  25. package/dist/components/explore.mjs.map +1 -1
  26. package/dist/components/partners.js.map +1 -1
  27. package/dist/components/partners.mjs.map +1 -1
  28. package/dist/content/index.d.mts +1 -1
  29. package/dist/content/index.d.ts +1 -1
  30. package/dist/content/index.js +32 -4
  31. package/dist/content/index.js.map +1 -1
  32. package/dist/content/index.mjs +32 -5
  33. package/dist/content/index.mjs.map +1 -1
  34. package/dist/{explore-BEgq1_0O.d.mts → explore-DUTNYUOm.d.mts} +1 -1
  35. package/dist/{explore-CHiP9u-4.d.ts → explore-DjQE7Xia.d.ts} +1 -1
  36. package/dist/explore-avatar-live-config-B171o1Yo.d.ts +283 -0
  37. package/dist/explore-avatar-live-config-BGsGwbcq.d.mts +283 -0
  38. package/dist/{explore-types-_9UJu6EA.d.mts → explore-types-Bb2Ih3d8.d.mts} +1 -1
  39. package/dist/{explore-types-_9UJu6EA.d.ts → explore-types-Bb2Ih3d8.d.ts} +1 -1
  40. package/dist/hooks/index.d.mts +3 -2
  41. package/dist/hooks/index.d.ts +3 -2
  42. package/dist/hooks/index.js +6 -1
  43. package/dist/hooks/index.js.map +1 -1
  44. package/dist/hooks/index.mjs +6 -1
  45. package/dist/hooks/index.mjs.map +1 -1
  46. package/dist/{index-CB0Uw1xD.d.ts → index-87BLB-Hj.d.ts} +26 -1
  47. package/dist/{index-Ctws7kGs.d.mts → index-Chw0pDXS.d.mts} +26 -1
  48. package/dist/index.d.mts +19 -255
  49. package/dist/index.d.ts +19 -255
  50. package/dist/index.js +358 -40
  51. package/dist/index.js.map +1 -1
  52. package/dist/index.mjs +352 -41
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/types-CndbmBK-.d.mts +68 -0
  55. package/dist/types-CndbmBK-.d.ts +68 -0
  56. package/dist/{use-progressive-reveal-C0hkdu_i.d.ts → use-explore-chat-DunjG-3p.d.ts} +10 -36
  57. package/dist/{use-progressive-reveal-BFPWbEXy.d.mts → use-explore-chat-zRuoAin6.d.mts} +10 -36
  58. package/dist/use-progressive-reveal-ppicEgzZ.d.mts +35 -0
  59. package/dist/use-progressive-reveal-ppicEgzZ.d.ts +35 -0
  60. package/package.json +20 -3
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { E as ExploreProduct, a as ExploreReference } from './explore-types-_9UJu6EA.mjs';
2
+ import { e as ExploreProduct, f as ExploreReference } from './explore-types-Bb2Ih3d8.mjs';
3
3
  import { Components } from 'react-markdown';
4
4
 
5
5
  /** The words the player needs. `AnswerRendererStrings`, and so `ExploreStrings`, carry them. */
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { E as ExploreProduct, a as ExploreReference } from './explore-types-_9UJu6EA.js';
2
+ import { e as ExploreProduct, f as ExploreReference } from './explore-types-Bb2Ih3d8.js';
3
3
  import { Components } from 'react-markdown';
4
4
 
5
5
  /** The words the player needs. `AnswerRendererStrings`, and so `ExploreStrings`, carry them. */
@@ -0,0 +1,283 @@
1
+ import { A as AvatarLiveModule } from './types-CndbmBK-.js';
2
+ import { e as UseExploreChatResult } from './use-explore-chat-DunjG-3p.js';
3
+
4
+ /**
5
+ * Localisation for the `/explore` chat surface.
6
+ *
7
+ * ## Why this is self-contained
8
+ *
9
+ * The app shells localise through `useI18n()` from `@burdenoff/fe-libs`, which is mounted by
10
+ * `AppShellProvider` and fetches translations at runtime from `global-i18n-svc`. None of that
11
+ * exists on a marketing website: no provider, no dictionary, no locale routing, and no
12
+ * translation files in any of the 39 site repos. Pulling that machinery in would mean adding
13
+ * a runtime translation fetch to a static prerendered page — a network round-trip in front of
14
+ * the first paint, on pages whose whole point is that they are prerendered.
15
+ *
16
+ * So the strings are bundled. There are few enough of them that the cost is bytes rather than
17
+ * a request, and a prerendered page stays fully rendered.
18
+ *
19
+ * ## Locales
20
+ *
21
+ * The six the products actually ship, taken from `{product}-app/src/components/chrome/
22
+ * languages.ts` (FALLBACK_LANGUAGES). Deliberately NOT the wider `Locale` union in fe-libs,
23
+ * which also lists fr/de/ja that no product ships, and deliberately not the backend's BCP-47
24
+ * set, which has fr/de/ja but lacks ta and ar.
25
+ */
26
+ declare const EXPLORE_LOCALES: readonly ["en", "zh", "hi", "es", "ar", "ta"];
27
+ type ExploreLocale = (typeof EXPLORE_LOCALES)[number];
28
+ interface ExploreStrings {
29
+ badge: string;
30
+ welcomeTitle: string;
31
+ welcomeBody: string;
32
+ /**
33
+ * BOFF-9796: the welcome body of ONE product's own assistant (`scope="product"`) when the host passes none. Takes
34
+ * `{product}`. Problem-first like `welcomeBody`, and unlike the catalog's copy for a product site it offers nothing
35
+ * beyond that product: no "compare it with anything else we build".
36
+ */
37
+ welcomeBodyProduct: string;
38
+ /**
39
+ * BOFF-9796: the product scope's welcome body when no product name is known (a slug no catalog lists, and no
40
+ * `productName`). Like `welcomeBodyProduct` without the name, so it never falls back to the portfolio's invitation
41
+ * to "ask about a specific product or compare a few".
42
+ */
43
+ welcomeBodyScoped: string;
44
+ tryAsking: string;
45
+ focusProduct: string;
46
+ allProducts: string;
47
+ showAll: string;
48
+ showLess: string;
49
+ sources: string;
50
+ nextYouCouldAsk: string;
51
+ placeholder: string;
52
+ placeholderProduct: string;
53
+ /**
54
+ * BOFF-9796: the composer's placeholder on ONE product's own assistant (`scope="product"`). Takes `{product}`.
55
+ * Short on purpose, and the one thing about the composer that the product scope changes: the field is the published
56
+ * one, one line tall on a phone, where a placeholder that wraps loses its second line. `placeholderProduct`
57
+ * ("Describe a problem, or ask about Healthy Bowl…") wraps there at 390px and under; the English "Ask about Healthy
58
+ * Bowl…" fits one line at 320px and wider. Spanish and Tamil, the longest here, may still wrap at 320px and
59
+ * narrower: a follow-up (HealthyBowl, the site this was made for, is English-only). The welcome above the composer
60
+ * already asks for the problem.
61
+ */
62
+ placeholderScoped: string;
63
+ send: string;
64
+ stop: string;
65
+ newChat: string;
66
+ history: string;
67
+ clearHistory: string;
68
+ share: string;
69
+ copied: string;
70
+ copying: string;
71
+ shareUnavailable: string;
72
+ disclaimer: string;
73
+ disclaimerShort: string;
74
+ dictate: string;
75
+ stopDictating: string;
76
+ attach: string;
77
+ attachHint: string;
78
+ removeAttachment: string;
79
+ attachmentNameOnly: string;
80
+ attachmentTooLarge: string;
81
+ attachmentTooMany: string;
82
+ noAnswer: string;
83
+ answerDidNotArrive: string;
84
+ /**
85
+ * BOFF-9796: what a turn that ran out of searches (`TOOL_BUDGET`) says on ONE product's own assistant
86
+ * (`scope="product"`). The default message asks for "two or three specific products", an invitation to other
87
+ * products that a product's own assistant must not make; here the narrowing offered is to one part of the question.
88
+ */
89
+ toolBudgetScoped: string;
90
+ askHuman: string;
91
+ feedbackPrompt: string;
92
+ feedbackHelpful: string;
93
+ feedbackNotHelpful: string;
94
+ feedbackReasonTitle: string;
95
+ feedbackReasonInaccurate: string;
96
+ feedbackReasonIncomplete: string;
97
+ feedbackReasonOffTopic: string;
98
+ feedbackReasonHardToFollow: string;
99
+ feedbackReasonOther: string;
100
+ feedbackCommentPlaceholder: string;
101
+ feedbackSend: string;
102
+ feedbackDismiss: string;
103
+ feedbackThanks: string;
104
+ feedbackNotSent: string;
105
+ /**
106
+ * The trigger, in its two homes: `escalateOpen` is the quiet one under an answer we DID
107
+ * give, and the amber "we could not find this" banner reuses `askHuman` so that sentence
108
+ * keeps reading as one sentence.
109
+ */
110
+ escalateOpen: string;
111
+ escalateTitle: string;
112
+ escalateBody: string;
113
+ escalateEmailLabel: string;
114
+ escalateEmailPlaceholder: string;
115
+ escalateNoteLabel: string;
116
+ escalateSubmit: string;
117
+ escalateSending: string;
118
+ escalateCancel: string;
119
+ /**
120
+ * Shown for BOTH the client's own pre-flight and the server's `INVALID_EMAIL`. The two
121
+ * disagree about what is deliverable and the server is right, but the visitor's next
122
+ * action is identical either way: check the address.
123
+ */
124
+ escalateInvalidEmail: string;
125
+ /**
126
+ * The success line. Takes `{email}` — and it is filled with the address the SERVER
127
+ * returned, not the one in the box, because on a repeat handover the reply goes to
128
+ * whichever address the first one used.
129
+ *
130
+ * Used for `created: false` as well: a visitor asking for help is not told "you already
131
+ * did that".
132
+ */
133
+ escalateSent: string;
134
+ escalateRateLimited: string;
135
+ escalateCaptcha: string;
136
+ escalateFailed: string;
137
+ prevSuggestion: string;
138
+ nextSuggestion: string;
139
+ /**
140
+ * The label every concept picture carries, wherever one is shown — inside an answer and on
141
+ * the welcome strip alike.
142
+ *
143
+ * These images are published mockups, so the page has to say so; it says it in ONE wording,
144
+ * because two phrasings for the same caveat read as two different caveats.
145
+ */
146
+ conceptIllustration: string;
147
+ /** Rail arrows on the concept strip — pointer devices only. */
148
+ conceptScrollPrev: string;
149
+ conceptScrollNext: string;
150
+ opensInNewTab: string;
151
+ /** Heading over the concept strip on the welcome screen. */
152
+ conceptStripTitle: string;
153
+ /** Accessible name of the strip itself. */
154
+ conceptStripLabel: string;
155
+ /** Accessible name of one card. Takes `{title}` and `{product}`. */
156
+ conceptAsk: string;
157
+ /**
158
+ * The question a card actually SENDS. Takes `{title}` and `{product}`.
159
+ *
160
+ * Localised because it becomes the visitor's own message in the transcript — an English
161
+ * sentence appearing above an Arabic answer would read as the page talking to itself.
162
+ */
163
+ conceptAskQuestion: string;
164
+ /** Label of the per-answer copy control, and its failure state. */
165
+ copyAnswer: string;
166
+ copyFailed: string;
167
+ /**
168
+ * Label of the per-answer read-aloud control, in its two states.
169
+ *
170
+ * A toggle, exactly like the composer's dictation button: one control whose label says
171
+ * what pressing it does NOW, never a second button that appears while it is speaking.
172
+ */
173
+ readAloud: string;
174
+ stopReading: string;
175
+ /**
176
+ * Accessible name of the scrollable box a table in an answer sits in.
177
+ *
178
+ * A scrollable region needs a name and a tab stop, or a keyboard visitor cannot reach the
179
+ * columns that are off the edge. The `<table>` inside it keeps its own semantics.
180
+ */
181
+ answerTable: string;
182
+ /**
183
+ * The product-video card in an answer (CONTRACT.md §7) and the player it opens.
184
+ *
185
+ * `productVideo` is the card's badge — the video counterpart of `conceptIllustration` —
186
+ * and names a video the answer gave no title. `productVideoTitle` names the video in this
187
+ * language and takes `{product}`: the harness always writes the line's text as the English
188
+ * "<Name> product video", so the card keeps only the name from it. `playVideo` is the
189
+ * card's accessible name and takes `{title}`, which is that name. The last four belong to
190
+ * the player: its Close button, the two states of its full-screen toggle, and the line
191
+ * shown in place of a video that cannot be played.
192
+ */
193
+ productVideo: string;
194
+ productVideoTitle: string;
195
+ playVideo: string;
196
+ closeVideo: string;
197
+ enterFullScreen: string;
198
+ exitFullScreen: string;
199
+ /**
200
+ * BOFF-9697: the site-wide assistant panel (`ExplorePanel`). The tab, view and avatar words are the ones the product
201
+ * apps' assistant already ships in all six locales (Chat, Avatar, Live avatar, Assistant views).
202
+ */
203
+ panelTitle: string;
204
+ /**
205
+ * BOFF-9796: the panel's title on one product's own assistant (`scope="product"`), "{product} assistant" in each
206
+ * language's own word order. Takes `{product}`. `panelTitle` stays the title wherever no product name is known.
207
+ */
208
+ panelTitleProduct: string;
209
+ panelViews: string;
210
+ tabChat: string;
211
+ tabAvatar: string;
212
+ closePanel: string;
213
+ liveAvatar: string;
214
+ avatarComingSoon: string;
215
+ continueInChat: string;
216
+ videoUnavailable: string;
217
+ /** Accessible name of the provenance row under an answer. */
218
+ groundedIn: string;
219
+ /** How many sources the answer cites. `sourceCountMany` takes `{count}`. */
220
+ sourceCountOne: string;
221
+ sourceCountMany: string;
222
+ /** What KIND of page a source is, inferred from its URL. */
223
+ sourceKindConcept: string;
224
+ sourceKindDocs: string;
225
+ sourceKindPricing: string;
226
+ sourceKindUseCase: string;
227
+ sourceKindPage: string;
228
+ /**
229
+ * The page's <title> and <meta description>.
230
+ *
231
+ * These are the surface a search result and a browser tab are built from, and they are
232
+ * the LAST place the old product-first framing survived: all 38 sites hard-coded
233
+ * "Explore Burdenoff products with AI" inline, so the tab announced our catalogue on a
234
+ * page that asks the visitor about their problem — and named the wrong brand on 37 of
235
+ * them. `seoTitle` carries no brand: PageHead appends "| {productName}" itself.
236
+ */
237
+ seoTitle: string;
238
+ seoDescription: string;
239
+ /** Used when the page belongs to a specific product's site. Takes `{product}`. */
240
+ seoDescriptionProduct: string;
241
+ /**
242
+ * BOFF-9796: the meta description of ONE product's own `/explore` (`scope="product"`). Takes `{product}`. Unlike
243
+ * `seoDescriptionProduct`, it promises nothing beyond that product: no "and every other product we build".
244
+ */
245
+ seoDescriptionScoped: string;
246
+ capabilities: [string, string, string];
247
+ prompts: string[];
248
+ }
249
+ declare function speechLocaleOf(locale: ExploreLocale): string;
250
+
251
+ /**
252
+ * BOFF-9797. The small part of the live avatar that the panel itself needs, whether or not it is ever opened: what a
253
+ * host's `avatar.live` is, whether the live avatar can run on this page at all, and where its requests go.
254
+ *
255
+ * Everything else (the view, its state machine, the requests, the words, the bot check) is a separate chunk that a
256
+ * site only downloads when its visitor first opens the Avatar view (see `explore-avatar-live.tsx`). That is why this
257
+ * file is separate and kept to a few lines: it is the only part of the live avatar in the package root for a site that
258
+ * does not pass `avatar.live`, and the part of it that decides, without loading anything, whether the chunk is wanted.
259
+ * Types only, plus plain functions: nothing here imports a component, a context or a string table.
260
+ */
261
+
262
+ /**
263
+ * BOFF-9797. A host's opt-in to the live avatar on its panel's Avatar tab. Every field is required; a config that is
264
+ * incomplete leaves the tab as it was (and a warning in the console).
265
+ */
266
+ interface ExplorePanelAvatarLive {
267
+ /** The site, as the live avatar service knows it: `healthybowl`. */
268
+ site: string;
269
+ /**
270
+ * Loads the live avatar's room module: `() => import('@burdenoff/website-sdk/avatar-live')`. Called only after the
271
+ * visitor presses Start on the consent card, never on page load or on opening the tab. That entry needs the
272
+ * package's optional peer dependency for media rooms (see the README).
273
+ */
274
+ load: () => Promise<AvatarLiveModule>;
275
+ /** The site's Cloudflare Turnstile site key, for the bot check that runs when the visitor presses Start. */
276
+ turnstileSiteKey: string;
277
+ /** The version of the suggested-question list the panel shows (its `examplePrompts`), such as `hb-en-1`. */
278
+ manifestVersion: string;
279
+ }
280
+ /** What the live avatar reads of the panel's conversation: the transcript, whether it is read-only, and the token. */
281
+ type AvatarConversation = Pick<UseExploreChatResult, "messages" | "isSharedView" | "getConversationToken">;
282
+
283
+ export { type AvatarConversation as A, type ExplorePanelAvatarLive as E, type ExploreLocale as a, EXPLORE_LOCALES as b, type ExploreStrings as c, speechLocaleOf as s };
@@ -0,0 +1,283 @@
1
+ import { A as AvatarLiveModule } from './types-CndbmBK-.mjs';
2
+ import { e as UseExploreChatResult } from './use-explore-chat-zRuoAin6.mjs';
3
+
4
+ /**
5
+ * Localisation for the `/explore` chat surface.
6
+ *
7
+ * ## Why this is self-contained
8
+ *
9
+ * The app shells localise through `useI18n()` from `@burdenoff/fe-libs`, which is mounted by
10
+ * `AppShellProvider` and fetches translations at runtime from `global-i18n-svc`. None of that
11
+ * exists on a marketing website: no provider, no dictionary, no locale routing, and no
12
+ * translation files in any of the 39 site repos. Pulling that machinery in would mean adding
13
+ * a runtime translation fetch to a static prerendered page — a network round-trip in front of
14
+ * the first paint, on pages whose whole point is that they are prerendered.
15
+ *
16
+ * So the strings are bundled. There are few enough of them that the cost is bytes rather than
17
+ * a request, and a prerendered page stays fully rendered.
18
+ *
19
+ * ## Locales
20
+ *
21
+ * The six the products actually ship, taken from `{product}-app/src/components/chrome/
22
+ * languages.ts` (FALLBACK_LANGUAGES). Deliberately NOT the wider `Locale` union in fe-libs,
23
+ * which also lists fr/de/ja that no product ships, and deliberately not the backend's BCP-47
24
+ * set, which has fr/de/ja but lacks ta and ar.
25
+ */
26
+ declare const EXPLORE_LOCALES: readonly ["en", "zh", "hi", "es", "ar", "ta"];
27
+ type ExploreLocale = (typeof EXPLORE_LOCALES)[number];
28
+ interface ExploreStrings {
29
+ badge: string;
30
+ welcomeTitle: string;
31
+ welcomeBody: string;
32
+ /**
33
+ * BOFF-9796: the welcome body of ONE product's own assistant (`scope="product"`) when the host passes none. Takes
34
+ * `{product}`. Problem-first like `welcomeBody`, and unlike the catalog's copy for a product site it offers nothing
35
+ * beyond that product: no "compare it with anything else we build".
36
+ */
37
+ welcomeBodyProduct: string;
38
+ /**
39
+ * BOFF-9796: the product scope's welcome body when no product name is known (a slug no catalog lists, and no
40
+ * `productName`). Like `welcomeBodyProduct` without the name, so it never falls back to the portfolio's invitation
41
+ * to "ask about a specific product or compare a few".
42
+ */
43
+ welcomeBodyScoped: string;
44
+ tryAsking: string;
45
+ focusProduct: string;
46
+ allProducts: string;
47
+ showAll: string;
48
+ showLess: string;
49
+ sources: string;
50
+ nextYouCouldAsk: string;
51
+ placeholder: string;
52
+ placeholderProduct: string;
53
+ /**
54
+ * BOFF-9796: the composer's placeholder on ONE product's own assistant (`scope="product"`). Takes `{product}`.
55
+ * Short on purpose, and the one thing about the composer that the product scope changes: the field is the published
56
+ * one, one line tall on a phone, where a placeholder that wraps loses its second line. `placeholderProduct`
57
+ * ("Describe a problem, or ask about Healthy Bowl…") wraps there at 390px and under; the English "Ask about Healthy
58
+ * Bowl…" fits one line at 320px and wider. Spanish and Tamil, the longest here, may still wrap at 320px and
59
+ * narrower: a follow-up (HealthyBowl, the site this was made for, is English-only). The welcome above the composer
60
+ * already asks for the problem.
61
+ */
62
+ placeholderScoped: string;
63
+ send: string;
64
+ stop: string;
65
+ newChat: string;
66
+ history: string;
67
+ clearHistory: string;
68
+ share: string;
69
+ copied: string;
70
+ copying: string;
71
+ shareUnavailable: string;
72
+ disclaimer: string;
73
+ disclaimerShort: string;
74
+ dictate: string;
75
+ stopDictating: string;
76
+ attach: string;
77
+ attachHint: string;
78
+ removeAttachment: string;
79
+ attachmentNameOnly: string;
80
+ attachmentTooLarge: string;
81
+ attachmentTooMany: string;
82
+ noAnswer: string;
83
+ answerDidNotArrive: string;
84
+ /**
85
+ * BOFF-9796: what a turn that ran out of searches (`TOOL_BUDGET`) says on ONE product's own assistant
86
+ * (`scope="product"`). The default message asks for "two or three specific products", an invitation to other
87
+ * products that a product's own assistant must not make; here the narrowing offered is to one part of the question.
88
+ */
89
+ toolBudgetScoped: string;
90
+ askHuman: string;
91
+ feedbackPrompt: string;
92
+ feedbackHelpful: string;
93
+ feedbackNotHelpful: string;
94
+ feedbackReasonTitle: string;
95
+ feedbackReasonInaccurate: string;
96
+ feedbackReasonIncomplete: string;
97
+ feedbackReasonOffTopic: string;
98
+ feedbackReasonHardToFollow: string;
99
+ feedbackReasonOther: string;
100
+ feedbackCommentPlaceholder: string;
101
+ feedbackSend: string;
102
+ feedbackDismiss: string;
103
+ feedbackThanks: string;
104
+ feedbackNotSent: string;
105
+ /**
106
+ * The trigger, in its two homes: `escalateOpen` is the quiet one under an answer we DID
107
+ * give, and the amber "we could not find this" banner reuses `askHuman` so that sentence
108
+ * keeps reading as one sentence.
109
+ */
110
+ escalateOpen: string;
111
+ escalateTitle: string;
112
+ escalateBody: string;
113
+ escalateEmailLabel: string;
114
+ escalateEmailPlaceholder: string;
115
+ escalateNoteLabel: string;
116
+ escalateSubmit: string;
117
+ escalateSending: string;
118
+ escalateCancel: string;
119
+ /**
120
+ * Shown for BOTH the client's own pre-flight and the server's `INVALID_EMAIL`. The two
121
+ * disagree about what is deliverable and the server is right, but the visitor's next
122
+ * action is identical either way: check the address.
123
+ */
124
+ escalateInvalidEmail: string;
125
+ /**
126
+ * The success line. Takes `{email}` — and it is filled with the address the SERVER
127
+ * returned, not the one in the box, because on a repeat handover the reply goes to
128
+ * whichever address the first one used.
129
+ *
130
+ * Used for `created: false` as well: a visitor asking for help is not told "you already
131
+ * did that".
132
+ */
133
+ escalateSent: string;
134
+ escalateRateLimited: string;
135
+ escalateCaptcha: string;
136
+ escalateFailed: string;
137
+ prevSuggestion: string;
138
+ nextSuggestion: string;
139
+ /**
140
+ * The label every concept picture carries, wherever one is shown — inside an answer and on
141
+ * the welcome strip alike.
142
+ *
143
+ * These images are published mockups, so the page has to say so; it says it in ONE wording,
144
+ * because two phrasings for the same caveat read as two different caveats.
145
+ */
146
+ conceptIllustration: string;
147
+ /** Rail arrows on the concept strip — pointer devices only. */
148
+ conceptScrollPrev: string;
149
+ conceptScrollNext: string;
150
+ opensInNewTab: string;
151
+ /** Heading over the concept strip on the welcome screen. */
152
+ conceptStripTitle: string;
153
+ /** Accessible name of the strip itself. */
154
+ conceptStripLabel: string;
155
+ /** Accessible name of one card. Takes `{title}` and `{product}`. */
156
+ conceptAsk: string;
157
+ /**
158
+ * The question a card actually SENDS. Takes `{title}` and `{product}`.
159
+ *
160
+ * Localised because it becomes the visitor's own message in the transcript — an English
161
+ * sentence appearing above an Arabic answer would read as the page talking to itself.
162
+ */
163
+ conceptAskQuestion: string;
164
+ /** Label of the per-answer copy control, and its failure state. */
165
+ copyAnswer: string;
166
+ copyFailed: string;
167
+ /**
168
+ * Label of the per-answer read-aloud control, in its two states.
169
+ *
170
+ * A toggle, exactly like the composer's dictation button: one control whose label says
171
+ * what pressing it does NOW, never a second button that appears while it is speaking.
172
+ */
173
+ readAloud: string;
174
+ stopReading: string;
175
+ /**
176
+ * Accessible name of the scrollable box a table in an answer sits in.
177
+ *
178
+ * A scrollable region needs a name and a tab stop, or a keyboard visitor cannot reach the
179
+ * columns that are off the edge. The `<table>` inside it keeps its own semantics.
180
+ */
181
+ answerTable: string;
182
+ /**
183
+ * The product-video card in an answer (CONTRACT.md §7) and the player it opens.
184
+ *
185
+ * `productVideo` is the card's badge — the video counterpart of `conceptIllustration` —
186
+ * and names a video the answer gave no title. `productVideoTitle` names the video in this
187
+ * language and takes `{product}`: the harness always writes the line's text as the English
188
+ * "<Name> product video", so the card keeps only the name from it. `playVideo` is the
189
+ * card's accessible name and takes `{title}`, which is that name. The last four belong to
190
+ * the player: its Close button, the two states of its full-screen toggle, and the line
191
+ * shown in place of a video that cannot be played.
192
+ */
193
+ productVideo: string;
194
+ productVideoTitle: string;
195
+ playVideo: string;
196
+ closeVideo: string;
197
+ enterFullScreen: string;
198
+ exitFullScreen: string;
199
+ /**
200
+ * BOFF-9697: the site-wide assistant panel (`ExplorePanel`). The tab, view and avatar words are the ones the product
201
+ * apps' assistant already ships in all six locales (Chat, Avatar, Live avatar, Assistant views).
202
+ */
203
+ panelTitle: string;
204
+ /**
205
+ * BOFF-9796: the panel's title on one product's own assistant (`scope="product"`), "{product} assistant" in each
206
+ * language's own word order. Takes `{product}`. `panelTitle` stays the title wherever no product name is known.
207
+ */
208
+ panelTitleProduct: string;
209
+ panelViews: string;
210
+ tabChat: string;
211
+ tabAvatar: string;
212
+ closePanel: string;
213
+ liveAvatar: string;
214
+ avatarComingSoon: string;
215
+ continueInChat: string;
216
+ videoUnavailable: string;
217
+ /** Accessible name of the provenance row under an answer. */
218
+ groundedIn: string;
219
+ /** How many sources the answer cites. `sourceCountMany` takes `{count}`. */
220
+ sourceCountOne: string;
221
+ sourceCountMany: string;
222
+ /** What KIND of page a source is, inferred from its URL. */
223
+ sourceKindConcept: string;
224
+ sourceKindDocs: string;
225
+ sourceKindPricing: string;
226
+ sourceKindUseCase: string;
227
+ sourceKindPage: string;
228
+ /**
229
+ * The page's <title> and <meta description>.
230
+ *
231
+ * These are the surface a search result and a browser tab are built from, and they are
232
+ * the LAST place the old product-first framing survived: all 38 sites hard-coded
233
+ * "Explore Burdenoff products with AI" inline, so the tab announced our catalogue on a
234
+ * page that asks the visitor about their problem — and named the wrong brand on 37 of
235
+ * them. `seoTitle` carries no brand: PageHead appends "| {productName}" itself.
236
+ */
237
+ seoTitle: string;
238
+ seoDescription: string;
239
+ /** Used when the page belongs to a specific product's site. Takes `{product}`. */
240
+ seoDescriptionProduct: string;
241
+ /**
242
+ * BOFF-9796: the meta description of ONE product's own `/explore` (`scope="product"`). Takes `{product}`. Unlike
243
+ * `seoDescriptionProduct`, it promises nothing beyond that product: no "and every other product we build".
244
+ */
245
+ seoDescriptionScoped: string;
246
+ capabilities: [string, string, string];
247
+ prompts: string[];
248
+ }
249
+ declare function speechLocaleOf(locale: ExploreLocale): string;
250
+
251
+ /**
252
+ * BOFF-9797. The small part of the live avatar that the panel itself needs, whether or not it is ever opened: what a
253
+ * host's `avatar.live` is, whether the live avatar can run on this page at all, and where its requests go.
254
+ *
255
+ * Everything else (the view, its state machine, the requests, the words, the bot check) is a separate chunk that a
256
+ * site only downloads when its visitor first opens the Avatar view (see `explore-avatar-live.tsx`). That is why this
257
+ * file is separate and kept to a few lines: it is the only part of the live avatar in the package root for a site that
258
+ * does not pass `avatar.live`, and the part of it that decides, without loading anything, whether the chunk is wanted.
259
+ * Types only, plus plain functions: nothing here imports a component, a context or a string table.
260
+ */
261
+
262
+ /**
263
+ * BOFF-9797. A host's opt-in to the live avatar on its panel's Avatar tab. Every field is required; a config that is
264
+ * incomplete leaves the tab as it was (and a warning in the console).
265
+ */
266
+ interface ExplorePanelAvatarLive {
267
+ /** The site, as the live avatar service knows it: `healthybowl`. */
268
+ site: string;
269
+ /**
270
+ * Loads the live avatar's room module: `() => import('@burdenoff/website-sdk/avatar-live')`. Called only after the
271
+ * visitor presses Start on the consent card, never on page load or on opening the tab. That entry needs the
272
+ * package's optional peer dependency for media rooms (see the README).
273
+ */
274
+ load: () => Promise<AvatarLiveModule>;
275
+ /** The site's Cloudflare Turnstile site key, for the bot check that runs when the visitor presses Start. */
276
+ turnstileSiteKey: string;
277
+ /** The version of the suggested-question list the panel shows (its `examplePrompts`), such as `hb-en-1`. */
278
+ manifestVersion: string;
279
+ }
280
+ /** What the live avatar reads of the panel's conversation: the transcript, whether it is read-only, and the token. */
281
+ type AvatarConversation = Pick<UseExploreChatResult, "messages" | "isSharedView" | "getConversationToken">;
282
+
283
+ export { type AvatarConversation as A, type ExplorePanelAvatarLive as E, type ExploreLocale as a, EXPLORE_LOCALES as b, type ExploreStrings as c, speechLocaleOf as s };
@@ -350,4 +350,4 @@ declare const EXPLORE_ESCALATION_NOTE_SOFT_MAX = 2000;
350
350
  */
351
351
  declare function looksLikeDeliverableEmail(value: string): boolean;
352
352
 
353
- export { looksLikeDeliverableEmail as A, type ExploreProduct as E, SEND_EXPLORE_MESSAGE_MUTATION as S, type ExploreReference as a, type ExploreCatalog as b, type ExploreMessage as c, type ExploreFeedbackRating as d, type ExploreFeedbackReason as e, type ExploreLimits as f, ESCALATE_EXPLORE_CONVERSATION_MUTATION as g, EXPLORE_CATALOG_QUERY as h, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS as i, EXPLORE_ESCALATION_NOTE_SOFT_MAX as j, EXPLORE_MESSAGE_QUERY as k, type EscalateExploreConversationInput as l, type EscalateExploreConversationResult as m, type ExploreCatalogQueryData as n, type ExploreConceptHighlight as o, type ExploreConversation as p, type ExploreCtaKind as q, type ExploreCtaLink as r, type ExploreErrorCode as s, type ExploreEscalation as t, type ExploreMessageQueryData as u, type ExploreMessageRole as v, type ExploreMessageStatus as w, type SendExploreMessageInput as x, type SendExploreMessageMutationData as y, type SendExploreMessageResult as z };
353
+ export { looksLikeDeliverableEmail as A, type ExploreCatalog as E, SEND_EXPLORE_MESSAGE_MUTATION as S, type ExploreMessage as a, type ExploreFeedbackRating as b, type ExploreFeedbackReason as c, type ExploreLimits as d, type ExploreProduct as e, type ExploreReference as f, ESCALATE_EXPLORE_CONVERSATION_MUTATION as g, EXPLORE_CATALOG_QUERY as h, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS as i, EXPLORE_ESCALATION_NOTE_SOFT_MAX as j, EXPLORE_MESSAGE_QUERY as k, type EscalateExploreConversationInput as l, type EscalateExploreConversationResult as m, type ExploreCatalogQueryData as n, type ExploreConceptHighlight as o, type ExploreConversation as p, type ExploreCtaKind as q, type ExploreCtaLink as r, type ExploreErrorCode as s, type ExploreEscalation as t, type ExploreMessageQueryData as u, type ExploreMessageRole as v, type ExploreMessageStatus as w, type SendExploreMessageInput as x, type SendExploreMessageMutationData as y, type SendExploreMessageResult as z };
@@ -350,4 +350,4 @@ declare const EXPLORE_ESCALATION_NOTE_SOFT_MAX = 2000;
350
350
  */
351
351
  declare function looksLikeDeliverableEmail(value: string): boolean;
352
352
 
353
- export { looksLikeDeliverableEmail as A, type ExploreProduct as E, SEND_EXPLORE_MESSAGE_MUTATION as S, type ExploreReference as a, type ExploreCatalog as b, type ExploreMessage as c, type ExploreFeedbackRating as d, type ExploreFeedbackReason as e, type ExploreLimits as f, ESCALATE_EXPLORE_CONVERSATION_MUTATION as g, EXPLORE_CATALOG_QUERY as h, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS as i, EXPLORE_ESCALATION_NOTE_SOFT_MAX as j, EXPLORE_MESSAGE_QUERY as k, type EscalateExploreConversationInput as l, type EscalateExploreConversationResult as m, type ExploreCatalogQueryData as n, type ExploreConceptHighlight as o, type ExploreConversation as p, type ExploreCtaKind as q, type ExploreCtaLink as r, type ExploreErrorCode as s, type ExploreEscalation as t, type ExploreMessageQueryData as u, type ExploreMessageRole as v, type ExploreMessageStatus as w, type SendExploreMessageInput as x, type SendExploreMessageMutationData as y, type SendExploreMessageResult as z };
353
+ export { looksLikeDeliverableEmail as A, type ExploreCatalog as E, SEND_EXPLORE_MESSAGE_MUTATION as S, type ExploreMessage as a, type ExploreFeedbackRating as b, type ExploreFeedbackReason as c, type ExploreLimits as d, type ExploreProduct as e, type ExploreReference as f, ESCALATE_EXPLORE_CONVERSATION_MUTATION as g, EXPLORE_CATALOG_QUERY as h, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS as i, EXPLORE_ESCALATION_NOTE_SOFT_MAX as j, EXPLORE_MESSAGE_QUERY as k, type EscalateExploreConversationInput as l, type EscalateExploreConversationResult as m, type ExploreCatalogQueryData as n, type ExploreConceptHighlight as o, type ExploreConversation as p, type ExploreCtaKind as q, type ExploreCtaLink as r, type ExploreErrorCode as s, type ExploreEscalation as t, type ExploreMessageQueryData as u, type ExploreMessageRole as v, type ExploreMessageStatus as w, type SendExploreMessageInput as x, type SendExploreMessageMutationData as y, type SendExploreMessageResult as z };
@@ -1,5 +1,6 @@
1
- export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from '../use-progressive-reveal-BFPWbEXy.mjs';
2
- import '../explore-types-_9UJu6EA.mjs';
1
+ export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as classifyExploreError, u as useExploreChat } from '../use-explore-chat-zRuoAin6.mjs';
2
+ export { U as UseSpeechOutputOptions, a as UseSpeechOutputResult, s as stopSpeaking, u as useProgressiveReveal, b as useSpeechOutput } from '../use-progressive-reveal-ppicEgzZ.mjs';
3
+ import '../explore-types-Bb2Ih3d8.mjs';
3
4
 
4
5
  interface UseSpeechInputOptions {
5
6
  /** Receives settled text as it is recognised. Append it to the draft. */
@@ -1,5 +1,6 @@
1
- export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as UseSpeechOutputOptions, g as UseSpeechOutputResult, h as classifyExploreError, s as stopSpeaking, u as useExploreChat, i as useProgressiveReveal, j as useSpeechOutput } from '../use-progressive-reveal-C0hkdu_i.js';
2
- import '../explore-types-_9UJu6EA.js';
1
+ export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, c as ExploreEscalateOutcome, d as ExploreEscalateResult, F as FALLBACK_EXPLORE_LIMITS, U as UseExploreChatOptions, e as UseExploreChatResult, f as classifyExploreError, u as useExploreChat } from '../use-explore-chat-DunjG-3p.js';
2
+ export { U as UseSpeechOutputOptions, a as UseSpeechOutputResult, s as stopSpeaking, u as useProgressiveReveal, b as useSpeechOutput } from '../use-progressive-reveal-ppicEgzZ.js';
3
+ import '../explore-types-Bb2Ih3d8.js';
3
4
 
4
5
  interface UseSpeechInputOptions {
5
6
  /** Receives settled text as it is recognised. Append it to the draft. */
@@ -1699,6 +1699,10 @@ function useExploreChat(options = {}) {
1699
1699
  [client, productId]
1700
1700
  );
1701
1701
  const canEscalate = hasConversation && !isSharedView;
1702
+ const getConversationToken = react.useCallback(
1703
+ () => conversationTokenRef.current,
1704
+ []
1705
+ );
1702
1706
  return {
1703
1707
  phase,
1704
1708
  catalog,
@@ -1723,7 +1727,8 @@ function useExploreChat(options = {}) {
1723
1727
  escalate,
1724
1728
  canEscalate,
1725
1729
  createShareLink,
1726
- isSharedView
1730
+ isSharedView,
1731
+ getConversationToken
1727
1732
  };
1728
1733
  }
1729
1734
  var optimisticCounter = 0;