@burdenoff/website-sdk 2026.1102.3 → 2026.1104.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.
Files changed (42) hide show
  1. package/README.md +46 -6
  2. package/dist/avatar-live/index.d.mts +2 -2
  3. package/dist/avatar-live/index.d.ts +2 -2
  4. package/dist/avatar-live/index.js +29 -4
  5. package/dist/avatar-live/index.js.map +1 -1
  6. package/dist/avatar-live/index.mjs +29 -4
  7. package/dist/avatar-live/index.mjs.map +1 -1
  8. package/dist/avatar-live-view/index.d.mts +19 -4
  9. package/dist/avatar-live-view/index.d.ts +19 -4
  10. package/dist/avatar-live-view/index.js +135 -28
  11. package/dist/avatar-live-view/index.js.map +1 -1
  12. package/dist/avatar-live-view/index.mjs +130 -23
  13. package/dist/avatar-live-view/index.mjs.map +1 -1
  14. package/dist/{chunk-DZLUZKOX.js → chunk-22OT6E26.js} +44 -12
  15. package/dist/chunk-22OT6E26.js.map +1 -0
  16. package/dist/{chunk-ZWEEBHXJ.mjs → chunk-5JQGE3XI.mjs} +44 -12
  17. package/dist/chunk-5JQGE3XI.mjs.map +1 -0
  18. package/dist/{chunk-K3QZGJEH.mjs → chunk-7MSB3EUI.mjs} +4 -3
  19. package/dist/chunk-7MSB3EUI.mjs.map +1 -0
  20. package/dist/{chunk-7O2I32ZN.js → chunk-WSEQ2I6I.js} +4 -3
  21. package/dist/chunk-WSEQ2I6I.js.map +1 -0
  22. package/dist/components/explore.d.mts +1 -1
  23. package/dist/components/explore.d.ts +1 -1
  24. package/dist/components/explore.js +13 -13
  25. package/dist/components/explore.mjs +1 -1
  26. package/dist/{explore-DtSPdlEy.d.ts → explore-BV4dRwoC.d.ts} +7 -0
  27. package/dist/{explore-DaSNdm4O.d.mts → explore-BgEeGPvY.d.mts} +7 -0
  28. package/dist/{explore-avatar-live-config-N4WhJzgS.d.mts → explore-avatar-live-config-B6_p0q1c.d.mts} +14 -1
  29. package/dist/{explore-avatar-live-config-CAfN5eAX.d.ts → explore-avatar-live-config-DRpS-mqQ.d.ts} +14 -1
  30. package/dist/index.d.mts +13 -7
  31. package/dist/index.d.ts +13 -7
  32. package/dist/index.js +59 -48
  33. package/dist/index.js.map +1 -1
  34. package/dist/index.mjs +16 -5
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/{types-CndbmBK-.d.mts → types-CXqaLlNB.d.mts} +14 -1
  37. package/dist/{types-CndbmBK-.d.ts → types-CXqaLlNB.d.ts} +14 -1
  38. package/package.json +1 -1
  39. package/dist/chunk-7O2I32ZN.js.map +0 -1
  40. package/dist/chunk-DZLUZKOX.js.map +0 -1
  41. package/dist/chunk-K3QZGJEH.mjs.map +0 -1
  42. package/dist/chunk-ZWEEBHXJ.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-K3QZGJEH.mjs';
1
+ import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-7MSB3EUI.mjs';
2
2
  import { fill } from '../chunk-TT3MHN42.mjs';
3
3
  import { cn } from '../chunk-R7G6TWIS.mjs';
4
4
  import '../chunk-VNS5WDWO.mjs';
@@ -857,6 +857,8 @@ var PRIVACY_HREF = "/privacy#live-avatar";
857
857
  var SPEAKER_WAIT_MS = 3e4;
858
858
  var END_GRACE_MS = 1e4;
859
859
  var CLOCK_TOLERANCE_MS = 5e3;
860
+ var UNHEARD_GRACE_MS = 5e3;
861
+ var PLAYOUT_TAIL_MS = 5e3;
860
862
  var SERVICE_MAX_AGE_MS = 15 * 6e4;
861
863
  var ANSWER_OFFER_MS = SERVICE_MAX_AGE_MS - 6e4;
862
864
  var MAX_TIMER_MS = 2147483647;
@@ -866,6 +868,12 @@ var USED_ON_KEY = "boff.explore.avatarUsedOn";
866
868
  var PRIMARY = '[data-avatar-primary], [data-boff-explore="panel-continue-chat"]';
867
869
  var IDLE = { name: "idle" };
868
870
  var INERT2 = { name: "inert" };
871
+ function stopAttending(handle) {
872
+ if (handle.unheard !== null) clearTimeout(handle.unheard);
873
+ if (handle.tail !== null) clearTimeout(handle.tail);
874
+ handle.unheard = null;
875
+ handle.tail = null;
876
+ }
869
877
  var REFUSAL_TEXT = {
870
878
  busy: "busy",
871
879
  limits: "limits",
@@ -1024,11 +1032,13 @@ function clock(seconds) {
1024
1032
  function AvatarLiveView({
1025
1033
  live,
1026
1034
  active,
1035
+ open,
1027
1036
  locale,
1028
1037
  productName,
1029
1038
  still,
1030
1039
  fallback,
1031
1040
  onContinueInChat,
1041
+ onVoiceHold,
1032
1042
  continueInChat,
1033
1043
  newChat,
1034
1044
  send,
@@ -1076,9 +1086,19 @@ function AvatarLiveView({
1076
1086
  const askMaxLength = chatMaxLength !== void 0 && Number.isFinite(chatMaxLength) && chatMaxLength >= 1 ? Math.min(ASK_MAX_LENGTH, Math.floor(chatMaxLength)) : ASK_MAX_LENGTH;
1077
1087
  const [note, setNote] = useState(null);
1078
1088
  const [usedToday, setUsedToday] = useState(false);
1089
+ const showing = active && !off;
1090
+ const behindChat = open && !active && !off;
1079
1091
  const phaseRef = useRef(IDLE);
1080
- const latest = useRef({ live, locale, base, headers, off, currentPath });
1081
- latest.current = { live, locale, base, headers, off, currentPath };
1092
+ const latest = useRef({
1093
+ live,
1094
+ locale,
1095
+ base,
1096
+ headers,
1097
+ off,
1098
+ currentPath,
1099
+ showing
1100
+ });
1101
+ latest.current = { live, locale, base, headers, off, currentPath, showing };
1082
1102
  const conversationRef = useRef(conversation);
1083
1103
  conversationRef.current = conversation;
1084
1104
  const waitRef = useRef(null);
@@ -1097,6 +1117,10 @@ function AvatarLiveView({
1097
1117
  phaseRef.current = next;
1098
1118
  setPhase(next);
1099
1119
  }, []);
1120
+ const inSight = useCallback(
1121
+ () => latest.current.showing && (typeof document === "undefined" || document.visibilityState !== "hidden"),
1122
+ []
1123
+ );
1100
1124
  const setMode = useCallback((next) => {
1101
1125
  questionsRef.current = next;
1102
1126
  setQuestions(next);
@@ -1133,6 +1157,7 @@ function AvatarLiveView({
1133
1157
  const handle = sessionRef.current;
1134
1158
  if (!handle || handle.done) return;
1135
1159
  handle.done = true;
1160
+ stopAttending(handle);
1136
1161
  sessionRef.current = null;
1137
1162
  if (reason !== null) {
1138
1163
  sendEnd({
@@ -1151,6 +1176,44 @@ function AvatarLiveView({
1151
1176
  },
1152
1177
  [go]
1153
1178
  );
1179
+ const goLive = useCallback(() => {
1180
+ const current = phaseRef.current;
1181
+ const handle = sessionRef.current;
1182
+ if (current.name !== "pending" || !handle) return;
1183
+ handle.speakerArrived = true;
1184
+ if (questionsRef.current === "any") {
1185
+ noteUsedToday();
1186
+ setUsedToday(true);
1187
+ }
1188
+ go({ name: "live", session: current.session });
1189
+ }, [go]);
1190
+ const attend = useCallback(() => {
1191
+ const handle = sessionRef.current;
1192
+ if (!handle || handle.done || latest.current.live.endUnattended !== true) {
1193
+ return;
1194
+ }
1195
+ const current = phaseRef.current.name;
1196
+ if (current !== "pending" && current !== "live") return;
1197
+ const away = !inSight();
1198
+ if (away && handle.playedOut && current === "live") {
1199
+ finish("finished", "user");
1200
+ return;
1201
+ }
1202
+ if (!(away && handle.soundHeld && handle.voiceArrived)) {
1203
+ if (handle.unheard !== null) {
1204
+ clearTimeout(handle.unheard);
1205
+ handle.unheard = null;
1206
+ }
1207
+ return;
1208
+ }
1209
+ if (handle.unheard !== null) return;
1210
+ handle.unheard = setTimeout(() => {
1211
+ handle.unheard = null;
1212
+ if (sessionRef.current === handle && !handle.done && latest.current.live.endUnattended === true && handle.soundHeld && handle.voiceArrived && !inSight()) {
1213
+ finish("interrupted", "user");
1214
+ }
1215
+ }, UNHEARD_GRACE_MS);
1216
+ }, [finish, inSight]);
1154
1217
  const cancelStart = useCallback((reason) => {
1155
1218
  const run = startRef.current;
1156
1219
  if (!run) return;
@@ -1227,6 +1290,11 @@ function AvatarLiveView({
1227
1290
  joined: null,
1228
1291
  endsAt,
1229
1292
  speakerArrived: false,
1293
+ voiceArrived: false,
1294
+ soundHeld: false,
1295
+ playedOut: false,
1296
+ unheard: null,
1297
+ tail: null,
1230
1298
  done: false
1231
1299
  };
1232
1300
  setBlocked(false);
@@ -1487,9 +1555,11 @@ function AvatarLiveView({
1487
1555
  }
1488
1556
  }, [cancelStart, cancelWaiting, finish, go, reoffer]);
1489
1557
  const leave = useCallback(
1490
- (reason) => {
1558
+ (event) => {
1491
1559
  const current = phaseRef.current;
1560
+ const reason = event === "user" || event === "chat" ? "user" : "page_hide";
1492
1561
  const how = reason === "user" ? "stopped" : "interrupted";
1562
+ const keepsSession = event === "chat" || event === "hidden";
1493
1563
  switch (current.name) {
1494
1564
  case "checking": {
1495
1565
  if (reason !== "user") return;
@@ -1507,26 +1577,36 @@ function AvatarLiveView({
1507
1577
  go(reason === "user" ? IDLE : reoffer(current.offer));
1508
1578
  return;
1509
1579
  case "creating":
1580
+ if (keepsSession) return;
1510
1581
  cancelStart(reason);
1511
1582
  go({ name: "ended", how });
1512
1583
  return;
1513
1584
  case "pending":
1514
1585
  case "live":
1586
+ if (keepsSession) {
1587
+ if (current.name === "pending" && sessionRef.current?.speakerArrived) {
1588
+ goLive();
1589
+ }
1590
+ return;
1591
+ }
1515
1592
  finish(how, reason);
1516
1593
  return;
1517
1594
  default:
1518
1595
  return;
1519
1596
  }
1520
1597
  },
1521
- [cancelStart, cancelWaiting, finish, go, reoffer]
1598
+ [cancelStart, cancelWaiting, finish, go, goLive, reoffer]
1522
1599
  );
1523
- const showing = active && !off;
1524
1600
  useEffect(() => {
1525
1601
  if (!showing) {
1526
- leave("user");
1602
+ leave(behindChat ? "chat" : "user");
1527
1603
  return;
1528
1604
  }
1529
1605
  const current = phaseRef.current;
1606
+ if (current.name === "creating" || current.name === "pending" || current.name === "live") {
1607
+ setNow(Date.now());
1608
+ return;
1609
+ }
1530
1610
  const offered = offeredNow();
1531
1611
  const used = offered !== null && claimedRef.current.has(offered);
1532
1612
  if (current.name === "ended" && used) return;
@@ -1539,7 +1619,10 @@ function AvatarLiveView({
1539
1619
  current.name === "checking" && checkRef.current === null) {
1540
1620
  check();
1541
1621
  }
1542
- }, [showing, check, leave, offeredNow]);
1622
+ }, [showing, behindChat, check, leave, offeredNow]);
1623
+ useEffect(() => {
1624
+ attend();
1625
+ }, [showing, attend]);
1543
1626
  useEffect(() => {
1544
1627
  if (askedLocale.current === locale) return;
1545
1628
  askedLocale.current = locale;
@@ -1626,10 +1709,29 @@ function AvatarLiveView({
1626
1709
  const wasLive = phaseRef.current.name === "live";
1627
1710
  switch (event.type) {
1628
1711
  case "speaker-track":
1629
- if (event.kind === "video") handle.speakerArrived = true;
1712
+ if (event.kind !== "video") {
1713
+ handle.voiceArrived = true;
1714
+ attend();
1715
+ return;
1716
+ }
1717
+ handle.speakerArrived = true;
1718
+ if (!inSight()) goLive();
1630
1719
  return;
1631
1720
  case "playback-blocked":
1632
1721
  setBlocked(event.blocked);
1722
+ handle.soundHeld = event.sound ?? event.blocked;
1723
+ attend();
1724
+ return;
1725
+ case "speech-ended":
1726
+ if (latest.current.live.endUnattended !== true || handle.tail !== null || handle.playedOut) {
1727
+ return;
1728
+ }
1729
+ handle.tail = setTimeout(() => {
1730
+ handle.tail = null;
1731
+ if (sessionRef.current !== handle || handle.done) return;
1732
+ handle.playedOut = true;
1733
+ attend();
1734
+ }, PLAYOUT_TAIL_MS);
1633
1735
  return;
1634
1736
  case "speaker-left":
1635
1737
  finish(
@@ -1643,7 +1745,7 @@ function AvatarLiveView({
1643
1745
  return;
1644
1746
  }
1645
1747
  },
1646
- [finish]
1748
+ [attend, finish, goLive, inSight]
1647
1749
  );
1648
1750
  useEffect(() => {
1649
1751
  if (phase.name !== "pending") return;
@@ -1717,11 +1819,25 @@ function AvatarLiveView({
1717
1819
  const timer = setInterval(() => setNow(Date.now()), 1e3);
1718
1820
  return () => clearInterval(timer);
1719
1821
  }, [ticking]);
1822
+ const voiceLine = phase.name === "live" ? S.speaking : phase.name === "creating" || phase.name === "pending" ? S.connecting : null;
1823
+ const onVoiceHoldRef = useRef(onVoiceHold);
1824
+ onVoiceHoldRef.current = onVoiceHold;
1825
+ useEffect(() => {
1826
+ onVoiceHoldRef.current?.(voiceLine);
1827
+ }, [voiceLine]);
1828
+ useEffect(() => () => onVoiceHoldRef.current?.(null), []);
1720
1829
  useEffect(() => {
1721
1830
  if (typeof window === "undefined") return;
1722
1831
  const onPageHide = () => leave("page_hide");
1723
1832
  const onVisibility = () => {
1724
- if (document.visibilityState === "hidden") leave("page_hide");
1833
+ if (document.visibilityState === "hidden") {
1834
+ leave("hidden");
1835
+ attend();
1836
+ return;
1837
+ }
1838
+ const current = phaseRef.current.name;
1839
+ if (current === "pending" || current === "live") setNow(Date.now());
1840
+ attend();
1725
1841
  };
1726
1842
  window.addEventListener("pagehide", onPageHide);
1727
1843
  document.addEventListener("visibilitychange", onVisibility);
@@ -1729,7 +1845,7 @@ function AvatarLiveView({
1729
1845
  window.removeEventListener("pagehide", onPageHide);
1730
1846
  document.removeEventListener("visibilitychange", onVisibility);
1731
1847
  };
1732
- }, [leave]);
1848
+ }, [attend, leave]);
1733
1849
  useEffect(
1734
1850
  () => () => {
1735
1851
  const controller = checkRef.current;
@@ -1748,6 +1864,7 @@ function AvatarLiveView({
1748
1864
  sessionRef.current = null;
1749
1865
  if (handle && !handle.done) {
1750
1866
  handle.done = true;
1867
+ stopAttending(handle);
1751
1868
  sendEnd({
1752
1869
  base: handle.base,
1753
1870
  headers: handle.headers,
@@ -1827,17 +1944,7 @@ function AvatarLiveView({
1827
1944
  if (focused && focused !== document.body && focused.isConnected) return;
1828
1945
  rootRef.current?.querySelector(PRIMARY)?.focus();
1829
1946
  }, [active, phase.name, askState, shown.pendingAnswerId, blocked]);
1830
- const onPlaying = useCallback(() => {
1831
- const current = phaseRef.current;
1832
- const handle = sessionRef.current;
1833
- if (current.name !== "pending" || !handle) return;
1834
- handle.speakerArrived = true;
1835
- if (questionsRef.current === "any") {
1836
- noteUsedToday();
1837
- setUsedToday(true);
1838
- }
1839
- go({ name: "live", session: current.session });
1840
- }, [go]);
1947
+ const onPlaying = goLive;
1841
1948
  const enablePlayback = useCallback(() => {
1842
1949
  void sessionRef.current?.joined?.enablePlayback().catch(() => void 0);
1843
1950
  }, []);