@burdenoff/website-sdk 2026.829.1 → 2026.829.2

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.
package/dist/index.mjs CHANGED
@@ -4929,6 +4929,7 @@ var EXPLORE_MESSAGE_FIELDS = (
4929
4929
  description
4930
4930
  product
4931
4931
  imageUrl
4932
+ index
4932
4933
  }
4933
4934
  ctas {
4934
4935
  kind
@@ -4936,6 +4937,8 @@ var EXPLORE_MESSAGE_FIELDS = (
4936
4937
  url
4937
4938
  product
4938
4939
  }
4940
+ followUps
4941
+ answered
4939
4942
  errorCode
4940
4943
  createdAt
4941
4944
  completedAt
@@ -5001,6 +5004,16 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
5001
5004
  }
5002
5005
  `
5003
5006
  );
5007
+ var RECORD_EXPLORE_CLICK_MUTATION = (
5008
+ /* GraphQL */
5009
+ `
5010
+ mutation RecordExploreClick($input: RecordExploreClickInput!) {
5011
+ recordExploreClick(input: $input) {
5012
+ recorded
5013
+ }
5014
+ }
5015
+ `
5016
+ );
5004
5017
 
5005
5018
  // src/data/products.ts
5006
5019
  var ECOSYSTEM_PRODUCTS = [
@@ -5933,6 +5946,20 @@ function useExploreChat(options = {}) {
5933
5946
  return null;
5934
5947
  }, [messages]);
5935
5948
  const canSend = (phase === "ready" || phase === "error") && catalog.enabled && turnCount < catalog.limits.maxTurnsPerConversation;
5949
+ const recordClick = useCallback(
5950
+ (messageId, kind, url) => {
5951
+ const token = conversationTokenRef.current;
5952
+ if (!token) return;
5953
+ try {
5954
+ void client.mutate(RECORD_EXPLORE_CLICK_MUTATION, {
5955
+ input: { conversationToken: token, messageId, kind, url }
5956
+ }).catch(() => {
5957
+ });
5958
+ } catch {
5959
+ }
5960
+ },
5961
+ [client]
5962
+ );
5936
5963
  return {
5937
5964
  phase,
5938
5965
  catalog,
@@ -5950,7 +5977,8 @@ function useExploreChat(options = {}) {
5950
5977
  history: archive,
5951
5978
  openConversation,
5952
5979
  deleteConversation,
5953
- clearHistory
5980
+ clearHistory,
5981
+ recordClick
5954
5982
  };
5955
5983
  }
5956
5984
  var optimisticCounter = 0;
@@ -6322,7 +6350,10 @@ function logoUrlOf(url) {
6322
6350
  return null;
6323
6351
  }
6324
6352
  }
6325
- function ReferenceCard({ reference }) {
6353
+ function ReferenceCard({
6354
+ reference,
6355
+ onFollow
6356
+ }) {
6326
6357
  const [imageFailed, setImageFailed] = useState(false);
6327
6358
  const [logoFailed, setLogoFailed] = useState(false);
6328
6359
  const host = hostnameOf(reference.url);
@@ -6344,9 +6375,11 @@ function ReferenceCard({ reference }) {
6344
6375
  "a",
6345
6376
  {
6346
6377
  "data-boff-explore": "reference",
6378
+ "data-index": reference.index ?? void 0,
6347
6379
  href: reference.url,
6348
6380
  target: "_blank",
6349
6381
  rel: "noopener noreferrer",
6382
+ onClick: () => onFollow?.(reference.url),
6350
6383
  className: "group flex flex-row items-center gap-3 overflow-hidden rounded-xl border border-border bg-card p-2 transition-colors hover:border-primary/40 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:flex-col sm:items-stretch sm:gap-0 sm:p-0",
6351
6384
  children: [
6352
6385
  /* @__PURE__ */ jsx("div", { className: "relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden", children: logoImg }),
@@ -6370,7 +6403,10 @@ function ReferenceCard({ reference }) {
6370
6403
  }
6371
6404
  ) }) : letterPlate }),
6372
6405
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3", children: [
6373
- /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: reference.title || host || reference.url }),
6406
+ /* @__PURE__ */ jsxs("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: [
6407
+ reference.index ? /* @__PURE__ */ jsx("span", { className: "mr-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded bg-primary/10 px-1 text-[10px] font-bold text-primary", children: reference.index }) : null,
6408
+ reference.title || host || reference.url
6409
+ ] }),
6374
6410
  reference.description ? /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden", children: reference.description }) : null,
6375
6411
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:mt-auto sm:pt-2", children: [
6376
6412
  reference.product ? /* @__PURE__ */ jsx("span", { className: "rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground max-sm:hidden", children: reference.product }) : null,
@@ -6386,7 +6422,8 @@ function ReferenceCard({ reference }) {
6386
6422
  }
6387
6423
  function CtaButton({
6388
6424
  cta,
6389
- onNavigate
6425
+ onNavigate,
6426
+ onFollow
6390
6427
  }) {
6391
6428
  const variant = CTA_VARIANTS[cta.kind] ?? "outline";
6392
6429
  const internal = isInternalPath(cta.url);
@@ -6399,7 +6436,10 @@ function CtaButton({
6399
6436
  type: "button",
6400
6437
  size: "sm",
6401
6438
  variant,
6402
- onClick: () => onNavigate(cta.url),
6439
+ onClick: () => {
6440
+ onFollow?.(cta.url);
6441
+ onNavigate(cta.url);
6442
+ },
6403
6443
  children: cta.label
6404
6444
  }
6405
6445
  );
@@ -6410,6 +6450,7 @@ function CtaButton({
6410
6450
  "data-boff-explore": "cta",
6411
6451
  "data-kind": cta.kind,
6412
6452
  href: cta.url,
6453
+ onClick: () => onFollow?.(cta.url),
6413
6454
  ...internal ? {} : { target: "_blank", rel: "noopener noreferrer" },
6414
6455
  children: [
6415
6456
  cta.label,
@@ -6461,7 +6502,9 @@ function AssistantBubble({
6461
6502
  message,
6462
6503
  activity,
6463
6504
  onNavigate,
6464
- anchorRef
6505
+ anchorRef,
6506
+ onFollow,
6507
+ onFollowUp
6465
6508
  }) {
6466
6509
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
6467
6510
  const body = message.content || message.partialContent || "";
@@ -6483,6 +6526,34 @@ function AssistantBubble({
6483
6526
  }
6484
6527
  ),
6485
6528
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
6529
+ message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxs(
6530
+ "div",
6531
+ {
6532
+ "data-boff-explore": "no-answer",
6533
+ className: "flex items-start gap-2 rounded-xl border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs leading-relaxed text-foreground",
6534
+ children: [
6535
+ /* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" }),
6536
+ /* @__PURE__ */ jsxs("span", { children: [
6537
+ "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
6538
+ " ",
6539
+ /* @__PURE__ */ jsx(
6540
+ "a",
6541
+ {
6542
+ href: "/contact",
6543
+ className: "underline underline-offset-2 hover:text-primary",
6544
+ onClick: (event) => {
6545
+ if (!onNavigate) return;
6546
+ event.preventDefault();
6547
+ onNavigate("/contact");
6548
+ },
6549
+ children: "ask a human"
6550
+ }
6551
+ ),
6552
+ "."
6553
+ ] })
6554
+ ]
6555
+ }
6556
+ ) : null,
6486
6557
  body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
6487
6558
  /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
6488
6559
  streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
@@ -6491,16 +6562,41 @@ function AssistantBubble({
6491
6562
  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,
6492
6563
  message.references.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
6493
6564
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Sources" }),
6494
- /* @__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(ReferenceCard, { reference }, reference.url)) })
6565
+ /* @__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(
6566
+ ReferenceCard,
6567
+ {
6568
+ reference,
6569
+ onFollow: (url) => onFollow?.("REFERENCE", url)
6570
+ },
6571
+ reference.url
6572
+ )) })
6495
6573
  ] }) : null,
6496
6574
  message.ctas.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 pt-0.5", children: message.ctas.map((cta) => /* @__PURE__ */ jsx(
6497
6575
  CtaButton,
6498
6576
  {
6499
6577
  cta,
6500
- onNavigate
6578
+ onNavigate,
6579
+ onFollow: (url) => onFollow?.("CTA", url)
6501
6580
  },
6502
6581
  `${cta.kind}-${cta.url}`
6503
- )) }) : null
6582
+ )) }) : null,
6583
+ message.status === "COMPLETED" && (message.followUps?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 pt-0.5", children: [
6584
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Next you could ask" }),
6585
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: (message.followUps ?? []).map((question) => /* @__PURE__ */ jsxs(
6586
+ "button",
6587
+ {
6588
+ "data-boff-explore": "follow-up",
6589
+ type: "button",
6590
+ onClick: () => onFollowUp?.(question),
6591
+ className: "group inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1 text-left text-xs text-card-foreground transition-colors hover:border-primary/40 hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
6592
+ children: [
6593
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: question }),
6594
+ /* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
6595
+ ]
6596
+ },
6597
+ question
6598
+ )) })
6599
+ ] }) : null
6504
6600
  ] })
6505
6601
  ]
6506
6602
  }
@@ -6574,6 +6670,9 @@ function PromptCarousel({
6574
6670
  "div",
6575
6671
  {
6576
6672
  className: "flex min-w-0 items-center gap-1.5",
6673
+ role: "group",
6674
+ "aria-roledescription": "carousel",
6675
+ "aria-label": "Example questions",
6577
6676
  onMouseEnter: () => setPaused(true),
6578
6677
  onMouseLeave: () => setPaused(false),
6579
6678
  onFocusCapture: () => setPaused(true),
@@ -6596,6 +6695,8 @@ function PromptCarousel({
6596
6695
  "data-chip-kind": "prompt",
6597
6696
  type: "button",
6598
6697
  disabled,
6698
+ "aria-label": `Ask: ${current}`,
6699
+ "aria-live": paused ? "polite" : "off",
6599
6700
  onClick: () => onPrompt(current),
6600
6701
  className: "boff-explore-fade group flex min-w-0 flex-1 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 text-left text-sm text-card-foreground shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
6601
6702
  children: [
@@ -6630,72 +6731,108 @@ function ProductStrip({
6630
6731
  "shrink-0 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
6631
6732
  active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
6632
6733
  );
6633
- return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
6634
- /* @__PURE__ */ jsxs(
6635
- "div",
6636
- {
6637
- className: cn(
6638
- "boff-explore-strip flex min-w-0 flex-1 gap-2",
6639
- expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
6734
+ return /* @__PURE__ */ jsxs(
6735
+ "div",
6736
+ {
6737
+ className: "flex min-w-0 items-center gap-2",
6738
+ role: "group",
6739
+ "aria-label": "Focus the assistant on one product",
6740
+ children: [
6741
+ /* @__PURE__ */ jsxs(
6742
+ "div",
6743
+ {
6744
+ className: cn(
6745
+ "boff-explore-strip flex min-w-0 flex-1 gap-2",
6746
+ expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
6747
+ ),
6748
+ children: [
6749
+ /* @__PURE__ */ jsx(
6750
+ "button",
6751
+ {
6752
+ "data-boff-explore": "chip",
6753
+ "data-chip-kind": "product",
6754
+ "data-product": "all",
6755
+ type: "button",
6756
+ "aria-pressed": focusProduct === null,
6757
+ onClick: () => onFocus(null),
6758
+ className: chipClass(focusProduct === null),
6759
+ children: "All products"
6760
+ }
6761
+ ),
6762
+ products.map((product) => /* @__PURE__ */ jsx(
6763
+ "button",
6764
+ {
6765
+ "data-boff-explore": "chip",
6766
+ "data-chip-kind": "product",
6767
+ "data-product": product.slug,
6768
+ type: "button",
6769
+ "aria-pressed": focusProduct === product.slug,
6770
+ title: product.tagline ?? product.name,
6771
+ onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
6772
+ className: chipClass(focusProduct === product.slug),
6773
+ children: product.name
6774
+ },
6775
+ product.slug
6776
+ ))
6777
+ ]
6778
+ }
6640
6779
  ),
6641
- children: [
6642
- /* @__PURE__ */ jsx(
6643
- "button",
6644
- {
6645
- "data-boff-explore": "chip",
6646
- "data-chip-kind": "product",
6647
- "data-product": "all",
6648
- type: "button",
6649
- "aria-pressed": focusProduct === null,
6650
- onClick: () => onFocus(null),
6651
- className: chipClass(focusProduct === null),
6652
- children: "All products"
6653
- }
6654
- ),
6655
- products.map((product) => /* @__PURE__ */ jsx(
6656
- "button",
6657
- {
6658
- "data-boff-explore": "chip",
6659
- "data-chip-kind": "product",
6660
- "data-product": product.slug,
6661
- type: "button",
6662
- "aria-pressed": focusProduct === product.slug,
6663
- title: product.tagline ?? product.name,
6664
- onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
6665
- className: chipClass(focusProduct === product.slug),
6666
- children: product.name
6667
- },
6668
- product.slug
6669
- ))
6670
- ]
6671
- }
6672
- ),
6673
- products.length > 0 ? /* @__PURE__ */ jsx(
6674
- "button",
6675
- {
6676
- type: "button",
6677
- "data-boff-explore": "products-toggle",
6678
- onClick: () => setExpanded((v) => !v),
6679
- className: "shrink-0 whitespace-nowrap rounded-full px-2 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
6680
- children: expanded ? "Show less" : `All ${products.length}`
6681
- }
6682
- ) : null
6683
- ] });
6780
+ products.length > 0 ? /* @__PURE__ */ jsx(
6781
+ "button",
6782
+ {
6783
+ type: "button",
6784
+ "data-boff-explore": "products-toggle",
6785
+ "aria-expanded": expanded,
6786
+ onClick: () => setExpanded((v) => !v),
6787
+ className: "shrink-0 whitespace-nowrap rounded-full px-2 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
6788
+ children: expanded ? "Show less" : `All ${products.length}`
6789
+ }
6790
+ ) : null
6791
+ ]
6792
+ }
6793
+ );
6684
6794
  }
6685
6795
  function DisclaimerDialog({
6686
6796
  open,
6687
6797
  onClose,
6688
6798
  captchaOn
6689
6799
  }) {
6800
+ const panelRef = useRef(null);
6690
6801
  const closeRef = useRef(null);
6802
+ const titleId = "boff-explore-disclaimer-title";
6691
6803
  useEffect(() => {
6692
6804
  if (!open) return;
6805
+ const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
6806
+ const focusable = () => Array.from(
6807
+ panelRef.current?.querySelectorAll(
6808
+ 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
6809
+ ) ?? []
6810
+ );
6693
6811
  const onKey = (event) => {
6694
- if (event.key === "Escape") onClose();
6812
+ if (event.key === "Escape") {
6813
+ onClose();
6814
+ return;
6815
+ }
6816
+ if (event.key !== "Tab") return;
6817
+ const items = focusable();
6818
+ if (items.length === 0) return;
6819
+ const first = items[0];
6820
+ const last = items[items.length - 1];
6821
+ const active = document.activeElement;
6822
+ if (event.shiftKey && (active === first || !panelRef.current?.contains(active))) {
6823
+ event.preventDefault();
6824
+ last?.focus();
6825
+ } else if (!event.shiftKey && active === last) {
6826
+ event.preventDefault();
6827
+ first?.focus();
6828
+ }
6695
6829
  };
6696
6830
  document.addEventListener("keydown", onKey);
6697
6831
  closeRef.current?.focus();
6698
- return () => document.removeEventListener("keydown", onKey);
6832
+ return () => {
6833
+ document.removeEventListener("keydown", onKey);
6834
+ opener?.focus();
6835
+ };
6699
6836
  }, [open, onClose]);
6700
6837
  if (!open) return null;
6701
6838
  return /* @__PURE__ */ jsx(
@@ -6704,19 +6841,34 @@ function DisclaimerDialog({
6704
6841
  "data-boff-explore": "disclaimer-dialog",
6705
6842
  role: "dialog",
6706
6843
  "aria-modal": "true",
6707
- "aria-label": "How this assistant works",
6844
+ "aria-labelledby": titleId,
6708
6845
  className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
6709
6846
  onClick: onClose,
6710
6847
  children: /* @__PURE__ */ jsxs(
6711
6848
  "div",
6712
6849
  {
6850
+ ref: panelRef,
6713
6851
  className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
6714
6852
  onClick: (event) => event.stopPropagation(),
6715
6853
  children: [
6716
6854
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
6717
- /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4" }) }),
6855
+ /* @__PURE__ */ jsx(
6856
+ "span",
6857
+ {
6858
+ "aria-hidden": "true",
6859
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary",
6860
+ children: /* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4" })
6861
+ }
6862
+ ),
6718
6863
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
6719
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-card-foreground", children: "How this assistant works" }),
6864
+ /* @__PURE__ */ jsx(
6865
+ "p",
6866
+ {
6867
+ id: titleId,
6868
+ className: "text-sm font-semibold text-card-foreground",
6869
+ children: "How this assistant works"
6870
+ }
6871
+ ),
6720
6872
  /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
6721
6873
  /* @__PURE__ */ jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
6722
6874
  /* @__PURE__ */ jsx("p", { children: "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." }),
@@ -6828,7 +6980,8 @@ function ExplorePage({
6828
6980
  history,
6829
6981
  openConversation,
6830
6982
  deleteConversation,
6831
- clearHistory
6983
+ clearHistory,
6984
+ recordClick
6832
6985
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
6833
6986
  const [draft, setDraft] = useState("");
6834
6987
  const textareaRef = useRef(null);
@@ -7102,7 +7255,9 @@ function ExplorePage({
7102
7255
  message,
7103
7256
  activity,
7104
7257
  onNavigate,
7105
- anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0
7258
+ anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
7259
+ onFollow: (kind, url) => recordClick(message.id, kind, url),
7260
+ onFollowUp: sendPrompt
7106
7261
  },
7107
7262
  message.id
7108
7263
  )