@burdenoff/website-sdk 2026.829.8 → 2026.921.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 +112 -1
  2. package/dist/components/contact.js +4 -1
  3. package/dist/components/contact.js.map +1 -1
  4. package/dist/components/contact.mjs +4 -1
  5. package/dist/components/contact.mjs.map +1 -1
  6. package/dist/components/explore.d.mts +14 -1
  7. package/dist/components/explore.d.ts +14 -1
  8. package/dist/components/explore.js +217 -43
  9. package/dist/components/explore.js.map +1 -1
  10. package/dist/components/explore.mjs +217 -45
  11. package/dist/components/explore.mjs.map +1 -1
  12. package/dist/components/newsletter.js +4 -1
  13. package/dist/components/newsletter.js.map +1 -1
  14. package/dist/components/newsletter.mjs +4 -1
  15. package/dist/components/newsletter.mjs.map +1 -1
  16. package/dist/components/partners.js +23 -13
  17. package/dist/components/partners.js.map +1 -1
  18. package/dist/components/partners.mjs +23 -13
  19. package/dist/components/partners.mjs.map +1 -1
  20. package/dist/components/pricing.js +4 -1
  21. package/dist/components/pricing.js.map +1 -1
  22. package/dist/components/pricing.mjs +4 -1
  23. package/dist/components/pricing.mjs.map +1 -1
  24. package/dist/components/unsubscribe.js +4 -1
  25. package/dist/components/unsubscribe.js.map +1 -1
  26. package/dist/components/unsubscribe.mjs +4 -1
  27. package/dist/components/unsubscribe.mjs.map +1 -1
  28. package/dist/components/waitlist.js +4 -1
  29. package/dist/components/waitlist.js.map +1 -1
  30. package/dist/components/waitlist.mjs +4 -1
  31. package/dist/components/waitlist.mjs.map +1 -1
  32. package/dist/content/index.js +23 -13
  33. package/dist/content/index.js.map +1 -1
  34. package/dist/content/index.mjs +23 -13
  35. package/dist/content/index.mjs.map +1 -1
  36. package/dist/{use-explore-chat-BzXCz2UM.d.mts → explore-types-CLw19R76.d.mts} +1 -131
  37. package/dist/{use-explore-chat-BzXCz2UM.d.ts → explore-types-CLw19R76.d.ts} +1 -131
  38. package/dist/hooks/index.d.mts +2 -1
  39. package/dist/hooks/index.d.ts +2 -1
  40. package/dist/hooks/index.js +23 -7
  41. package/dist/hooks/index.js.map +1 -1
  42. package/dist/hooks/index.mjs +23 -7
  43. package/dist/hooks/index.mjs.map +1 -1
  44. package/dist/index.d.mts +143 -3
  45. package/dist/index.d.ts +143 -3
  46. package/dist/index.js +1552 -207
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +1548 -210
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/seo/index.js +4 -1
  51. package/dist/seo/index.js.map +1 -1
  52. package/dist/seo/index.mjs +4 -1
  53. package/dist/seo/index.mjs.map +1 -1
  54. package/dist/store/index.js +23 -13
  55. package/dist/store/index.js.map +1 -1
  56. package/dist/store/index.mjs +23 -13
  57. package/dist/store/index.mjs.map +1 -1
  58. package/dist/use-explore-chat-CvW-kyIm.d.mts +145 -0
  59. package/dist/use-explore-chat-DdGBimiz.d.ts +145 -0
  60. package/package.json +1 -1
@@ -4,7 +4,7 @@ import { Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square,
4
4
  import ReactMarkdown from 'react-markdown';
5
5
  import rehypeSanitize from 'rehype-sanitize';
6
6
  import remarkGfm from 'remark-gfm';
7
- import { jsx, jsxs } from 'react/jsx-runtime';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import { Helmet } from 'react-helmet-async';
9
9
  import { Slot } from '@radix-ui/react-slot';
10
10
  import { cva } from 'class-variance-authority';
@@ -54,9 +54,12 @@ var EN = {
54
54
  attachmentTooLarge: "{{name}} is larger than {{size}} MB and was not attached.",
55
55
  attachmentTooMany: "Only {{max}} files can be attached, so {{name}} was skipped.",
56
56
  noAnswer: "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
57
+ answerDidNotArrive: "That answer didn't come through. Try asking again.",
57
58
  askHuman: "ask a human",
58
59
  prevSuggestion: "Previous suggestion",
59
60
  nextSuggestion: "Next suggestion",
61
+ conceptIllustration: "Concept illustration",
62
+ opensInNewTab: "opens in a new tab",
60
63
  capabilities: [
61
64
  "Grounded in our own docs",
62
65
  "Compare across the ecosystem",
@@ -102,9 +105,12 @@ var ZH = {
102
105
  attachmentTooLarge: "{{name}} \u8D85\u8FC7 {{size}} MB\uFF0C\u672A\u80FD\u6DFB\u52A0\u3002",
103
106
  attachmentTooMany: "\u6700\u591A\u53EA\u80FD\u6DFB\u52A0 {{max}} \u4E2A\u6587\u4EF6\uFF0C\u5DF2\u8DF3\u8FC7 {{name}}\u3002",
104
107
  noAnswer: "\u6211\u5728\u6587\u6863\u4E2D\u6CA1\u6709\u627E\u5230\u76F8\u5173\u5185\u5BB9\uFF0C\u4E0B\u9762\u7684\u56DE\u7B54\u6CA1\u6709\u6765\u6E90\u652F\u6301\u3002\u8BF7\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216",
108
+ answerDidNotArrive: "\u8FD9\u6761\u56DE\u7B54\u6CA1\u6709\u8FD4\u56DE\u3002\u8BF7\u518D\u95EE\u4E00\u6B21\u3002",
105
109
  askHuman: "\u8054\u7CFB\u6211\u4EEC",
106
110
  prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
107
111
  nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
112
+ conceptIllustration: "\u6982\u5FF5\u793A\u610F\u56FE",
113
+ opensInNewTab: "\u5728\u65B0\u6807\u7B7E\u9875\u4E2D\u6253\u5F00",
108
114
  capabilities: ["\u57FA\u4E8E\u6211\u4EEC\u81EA\u5DF1\u7684\u6587\u6863", "\u8DE8\u4EA7\u54C1\u5BF9\u6BD4", "\u76F4\u8FBE\u6B63\u786E\u7684\u9875\u9762"],
109
115
  prompts: [
110
116
  "\u8FD9\u4E2A\u4EA7\u54C1\u5230\u5E95\u80FD\u505A\u4EC0\u4E48\uFF1F",
@@ -146,9 +152,12 @@ var HI = {
146
152
  attachmentTooLarge: "{{name}} {{size}} MB \u0938\u0947 \u092C\u0921\u093C\u0940 \u0939\u0948, \u0907\u0938\u0932\u093F\u090F \u091C\u094B\u0921\u093C\u0940 \u0928\u0939\u0940\u0902 \u0917\u0908\u0964",
147
153
  attachmentTooMany: "\u0915\u0947\u0935\u0932 {{max}} \u092B\u093C\u093E\u0907\u0932\u0947\u0902 \u091C\u094B\u0921\u093C\u0940 \u091C\u093E \u0938\u0915\u0924\u0940 \u0939\u0948\u0902, \u0907\u0938\u0932\u093F\u090F {{name}} \u091B\u094B\u0921\u093C \u0926\u0940 \u0917\u0908\u0964",
148
154
  noAnswer: "\u092F\u0939 \u092E\u0941\u091D\u0947 \u0939\u092E\u093E\u0930\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092E\u0947\u0902 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E, \u0907\u0938\u0932\u093F\u090F \u0928\u0940\u091A\u0947 \u0926\u093F\u092F\u093E \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938\u0940 \u0938\u094D\u0930\u094B\u0924 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964 \u0926\u0942\u0938\u0930\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902, \u092F\u093E",
155
+ answerDidNotArrive: "\u0935\u0939 \u0909\u0924\u094D\u0924\u0930 \u0928\u0939\u0940\u0902 \u0906 \u0938\u0915\u093E\u0964 \u0915\u0943\u092A\u092F\u093E \u0926\u094B\u092C\u093E\u0930\u093E \u092A\u0942\u091B\u0947\u0902\u0964",
149
156
  askHuman: "\u0939\u092E\u0938\u0947 \u0938\u0902\u092A\u0930\u094D\u0915 \u0915\u0930\u0947\u0902",
150
157
  prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
151
158
  nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
159
+ conceptIllustration: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E \u091A\u093F\u0924\u094D\u0930\u0923",
160
+ opensInNewTab: "\u0928\u090F \u091F\u0948\u092C \u092E\u0947\u0902 \u0916\u0941\u0932\u0924\u093E \u0939\u0948",
152
161
  capabilities: [
153
162
  "\u0939\u092E\u093E\u0930\u0947 \u0905\u092A\u0928\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924",
154
163
  "\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0940 \u0924\u0941\u0932\u0928\u093E \u0915\u0930\u0947\u0902",
@@ -194,9 +203,12 @@ var ES = {
194
203
  attachmentTooLarge: "{{name}} supera los {{size}} MB y no se adjunt\xF3.",
195
204
  attachmentTooMany: "Solo se pueden adjuntar {{max}} archivos, as\xED que se omiti\xF3 {{name}}.",
196
205
  noAnswer: "No he encontrado esto en nuestra documentaci\xF3n, as\xED que la respuesta de abajo no se apoya en ninguna fuente. Prueba a reformularla, o",
206
+ answerDidNotArrive: "Esa respuesta no lleg\xF3. Int\xE9ntalo de nuevo.",
197
207
  askHuman: "habla con una persona",
198
208
  prevSuggestion: "Sugerencia anterior",
199
209
  nextSuggestion: "Sugerencia siguiente",
210
+ conceptIllustration: "Ilustraci\xF3n del concepto",
211
+ opensInNewTab: "se abre en una pesta\xF1a nueva",
200
212
  capabilities: [
201
213
  "Basado en nuestra documentaci\xF3n",
202
214
  "Compara todo el ecosistema",
@@ -242,9 +254,12 @@ var AR = {
242
254
  attachmentTooLarge: "{{name}} \u0623\u0643\u0628\u0631 \u0645\u0646 {{size}} \u0645\u064A\u063A\u0627\u0628\u0627\u064A\u062A \u0648\u0644\u0645 \u064A\u062A\u0645 \u0625\u0631\u0641\u0627\u0642\u0647.",
243
255
  attachmentTooMany: "\u064A\u0645\u0643\u0646 \u0625\u0631\u0641\u0627\u0642 {{max}} \u0645\u0644\u0641\u0627\u062A \u0641\u0642\u0637\u060C \u0644\u0630\u0627 \u062A\u0645 \u062A\u062E\u0637\u064A {{name}}.",
244
256
  noAnswer: "\u0644\u0645 \u0623\u062C\u062F \u0647\u0630\u0627 \u0641\u064A \u0648\u062B\u0627\u0626\u0642\u0646\u0627\u060C \u0644\u0630\u0627 \u0641\u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0623\u062F\u0646\u0627\u0647 \u063A\u064A\u0631 \u0645\u0633\u062A\u0646\u062F\u0629 \u0625\u0644\u0649 \u0645\u0635\u062F\u0631. \u062D\u0627\u0648\u0644 \u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u0635\u064A\u0627\u063A\u0629\u060C \u0623\u0648",
257
+ answerDidNotArrive: "\u0644\u0645 \u062A\u0635\u0644 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
245
258
  askHuman: "\u062A\u062D\u062F\u0651\u062B \u0625\u0644\u0649 \u0634\u062E\u0635",
246
259
  prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
247
260
  nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
261
+ conceptIllustration: "\u0631\u0633\u0645 \u062A\u0648\u0636\u064A\u062D\u064A \u0644\u0644\u0645\u0641\u0647\u0648\u0645",
262
+ opensInNewTab: "\u064A\u064F\u0641\u062A\u062D \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u062C\u062F\u064A\u062F\u0629",
248
263
  capabilities: [
249
264
  "\u0645\u0628\u0646\u064A \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627",
250
265
  "\u0642\u0627\u0631\u0646 \u0639\u0628\u0631 \u0627\u0644\u0645\u0646\u0638\u0648\u0645\u0629",
@@ -290,9 +305,12 @@ var TA = {
290
305
  attachmentTooLarge: "{{name}} {{size}} MB-\u0B90 \u0BB5\u0BBF\u0B9F \u0BAA\u0BC6\u0BB0\u0BBF\u0BAF\u0BA4\u0BC1, \u0B8E\u0BA9\u0BB5\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
291
306
  attachmentTooMany: "{{max}} \u0B95\u0BCB\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BCD \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7 \u0B87\u0BA3\u0BC8\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BC1\u0BAE\u0BCD, \u0B8E\u0BA9\u0BB5\u0BC7 {{name}} \u0BA4\u0BB5\u0BBF\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
292
307
  noAnswer: "\u0B87\u0BA4\u0BC1 \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8, \u0B8E\u0BA9\u0BB5\u0BC7 \u0B95\u0BC0\u0BB4\u0BC7 \u0B89\u0BB3\u0BCD\u0BB3 \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0B95\u0BCD\u0B95\u0BC1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD \u0B87\u0BB2\u0BCD\u0BB2\u0BC8. \u0BB5\u0BC7\u0BB1\u0BC1 \u0BB5\u0B95\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1",
308
+ answerDidNotArrive: "\u0B85\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BB5\u0BB0\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B9F\u0BC1\u0BAA\u0BCD \u0BAA\u0BBE\u0BB0\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD.",
293
309
  askHuman: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1 \u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
294
310
  prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
295
311
  nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
312
+ conceptIllustration: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BB5\u0BBF\u0BB3\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BAE\u0BCD",
313
+ opensInNewTab: "\u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BBF\u0BB1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD",
296
314
  capabilities: [
297
315
  "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B9A\u0BCA\u0BA8\u0BCD\u0BA4 \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BA9\u0BCD \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD",
298
316
  "\u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B92\u0BAA\u0BCD\u0BAA\u0BBF\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
@@ -333,19 +351,26 @@ function exploreStrings(locale) {
333
351
  function fill(template, values) {
334
352
  return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
335
353
  }
354
+ function MarkdownLink({
355
+ href,
356
+ children,
357
+ // react-markdown passes the hast node to every override; it is not a DOM attribute.
358
+ node: _node,
359
+ ...props
360
+ }) {
361
+ const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
362
+ return /* @__PURE__ */ jsx(
363
+ "a",
364
+ {
365
+ href,
366
+ ...props,
367
+ ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
368
+ children
369
+ }
370
+ );
371
+ }
336
372
  var defaultComponents = {
337
- a: ({ href, children, ...props }) => {
338
- const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
339
- return /* @__PURE__ */ jsx(
340
- "a",
341
- {
342
- href,
343
- ...props,
344
- ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
345
- children
346
- }
347
- );
348
- }
373
+ a: MarkdownLink
349
374
  };
350
375
  function Markdown({
351
376
  children,
@@ -906,10 +931,13 @@ var ECOSYSTEM_PRODUCTS = [
906
931
  name: "VibeControls",
907
932
  websiteUrl: "https://vibecontrols.com"
908
933
  },
934
+ // FluidGrids ships on www.fluidgrids.ai — fluidgrids.com only redirects there. The explore
935
+ // catalog and the site's own sitemap use this origin, and so must the fallback catalog
936
+ // built from this list, or /explore rejects FluidGrids concept images until it loads.
909
937
  {
910
938
  slug: "fluidgrids",
911
939
  name: "FluidGrids",
912
- websiteUrl: "https://fluidgrids.com"
940
+ websiteUrl: "https://www.fluidgrids.ai"
913
941
  },
914
942
  // Botlit ships on botlit.ai — botlit.com does not resolve.
915
943
  { slug: "botlit", name: "Botlit", websiteUrl: "https://www.botlit.ai" },
@@ -1160,7 +1188,7 @@ var DEFAULT_EXPLORE_EXAMPLE_PROMPTS = [
1160
1188
  ];
1161
1189
  var FALLBACK_WELCOME_TITLE = "Ask anything about our products";
1162
1190
  var FALLBACK_WELCOME_BODY = "Get straight answers drawn from our product documentation and public pages \u2014 with links back to the exact page each answer came from.";
1163
- function buildFallbackCatalog(examplePrompts) {
1191
+ function buildFallbackCatalog(examplePrompts, welcome) {
1164
1192
  return {
1165
1193
  enabled: true,
1166
1194
  products: ECOSYSTEM_PRODUCTS.map((p) => ({
@@ -1170,8 +1198,8 @@ function buildFallbackCatalog(examplePrompts) {
1170
1198
  website: p.websiteUrl
1171
1199
  })),
1172
1200
  examplePrompts: examplePrompts?.length ? examplePrompts : DEFAULT_EXPLORE_EXAMPLE_PROMPTS,
1173
- welcomeTitle: FALLBACK_WELCOME_TITLE,
1174
- welcomeBody: FALLBACK_WELCOME_BODY,
1201
+ welcomeTitle: welcome?.title ?? FALLBACK_WELCOME_TITLE,
1202
+ welcomeBody: welcome?.body ?? FALLBACK_WELCOME_BODY,
1175
1203
  limits: FALLBACK_EXPLORE_LIMITS,
1176
1204
  captchaRequired: false,
1177
1205
  recaptchaSiteKey: null
@@ -1231,7 +1259,15 @@ function classifyExploreError(code, serverMessage) {
1231
1259
  retryable: true
1232
1260
  };
1233
1261
  }
1234
- if (c === "TIMEOUT" || c === "TOOL_BUDGET") {
1262
+ if (c === "TOOL_BUDGET") {
1263
+ return {
1264
+ kind: "scope",
1265
+ code: c,
1266
+ message: "That question spans more of our products than I can look through in one go. Try asking about two or three specific products.",
1267
+ retryable: false
1268
+ };
1269
+ }
1270
+ if (c === "TIMEOUT") {
1235
1271
  return {
1236
1272
  kind: "timeout",
1237
1273
  code: c,
@@ -1363,6 +1399,7 @@ function useExploreChat(options = {}) {
1363
1399
  pageUrl,
1364
1400
  locale,
1365
1401
  examplePrompts,
1402
+ fallbackWelcome,
1366
1403
  pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,
1367
1404
  pollTimeoutMs = DEFAULT_POLL_TIMEOUT_MS,
1368
1405
  storageKey = DEFAULT_STORAGE_KEY,
@@ -1371,9 +1408,13 @@ function useExploreChat(options = {}) {
1371
1408
  } = options;
1372
1409
  const client = useWebSDK();
1373
1410
  const promptKey = JSON.stringify(examplePrompts ?? []);
1411
+ const welcomeKey = JSON.stringify(fallbackWelcome ?? null);
1374
1412
  const fallbackCatalog = useMemo(
1375
- () => buildFallbackCatalog(JSON.parse(promptKey)),
1376
- [promptKey]
1413
+ () => buildFallbackCatalog(
1414
+ JSON.parse(promptKey),
1415
+ JSON.parse(welcomeKey) ?? void 0
1416
+ ),
1417
+ [promptKey, welcomeKey]
1377
1418
  );
1378
1419
  const [catalog, setCatalog] = useState(fallbackCatalog);
1379
1420
  const [messages, setMessages] = useState([]);
@@ -2200,6 +2241,9 @@ function resolveImageUrl(image, base) {
2200
2241
  return image;
2201
2242
  }
2202
2243
  }
2244
+ function serializeJsonLd(data) {
2245
+ return JSON.stringify(data).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2246
+ }
2203
2247
  function PageHead({
2204
2248
  title,
2205
2249
  description,
@@ -2241,7 +2285,7 @@ function PageHead({
2241
2285
  fullImageUrl && /* @__PURE__ */ jsx("meta", { name: "twitter:image", content: fullImageUrl }),
2242
2286
  twitterHandle && /* @__PURE__ */ jsx("meta", { name: "twitter:creator", content: twitterHandle }),
2243
2287
  /* @__PURE__ */ jsx("meta", { name: "theme-color", content: themeColor }),
2244
- structuredDataItems.map((data, index) => /* @__PURE__ */ jsx("script", { type: "application/ld+json", children: JSON.stringify(data) }, `ld-${index}`)),
2288
+ structuredDataItems.map((data, index) => /* @__PURE__ */ jsx("script", { type: "application/ld+json", children: serializeJsonLd(data) }, `ld-${index}`)),
2245
2289
  additionalMeta?.map((meta, index) => /* @__PURE__ */ jsx(
2246
2290
  "meta",
2247
2291
  {
@@ -2658,6 +2702,93 @@ function logoUrlOf(url) {
2658
2702
  return null;
2659
2703
  }
2660
2704
  }
2705
+ function inlineImageOrigins(products) {
2706
+ const origins = /* @__PURE__ */ new Set();
2707
+ for (const product of products) {
2708
+ let url;
2709
+ try {
2710
+ url = new URL(product.website);
2711
+ } catch {
2712
+ continue;
2713
+ }
2714
+ if (url.protocol !== "https:") continue;
2715
+ const apex = url.hostname.replace(/^www\./, "");
2716
+ const port = url.port ? `:${url.port}` : "";
2717
+ origins.add(`https://${apex}${port}`);
2718
+ origins.add(`https://www.${apex}${port}`);
2719
+ }
2720
+ return origins;
2721
+ }
2722
+ function isInlineImageAllowed(src, origins) {
2723
+ if (typeof src !== "string" || src === "") return false;
2724
+ let url;
2725
+ try {
2726
+ url = new URL(src);
2727
+ } catch {
2728
+ return false;
2729
+ }
2730
+ if (url.protocol !== "https:" || url.username || url.password) return false;
2731
+ return origins.has(url.origin);
2732
+ }
2733
+ var InlineImageScopeContext = createContext(null);
2734
+ var InsideLinkContext = createContext(false);
2735
+ function AnswerLink(props) {
2736
+ return /* @__PURE__ */ jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx(MarkdownLink, { ...props }) });
2737
+ }
2738
+ var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
2739
+ function InlineConceptImage({ src, alt }) {
2740
+ const scope = useContext(InlineImageScopeContext);
2741
+ const insideLink = useContext(InsideLinkContext);
2742
+ if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
2743
+ return null;
2744
+ }
2745
+ const { strings: T, onFailed } = scope;
2746
+ const picture = /* @__PURE__ */ jsxs(Fragment, { children: [
2747
+ /* @__PURE__ */ jsx(
2748
+ "img",
2749
+ {
2750
+ src,
2751
+ alt: alt ?? "",
2752
+ loading: "lazy",
2753
+ decoding: "async",
2754
+ onError: () => onFailed(src),
2755
+ className: "block h-auto max-h-80 w-auto max-w-full object-contain"
2756
+ }
2757
+ ),
2758
+ /* @__PURE__ */ jsx(
2759
+ "span",
2760
+ {
2761
+ "aria-hidden": "true",
2762
+ className: "pointer-events-none absolute left-2 top-2 rounded-full border border-border bg-background/90 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-foreground shadow-sm",
2763
+ children: T.conceptIllustration
2764
+ }
2765
+ )
2766
+ ] });
2767
+ return /* @__PURE__ */ jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxs(
2768
+ "a",
2769
+ {
2770
+ href: src,
2771
+ target: "_blank",
2772
+ rel: "noopener noreferrer",
2773
+ className: cn(
2774
+ INLINE_IMAGE_FRAME,
2775
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
2776
+ ),
2777
+ children: [
2778
+ picture,
2779
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
2780
+ "(",
2781
+ T.opensInNewTab,
2782
+ ")"
2783
+ ] })
2784
+ ]
2785
+ }
2786
+ ) });
2787
+ }
2788
+ var ANSWER_MARKDOWN_COMPONENTS = {
2789
+ a: AnswerLink,
2790
+ img: InlineConceptImage
2791
+ };
2661
2792
  function ReferenceCard({
2662
2793
  reference,
2663
2794
  onFollow
@@ -2840,6 +2971,7 @@ function AssistantBubble({
2840
2971
  strings: T,
2841
2972
  message,
2842
2973
  activity,
2974
+ imageOrigins,
2843
2975
  onNavigate,
2844
2976
  anchorRef,
2845
2977
  onFollow,
@@ -2848,6 +2980,25 @@ function AssistantBubble({
2848
2980
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
2849
2981
  const body = message.content || message.partialContent || "";
2850
2982
  const failed = message.status === "FAILED";
2983
+ const completed = message.status === "COMPLETED";
2984
+ const [failedImages, setFailedImages] = useState(
2985
+ () => /* @__PURE__ */ new Set()
2986
+ );
2987
+ const markImageFailed = useCallback((src) => {
2988
+ setFailedImages(
2989
+ (current) => current.has(src) ? current : new Set(current).add(src)
2990
+ );
2991
+ }, []);
2992
+ const imageScope = useMemo(
2993
+ () => ({
2994
+ strings: T,
2995
+ enabled: completed,
2996
+ origins: imageOrigins,
2997
+ failed: failedImages,
2998
+ onFailed: markImageFailed
2999
+ }),
3000
+ [T, completed, imageOrigins, failedImages, markImageFailed]
3001
+ );
2851
3002
  return /* @__PURE__ */ jsxs(
2852
3003
  "div",
2853
3004
  {
@@ -2873,7 +3024,7 @@ function AssistantBubble({
2873
3024
  children: [
2874
3025
  /* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" }),
2875
3026
  /* @__PURE__ */ jsxs("span", { children: [
2876
- "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
3027
+ T.noAnswer,
2877
3028
  " ",
2878
3029
  /* @__PURE__ */ jsx(
2879
3030
  "a",
@@ -2894,11 +3045,11 @@ function AssistantBubble({
2894
3045
  }
2895
3046
  ) : null,
2896
3047
  body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
2897
- /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
3048
+ /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(InlineImageScopeContext.Provider, { value: imageScope, children: /* @__PURE__ */ jsx(Markdown, { components: ANSWER_MARKDOWN_COMPONENTS, children: body }) }) }),
2898
3049
  streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
2899
3050
  ] }) : null,
2900
3051
  streaming ? /* @__PURE__ */ jsx(ThinkingIndicator, { activity }) : null,
2901
- failed && !body ? /* @__PURE__ */ jsx("div", { className: "rounded-2xl rounded-tl-md border border-border bg-muted px-4 py-3 text-sm text-muted-foreground", children: "That answer didn't come through. Try asking again." }) : null,
3052
+ failed && !body ? /* @__PURE__ */ jsx("div", { className: "rounded-2xl rounded-tl-md border border-border bg-muted px-4 py-3 text-sm text-muted-foreground", children: T.answerDidNotArrive }) : null,
2902
3053
  message.references.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
2903
3054
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.sources }),
2904
3055
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: message.references.map((reference) => /* @__PURE__ */ jsx(
@@ -3314,6 +3465,12 @@ function ExplorePage({
3314
3465
  () => typeof window === "undefined" ? void 0 : window.location.href,
3315
3466
  []
3316
3467
  );
3468
+ const activeLocale = useMemo(
3469
+ () => resolveExploreLocale(locale),
3470
+ [locale]
3471
+ );
3472
+ const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);
3473
+ const rtl = isRtlLocale(activeLocale);
3317
3474
  const {
3318
3475
  phase,
3319
3476
  catalog,
@@ -3335,7 +3492,15 @@ function ExplorePage({
3335
3492
  recordClick,
3336
3493
  createShareLink,
3337
3494
  isSharedView
3338
- } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
3495
+ } = useExploreChat({
3496
+ productSlug,
3497
+ pageUrl,
3498
+ onSend,
3499
+ // Locale-aware, so a catalog outage degrades to a translated welcome rather than an
3500
+ // English one. `T.prompts` seeds the chips the same way.
3501
+ examplePrompts: examplePrompts ?? T.prompts,
3502
+ fallbackWelcome: { title: T.welcomeTitle, body: T.welcomeBody }
3503
+ });
3339
3504
  const [draft, setDraft] = useState("");
3340
3505
  const textareaRef = useRef(null);
3341
3506
  const [historyOpen, setHistoryOpen] = useState(false);
@@ -3353,12 +3518,6 @@ function ExplorePage({
3353
3518
  }
3354
3519
  });
3355
3520
  speechStopRef.current = speech.stop;
3356
- const activeLocale = useMemo(
3357
- () => resolveExploreLocale(locale),
3358
- [locale]
3359
- );
3360
- const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);
3361
- const rtl = isRtlLocale(activeLocale);
3362
3521
  const [disclaimerOpen, setDisclaimerOpen] = useState(false);
3363
3522
  const [staged, setStaged] = useState([]);
3364
3523
  const [attachmentNotice, setAttachmentNotice] = useState(null);
@@ -3366,7 +3525,7 @@ function ExplorePage({
3366
3525
  const stagedRef = useRef([]);
3367
3526
  stagedRef.current = staged;
3368
3527
  const pickQueueRef = useRef(Promise.resolve());
3369
- const [shareLabel, setShareLabel] = useState("Share");
3528
+ const [shareLabel, setShareLabel] = useState(T.share);
3370
3529
  const [shareUrl, setShareUrl] = useState(null);
3371
3530
  const scrollRef = useRef(null);
3372
3531
  const latestAssistantRef = useRef(null);
@@ -3385,6 +3544,10 @@ function ExplorePage({
3385
3544
  () => catalog.products.find((p) => p.slug === focusProduct)?.name ?? null,
3386
3545
  [catalog.products, focusProduct]
3387
3546
  );
3547
+ const imageOrigins = useMemo(
3548
+ () => inlineImageOrigins(catalog.products),
3549
+ [catalog.products]
3550
+ );
3388
3551
  useEffect(() => {
3389
3552
  const el = textareaRef.current;
3390
3553
  if (!el) return;
@@ -3423,12 +3586,12 @@ function ExplorePage({
3423
3586
  el.scrollTop = el.scrollHeight;
3424
3587
  }, [activity, latestAssistantId, messages]);
3425
3588
  const handleShare = useCallback(async () => {
3426
- setShareLabel("Copying\u2026");
3589
+ setShareLabel(T.copying);
3427
3590
  setShareUrl(null);
3428
3591
  const token = await createShareLink();
3429
3592
  if (!token) {
3430
- setShareLabel("Unavailable");
3431
- setTimeout(() => setShareLabel("Share"), 2500);
3593
+ setShareLabel(T.shareUnavailable);
3594
+ setTimeout(() => setShareLabel(T.share), 2500);
3432
3595
  return;
3433
3596
  }
3434
3597
  const url = new URL(pageUrl ?? window.location.href);
@@ -3438,13 +3601,20 @@ function ExplorePage({
3438
3601
  const shareable = url.toString();
3439
3602
  try {
3440
3603
  await navigator.clipboard.writeText(shareable);
3441
- setShareLabel("Copied");
3442
- setTimeout(() => setShareLabel("Share"), 2500);
3604
+ setShareLabel(T.copied);
3605
+ setTimeout(() => setShareLabel(T.share), 2500);
3443
3606
  } catch {
3444
3607
  setShareUrl(shareable);
3445
- setShareLabel("Share");
3608
+ setShareLabel(T.share);
3446
3609
  }
3447
- }, [createShareLink, pageUrl]);
3610
+ }, [
3611
+ createShareLink,
3612
+ pageUrl,
3613
+ T.copied,
3614
+ T.copying,
3615
+ T.share,
3616
+ T.shareUnavailable
3617
+ ]);
3448
3618
  const handleFilesPicked = useCallback(
3449
3619
  (picked) => {
3450
3620
  if (!picked || picked.length === 0) return pickQueueRef.current;
@@ -3560,7 +3730,7 @@ function ExplorePage({
3560
3730
  onClick: reset,
3561
3731
  children: [
3562
3732
  /* @__PURE__ */ jsx(RotateCcw, { className: "h-3.5 w-3.5" }),
3563
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "New chat" })
3733
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: T.newChat })
3564
3734
  ]
3565
3735
  }
3566
3736
  ),
@@ -3597,7 +3767,8 @@ function ExplorePage({
3597
3767
  children: [
3598
3768
  /* @__PURE__ */ jsx(History, { className: "h-3.5 w-3.5" }),
3599
3769
  /* @__PURE__ */ jsxs("span", { className: "hidden sm:inline", children: [
3600
- "History (",
3770
+ T.history,
3771
+ " (",
3601
3772
  history.length,
3602
3773
  ")"
3603
3774
  ] })
@@ -3627,7 +3798,7 @@ function ExplorePage({
3627
3798
  },
3628
3799
  children: [
3629
3800
  /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
3630
- "Clear history"
3801
+ T.clearHistory
3631
3802
  ]
3632
3803
  }
3633
3804
  )
@@ -3707,6 +3878,7 @@ function ExplorePage({
3707
3878
  strings: T,
3708
3879
  message,
3709
3880
  activity,
3881
+ imageOrigins,
3710
3882
  onNavigate,
3711
3883
  anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
3712
3884
  onFollow: (kind, url) => recordClick(message.id, kind, url),
@@ -3893,7 +4065,7 @@ function ExplorePage({
3893
4065
  type: "button",
3894
4066
  size: "icon",
3895
4067
  variant: "secondary",
3896
- "aria-label": "Stop generating",
4068
+ "aria-label": T.stop,
3897
4069
  onClick: stop,
3898
4070
  children: /* @__PURE__ */ jsx(Square, { className: "h-4 w-4" })
3899
4071
  }
@@ -3904,7 +4076,7 @@ function ExplorePage({
3904
4076
  type: "submit",
3905
4077
  size: "icon",
3906
4078
  disabled: !canSubmit,
3907
- "aria-label": "Send message",
4079
+ "aria-label": T.send,
3908
4080
  children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" })
3909
4081
  }
3910
4082
  )
@@ -4000,6 +4172,6 @@ function ExplorePage({
4000
4172
  );
4001
4173
  }
4002
4174
 
4003
- export { ExplorePage, logoUrlOf };
4175
+ export { ExplorePage, inlineImageOrigins, isInlineImageAllowed, logoUrlOf };
4004
4176
  //# sourceMappingURL=explore.mjs.map
4005
4177
  //# sourceMappingURL=explore.mjs.map