@burdenoff/website-sdk 2026.828.4 → 2026.828.5

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.
@@ -806,6 +806,8 @@ async function getRecaptchaV3Token(siteKey, action = EXPLORE_RECAPTCHA_ACTION) {
806
806
 
807
807
  // src/hooks/use-explore-chat.ts
808
808
  var DEFAULT_STORAGE_KEY = "boff.explore.v1";
809
+ var HISTORY_SUFFIX = ".history";
810
+ var MAX_ARCHIVED_CONVERSATIONS = 15;
809
811
  var DEFAULT_POLL_INTERVAL_MS = 1500;
810
812
  var DEFAULT_POLL_TIMEOUT_MS = 9e4;
811
813
  var POLL_REQUEST_TIMEOUT_MS = 1e4;
@@ -944,10 +946,58 @@ function classifyExploreError(code, serverMessage) {
944
946
  retryable: true
945
947
  };
946
948
  }
949
+ function historyKey(key) {
950
+ return `${key}${HISTORY_SUFFIX}`;
951
+ }
952
+ function readArchive(key) {
953
+ if (typeof window === "undefined") return [];
954
+ try {
955
+ const raw = window.localStorage.getItem(historyKey(key));
956
+ if (!raw) return [];
957
+ const parsed = JSON.parse(raw);
958
+ if (!Array.isArray(parsed)) return [];
959
+ return parsed.filter(
960
+ (entry) => typeof entry === "object" && entry !== null && typeof entry.token === "string" && Array.isArray(entry.messages)
961
+ );
962
+ } catch {
963
+ return [];
964
+ }
965
+ }
966
+ function writeArchive(key, entries) {
967
+ if (typeof window === "undefined") return;
968
+ try {
969
+ if (entries.length === 0) {
970
+ window.localStorage.removeItem(historyKey(key));
971
+ return;
972
+ }
973
+ window.localStorage.setItem(historyKey(key), JSON.stringify(entries));
974
+ } catch {
975
+ }
976
+ }
977
+ function upsertArchive(key, thread) {
978
+ if (!thread.token) return readArchive(key);
979
+ const real = thread.messages.filter(
980
+ (m) => m.content.trim() !== "" || m.role === "USER"
981
+ );
982
+ if (real.length === 0) return readArchive(key);
983
+ const firstUser = real.find((m) => m.role === "USER");
984
+ const entry = {
985
+ token: thread.token,
986
+ title: (firstUser?.content ?? "Conversation").trim().slice(0, 80),
987
+ updatedAt: real[real.length - 1]?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
988
+ messageCount: real.length,
989
+ focusProduct: thread.focusProduct,
990
+ messages: real.slice(-20)
991
+ };
992
+ const rest = readArchive(key).filter((e) => e.token !== entry.token);
993
+ const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);
994
+ writeArchive(key, next);
995
+ return next;
996
+ }
947
997
  function readPersisted(key) {
948
998
  if (typeof window === "undefined") return null;
949
999
  try {
950
- const raw = window.sessionStorage.getItem(key);
1000
+ const raw = window.localStorage.getItem(key);
951
1001
  if (!raw) return null;
952
1002
  const parsed = JSON.parse(raw);
953
1003
  if (!parsed || typeof parsed !== "object") return null;
@@ -992,6 +1042,8 @@ function useExploreChat(options = {}) {
992
1042
  const [remainingToday, setRemainingToday] = React.useState(null);
993
1043
  const [focusProduct, setFocusProductState] = React.useState(null);
994
1044
  const [turnCount, setTurnCount] = React.useState(0);
1045
+ const messagesRef = React.useRef([]);
1046
+ const [archive, setArchive] = React.useState([]);
995
1047
  const [hydrated, setHydrated] = React.useState(false);
996
1048
  const mountedRef = React.useRef(true);
997
1049
  const pollGenerationRef = React.useRef(0);
@@ -1029,6 +1081,7 @@ function useExploreChat(options = {}) {
1029
1081
  setHydrated(true);
1030
1082
  return;
1031
1083
  }
1084
+ setArchive(readArchive(storageKey));
1032
1085
  const stored = readPersisted(storageKey);
1033
1086
  if (stored) {
1034
1087
  conversationTokenRef.current = stored.conversationToken;
@@ -1057,13 +1110,28 @@ function useExploreChat(options = {}) {
1057
1110
  focusProduct
1058
1111
  };
1059
1112
  if (!payload.conversationToken && payload.messages.length === 0 && !payload.focusProduct) {
1060
- window.sessionStorage.removeItem(storageKey);
1113
+ window.localStorage.removeItem(storageKey);
1061
1114
  return;
1062
1115
  }
1063
- window.sessionStorage.setItem(storageKey, JSON.stringify(payload));
1116
+ window.localStorage.setItem(storageKey, JSON.stringify(payload));
1064
1117
  } catch {
1065
1118
  }
1066
1119
  }, [persist, hydrated, storageKey, messages, focusProduct]);
1120
+ React.useEffect(() => {
1121
+ messagesRef.current = messages;
1122
+ if (!persist || !hydrated) return;
1123
+ const settled = messages.some(
1124
+ (m) => m.role === "ASSISTANT" && (m.status === "COMPLETED" || m.status === "FAILED")
1125
+ );
1126
+ if (!settled) return;
1127
+ setArchive(
1128
+ upsertArchive(storageKey, {
1129
+ token: conversationTokenRef.current,
1130
+ messages,
1131
+ focusProduct: focusProductRef.current
1132
+ })
1133
+ );
1134
+ }, [messages, persist, hydrated, storageKey]);
1067
1135
  React.useEffect(() => {
1068
1136
  let cancelled = false;
1069
1137
  const load = async () => {
@@ -1349,6 +1417,13 @@ function useExploreChat(options = {}) {
1349
1417
  void send(text);
1350
1418
  }, [cancelPolling, send]);
1351
1419
  const reset = React.useCallback(() => {
1420
+ setArchive(
1421
+ upsertArchive(storageKey, {
1422
+ token: conversationTokenRef.current,
1423
+ messages: messagesRef.current,
1424
+ focusProduct: focusProductRef.current
1425
+ })
1426
+ );
1352
1427
  cancelPolling();
1353
1428
  inFlightRef.current = false;
1354
1429
  conversationTokenRef.current = null;
@@ -1361,11 +1436,48 @@ function useExploreChat(options = {}) {
1361
1436
  setPhase(catalogRef.current.enabled ? "ready" : "disabled");
1362
1437
  if (typeof window !== "undefined") {
1363
1438
  try {
1364
- window.sessionStorage.removeItem(storageKey);
1439
+ window.localStorage.removeItem(storageKey);
1365
1440
  } catch {
1366
1441
  }
1367
1442
  }
1368
1443
  }, [cancelPolling, storageKey]);
1444
+ const openConversation = React.useCallback(
1445
+ (token) => {
1446
+ const entry = readArchive(storageKey).find((e) => e.token === token);
1447
+ if (!entry) return;
1448
+ upsertArchive(storageKey, {
1449
+ token: conversationTokenRef.current,
1450
+ messages: messagesRef.current,
1451
+ focusProduct: focusProductRef.current
1452
+ });
1453
+ cancelPolling();
1454
+ inFlightRef.current = false;
1455
+ conversationTokenRef.current = entry.token;
1456
+ turnCountRef.current = entry.messages.filter(
1457
+ (m) => m.role === "USER"
1458
+ ).length;
1459
+ setTurnCount(turnCountRef.current);
1460
+ setMessages(entry.messages);
1461
+ focusProductRef.current = entry.focusProduct;
1462
+ setFocusProductState(entry.focusProduct);
1463
+ setError(null);
1464
+ setPhase(catalogRef.current.enabled ? "ready" : "disabled");
1465
+ setArchive(readArchive(storageKey));
1466
+ },
1467
+ [cancelPolling, storageKey]
1468
+ );
1469
+ const deleteConversation = React.useCallback(
1470
+ (token) => {
1471
+ const next = readArchive(storageKey).filter((e) => e.token !== token);
1472
+ writeArchive(storageKey, next);
1473
+ setArchive(next);
1474
+ },
1475
+ [storageKey]
1476
+ );
1477
+ const clearHistory = React.useCallback(() => {
1478
+ writeArchive(storageKey, []);
1479
+ setArchive([]);
1480
+ }, [storageKey]);
1369
1481
  const setFocusProduct = React.useCallback((slug) => {
1370
1482
  focusProductRef.current = slug;
1371
1483
  setFocusProductState(slug);
@@ -1394,7 +1506,11 @@ function useExploreChat(options = {}) {
1394
1506
  stop,
1395
1507
  retry,
1396
1508
  reset,
1397
- canSend
1509
+ canSend,
1510
+ history: archive,
1511
+ openConversation,
1512
+ deleteConversation,
1513
+ clearHistory
1398
1514
  };
1399
1515
  }
1400
1516
  var optimisticCounter = 0;
@@ -1402,6 +1518,119 @@ function makeOptimisticId() {
1402
1518
  optimisticCounter += 1;
1403
1519
  return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
1404
1520
  }
1521
+ function getRecognitionCtor() {
1522
+ if (typeof window === "undefined") return null;
1523
+ const w = window;
1524
+ return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
1525
+ }
1526
+ function describeError(code) {
1527
+ switch (code) {
1528
+ case "not-allowed":
1529
+ case "service-not-allowed":
1530
+ return "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
1531
+ case "no-speech":
1532
+ return "I didn't catch anything \u2014 try again a little closer to the mic.";
1533
+ case "audio-capture":
1534
+ return "No microphone was found.";
1535
+ case "network":
1536
+ return "Speech recognition needs a network connection.";
1537
+ case "aborted":
1538
+ return "";
1539
+ default:
1540
+ return "Dictation stopped unexpectedly. You can type instead.";
1541
+ }
1542
+ }
1543
+ function useSpeechInput({
1544
+ onFinalTranscript,
1545
+ lang,
1546
+ onError
1547
+ }) {
1548
+ const [supported] = React.useState(() => getRecognitionCtor() !== null);
1549
+ const [listening, setListening] = React.useState(false);
1550
+ const [interim, setInterim] = React.useState("");
1551
+ const [error, setError] = React.useState(null);
1552
+ const recognitionRef = React.useRef(null);
1553
+ const finalRef = React.useRef(onFinalTranscript);
1554
+ const errorRef = React.useRef(onError);
1555
+ finalRef.current = onFinalTranscript;
1556
+ errorRef.current = onError;
1557
+ const stop = React.useCallback(() => {
1558
+ const recognition = recognitionRef.current;
1559
+ if (!recognition) return;
1560
+ try {
1561
+ recognition.stop();
1562
+ } catch {
1563
+ }
1564
+ setListening(false);
1565
+ setInterim("");
1566
+ }, []);
1567
+ const start = React.useCallback(() => {
1568
+ const Ctor = getRecognitionCtor();
1569
+ if (!Ctor) return;
1570
+ if (recognitionRef.current) stop();
1571
+ const recognition = new Ctor();
1572
+ recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
1573
+ recognition.continuous = true;
1574
+ recognition.interimResults = true;
1575
+ recognition.maxAlternatives = 1;
1576
+ recognition.onstart = () => {
1577
+ setError(null);
1578
+ setListening(true);
1579
+ };
1580
+ recognition.onresult = (event) => {
1581
+ let settled = "";
1582
+ let pending = "";
1583
+ for (let i = event.resultIndex; i < event.results.length; i += 1) {
1584
+ const result = event.results[i];
1585
+ if (!result) continue;
1586
+ const text = result[0]?.transcript ?? "";
1587
+ if (result.isFinal) settled += text;
1588
+ else pending += text;
1589
+ }
1590
+ setInterim(pending);
1591
+ if (settled.trim() !== "") finalRef.current(settled);
1592
+ };
1593
+ recognition.onerror = (event) => {
1594
+ const message = describeError(event.error);
1595
+ setListening(false);
1596
+ setInterim("");
1597
+ if (message !== "") {
1598
+ setError(message);
1599
+ errorRef.current?.(message);
1600
+ }
1601
+ };
1602
+ recognition.onend = () => {
1603
+ setListening(false);
1604
+ setInterim("");
1605
+ };
1606
+ recognitionRef.current = recognition;
1607
+ try {
1608
+ recognition.start();
1609
+ } catch {
1610
+ setListening(false);
1611
+ }
1612
+ }, [lang, stop]);
1613
+ const toggle = React.useCallback(() => {
1614
+ if (listening) stop();
1615
+ else start();
1616
+ }, [listening, start, stop]);
1617
+ React.useEffect(
1618
+ () => () => {
1619
+ const recognition = recognitionRef.current;
1620
+ if (!recognition) return;
1621
+ recognition.onresult = null;
1622
+ recognition.onerror = null;
1623
+ recognition.onend = null;
1624
+ recognition.onstart = null;
1625
+ try {
1626
+ recognition.abort();
1627
+ } catch {
1628
+ }
1629
+ },
1630
+ []
1631
+ );
1632
+ return { supported, listening, interim, error, start, stop, toggle };
1633
+ }
1405
1634
  function canonicalFromLocation() {
1406
1635
  if (typeof window === "undefined" || !window.location) return void 0;
1407
1636
  const { origin, pathname } = window.location;
@@ -1954,10 +2183,29 @@ function ExplorePage({
1954
2183
  stop,
1955
2184
  retry,
1956
2185
  reset,
1957
- canSend
2186
+ canSend,
2187
+ history,
2188
+ openConversation,
2189
+ deleteConversation,
2190
+ clearHistory
1958
2191
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
1959
2192
  const [draft, setDraft] = React.useState("");
1960
2193
  const textareaRef = React.useRef(null);
2194
+ const [historyOpen, setHistoryOpen] = React.useState(false);
2195
+ const speechStopRef = React.useRef(() => void 0);
2196
+ const stopDictation = React.useCallback(() => {
2197
+ speechStopRef.current();
2198
+ }, []);
2199
+ const speech = useSpeechInput({
2200
+ onFinalTranscript: (text) => {
2201
+ setDraft((current) => {
2202
+ const joined = current.trim() === "" ? text.trimStart() : `${current.trimEnd()} ${text.trim()}`;
2203
+ return joined;
2204
+ });
2205
+ textareaRef.current?.focus();
2206
+ }
2207
+ });
2208
+ speechStopRef.current = speech.stop;
1961
2209
  const scrollRef = React.useRef(null);
1962
2210
  const stickToBottomRef = React.useRef(true);
1963
2211
  const composingRef = React.useRef(false);
@@ -1993,11 +2241,12 @@ function ExplorePage({
1993
2241
  const submitDraft = React.useCallback(() => {
1994
2242
  const text = draft.trim();
1995
2243
  if (!text || overLimit || busy || !canSend) return;
2244
+ stopDictation();
1996
2245
  setDraft("");
1997
2246
  stickToBottomRef.current = true;
1998
2247
  void send(text);
1999
2248
  textareaRef.current?.focus();
2000
- }, [busy, canSend, draft, overLimit, send]);
2249
+ }, [busy, canSend, draft, overLimit, send, stopDictation]);
2001
2250
  const sendPrompt = React.useCallback(
2002
2251
  (prompt) => {
2003
2252
  if (!canSend || busy) return;
@@ -2070,8 +2319,96 @@ function ExplorePage({
2070
2319
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "New chat" })
2071
2320
  ]
2072
2321
  }
2073
- )
2322
+ ),
2323
+ history.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
2324
+ Button,
2325
+ {
2326
+ "data-boff-explore": "history-toggle",
2327
+ type: "button",
2328
+ size: "sm",
2329
+ variant: "ghost",
2330
+ className: "shrink-0 text-muted-foreground",
2331
+ "aria-expanded": historyOpen,
2332
+ onClick: () => {
2333
+ setHistoryOpen((open) => !open);
2334
+ },
2335
+ children: [
2336
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-3.5 w-3.5" }),
2337
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden sm:inline", children: [
2338
+ "History (",
2339
+ history.length,
2340
+ ")"
2341
+ ] })
2342
+ ]
2343
+ }
2344
+ ) : null
2074
2345
  ] }) : null,
2346
+ historyOpen && history.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2347
+ "div",
2348
+ {
2349
+ "data-boff-explore": "history-panel",
2350
+ className: "border-b border-border bg-muted/30 px-4 py-3",
2351
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-3xl", children: [
2352
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
2353
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Your recent conversations" }),
2354
+ /* @__PURE__ */ jsxRuntime.jsxs(
2355
+ Button,
2356
+ {
2357
+ "data-boff-explore": "history-clear",
2358
+ type: "button",
2359
+ size: "sm",
2360
+ variant: "ghost",
2361
+ className: "h-7 shrink-0 text-xs text-muted-foreground hover:text-destructive",
2362
+ onClick: () => {
2363
+ clearHistory();
2364
+ setHistoryOpen(false);
2365
+ },
2366
+ children: [
2367
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }),
2368
+ "Clear history"
2369
+ ]
2370
+ }
2371
+ )
2372
+ ] }),
2373
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: history.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-1", children: [
2374
+ /* @__PURE__ */ jsxRuntime.jsxs(
2375
+ "button",
2376
+ {
2377
+ "data-boff-explore": "history-item",
2378
+ type: "button",
2379
+ className: "flex-1 truncate rounded-md px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
2380
+ onClick: () => {
2381
+ openConversation(entry.token);
2382
+ setHistoryOpen(false);
2383
+ },
2384
+ children: [
2385
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: entry.title }),
2386
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: [
2387
+ entry.messageCount,
2388
+ " message",
2389
+ entry.messageCount === 1 ? "" : "s"
2390
+ ] })
2391
+ ]
2392
+ }
2393
+ ),
2394
+ /* @__PURE__ */ jsxRuntime.jsx(
2395
+ Button,
2396
+ {
2397
+ type: "button",
2398
+ size: "icon",
2399
+ variant: "ghost",
2400
+ className: "h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive",
2401
+ "aria-label": `Delete conversation: ${entry.title}`,
2402
+ onClick: () => {
2403
+ deleteConversation(entry.token);
2404
+ },
2405
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
2406
+ }
2407
+ )
2408
+ ] }, entry.token)) })
2409
+ ] })
2410
+ }
2411
+ ) : null,
2075
2412
  /* @__PURE__ */ jsxRuntime.jsx(
2076
2413
  "div",
2077
2414
  {
@@ -2146,6 +2483,23 @@ function ExplorePage({
2146
2483
  className: "max-h-[200px] min-h-[44px] flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-sm shadow-none focus-visible:ring-0 md:text-sm"
2147
2484
  }
2148
2485
  ),
2486
+ speech.supported ? /* @__PURE__ */ jsxRuntime.jsx(
2487
+ Button,
2488
+ {
2489
+ "data-boff-explore": "mic",
2490
+ "data-listening": speech.listening ? "true" : "false",
2491
+ type: "button",
2492
+ size: "icon",
2493
+ variant: speech.listening ? "default" : "ghost",
2494
+ disabled: composerDisabled,
2495
+ "aria-label": speech.listening ? "Stop dictating" : "Dictate your question",
2496
+ "aria-pressed": speech.listening,
2497
+ title: speech.listening ? "Stop dictating" : "Dictate your question",
2498
+ onClick: speech.toggle,
2499
+ className: cn(speech.listening && "animate-pulse"),
2500
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-4 w-4" })
2501
+ }
2502
+ ) : null,
2149
2503
  busy ? /* @__PURE__ */ jsxRuntime.jsx(
2150
2504
  Button,
2151
2505
  {
@@ -2171,6 +2525,29 @@ function ExplorePage({
2171
2525
  ]
2172
2526
  }
2173
2527
  ),
2528
+ speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxRuntime.jsxs(
2529
+ "p",
2530
+ {
2531
+ "data-boff-explore": "dictation",
2532
+ className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
2533
+ "aria-live": "polite",
2534
+ children: [
2535
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
2536
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
2537
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
2538
+ ] }),
2539
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
2540
+ ]
2541
+ }
2542
+ ) : null,
2543
+ speech.error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
2544
+ "p",
2545
+ {
2546
+ "data-boff-explore": "dictation-error",
2547
+ className: "mt-2 text-xs text-destructive",
2548
+ children: speech.error
2549
+ }
2550
+ ) : null,
2174
2551
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
2175
2552
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
2176
2553
  remainingToday !== null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-boff-explore": "remaining", children: [
@@ -2194,39 +2571,48 @@ function ExplorePage({
2194
2571
  }
2195
2572
  )
2196
2573
  ] }),
2197
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: [
2198
- "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources.",
2199
- captchaOn ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2200
- " ",
2201
- "This site is protected by reCAPTCHA; the Google",
2202
- " ",
2203
- /* @__PURE__ */ jsxRuntime.jsx(
2204
- "a",
2205
- {
2206
- href: "https://policies.google.com/privacy",
2207
- target: "_blank",
2208
- rel: "noopener noreferrer",
2209
- className: "underline underline-offset-2 hover:text-foreground",
2210
- children: "Privacy Policy"
2211
- }
2212
- ),
2213
- " ",
2214
- "and",
2215
- " ",
2216
- /* @__PURE__ */ jsxRuntime.jsx(
2217
- "a",
2218
- {
2219
- href: "https://policies.google.com/terms",
2220
- target: "_blank",
2221
- rel: "noopener noreferrer",
2222
- className: "underline underline-offset-2 hover:text-foreground",
2223
- children: "Terms of Service"
2224
- }
2225
- ),
2226
- " ",
2227
- "apply."
2228
- ] }) : null
2229
- ] })
2574
+ /* @__PURE__ */ jsxRuntime.jsxs(
2575
+ "p",
2576
+ {
2577
+ "data-boff-explore": "disclaimer",
2578
+ className: "mt-2 text-xs leading-relaxed text-muted-foreground",
2579
+ children: [
2580
+ "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources.",
2581
+ " ",
2582
+ "Conversations are saved in this browser so you can come back to them, and are also stored on our servers to help us improve these answers. Please don't share personal or confidential information.",
2583
+ captchaOn ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2584
+ " ",
2585
+ "This site is protected by reCAPTCHA; the Google",
2586
+ " ",
2587
+ /* @__PURE__ */ jsxRuntime.jsx(
2588
+ "a",
2589
+ {
2590
+ href: "https://policies.google.com/privacy",
2591
+ target: "_blank",
2592
+ rel: "noopener noreferrer",
2593
+ className: "underline underline-offset-2 hover:text-foreground",
2594
+ children: "Privacy Policy"
2595
+ }
2596
+ ),
2597
+ " ",
2598
+ "and",
2599
+ " ",
2600
+ /* @__PURE__ */ jsxRuntime.jsx(
2601
+ "a",
2602
+ {
2603
+ href: "https://policies.google.com/terms",
2604
+ target: "_blank",
2605
+ rel: "noopener noreferrer",
2606
+ className: "underline underline-offset-2 hover:text-foreground",
2607
+ children: "Terms of Service"
2608
+ }
2609
+ ),
2610
+ " ",
2611
+ "apply."
2612
+ ] }) : null
2613
+ ]
2614
+ }
2615
+ )
2230
2616
  ]
2231
2617
  }
2232
2618
  ) })