@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.
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
- import { createContext, useMemo, useState, useRef, useEffect, useCallback, useContext } from 'react';
3
- import { Sparkles, RotateCcw, Square, ArrowUp, BookOpenText, Layers, Link2, TriangleAlert, ExternalLink } from 'lucide-react';
2
+ import { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext } from 'react';
3
+ import { Sparkles, RotateCcw, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, Link2, TriangleAlert, ExternalLink } from 'lucide-react';
4
4
  import ReactMarkdown from 'react-markdown';
5
5
  import rehypeSanitize from 'rehype-sanitize';
6
6
  import remarkGfm from 'remark-gfm';
@@ -780,6 +780,8 @@ async function getRecaptchaV3Token(siteKey, action = EXPLORE_RECAPTCHA_ACTION) {
780
780
 
781
781
  // src/hooks/use-explore-chat.ts
782
782
  var DEFAULT_STORAGE_KEY = "boff.explore.v1";
783
+ var HISTORY_SUFFIX = ".history";
784
+ var MAX_ARCHIVED_CONVERSATIONS = 15;
783
785
  var DEFAULT_POLL_INTERVAL_MS = 1500;
784
786
  var DEFAULT_POLL_TIMEOUT_MS = 9e4;
785
787
  var POLL_REQUEST_TIMEOUT_MS = 1e4;
@@ -918,10 +920,58 @@ function classifyExploreError(code, serverMessage) {
918
920
  retryable: true
919
921
  };
920
922
  }
923
+ function historyKey(key) {
924
+ return `${key}${HISTORY_SUFFIX}`;
925
+ }
926
+ function readArchive(key) {
927
+ if (typeof window === "undefined") return [];
928
+ try {
929
+ const raw = window.localStorage.getItem(historyKey(key));
930
+ if (!raw) return [];
931
+ const parsed = JSON.parse(raw);
932
+ if (!Array.isArray(parsed)) return [];
933
+ return parsed.filter(
934
+ (entry) => typeof entry === "object" && entry !== null && typeof entry.token === "string" && Array.isArray(entry.messages)
935
+ );
936
+ } catch {
937
+ return [];
938
+ }
939
+ }
940
+ function writeArchive(key, entries) {
941
+ if (typeof window === "undefined") return;
942
+ try {
943
+ if (entries.length === 0) {
944
+ window.localStorage.removeItem(historyKey(key));
945
+ return;
946
+ }
947
+ window.localStorage.setItem(historyKey(key), JSON.stringify(entries));
948
+ } catch {
949
+ }
950
+ }
951
+ function upsertArchive(key, thread) {
952
+ if (!thread.token) return readArchive(key);
953
+ const real = thread.messages.filter(
954
+ (m) => m.content.trim() !== "" || m.role === "USER"
955
+ );
956
+ if (real.length === 0) return readArchive(key);
957
+ const firstUser = real.find((m) => m.role === "USER");
958
+ const entry = {
959
+ token: thread.token,
960
+ title: (firstUser?.content ?? "Conversation").trim().slice(0, 80),
961
+ updatedAt: real[real.length - 1]?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
962
+ messageCount: real.length,
963
+ focusProduct: thread.focusProduct,
964
+ messages: real.slice(-20)
965
+ };
966
+ const rest = readArchive(key).filter((e) => e.token !== entry.token);
967
+ const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);
968
+ writeArchive(key, next);
969
+ return next;
970
+ }
921
971
  function readPersisted(key) {
922
972
  if (typeof window === "undefined") return null;
923
973
  try {
924
- const raw = window.sessionStorage.getItem(key);
974
+ const raw = window.localStorage.getItem(key);
925
975
  if (!raw) return null;
926
976
  const parsed = JSON.parse(raw);
927
977
  if (!parsed || typeof parsed !== "object") return null;
@@ -966,6 +1016,8 @@ function useExploreChat(options = {}) {
966
1016
  const [remainingToday, setRemainingToday] = useState(null);
967
1017
  const [focusProduct, setFocusProductState] = useState(null);
968
1018
  const [turnCount, setTurnCount] = useState(0);
1019
+ const messagesRef = useRef([]);
1020
+ const [archive, setArchive] = useState([]);
969
1021
  const [hydrated, setHydrated] = useState(false);
970
1022
  const mountedRef = useRef(true);
971
1023
  const pollGenerationRef = useRef(0);
@@ -1003,6 +1055,7 @@ function useExploreChat(options = {}) {
1003
1055
  setHydrated(true);
1004
1056
  return;
1005
1057
  }
1058
+ setArchive(readArchive(storageKey));
1006
1059
  const stored = readPersisted(storageKey);
1007
1060
  if (stored) {
1008
1061
  conversationTokenRef.current = stored.conversationToken;
@@ -1031,13 +1084,28 @@ function useExploreChat(options = {}) {
1031
1084
  focusProduct
1032
1085
  };
1033
1086
  if (!payload.conversationToken && payload.messages.length === 0 && !payload.focusProduct) {
1034
- window.sessionStorage.removeItem(storageKey);
1087
+ window.localStorage.removeItem(storageKey);
1035
1088
  return;
1036
1089
  }
1037
- window.sessionStorage.setItem(storageKey, JSON.stringify(payload));
1090
+ window.localStorage.setItem(storageKey, JSON.stringify(payload));
1038
1091
  } catch {
1039
1092
  }
1040
1093
  }, [persist, hydrated, storageKey, messages, focusProduct]);
1094
+ useEffect(() => {
1095
+ messagesRef.current = messages;
1096
+ if (!persist || !hydrated) return;
1097
+ const settled = messages.some(
1098
+ (m) => m.role === "ASSISTANT" && (m.status === "COMPLETED" || m.status === "FAILED")
1099
+ );
1100
+ if (!settled) return;
1101
+ setArchive(
1102
+ upsertArchive(storageKey, {
1103
+ token: conversationTokenRef.current,
1104
+ messages,
1105
+ focusProduct: focusProductRef.current
1106
+ })
1107
+ );
1108
+ }, [messages, persist, hydrated, storageKey]);
1041
1109
  useEffect(() => {
1042
1110
  let cancelled = false;
1043
1111
  const load = async () => {
@@ -1323,6 +1391,13 @@ function useExploreChat(options = {}) {
1323
1391
  void send(text);
1324
1392
  }, [cancelPolling, send]);
1325
1393
  const reset = useCallback(() => {
1394
+ setArchive(
1395
+ upsertArchive(storageKey, {
1396
+ token: conversationTokenRef.current,
1397
+ messages: messagesRef.current,
1398
+ focusProduct: focusProductRef.current
1399
+ })
1400
+ );
1326
1401
  cancelPolling();
1327
1402
  inFlightRef.current = false;
1328
1403
  conversationTokenRef.current = null;
@@ -1335,11 +1410,48 @@ function useExploreChat(options = {}) {
1335
1410
  setPhase(catalogRef.current.enabled ? "ready" : "disabled");
1336
1411
  if (typeof window !== "undefined") {
1337
1412
  try {
1338
- window.sessionStorage.removeItem(storageKey);
1413
+ window.localStorage.removeItem(storageKey);
1339
1414
  } catch {
1340
1415
  }
1341
1416
  }
1342
1417
  }, [cancelPolling, storageKey]);
1418
+ const openConversation = useCallback(
1419
+ (token) => {
1420
+ const entry = readArchive(storageKey).find((e) => e.token === token);
1421
+ if (!entry) return;
1422
+ upsertArchive(storageKey, {
1423
+ token: conversationTokenRef.current,
1424
+ messages: messagesRef.current,
1425
+ focusProduct: focusProductRef.current
1426
+ });
1427
+ cancelPolling();
1428
+ inFlightRef.current = false;
1429
+ conversationTokenRef.current = entry.token;
1430
+ turnCountRef.current = entry.messages.filter(
1431
+ (m) => m.role === "USER"
1432
+ ).length;
1433
+ setTurnCount(turnCountRef.current);
1434
+ setMessages(entry.messages);
1435
+ focusProductRef.current = entry.focusProduct;
1436
+ setFocusProductState(entry.focusProduct);
1437
+ setError(null);
1438
+ setPhase(catalogRef.current.enabled ? "ready" : "disabled");
1439
+ setArchive(readArchive(storageKey));
1440
+ },
1441
+ [cancelPolling, storageKey]
1442
+ );
1443
+ const deleteConversation = useCallback(
1444
+ (token) => {
1445
+ const next = readArchive(storageKey).filter((e) => e.token !== token);
1446
+ writeArchive(storageKey, next);
1447
+ setArchive(next);
1448
+ },
1449
+ [storageKey]
1450
+ );
1451
+ const clearHistory = useCallback(() => {
1452
+ writeArchive(storageKey, []);
1453
+ setArchive([]);
1454
+ }, [storageKey]);
1343
1455
  const setFocusProduct = useCallback((slug) => {
1344
1456
  focusProductRef.current = slug;
1345
1457
  setFocusProductState(slug);
@@ -1368,7 +1480,11 @@ function useExploreChat(options = {}) {
1368
1480
  stop,
1369
1481
  retry,
1370
1482
  reset,
1371
- canSend
1483
+ canSend,
1484
+ history: archive,
1485
+ openConversation,
1486
+ deleteConversation,
1487
+ clearHistory
1372
1488
  };
1373
1489
  }
1374
1490
  var optimisticCounter = 0;
@@ -1376,6 +1492,119 @@ function makeOptimisticId() {
1376
1492
  optimisticCounter += 1;
1377
1493
  return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
1378
1494
  }
1495
+ function getRecognitionCtor() {
1496
+ if (typeof window === "undefined") return null;
1497
+ const w = window;
1498
+ return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
1499
+ }
1500
+ function describeError(code) {
1501
+ switch (code) {
1502
+ case "not-allowed":
1503
+ case "service-not-allowed":
1504
+ return "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
1505
+ case "no-speech":
1506
+ return "I didn't catch anything \u2014 try again a little closer to the mic.";
1507
+ case "audio-capture":
1508
+ return "No microphone was found.";
1509
+ case "network":
1510
+ return "Speech recognition needs a network connection.";
1511
+ case "aborted":
1512
+ return "";
1513
+ default:
1514
+ return "Dictation stopped unexpectedly. You can type instead.";
1515
+ }
1516
+ }
1517
+ function useSpeechInput({
1518
+ onFinalTranscript,
1519
+ lang,
1520
+ onError
1521
+ }) {
1522
+ const [supported] = useState(() => getRecognitionCtor() !== null);
1523
+ const [listening, setListening] = useState(false);
1524
+ const [interim, setInterim] = useState("");
1525
+ const [error, setError] = useState(null);
1526
+ const recognitionRef = useRef(null);
1527
+ const finalRef = useRef(onFinalTranscript);
1528
+ const errorRef = useRef(onError);
1529
+ finalRef.current = onFinalTranscript;
1530
+ errorRef.current = onError;
1531
+ const stop = useCallback(() => {
1532
+ const recognition = recognitionRef.current;
1533
+ if (!recognition) return;
1534
+ try {
1535
+ recognition.stop();
1536
+ } catch {
1537
+ }
1538
+ setListening(false);
1539
+ setInterim("");
1540
+ }, []);
1541
+ const start = useCallback(() => {
1542
+ const Ctor = getRecognitionCtor();
1543
+ if (!Ctor) return;
1544
+ if (recognitionRef.current) stop();
1545
+ const recognition = new Ctor();
1546
+ recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
1547
+ recognition.continuous = true;
1548
+ recognition.interimResults = true;
1549
+ recognition.maxAlternatives = 1;
1550
+ recognition.onstart = () => {
1551
+ setError(null);
1552
+ setListening(true);
1553
+ };
1554
+ recognition.onresult = (event) => {
1555
+ let settled = "";
1556
+ let pending = "";
1557
+ for (let i = event.resultIndex; i < event.results.length; i += 1) {
1558
+ const result = event.results[i];
1559
+ if (!result) continue;
1560
+ const text = result[0]?.transcript ?? "";
1561
+ if (result.isFinal) settled += text;
1562
+ else pending += text;
1563
+ }
1564
+ setInterim(pending);
1565
+ if (settled.trim() !== "") finalRef.current(settled);
1566
+ };
1567
+ recognition.onerror = (event) => {
1568
+ const message = describeError(event.error);
1569
+ setListening(false);
1570
+ setInterim("");
1571
+ if (message !== "") {
1572
+ setError(message);
1573
+ errorRef.current?.(message);
1574
+ }
1575
+ };
1576
+ recognition.onend = () => {
1577
+ setListening(false);
1578
+ setInterim("");
1579
+ };
1580
+ recognitionRef.current = recognition;
1581
+ try {
1582
+ recognition.start();
1583
+ } catch {
1584
+ setListening(false);
1585
+ }
1586
+ }, [lang, stop]);
1587
+ const toggle = useCallback(() => {
1588
+ if (listening) stop();
1589
+ else start();
1590
+ }, [listening, start, stop]);
1591
+ useEffect(
1592
+ () => () => {
1593
+ const recognition = recognitionRef.current;
1594
+ if (!recognition) return;
1595
+ recognition.onresult = null;
1596
+ recognition.onerror = null;
1597
+ recognition.onend = null;
1598
+ recognition.onstart = null;
1599
+ try {
1600
+ recognition.abort();
1601
+ } catch {
1602
+ }
1603
+ },
1604
+ []
1605
+ );
1606
+ return { supported, listening, interim, error, start, stop, toggle };
1607
+ }
1379
1608
  function canonicalFromLocation() {
1380
1609
  if (typeof window === "undefined" || !window.location) return void 0;
1381
1610
  const { origin, pathname } = window.location;
@@ -1928,10 +2157,29 @@ function ExplorePage({
1928
2157
  stop,
1929
2158
  retry,
1930
2159
  reset,
1931
- canSend
2160
+ canSend,
2161
+ history,
2162
+ openConversation,
2163
+ deleteConversation,
2164
+ clearHistory
1932
2165
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
1933
2166
  const [draft, setDraft] = useState("");
1934
2167
  const textareaRef = useRef(null);
2168
+ const [historyOpen, setHistoryOpen] = useState(false);
2169
+ const speechStopRef = useRef(() => void 0);
2170
+ const stopDictation = useCallback(() => {
2171
+ speechStopRef.current();
2172
+ }, []);
2173
+ const speech = useSpeechInput({
2174
+ onFinalTranscript: (text) => {
2175
+ setDraft((current) => {
2176
+ const joined = current.trim() === "" ? text.trimStart() : `${current.trimEnd()} ${text.trim()}`;
2177
+ return joined;
2178
+ });
2179
+ textareaRef.current?.focus();
2180
+ }
2181
+ });
2182
+ speechStopRef.current = speech.stop;
1935
2183
  const scrollRef = useRef(null);
1936
2184
  const stickToBottomRef = useRef(true);
1937
2185
  const composingRef = useRef(false);
@@ -1967,11 +2215,12 @@ function ExplorePage({
1967
2215
  const submitDraft = useCallback(() => {
1968
2216
  const text = draft.trim();
1969
2217
  if (!text || overLimit || busy || !canSend) return;
2218
+ stopDictation();
1970
2219
  setDraft("");
1971
2220
  stickToBottomRef.current = true;
1972
2221
  void send(text);
1973
2222
  textareaRef.current?.focus();
1974
- }, [busy, canSend, draft, overLimit, send]);
2223
+ }, [busy, canSend, draft, overLimit, send, stopDictation]);
1975
2224
  const sendPrompt = useCallback(
1976
2225
  (prompt) => {
1977
2226
  if (!canSend || busy) return;
@@ -2044,8 +2293,96 @@ function ExplorePage({
2044
2293
  /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "New chat" })
2045
2294
  ]
2046
2295
  }
2047
- )
2296
+ ),
2297
+ history.length > 0 ? /* @__PURE__ */ jsxs(
2298
+ Button,
2299
+ {
2300
+ "data-boff-explore": "history-toggle",
2301
+ type: "button",
2302
+ size: "sm",
2303
+ variant: "ghost",
2304
+ className: "shrink-0 text-muted-foreground",
2305
+ "aria-expanded": historyOpen,
2306
+ onClick: () => {
2307
+ setHistoryOpen((open) => !open);
2308
+ },
2309
+ children: [
2310
+ /* @__PURE__ */ jsx(History, { className: "h-3.5 w-3.5" }),
2311
+ /* @__PURE__ */ jsxs("span", { className: "hidden sm:inline", children: [
2312
+ "History (",
2313
+ history.length,
2314
+ ")"
2315
+ ] })
2316
+ ]
2317
+ }
2318
+ ) : null
2048
2319
  ] }) : null,
2320
+ historyOpen && history.length > 0 ? /* @__PURE__ */ jsx(
2321
+ "div",
2322
+ {
2323
+ "data-boff-explore": "history-panel",
2324
+ className: "border-b border-border bg-muted/30 px-4 py-3",
2325
+ children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl", children: [
2326
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
2327
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Your recent conversations" }),
2328
+ /* @__PURE__ */ jsxs(
2329
+ Button,
2330
+ {
2331
+ "data-boff-explore": "history-clear",
2332
+ type: "button",
2333
+ size: "sm",
2334
+ variant: "ghost",
2335
+ className: "h-7 shrink-0 text-xs text-muted-foreground hover:text-destructive",
2336
+ onClick: () => {
2337
+ clearHistory();
2338
+ setHistoryOpen(false);
2339
+ },
2340
+ children: [
2341
+ /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
2342
+ "Clear history"
2343
+ ]
2344
+ }
2345
+ )
2346
+ ] }),
2347
+ /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: history.map((entry) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1", children: [
2348
+ /* @__PURE__ */ jsxs(
2349
+ "button",
2350
+ {
2351
+ "data-boff-explore": "history-item",
2352
+ type: "button",
2353
+ 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",
2354
+ onClick: () => {
2355
+ openConversation(entry.token);
2356
+ setHistoryOpen(false);
2357
+ },
2358
+ children: [
2359
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: entry.title }),
2360
+ /* @__PURE__ */ jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: [
2361
+ entry.messageCount,
2362
+ " message",
2363
+ entry.messageCount === 1 ? "" : "s"
2364
+ ] })
2365
+ ]
2366
+ }
2367
+ ),
2368
+ /* @__PURE__ */ jsx(
2369
+ Button,
2370
+ {
2371
+ type: "button",
2372
+ size: "icon",
2373
+ variant: "ghost",
2374
+ className: "h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive",
2375
+ "aria-label": `Delete conversation: ${entry.title}`,
2376
+ onClick: () => {
2377
+ deleteConversation(entry.token);
2378
+ },
2379
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
2380
+ }
2381
+ )
2382
+ ] }, entry.token)) })
2383
+ ] })
2384
+ }
2385
+ ) : null,
2049
2386
  /* @__PURE__ */ jsx(
2050
2387
  "div",
2051
2388
  {
@@ -2120,6 +2457,23 @@ function ExplorePage({
2120
2457
  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"
2121
2458
  }
2122
2459
  ),
2460
+ speech.supported ? /* @__PURE__ */ jsx(
2461
+ Button,
2462
+ {
2463
+ "data-boff-explore": "mic",
2464
+ "data-listening": speech.listening ? "true" : "false",
2465
+ type: "button",
2466
+ size: "icon",
2467
+ variant: speech.listening ? "default" : "ghost",
2468
+ disabled: composerDisabled,
2469
+ "aria-label": speech.listening ? "Stop dictating" : "Dictate your question",
2470
+ "aria-pressed": speech.listening,
2471
+ title: speech.listening ? "Stop dictating" : "Dictate your question",
2472
+ onClick: speech.toggle,
2473
+ className: cn(speech.listening && "animate-pulse"),
2474
+ children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" })
2475
+ }
2476
+ ) : null,
2123
2477
  busy ? /* @__PURE__ */ jsx(
2124
2478
  Button,
2125
2479
  {
@@ -2145,6 +2499,29 @@ function ExplorePage({
2145
2499
  ]
2146
2500
  }
2147
2501
  ),
2502
+ speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxs(
2503
+ "p",
2504
+ {
2505
+ "data-boff-explore": "dictation",
2506
+ className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
2507
+ "aria-live": "polite",
2508
+ children: [
2509
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
2510
+ /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
2511
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
2512
+ ] }),
2513
+ /* @__PURE__ */ jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
2514
+ ]
2515
+ }
2516
+ ) : null,
2517
+ speech.error !== null ? /* @__PURE__ */ jsx(
2518
+ "p",
2519
+ {
2520
+ "data-boff-explore": "dictation-error",
2521
+ className: "mt-2 text-xs text-destructive",
2522
+ children: speech.error
2523
+ }
2524
+ ) : null,
2148
2525
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
2149
2526
  /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
2150
2527
  remainingToday !== null ? /* @__PURE__ */ jsxs("span", { "data-boff-explore": "remaining", children: [
@@ -2168,39 +2545,48 @@ function ExplorePage({
2168
2545
  }
2169
2546
  )
2170
2547
  ] }),
2171
- /* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: [
2172
- "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources.",
2173
- captchaOn ? /* @__PURE__ */ jsxs(Fragment, { children: [
2174
- " ",
2175
- "This site is protected by reCAPTCHA; the Google",
2176
- " ",
2177
- /* @__PURE__ */ jsx(
2178
- "a",
2179
- {
2180
- href: "https://policies.google.com/privacy",
2181
- target: "_blank",
2182
- rel: "noopener noreferrer",
2183
- className: "underline underline-offset-2 hover:text-foreground",
2184
- children: "Privacy Policy"
2185
- }
2186
- ),
2187
- " ",
2188
- "and",
2189
- " ",
2190
- /* @__PURE__ */ jsx(
2191
- "a",
2192
- {
2193
- href: "https://policies.google.com/terms",
2194
- target: "_blank",
2195
- rel: "noopener noreferrer",
2196
- className: "underline underline-offset-2 hover:text-foreground",
2197
- children: "Terms of Service"
2198
- }
2199
- ),
2200
- " ",
2201
- "apply."
2202
- ] }) : null
2203
- ] })
2548
+ /* @__PURE__ */ jsxs(
2549
+ "p",
2550
+ {
2551
+ "data-boff-explore": "disclaimer",
2552
+ className: "mt-2 text-xs leading-relaxed text-muted-foreground",
2553
+ children: [
2554
+ "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources.",
2555
+ " ",
2556
+ "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.",
2557
+ captchaOn ? /* @__PURE__ */ jsxs(Fragment, { children: [
2558
+ " ",
2559
+ "This site is protected by reCAPTCHA; the Google",
2560
+ " ",
2561
+ /* @__PURE__ */ jsx(
2562
+ "a",
2563
+ {
2564
+ href: "https://policies.google.com/privacy",
2565
+ target: "_blank",
2566
+ rel: "noopener noreferrer",
2567
+ className: "underline underline-offset-2 hover:text-foreground",
2568
+ children: "Privacy Policy"
2569
+ }
2570
+ ),
2571
+ " ",
2572
+ "and",
2573
+ " ",
2574
+ /* @__PURE__ */ jsx(
2575
+ "a",
2576
+ {
2577
+ href: "https://policies.google.com/terms",
2578
+ target: "_blank",
2579
+ rel: "noopener noreferrer",
2580
+ className: "underline underline-offset-2 hover:text-foreground",
2581
+ children: "Terms of Service"
2582
+ }
2583
+ ),
2584
+ " ",
2585
+ "apply."
2586
+ ] }) : null
2587
+ ]
2588
+ }
2589
+ )
2204
2590
  ]
2205
2591
  }
2206
2592
  ) })