@flamingo-stack/openframe-frontend-core 0.0.210 → 0.0.212-snapshot.20260528112413

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 (128) hide show
  1. package/dist/{chunk-VBFOCTMD.cjs → chunk-35XIT2CF.cjs} +17 -17
  2. package/dist/{chunk-VBFOCTMD.cjs.map → chunk-35XIT2CF.cjs.map} +1 -1
  3. package/dist/{chunk-ATEUJQKU.js → chunk-3JWIJJ44.js} +2 -2
  4. package/dist/chunk-CZR7ARBA.js +698 -0
  5. package/dist/chunk-CZR7ARBA.js.map +1 -0
  6. package/dist/{chunk-UYQOPC57.js → chunk-HICZPTRR.js} +4 -351
  7. package/dist/chunk-HICZPTRR.js.map +1 -0
  8. package/dist/{chunk-WJBPLMBX.js → chunk-IK2X5YJU.js} +3 -3
  9. package/dist/{chunk-MDTIOPVS.cjs → chunk-OTKJASSX.cjs} +26 -26
  10. package/dist/{chunk-MDTIOPVS.cjs.map → chunk-OTKJASSX.cjs.map} +1 -1
  11. package/dist/chunk-OZ3GH6OQ.cjs +698 -0
  12. package/dist/chunk-OZ3GH6OQ.cjs.map +1 -0
  13. package/dist/{chunk-6RZYJICV.cjs → chunk-P5EE2VJX.cjs} +1 -1
  14. package/dist/chunk-P5EE2VJX.cjs.map +1 -0
  15. package/dist/{chunk-EH3RWVF3.cjs → chunk-WT5JV2GS.cjs} +8 -355
  16. package/dist/chunk-WT5JV2GS.cjs.map +1 -0
  17. package/dist/{chunk-TWKPYZNQ.cjs → chunk-ZDF6F7ED.cjs} +569 -694
  18. package/dist/chunk-ZDF6F7ED.cjs.map +1 -0
  19. package/dist/{chunk-7L4DWM7P.js → chunk-ZG2YY5E7.js} +1 -1
  20. package/dist/chunk-ZG2YY5E7.js.map +1 -0
  21. package/dist/{chunk-R5RNRH62.js → chunk-ZTJVRSN5.js} +422 -547
  22. package/dist/chunk-ZTJVRSN5.js.map +1 -0
  23. package/dist/components/chat/hooks/use-chat-identity.d.ts +3 -3
  24. package/dist/components/chat/hooks/use-chat-identity.d.ts.map +1 -1
  25. package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts.map +1 -1
  26. package/dist/components/chat/hooks/use-nats-dialog-subscription.d.ts +0 -9
  27. package/dist/components/chat/hooks/use-nats-dialog-subscription.d.ts.map +1 -1
  28. package/dist/components/chat/index.cjs +6 -5
  29. package/dist/components/chat/index.cjs.map +1 -1
  30. package/dist/components/chat/index.js +5 -4
  31. package/dist/components/contact/index.cjs +7 -6
  32. package/dist/components/contact/index.cjs.map +1 -1
  33. package/dist/components/contact/index.js +6 -5
  34. package/dist/components/features/index.cjs +6 -5
  35. package/dist/components/features/index.cjs.map +1 -1
  36. package/dist/components/features/index.js +5 -4
  37. package/dist/components/features/notifications/index.d.ts +2 -2
  38. package/dist/components/features/notifications/index.d.ts.map +1 -1
  39. package/dist/components/features/notifications/notifications-context.d.ts +16 -1
  40. package/dist/components/features/notifications/notifications-context.d.ts.map +1 -1
  41. package/dist/components/features/notifications/types.d.ts +4 -0
  42. package/dist/components/features/notifications/types.d.ts.map +1 -1
  43. package/dist/components/footer-waitlist-button.d.ts +21 -2
  44. package/dist/components/footer-waitlist-button.d.ts.map +1 -1
  45. package/dist/components/index.cjs +93 -96
  46. package/dist/components/index.cjs.map +1 -1
  47. package/dist/components/index.js +17 -20
  48. package/dist/components/index.js.map +1 -1
  49. package/dist/components/navigation/app-header.d.ts.map +1 -1
  50. package/dist/components/navigation/index.cjs +6 -5
  51. package/dist/components/navigation/index.cjs.map +1 -1
  52. package/dist/components/navigation/index.js +5 -4
  53. package/dist/components/navigation/sticky-section-nav.d.ts.map +1 -1
  54. package/dist/components/tickets/help-center-card.d.ts.map +1 -1
  55. package/dist/components/tickets/index.cjs +144 -102
  56. package/dist/components/tickets/index.cjs.map +1 -1
  57. package/dist/components/tickets/index.js +98 -56
  58. package/dist/components/tickets/index.js.map +1 -1
  59. package/dist/components/tickets/ticket-row.d.ts.map +1 -1
  60. package/dist/components/ui/index.cjs +6 -5
  61. package/dist/components/ui/index.cjs.map +1 -1
  62. package/dist/components/ui/index.js +5 -4
  63. package/dist/contexts/chat-runtime-context.d.ts +6 -3
  64. package/dist/contexts/chat-runtime-context.d.ts.map +1 -1
  65. package/dist/contexts/index.cjs +2 -2
  66. package/dist/contexts/index.js +1 -1
  67. package/dist/embed-shims/index.cjs +3 -3
  68. package/dist/embed-shims/index.cjs.map +1 -1
  69. package/dist/embed-shims/index.js +4 -4
  70. package/dist/hooks/index.cjs +3 -2
  71. package/dist/hooks/index.cjs.map +1 -1
  72. package/dist/hooks/index.js +2 -1
  73. package/dist/index.cjs +8 -5
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.js +7 -4
  76. package/dist/nats/index.cjs +28 -346
  77. package/dist/nats/index.cjs.map +1 -1
  78. package/dist/nats/index.d.ts +3 -0
  79. package/dist/nats/index.d.ts.map +1 -1
  80. package/dist/nats/index.js +30 -346
  81. package/dist/nats/index.js.map +1 -1
  82. package/dist/nats/nats-provider.d.ts +28 -0
  83. package/dist/nats/nats-provider.d.ts.map +1 -0
  84. package/dist/nats/nats.d.ts +1 -0
  85. package/dist/nats/nats.d.ts.map +1 -1
  86. package/dist/nats/shared-connection.d.ts +73 -0
  87. package/dist/nats/shared-connection.d.ts.map +1 -0
  88. package/dist/nats/use-nats-subscription.d.ts +18 -0
  89. package/dist/nats/use-nats-subscription.d.ts.map +1 -0
  90. package/dist/utils/index.cjs +10 -0
  91. package/dist/utils/index.cjs.map +1 -1
  92. package/dist/utils/index.d.ts +1 -0
  93. package/dist/utils/index.d.ts.map +1 -1
  94. package/dist/utils/index.js +10 -1
  95. package/dist/utils/index.js.map +1 -1
  96. package/dist/utils/scroll-into-view.d.ts +63 -0
  97. package/dist/utils/scroll-into-view.d.ts.map +1 -0
  98. package/package.json +1 -1
  99. package/src/components/chat/hooks/use-chat-identity.ts +8 -7
  100. package/src/components/chat/hooks/use-jetstream-dialog-subscription.ts +60 -207
  101. package/src/components/chat/hooks/use-nats-dialog-subscription.ts +71 -214
  102. package/src/components/features/notifications/index.ts +2 -1
  103. package/src/components/features/notifications/notifications-context.tsx +104 -6
  104. package/src/components/features/notifications/types.ts +5 -0
  105. package/src/components/footer-waitlist-button.tsx +33 -16
  106. package/src/components/navigation/app-header.tsx +7 -9
  107. package/src/components/navigation/sticky-section-nav.tsx +6 -4
  108. package/src/components/tickets/help-center-card.tsx +55 -1
  109. package/src/components/tickets/help-center-list.tsx +9 -1
  110. package/src/components/tickets/ticket-detail-drawer.tsx +19 -4
  111. package/src/components/tickets/ticket-row.tsx +30 -19
  112. package/src/contexts/chat-runtime-context.tsx +6 -3
  113. package/src/nats/index.ts +3 -0
  114. package/src/nats/nats-provider.tsx +146 -0
  115. package/src/nats/nats.ts +2 -0
  116. package/src/nats/shared-connection.ts +285 -0
  117. package/src/nats/use-nats-subscription.ts +99 -0
  118. package/src/stories/EmbeddableChat.stories.tsx +1 -1
  119. package/src/utils/index.ts +12 -0
  120. package/src/utils/scroll-into-view.ts +74 -0
  121. package/dist/chunk-6RZYJICV.cjs.map +0 -1
  122. package/dist/chunk-7L4DWM7P.js.map +0 -1
  123. package/dist/chunk-EH3RWVF3.cjs.map +0 -1
  124. package/dist/chunk-R5RNRH62.js.map +0 -1
  125. package/dist/chunk-TWKPYZNQ.cjs.map +0 -1
  126. package/dist/chunk-UYQOPC57.js.map +0 -1
  127. /package/dist/{chunk-ATEUJQKU.js.map → chunk-3JWIJJ44.js.map} +0 -0
  128. /package/dist/{chunk-WJBPLMBX.js.map → chunk-IK2X5YJU.js.map} +0 -0
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import {
3
3
  ToolIcon,
4
- createNatsClient,
5
4
  dotColorByVariant,
6
5
  getSmallPlatformIcon,
7
6
  progressColorByVariant,
@@ -17,7 +16,7 @@ import {
17
16
  useNearViewport,
18
17
  useOnboardingState,
19
18
  useToast
20
- } from "./chunk-UYQOPC57.js";
19
+ } from "./chunk-HICZPTRR.js";
21
20
  import {
22
21
  BashIcon,
23
22
  ClickUpIcon,
@@ -68,7 +67,6 @@ import {
68
67
  Arrow02RightIcon,
69
68
  BellIcon,
70
69
  BellOffIcon,
71
- BellRingingIcon,
72
70
  BookIcon,
73
71
  BracketCurlyIcon,
74
72
  BriefcaseIcon,
@@ -139,7 +137,10 @@ import {
139
137
  } from "./chunk-W72U7OU7.js";
140
138
  import {
141
139
  useRequiredChatRuntime
142
- } from "./chunk-7L4DWM7P.js";
140
+ } from "./chunk-ZG2YY5E7.js";
141
+ import {
142
+ next_image_default
143
+ } from "./chunk-LXC6P2EO.js";
143
144
  import {
144
145
  dynamic
145
146
  } from "./chunk-EL5YVPD5.js";
@@ -150,8 +151,10 @@ import {
150
151
  useSearchParams
151
152
  } from "./chunk-PLJLE4A4.js";
152
153
  import {
153
- next_image_default
154
- } from "./chunk-LXC6P2EO.js";
154
+ acquireClient,
155
+ releaseClient,
156
+ startConnectionLifecycle
157
+ } from "./chunk-CZR7ARBA.js";
155
158
  import {
156
159
  Button,
157
160
  Checkbox,
@@ -7440,7 +7443,7 @@ function RoadmapVoteButton({
7440
7443
  init_button();
7441
7444
 
7442
7445
  // src/components/ui/image-gallery-modal.tsx
7443
- import { useState as useState70, useEffect as useEffect49 } from "react";
7446
+ import { useState as useState70, useEffect as useEffect50 } from "react";
7444
7447
 
7445
7448
  // src/components/ui/allowed-domains-input.tsx
7446
7449
  init_cn();
@@ -15016,6 +15019,15 @@ var OPENFRAME_DEV_SECTIONS = {
15016
15019
  }
15017
15020
  };
15018
15021
 
15022
+ // src/utils/scroll-into-view.ts
15023
+ function scrollElementIntoView(target, options = {}) {
15024
+ if (typeof window === "undefined" || !target) return;
15025
+ const { headerOffset = 0, behavior = "smooth", adjustTargetY } = options;
15026
+ const rawTargetY = target.getBoundingClientRect().top + window.scrollY - headerOffset;
15027
+ const finalY = adjustTargetY ? adjustTargetY(rawTargetY) : rawTargetY;
15028
+ window.scrollTo({ top: Math.max(0, finalY), behavior });
15029
+ }
15030
+
15019
15031
  // src/components/ui/benefit-card.tsx
15020
15032
  import { jsx as jsx111, jsxs as jsxs87 } from "react/jsx-runtime";
15021
15033
  var BenefitCard = ({
@@ -21962,12 +21974,48 @@ function WaitlistForm({
21962
21974
  import * as React73 from "react";
21963
21975
  import { jsx as jsx182 } from "react/jsx-runtime";
21964
21976
  var NotificationsContext = React73.createContext(null);
21977
+ function mergeNotification(base, incoming) {
21978
+ const out = { ...base };
21979
+ for (const key of Object.keys(incoming)) {
21980
+ const value = incoming[key];
21981
+ if (value !== void 0) out[key] = value;
21982
+ }
21983
+ out.read = (incoming.read ?? false) || (base.read ?? false) || false;
21984
+ out.settled = (incoming.settled ?? false) || (base.settled ?? false) || false;
21985
+ return out;
21986
+ }
21965
21987
  function reducer(state, action) {
21966
21988
  switch (action.type) {
21967
21989
  case "add": {
21968
- const next = [action.notification, ...state.filter((n) => n.id !== action.notification.id)];
21990
+ const existing = state.find((n) => n.id === action.notification.id);
21991
+ if (existing) {
21992
+ const merged = mergeNotification(existing, action.notification);
21993
+ return [merged, ...state.filter((n) => n.id !== action.notification.id)];
21994
+ }
21995
+ const next = [action.notification, ...state];
21996
+ return next.length > action.max ? next.slice(0, action.max) : next;
21997
+ }
21998
+ case "upsert": {
21999
+ const existing = state.find((n) => n.id === action.notification.id);
22000
+ if (existing) {
22001
+ const merged = mergeNotification(existing, action.notification);
22002
+ return state.map((n) => n.id === action.notification.id ? merged : n);
22003
+ }
22004
+ const next = [action.notification, ...state];
21969
22005
  return next.length > action.max ? next.slice(0, action.max) : next;
21970
22006
  }
22007
+ case "set": {
22008
+ const existingById = new Map(state.map((n) => [n.id, n]));
22009
+ return action.notifications.map((incoming) => {
22010
+ const existing = existingById.get(incoming.id);
22011
+ if (!existing) return incoming;
22012
+ return {
22013
+ ...incoming,
22014
+ read: incoming.read || existing.read,
22015
+ settled: incoming.settled || existing.settled
22016
+ };
22017
+ });
22018
+ }
21971
22019
  case "markRead":
21972
22020
  return state.map((n) => n.id === action.id ? { ...n, read: true } : n);
21973
22021
  case "markAllRead":
@@ -21994,11 +22042,16 @@ function NotificationsProvider({
21994
22042
  maxNotifications = 50,
21995
22043
  defaultShowPopups = true,
21996
22044
  onShowPopupsChange,
21997
- onHistoryClick
22045
+ onHistoryClick,
22046
+ actions
21998
22047
  }) {
21999
22048
  const [notifications, dispatch] = React73.useReducer(reducer, initialNotifications);
22000
22049
  const [isOpen, setIsOpen] = React73.useState(false);
22001
22050
  const [showPopups, setShowPopupsState] = React73.useState(defaultShowPopups);
22051
+ const actionsRef = React73.useRef(actions);
22052
+ React73.useEffect(() => {
22053
+ actionsRef.current = actions;
22054
+ }, [actions]);
22002
22055
  const addNotification = React73.useCallback(
22003
22056
  (input) => {
22004
22057
  const id = input.id ?? generateId();
@@ -22006,17 +22059,45 @@ function NotificationsProvider({
22006
22059
  ...input,
22007
22060
  id,
22008
22061
  createdAt: input.createdAt ?? Date.now(),
22009
- read: false
22062
+ read: input.read ?? false
22010
22063
  };
22011
22064
  dispatch({ type: "add", notification, max: maxNotifications });
22012
22065
  return id;
22013
22066
  },
22014
22067
  [maxNotifications]
22015
22068
  );
22016
- const markRead = React73.useCallback((id) => dispatch({ type: "markRead", id }), []);
22017
- const markAllRead = React73.useCallback(() => dispatch({ type: "markAllRead" }), []);
22018
- const markSettled = React73.useCallback((id) => dispatch({ type: "markSettled", id }), []);
22019
- const remove = React73.useCallback((id) => dispatch({ type: "remove", id }), []);
22069
+ const upsertNotification = React73.useCallback(
22070
+ (input) => {
22071
+ const notification = {
22072
+ ...input,
22073
+ id: input.id,
22074
+ createdAt: input.createdAt ?? Date.now(),
22075
+ read: input.read ?? false
22076
+ };
22077
+ dispatch({ type: "upsert", notification, max: maxNotifications });
22078
+ return input.id;
22079
+ },
22080
+ [maxNotifications]
22081
+ );
22082
+ const setNotifications = React73.useCallback((list) => {
22083
+ dispatch({ type: "set", notifications: list });
22084
+ }, []);
22085
+ const markRead = React73.useCallback((id) => {
22086
+ dispatch({ type: "markRead", id });
22087
+ void actionsRef.current?.onMarkRead?.(id);
22088
+ }, []);
22089
+ const markAllRead = React73.useCallback(() => {
22090
+ dispatch({ type: "markAllRead" });
22091
+ void actionsRef.current?.onMarkAllRead?.();
22092
+ }, []);
22093
+ const markSettled = React73.useCallback((id) => {
22094
+ dispatch({ type: "markSettled", id });
22095
+ void actionsRef.current?.onMarkSettled?.(id);
22096
+ }, []);
22097
+ const remove = React73.useCallback((id) => {
22098
+ dispatch({ type: "remove", id });
22099
+ void actionsRef.current?.onRemove?.(id);
22100
+ }, []);
22020
22101
  const clear = React73.useCallback(() => dispatch({ type: "clear" }), []);
22021
22102
  const open = React73.useCallback(() => setIsOpen(true), []);
22022
22103
  const close = React73.useCallback(() => setIsOpen(false), []);
@@ -22039,6 +22120,8 @@ function NotificationsProvider({
22039
22120
  isOpen,
22040
22121
  showPopups,
22041
22122
  addNotification,
22123
+ upsertNotification,
22124
+ setNotifications,
22042
22125
  markRead,
22043
22126
  markAllRead,
22044
22127
  markSettled,
@@ -22056,6 +22139,8 @@ function NotificationsProvider({
22056
22139
  isOpen,
22057
22140
  showPopups,
22058
22141
  addNotification,
22142
+ upsertNotification,
22143
+ setNotifications,
22059
22144
  markRead,
22060
22145
  markAllRead,
22061
22146
  markSettled,
@@ -22087,7 +22172,7 @@ init_button();
22087
22172
  init_cn();
22088
22173
 
22089
22174
  // src/components/features/notifications/notification-tile.tsx
22090
- import { useMemo as useMemo16, useEffect as useEffect32 } from "react";
22175
+ import { useMemo as useMemo16, useEffect as useEffect33 } from "react";
22091
22176
  init_button();
22092
22177
  init_cn();
22093
22178
  import { jsx as jsx183, jsxs as jsxs142 } from "react/jsx-runtime";
@@ -22101,7 +22186,7 @@ function NotificationTile({
22101
22186
  const { id, variant = "default", title, description, createdAt, read, settled } = notification;
22102
22187
  const initialElapsed = useMemo16(() => Date.now() - createdAt, [createdAt]);
22103
22188
  const isLive = !read && !settled && initialElapsed < liveDurationMs;
22104
- useEffect32(() => {
22189
+ useEffect33(() => {
22105
22190
  if (!isLive) return;
22106
22191
  const remaining = Math.max(0, liveDurationMs - initialElapsed);
22107
22192
  const timer = window.setTimeout(() => {
@@ -23029,16 +23114,16 @@ function canonicalize(status) {
23029
23114
 
23030
23115
  // src/components/navigation/header.tsx
23031
23116
  init_next_link();
23032
- import React78, { useEffect as useEffect35, useRef as useRef27, useState as useState53 } from "react";
23117
+ import React78, { useEffect as useEffect36, useRef as useRef28, useState as useState53 } from "react";
23033
23118
  init_button2();
23034
23119
  import { Fragment as Fragment26, jsx as jsx190, jsxs as jsxs149 } from "react/jsx-runtime";
23035
23120
  function Header2({ config, platform }) {
23036
23121
  const [show, setShow] = useState53(true);
23037
23122
  const [lastScrollY, setLastScrollY] = useState53(0);
23038
23123
  const [openDropdowns, setOpenDropdowns] = useState53({});
23039
- const dropdownRefs = useRef27({});
23040
- const triggerRefs = useRef27({});
23041
- useEffect35(() => {
23124
+ const dropdownRefs = useRef28({});
23125
+ const triggerRefs = useRef28({});
23126
+ useEffect36(() => {
23042
23127
  const handleClickOutside = (event) => {
23043
23128
  const target = event.target;
23044
23129
  if (!target) return;
@@ -23067,14 +23152,14 @@ function Header2({ config, platform }) {
23067
23152
  document.removeEventListener("keydown", handleEscapeKey);
23068
23153
  };
23069
23154
  }, [openDropdowns]);
23070
- useEffect35(() => {
23155
+ useEffect36(() => {
23071
23156
  return () => {
23072
23157
  setOpenDropdowns({});
23073
23158
  dropdownRefs.current = {};
23074
23159
  triggerRefs.current = {};
23075
23160
  };
23076
23161
  }, []);
23077
- useEffect35(() => {
23162
+ useEffect36(() => {
23078
23163
  if (!config.autoHide) {
23079
23164
  setShow(true);
23080
23165
  return;
@@ -23297,7 +23382,7 @@ function Header2({ config, platform }) {
23297
23382
  }
23298
23383
 
23299
23384
  // src/components/navigation/client-only-header.tsx
23300
- import { useState as useState54, useEffect as useEffect36 } from "react";
23385
+ import { useState as useState54, useEffect as useEffect37 } from "react";
23301
23386
 
23302
23387
  // src/components/navigation/header-skeleton.tsx
23303
23388
  import { jsx as jsx191, jsxs as jsxs150 } from "react/jsx-runtime";
@@ -23346,7 +23431,7 @@ function HeaderSkeleton({ config }) {
23346
23431
  import { jsx as jsx192 } from "react/jsx-runtime";
23347
23432
  function ClientOnlyHeader({ config, skeleton }) {
23348
23433
  const [isClient, setIsClient] = useState54(false);
23349
- useEffect36(() => {
23434
+ useEffect37(() => {
23350
23435
  setIsClient(true);
23351
23436
  }, []);
23352
23437
  if (!isClient) {
@@ -23356,13 +23441,13 @@ function ClientOnlyHeader({ config, skeleton }) {
23356
23441
  }
23357
23442
 
23358
23443
  // src/components/navigation/mobile-nav-panel.tsx
23359
- import { useEffect as useEffect37, useRef as useRef28 } from "react";
23444
+ import { useEffect as useEffect38, useRef as useRef29 } from "react";
23360
23445
  init_button2();
23361
23446
  import { X as X10 } from "lucide-react";
23362
23447
  import { Fragment as Fragment27, jsx as jsx193, jsxs as jsxs151 } from "react/jsx-runtime";
23363
23448
  function MobileNavPanel({ isOpen, config }) {
23364
- const panelRef = useRef28(null);
23365
- useEffect37(() => {
23449
+ const panelRef = useRef29(null);
23450
+ useEffect38(() => {
23366
23451
  if (isOpen) {
23367
23452
  document.body.style.overflow = "hidden";
23368
23453
  } else {
@@ -23372,7 +23457,7 @@ function MobileNavPanel({ isOpen, config }) {
23372
23457
  document.body.style.overflow = "unset";
23373
23458
  };
23374
23459
  }, [isOpen]);
23375
- useEffect37(() => {
23460
+ useEffect38(() => {
23376
23461
  const handleKeyDown = (e) => {
23377
23462
  if (e.key === "Escape" && isOpen) {
23378
23463
  config.onClose?.();
@@ -23480,7 +23565,7 @@ function MobileNavPanel({ isOpen, config }) {
23480
23565
  }
23481
23566
 
23482
23567
  // src/components/navigation/sliding-sidebar.tsx
23483
- import { useState as useState55, useEffect as useEffect38 } from "react";
23568
+ import { useState as useState55, useEffect as useEffect39 } from "react";
23484
23569
  import { motion as motion2, AnimatePresence } from "framer-motion";
23485
23570
  init_button2();
23486
23571
  import { Fragment as Fragment28, jsx as jsx194, jsxs as jsxs152 } from "react/jsx-runtime";
@@ -23488,7 +23573,7 @@ function SlidingSidebar({ config }) {
23488
23573
  const [expandedItems, setExpandedItems] = useState55(/* @__PURE__ */ new Set());
23489
23574
  const [mounted, setMounted] = useState55(false);
23490
23575
  const [headerHeight, setHeaderHeight] = useState55(64);
23491
- useEffect38(() => {
23576
+ useEffect39(() => {
23492
23577
  setMounted(true);
23493
23578
  const calculateHeaderHeight = () => {
23494
23579
  let totalHeight = 0;
@@ -23699,7 +23784,7 @@ function SlidingSidebar({ config }) {
23699
23784
  }
23700
23785
 
23701
23786
  // src/components/navigation/sticky-section-nav.tsx
23702
- import { useEffect as useEffect39, useState as useState56, useCallback as useCallback19, useRef as useRef29 } from "react";
23787
+ import { useEffect as useEffect40, useState as useState56, useCallback as useCallback19, useRef as useRef30 } from "react";
23703
23788
  import { jsx as jsx195, jsxs as jsxs153 } from "react/jsx-runtime";
23704
23789
  function StickySectionNav({
23705
23790
  sections,
@@ -23761,27 +23846,26 @@ function StickySectionNav({
23761
23846
  }
23762
23847
  function useSectionNavigation(sections, options) {
23763
23848
  const [activeSection, setActiveSection] = useState56(sections[0]?.id || "");
23764
- const isScrollingFromClick = useRef29(false);
23849
+ const isScrollingFromClick = useRef30(false);
23765
23850
  const { offset: offset2 = 100 } = options || {};
23766
23851
  const handleSectionClick = useCallback19((sectionId) => {
23767
23852
  const targetElement = document.getElementById(sectionId);
23768
23853
  if (!targetElement) return;
23769
23854
  isScrollingFromClick.current = true;
23770
23855
  setActiveSection(sectionId);
23771
- const top = targetElement.offsetTop - offset2;
23772
- window.scrollTo({ top, behavior: "smooth" });
23856
+ scrollElementIntoView(targetElement, { headerOffset: offset2 });
23773
23857
  setTimeout(() => {
23774
23858
  isScrollingFromClick.current = false;
23775
23859
  }, 500);
23776
23860
  }, [offset2]);
23777
- useEffect39(() => {
23861
+ useEffect40(() => {
23778
23862
  sections.forEach((section) => {
23779
23863
  if (section.ref.current && !section.ref.current.id) {
23780
23864
  section.ref.current.id = section.id;
23781
23865
  }
23782
23866
  });
23783
23867
  }, [sections]);
23784
- useEffect39(() => {
23868
+ useEffect40(() => {
23785
23869
  const handleScroll = () => {
23786
23870
  if (isScrollingFromClick.current) return;
23787
23871
  const scrollPosition = window.scrollY + offset2 + 50;
@@ -23814,7 +23898,7 @@ function useSectionNavigation(sections, options) {
23814
23898
  }
23815
23899
 
23816
23900
  // src/components/navigation/navigation-sidebar.tsx
23817
- import { useCallback as useCallback20, useEffect as useEffect40, useLayoutEffect as useLayoutEffect4, useMemo as useMemo19, useState as useState57 } from "react";
23901
+ import { useCallback as useCallback20, useEffect as useEffect41, useLayoutEffect as useLayoutEffect4, useMemo as useMemo19, useState as useState57 } from "react";
23818
23902
 
23819
23903
  // src/components/navigation/navigation-sidebar-header.tsx
23820
23904
  import { jsx as jsx196, jsxs as jsxs154 } from "react/jsx-runtime";
@@ -23967,7 +24051,7 @@ function NavigationSidebar({ config, disabled = false }) {
23967
24051
  config.minimized ?? false
23968
24052
  );
23969
24053
  const [tabletMinimized, setTabletMinimized] = useState57(true);
23970
- useEffect40(() => {
24054
+ useEffect41(() => {
23971
24055
  if (isTablet) setTabletMinimized(true);
23972
24056
  }, [isTablet]);
23973
24057
  const minimized = isTablet ? tabletMinimized : desktopMinimized;
@@ -23985,7 +24069,7 @@ function NavigationSidebar({ config, disabled = false }) {
23985
24069
  const closeOverlay = useCallback20(() => {
23986
24070
  setTabletMinimized(true);
23987
24071
  }, []);
23988
- useEffect40(() => {
24072
+ useEffect41(() => {
23989
24073
  if (!isOverlayOpen) return;
23990
24074
  const handleKeyDown = (e) => {
23991
24075
  if (e.key === "Escape") closeOverlay();
@@ -24395,16 +24479,20 @@ function NotificationsHeaderButton({
24395
24479
  dimmedClass
24396
24480
  }) {
24397
24481
  const ctx = useOptionalNotifications();
24398
- const unreadCount = ctx?.unreadCount ?? fallbackUnreadCount;
24482
+ const hasUnread = (ctx?.unreadCount ?? fallbackUnreadCount) > 0;
24399
24483
  const isActive = ctx?.isOpen ?? false;
24400
24484
  const onClick = ctx?.toggle;
24401
- const Icon2 = unreadCount > 0 ? BellRingingIcon : BellIcon;
24402
24485
  return /* @__PURE__ */ jsx203(
24403
24486
  HeaderButton,
24404
24487
  {
24405
- icon: /* @__PURE__ */ jsxs160("div", { className: "relative w-full h-full flex items-center justify-center", children: [
24406
- /* @__PURE__ */ jsx203(Icon2, { className: "h-4 w-4 md:w-6 md:h-6" }),
24407
- unreadCount > 0 && /* @__PURE__ */ jsx203("span", { className: "absolute top-2 right-2 bg-ods-accent text-ods-text-on-accent text-[8px] rounded-full w-3 h-3 md:w-4 md:h-4 flex items-center justify-center", children: unreadCount > 9 ? "9+" : unreadCount })
24488
+ icon: /* @__PURE__ */ jsxs160("div", { className: "relative w-4 h-4 md:w-6 md:h-6", children: [
24489
+ /* @__PURE__ */ jsx203(BellIcon, { className: "w-full h-full" }),
24490
+ hasUnread && /* @__PURE__ */ jsx203(
24491
+ "span",
24492
+ {
24493
+ className: "absolute top-0 right-0 bg-ods-warning rounded-full w-1.5 h-1.5 md:w-2 md:h-2"
24494
+ }
24495
+ )
24408
24496
  ] }),
24409
24497
  "aria-label": "Notifications",
24410
24498
  onClick,
@@ -24419,7 +24507,7 @@ function NotificationsHeaderButton({
24419
24507
  import { Suspense, useCallback as useCallback22, useState as useState58 } from "react";
24420
24508
 
24421
24509
  // src/components/navigation/mobile-burger-menu.tsx
24422
- import React84, { useCallback as useCallback21, useEffect as useEffect41 } from "react";
24510
+ import React84, { useCallback as useCallback21, useEffect as useEffect42 } from "react";
24423
24511
  import { Fragment as Fragment30, jsx as jsx204, jsxs as jsxs161 } from "react/jsx-runtime";
24424
24512
  var HEADER_HEIGHT = 48;
24425
24513
  var MobileBurgerMenu = React84.memo(function MobileBurgerMenu2({
@@ -24432,7 +24520,7 @@ var MobileBurgerMenu = React84.memo(function MobileBurgerMenu2({
24432
24520
  onLogout,
24433
24521
  disabled = false
24434
24522
  }) {
24435
- useEffect41(() => {
24523
+ useEffect42(() => {
24436
24524
  if (isOpen) {
24437
24525
  document.body.style.overflow = "hidden";
24438
24526
  } else {
@@ -24442,7 +24530,7 @@ var MobileBurgerMenu = React84.memo(function MobileBurgerMenu2({
24442
24530
  document.body.style.overflow = "unset";
24443
24531
  };
24444
24532
  }, [isOpen]);
24445
- useEffect41(() => {
24533
+ useEffect42(() => {
24446
24534
  const handleKeyDown = (e) => {
24447
24535
  if (e.key === "Escape" && isOpen) {
24448
24536
  onClose();
@@ -25002,7 +25090,7 @@ ScriptArguments.displayName = "ScriptArguments";
25002
25090
 
25003
25091
  // src/components/shared/onboarding/onboarding-walkthrough.tsx
25004
25092
  init_button2();
25005
- import React86, { useRef as useRef30, useCallback as useCallback23 } from "react";
25093
+ import React86, { useRef as useRef31, useCallback as useCallback23 } from "react";
25006
25094
 
25007
25095
  // src/components/shared/onboarding/onboarding-step-card.tsx
25008
25096
  import React85 from "react";
@@ -25126,10 +25214,10 @@ function OnboardingWalkthrough({
25126
25214
  allStepsComplete,
25127
25215
  markMultipleComplete
25128
25216
  } = useOnboardingState(storageKey);
25129
- const hasAutoMarkedRef = useRef30(false);
25130
- const autoMarkingInProgressRef = useRef30(false);
25131
- const lastCompletionStatusRef = useRef30(null);
25132
- const actionInProgressRef = useRef30(/* @__PURE__ */ new Set());
25217
+ const hasAutoMarkedRef = useRef31(false);
25218
+ const autoMarkingInProgressRef = useRef31(false);
25219
+ const lastCompletionStatusRef = useRef31(null);
25220
+ const actionInProgressRef = useRef31(/* @__PURE__ */ new Set());
25133
25221
  React86.useEffect(() => {
25134
25222
  if (isLoadingCompletion) {
25135
25223
  hasAutoMarkedRef.current = false;
@@ -25836,7 +25924,7 @@ var ListLoader = (props) => /* @__PURE__ */ jsx223(ContentLoader, { ...props, va
25836
25924
 
25837
25925
  // src/components/ui/table/table.tsx
25838
25926
  init_cn();
25839
- import { useEffect as useEffect42, useRef as useRef32 } from "react";
25927
+ import { useEffect as useEffect43, useRef as useRef33 } from "react";
25840
25928
  init_pagination();
25841
25929
  init_button2();
25842
25930
 
@@ -26587,10 +26675,10 @@ function Table({
26587
26675
  };
26588
26676
  const allSelected = selectedRows.length > 0 && selectedRows.length === data.length;
26589
26677
  const someSelected = selectedRows.length > 0 && selectedRows.length < data.length;
26590
- const sentinelRef = useRef32(null);
26591
- const onLoadMoreRef = useRef32(infiniteScroll?.onLoadMore);
26678
+ const sentinelRef = useRef33(null);
26679
+ const onLoadMoreRef = useRef33(infiniteScroll?.onLoadMore);
26592
26680
  onLoadMoreRef.current = infiniteScroll?.onLoadMore;
26593
- useEffect42(() => {
26681
+ useEffect43(() => {
26594
26682
  if (!infiniteScroll?.hasNextPage || infiniteScroll.isFetchingNextPage) return;
26595
26683
  const sentinel = sentinelRef.current;
26596
26684
  if (!sentinel) return;
@@ -26802,7 +26890,7 @@ import { useMemo as useMemo21 } from "react";
26802
26890
 
26803
26891
  // src/components/ui/query-report-table/query-report-table-header.tsx
26804
26892
  init_cn();
26805
- import { useRef as useRef33, useState as useState60, useCallback as useCallback24 } from "react";
26893
+ import { useRef as useRef34, useState as useState60, useCallback as useCallback24 } from "react";
26806
26894
  import { jsx as jsx235, jsxs as jsxs187 } from "react/jsx-runtime";
26807
26895
  function QueryReportTableHeader({
26808
26896
  columns,
@@ -26831,7 +26919,7 @@ function QueryReportTableHeader({
26831
26919
  );
26832
26920
  }
26833
26921
  function TruncatedHeaderCell({ value, width }) {
26834
- const textRef = useRef33(null);
26922
+ const textRef = useRef34(null);
26835
26923
  const [isTruncated, setIsTruncated] = useState60(false);
26836
26924
  const checkTruncation = useCallback24(() => {
26837
26925
  const el = textRef.current;
@@ -26861,7 +26949,7 @@ function TruncatedHeaderCell({ value, width }) {
26861
26949
 
26862
26950
  // src/components/ui/query-report-table/query-report-table-row.tsx
26863
26951
  init_cn();
26864
- import { useRef as useRef34, useState as useState61, useCallback as useCallback25 } from "react";
26952
+ import { useRef as useRef35, useState as useState61, useCallback as useCallback25 } from "react";
26865
26953
  import { jsx as jsx236, jsxs as jsxs188 } from "react/jsx-runtime";
26866
26954
  function QueryReportTableRow({
26867
26955
  row,
@@ -26907,7 +26995,7 @@ function QueryReportTableRow({
26907
26995
  );
26908
26996
  }
26909
26997
  function TruncatedCell({ value, className }) {
26910
- const textRef = useRef34(null);
26998
+ const textRef = useRef35(null);
26911
26999
  const [isTruncated, setIsTruncated] = useState61(false);
26912
27000
  const checkTruncation = useCallback25(() => {
26913
27001
  const el = textRef.current;
@@ -27426,7 +27514,7 @@ function DataTableEmpty({
27426
27514
  // src/components/ui/data-table/data-table-row.tsx
27427
27515
  init_next_link();
27428
27516
  init_cn();
27429
- import { memo as memo3, useCallback as useCallback27, useRef as useRef35 } from "react";
27517
+ import { memo as memo3, useCallback as useCallback27, useRef as useRef36 } from "react";
27430
27518
  import { flexRender as flexRender2 } from "@tanstack/react-table";
27431
27519
 
27432
27520
  // src/components/ui/data-table/data-table-skeleton.tsx
@@ -27507,7 +27595,7 @@ function DataTableRowImpl({
27507
27595
  className
27508
27596
  }) {
27509
27597
  const isLinkMode = Boolean(href) && !onClick;
27510
- const containerRef = useRef35(null);
27598
+ const containerRef = useRef36(null);
27511
27599
  const handleClick = useCallback27(
27512
27600
  (e) => {
27513
27601
  const target = e.target;
@@ -27656,7 +27744,7 @@ function DataTableBody({
27656
27744
  }
27657
27745
 
27658
27746
  // src/components/ui/data-table/data-table-infinite-footer.tsx
27659
- import { useEffect as useEffect43, useRef as useRef36 } from "react";
27747
+ import { useEffect as useEffect44, useRef as useRef37 } from "react";
27660
27748
  import { Fragment as Fragment38, jsx as jsx246, jsxs as jsxs196 } from "react/jsx-runtime";
27661
27749
  function DataTableInfiniteFooter({
27662
27750
  hasNextPage,
@@ -27665,10 +27753,10 @@ function DataTableInfiniteFooter({
27665
27753
  skeletonRows = 3,
27666
27754
  rootMargin = "200px"
27667
27755
  }) {
27668
- const sentinelRef = useRef36(null);
27669
- const onLoadMoreRef = useRef36(onLoadMore);
27756
+ const sentinelRef = useRef37(null);
27757
+ const onLoadMoreRef = useRef37(onLoadMore);
27670
27758
  onLoadMoreRef.current = onLoadMore;
27671
- useEffect43(() => {
27759
+ useEffect44(() => {
27672
27760
  if (!hasNextPage || isFetchingNextPage) return;
27673
27761
  const sentinel = sentinelRef.current;
27674
27762
  if (!sentinel) return;
@@ -28299,8 +28387,8 @@ function FilterList({
28299
28387
 
28300
28388
  // src/components/ui/tag-search-input.tsx
28301
28389
  import {
28302
- useEffect as useEffect45,
28303
- useRef as useRef38,
28390
+ useEffect as useEffect46,
28391
+ useRef as useRef39,
28304
28392
  useState as useState63
28305
28393
  } from "react";
28306
28394
  init_cn();
@@ -28335,11 +28423,11 @@ function TagSearchInput({
28335
28423
  limitTags,
28336
28424
  placeholder: currentPlaceholder
28337
28425
  });
28338
- const wrapperRef = useRef38(null);
28339
- const hiddenTagsRef = useRef38(null);
28340
- const hiddenTagsPopupRef = useRef38(null);
28426
+ const wrapperRef = useRef39(null);
28427
+ const hiddenTagsRef = useRef39(null);
28428
+ const hiddenTagsPopupRef = useRef39(null);
28341
28429
  const [showHiddenTags, setShowHiddenTags] = useState63(false);
28342
- useEffect45(() => {
28430
+ useEffect46(() => {
28343
28431
  if (!showHiddenTags) return;
28344
28432
  const handleClick = (e) => {
28345
28433
  const target = e.target;
@@ -28494,7 +28582,7 @@ function TagSearchInput({
28494
28582
  }
28495
28583
 
28496
28584
  // src/components/ui/markdown-editor.tsx
28497
- import { useRef as useRef39, useCallback as useCallback28, useState as useState64, useEffect as useEffect46 } from "react";
28585
+ import { useRef as useRef40, useCallback as useCallback28, useState as useState64, useEffect as useEffect47 } from "react";
28498
28586
  init_cn();
28499
28587
  import { Loader2 as Loader28, Upload as Upload8 } from "lucide-react";
28500
28588
  import { jsx as jsx251, jsxs as jsxs201 } from "react/jsx-runtime";
@@ -28525,7 +28613,7 @@ body .w-md-editor .w-md-editor-bar::after { content: '' !important; display: blo
28525
28613
  body .w-md-editor .w-md-editor-bar:hover::after { border-color: var(--color-text-secondary) !important; }
28526
28614
  `;
28527
28615
  function MarkdownEditorStyles() {
28528
- useEffect46(() => {
28616
+ useEffect47(() => {
28529
28617
  if (document.getElementById(MARKDOWN_EDITOR_STYLE_ID)) return;
28530
28618
  const style = document.createElement("style");
28531
28619
  style.id = MARKDOWN_EDITOR_STYLE_ID;
@@ -28549,11 +28637,11 @@ function MarkdownEditor({
28549
28637
  onFileUploaded,
28550
28638
  renderPreview
28551
28639
  }) {
28552
- const fileInputRef = useRef39(null);
28640
+ const fileInputRef = useRef40(null);
28553
28641
  const [isUploading, setIsUploading] = useState64(false);
28554
28642
  const [uploadProgress, setUploadProgress] = useState64("");
28555
28643
  const [defaultExtraCommands, setDefaultExtraCommands] = useState64([]);
28556
- useEffect46(() => {
28644
+ useEffect47(() => {
28557
28645
  import("@uiw/react-md-editor").then((mod) => {
28558
28646
  if (mod.commands?.getExtraCommands) {
28559
28647
  setDefaultExtraCommands(mod.commands.getExtraCommands());
@@ -28642,11 +28730,11 @@ function MarkdownEditor({
28642
28730
  }
28643
28731
  } : null;
28644
28732
  const extraCommands = uploadCommand ? [...defaultExtraCommands, uploadCommand] : defaultExtraCommands;
28645
- const wrapperRef = useRef39(null);
28646
- const isDraggingRef = useRef39(false);
28647
- const mouseYRef = useRef39(0);
28648
- const rafRef = useRef39(0);
28649
- const scrollParentRef = useRef39(window);
28733
+ const wrapperRef = useRef40(null);
28734
+ const isDraggingRef = useRef40(false);
28735
+ const mouseYRef = useRef40(0);
28736
+ const rafRef = useRef40(0);
28737
+ const scrollParentRef = useRef40(window);
28650
28738
  const EDGE_ZONE = 60;
28651
28739
  const MAX_SCROLL_SPEED = 15;
28652
28740
  const findScrollParent = useCallback28((el) => {
@@ -28676,7 +28764,7 @@ function MarkdownEditor({
28676
28764
  }
28677
28765
  rafRef.current = requestAnimationFrame(scrollLoop);
28678
28766
  }, []);
28679
- useEffect46(() => {
28767
+ useEffect47(() => {
28680
28768
  const wrapper = wrapperRef.current;
28681
28769
  if (!wrapper) return;
28682
28770
  const onMouseMove = (e) => {
@@ -29925,7 +30013,7 @@ function ImageGalleryModal({
29925
30013
  initialIndex = 0
29926
30014
  }) {
29927
30015
  const [selectedImageIndex, setSelectedImageIndex] = useState70(initialIndex);
29928
- useEffect49(() => {
30016
+ useEffect50(() => {
29929
30017
  if (isOpen) {
29930
30018
  setSelectedImageIndex(initialIndex);
29931
30019
  }
@@ -29940,7 +30028,7 @@ function ImageGalleryModal({
29940
30028
  setSelectedImageIndex(selectedImageIndex + 1);
29941
30029
  }
29942
30030
  };
29943
- useEffect49(() => {
30031
+ useEffect50(() => {
29944
30032
  const handleKeyPress = (event) => {
29945
30033
  if (!isOpen) return;
29946
30034
  switch (event.key) {
@@ -33694,7 +33782,7 @@ function transformWebinarToProgram(webinar) {
33694
33782
  }
33695
33783
 
33696
33784
  // src/components/chat/hooks/use-chunk-catchup.ts
33697
- import { useCallback as useCallback30, useRef as useRef42 } from "react";
33785
+ import { useCallback as useCallback30, useRef as useRef43 } from "react";
33698
33786
  function makeSeqKey(messageType, chunkType, sequenceId) {
33699
33787
  return `${messageType}:${chunkType}:${sequenceId}`;
33700
33788
  }
@@ -33716,20 +33804,20 @@ function useChunkCatchup({
33716
33804
  chatTypes = [CHAT_TYPE.CLIENT],
33717
33805
  fetchChunks
33718
33806
  }) {
33719
- const processedSequenceKeys = useRef42(/* @__PURE__ */ new Set());
33720
- const lastSequenceId = useRef42(null);
33721
- const fetchingInProgress = useRef42(false);
33722
- const lastFetchParams = useRef42(null);
33723
- const chunkBuffer = useRef42([]);
33724
- const bufferUntilInitialCatchupComplete = useRef42(false);
33725
- const hasCompletedInitialCatchup = useRef42(false);
33726
- const dialogIdRef = useRef42(dialogId);
33807
+ const processedSequenceKeys = useRef43(/* @__PURE__ */ new Set());
33808
+ const lastSequenceId = useRef43(null);
33809
+ const fetchingInProgress = useRef43(false);
33810
+ const lastFetchParams = useRef43(null);
33811
+ const chunkBuffer = useRef43([]);
33812
+ const bufferUntilInitialCatchupComplete = useRef43(false);
33813
+ const hasCompletedInitialCatchup = useRef43(false);
33814
+ const dialogIdRef = useRef43(dialogId);
33727
33815
  dialogIdRef.current = dialogId;
33728
- const chatTypesRef = useRef42(chatTypes);
33816
+ const chatTypesRef = useRef43(chatTypes);
33729
33817
  chatTypesRef.current = chatTypes;
33730
- const fetchChunksRef = useRef42(fetchChunks);
33818
+ const fetchChunksRef = useRef43(fetchChunks);
33731
33819
  fetchChunksRef.current = fetchChunks;
33732
- const onChunkReceivedRef = useRef42(onChunkReceived);
33820
+ const onChunkReceivedRef = useRef43(onChunkReceived);
33733
33821
  onChunkReceivedRef.current = onChunkReceived;
33734
33822
  const processChunk = useCallback30((chunk, messageType, forceProcess = false) => {
33735
33823
  if (bufferUntilInitialCatchupComplete.current && !forceProcess) {
@@ -33906,8 +33994,7 @@ function useChunkCatchup({
33906
33994
  }
33907
33995
 
33908
33996
  // src/components/chat/hooks/use-jetstream-dialog-subscription.ts
33909
- import { useCallback as useCallback31, useEffect as useEffect50, useRef as useRef43, useState as useState73 } from "react";
33910
- var shared = null;
33997
+ import { useEffect as useEffect51, useRef as useRef44, useState as useState73 } from "react";
33911
33998
  var DEFAULT_INACTIVE_THRESHOLD_MS = 5 * 6e4;
33912
33999
  var DEFAULT_STREAM_NAME = "CHAT_CHUNKS";
33913
34000
  function useJetStreamDialogSubscription({
@@ -33930,105 +34017,53 @@ function useJetStreamDialogSubscription({
33930
34017
  const [isSubscribed, setIsSubscribed] = useState73(false);
33931
34018
  const [reconnectionCount, setReconnectionCount] = useState73(0);
33932
34019
  const [currentStreamSeq, setCurrentStreamSeq] = useState73(null);
33933
- const clientRef = useRef43(null);
33934
- const subscriptionRef = useRef43(null);
33935
- const highestStreamSeqRef = useRef43(null);
33936
- const onEventRef = useRef43(onEvent);
33937
- useEffect50(() => {
34020
+ const clientRef = useRef44(null);
34021
+ const subscriptionRef = useRef44(null);
34022
+ const highestStreamSeqRef = useRef44(null);
34023
+ const onEventRef = useRef44(onEvent);
34024
+ useEffect51(() => {
33938
34025
  onEventRef.current = onEvent;
33939
34026
  }, [onEvent]);
33940
- const onConnectRef = useRef43(onConnect);
33941
- useEffect50(() => {
34027
+ const onConnectRef = useRef44(onConnect);
34028
+ useEffect51(() => {
33942
34029
  onConnectRef.current = onConnect;
33943
34030
  }, [onConnect]);
33944
- const onDisconnectRef = useRef43(onDisconnect);
33945
- useEffect50(() => {
34031
+ const onDisconnectRef = useRef44(onDisconnect);
34032
+ useEffect51(() => {
33946
34033
  onDisconnectRef.current = onDisconnect;
33947
34034
  }, [onDisconnect]);
33948
- const onSubscribedRef = useRef43(onSubscribed);
33949
- useEffect50(() => {
34035
+ const onSubscribedRef = useRef44(onSubscribed);
34036
+ useEffect51(() => {
33950
34037
  onSubscribedRef.current = onSubscribed;
33951
34038
  }, [onSubscribed]);
33952
- const onBeforeReconnectRef = useRef43(onBeforeReconnect);
33953
- useEffect50(() => {
34039
+ const onBeforeReconnectRef = useRef44(onBeforeReconnect);
34040
+ useEffect51(() => {
33954
34041
  onBeforeReconnectRef.current = onBeforeReconnect;
33955
34042
  }, [onBeforeReconnect]);
33956
- const getNatsWsUrlRef = useRef43(getNatsWsUrl);
33957
- useEffect50(() => {
34043
+ const getNatsWsUrlRef = useRef44(getNatsWsUrl);
34044
+ useEffect51(() => {
33958
34045
  getNatsWsUrlRef.current = getNatsWsUrl;
33959
34046
  }, [getNatsWsUrl]);
33960
- const reconnectionBackoffRef = useRef43(reconnectionBackoff);
33961
- useEffect50(() => {
34047
+ const reconnectionBackoffRef = useRef44(reconnectionBackoff);
34048
+ useEffect51(() => {
33962
34049
  reconnectionBackoffRef.current = reconnectionBackoff;
33963
34050
  }, [reconnectionBackoff]);
33964
- const optStartSeqRef = useRef43(optStartSeq);
33965
- useEffect50(() => {
34051
+ const optStartSeqRef = useRef44(optStartSeq);
34052
+ useEffect51(() => {
33966
34053
  optStartSeqRef.current = optStartSeq;
33967
34054
  }, [optStartSeq]);
33968
- const inactiveThresholdRef = useRef43(inactiveThresholdMs);
33969
- useEffect50(() => {
34055
+ const inactiveThresholdRef = useRef44(inactiveThresholdMs);
34056
+ useEffect51(() => {
33970
34057
  inactiveThresholdRef.current = inactiveThresholdMs;
33971
34058
  }, [inactiveThresholdMs]);
33972
- const hadConnectionBeforeRef = useRef43(false);
33973
- const acquireClient = useCallback31(
33974
- (url) => {
33975
- if (shared?.wsUrl !== url) {
33976
- if (shared) {
33977
- if (shared.closeTimer) clearTimeout(shared.closeTimer);
33978
- const old = shared;
33979
- shared = null;
33980
- void old.client.close().catch(() => {
33981
- });
33982
- }
33983
- const { name = "openframe-frontend-jetstream", user = "machine", pass = "" } = clientConfig;
33984
- const client = createNatsClient({
33985
- servers: url,
33986
- name,
33987
- user,
33988
- pass,
33989
- connectTimeoutMs: NETWORK_CONFIG.CONNECT_TIMEOUT_MS,
33990
- reconnect: false,
33991
- pingIntervalMs: NETWORK_CONFIG.PING_INTERVAL_MS,
33992
- maxPingOut: NETWORK_CONFIG.MAX_PING_OUT
33993
- });
33994
- shared = {
33995
- wsUrl: url,
33996
- client,
33997
- connectPromise: null,
33998
- refCount: 0,
33999
- closeTimer: null,
34000
- retryTimer: null
34001
- };
34002
- }
34003
- shared.refCount += 1;
34004
- if (shared.closeTimer) {
34005
- clearTimeout(shared.closeTimer);
34006
- shared.closeTimer = null;
34007
- }
34008
- return shared;
34009
- },
34010
- [clientConfig]
34011
- );
34012
- const releaseClient = useCallback31((url) => {
34013
- if (!shared || shared.wsUrl !== url) return;
34014
- shared.refCount = Math.max(0, shared.refCount - 1);
34015
- if (shared.refCount > 0) return;
34016
- shared.closeTimer = setTimeout(() => {
34017
- const s = shared;
34018
- shared = null;
34019
- if (s) {
34020
- if (s.retryTimer) {
34021
- clearTimeout(s.retryTimer);
34022
- s.retryTimer = null;
34023
- }
34024
- void s.client.close().catch(() => {
34025
- });
34026
- }
34027
- }, NETWORK_CONFIG.SHARED_CLOSE_DELAY_MS);
34028
- }, []);
34029
- const currentWsUrlRef = useRef43("");
34030
- useEffect50(() => {
34031
- const wsUrl = getNatsWsUrl();
34059
+ const hadConnectionBeforeRef = useRef44(false);
34060
+ const clientConfigRef = useRef44(clientConfig);
34061
+ useEffect51(() => {
34062
+ clientConfigRef.current = clientConfig;
34063
+ }, [clientConfig]);
34064
+ const currentWsUrlRef = useRef44("");
34065
+ const wsUrl = getNatsWsUrl();
34066
+ useEffect51(() => {
34032
34067
  if (!enabled || !wsUrl) {
34033
34068
  if (currentWsUrlRef.current && clientRef.current) {
34034
34069
  releaseClient(currentWsUrlRef.current);
@@ -34047,127 +34082,69 @@ function useJetStreamDialogSubscription({
34047
34082
  setIsConnected(false);
34048
34083
  }
34049
34084
  currentWsUrlRef.current = wsUrl;
34050
- const sharedConn = acquireClient(wsUrl);
34085
+ const cfg = clientConfigRef.current;
34086
+ const sharedConn = acquireClient(wsUrl, {
34087
+ name: cfg.name ?? "openframe-frontend-jetstream",
34088
+ user: cfg.user ?? "machine",
34089
+ pass: cfg.pass ?? ""
34090
+ });
34051
34091
  const client = sharedConn.client;
34052
34092
  clientRef.current = client;
34053
- setIsConnected(false);
34054
- let closed = false;
34055
- let retryAttempt = 0;
34056
- function scheduleRetry() {
34057
- if (closed) return;
34058
- if (shared !== sharedConn) return;
34059
- if (sharedConn.retryTimer) {
34060
- clearTimeout(sharedConn.retryTimer);
34061
- sharedConn.retryTimer = null;
34062
- }
34063
- const cfg = reconnectionBackoffRef.current ?? {};
34064
- const fastRetries = cfg.fastRetries ?? 0;
34065
- const fastDelay = cfg.fastRetryDelayMs ?? NETWORK_CONFIG.RETRY_INITIAL_DELAY_MS;
34066
- const baseDelay = cfg.initialDelayMs ?? NETWORK_CONFIG.RETRY_INITIAL_DELAY_MS;
34067
- const maxDelay = cfg.maxDelayMs ?? NETWORK_CONFIG.RETRY_MAX_DELAY_MS;
34068
- const multiplier = cfg.multiplier ?? NETWORK_CONFIG.RETRY_BACKOFF_MULTIPLIER;
34069
- const delay2 = retryAttempt < fastRetries ? fastDelay : Math.min(baseDelay * multiplier ** (retryAttempt - fastRetries), maxDelay);
34070
- const jitteredDelay = delay2 * (0.5 + Math.random() * 0.5);
34071
- retryAttempt++;
34072
- sharedConn.retryTimer = setTimeout(async () => {
34073
- sharedConn.retryTimer = null;
34074
- if (closed) return;
34075
- if (shared !== sharedConn) return;
34076
- try {
34077
- await onBeforeReconnectRef.current?.();
34078
- } catch {
34079
- }
34080
- if (closed) return;
34081
- if (shared !== sharedConn) return;
34082
- const freshUrl = getNatsWsUrlRef.current();
34083
- if (freshUrl !== wsUrl) return;
34093
+ setIsConnected(client.isConnected());
34094
+ const tearDownSubscription = () => {
34095
+ if (subscriptionRef.current) {
34084
34096
  try {
34085
- sharedConn.connectPromise = null;
34086
- sharedConn.connectPromise = client.connect();
34087
- await sharedConn.connectPromise;
34088
- if (!closed && shared === sharedConn) {
34089
- retryAttempt = 0;
34090
- setIsConnected(true);
34091
- }
34097
+ subscriptionRef.current.unsubscribe();
34092
34098
  } catch {
34093
- sharedConn.connectPromise = null;
34094
- if (!closed && shared === sharedConn) {
34095
- scheduleRetry();
34096
- }
34097
- }
34098
- }, jitteredDelay);
34099
- }
34100
- const unsubscribeStatus = client.onStatus((event) => {
34101
- const connected = event.status === "connected";
34102
- const disconnected = event.status === "closed" || event.status === "disconnected";
34103
- if (connected) {
34104
- setIsConnected(true);
34105
- if (hadConnectionBeforeRef.current) {
34106
- setReconnectionCount((c) => c + 1);
34107
- }
34108
- hadConnectionBeforeRef.current = true;
34109
- retryAttempt = 0;
34110
- onConnectRef.current?.();
34111
- }
34112
- if (event.status === "error") {
34113
- console.warn("[JetStream] NATS protocol error:", event.data);
34114
- return;
34115
- }
34116
- if (disconnected) {
34117
- setIsConnected(false);
34118
- setIsSubscribed(false);
34119
- if (subscriptionRef.current) {
34120
- try {
34121
- subscriptionRef.current.unsubscribe();
34122
- } catch {
34123
- }
34124
- subscriptionRef.current = null;
34125
34099
  }
34126
- onDisconnectRef.current?.();
34127
- scheduleRetry();
34100
+ subscriptionRef.current = null;
34128
34101
  }
34129
- });
34130
- (async () => {
34131
- try {
34132
- sharedConn.connectPromise || (sharedConn.connectPromise = client.connect());
34133
- await sharedConn.connectPromise;
34134
- if (!closed) {
34102
+ };
34103
+ const lifecycle = startConnectionLifecycle({
34104
+ conn: sharedConn,
34105
+ wsUrl,
34106
+ onBeforeReconnect: () => onBeforeReconnectRef.current?.(),
34107
+ backoff: reconnectionBackoffRef.current,
34108
+ getFreshUrl: () => getNatsWsUrlRef.current(),
34109
+ // JetStream emits 'error' for protocol-level failures (e.g. -ERR Permissions
34110
+ // Violation when CONSUMER.CREATE is denied) without closing the WebSocket.
34111
+ // Retrying on 'error' would loop onBeforeReconnect on every -ERR; let the
34112
+ // subscribe effect surface those via its own rejected promise instead.
34113
+ shouldRetryOn: (status) => status === "closed" || status === "disconnected",
34114
+ onStatusChange: (status, evt) => {
34115
+ if (status === "connected") {
34135
34116
  setIsConnected(true);
34117
+ if (hadConnectionBeforeRef.current) {
34118
+ setReconnectionCount((c) => c + 1);
34119
+ }
34136
34120
  hadConnectionBeforeRef.current = true;
34121
+ onConnectRef.current?.();
34137
34122
  }
34138
- } catch {
34139
- sharedConn.connectPromise = null;
34140
- if (!closed) {
34123
+ if (status === "error") {
34124
+ console.warn("[JetStream] NATS protocol error:", evt.data);
34125
+ return;
34126
+ }
34127
+ if (status === "closed" || status === "disconnected") {
34141
34128
  setIsConnected(false);
34129
+ setIsSubscribed(false);
34130
+ tearDownSubscription();
34142
34131
  onDisconnectRef.current?.();
34143
- scheduleRetry();
34144
34132
  }
34145
34133
  }
34146
- })();
34134
+ });
34147
34135
  return () => {
34148
- closed = true;
34136
+ lifecycle.stop();
34149
34137
  setIsConnected(false);
34150
34138
  setIsSubscribed(false);
34151
- unsubscribeStatus();
34152
- if (sharedConn.retryTimer) {
34153
- clearTimeout(sharedConn.retryTimer);
34154
- sharedConn.retryTimer = null;
34155
- }
34156
- if (subscriptionRef.current) {
34157
- try {
34158
- subscriptionRef.current.unsubscribe();
34159
- } catch {
34160
- }
34161
- subscriptionRef.current = null;
34162
- }
34139
+ tearDownSubscription();
34163
34140
  if (clientRef.current && currentWsUrlRef.current) {
34164
34141
  releaseClient(currentWsUrlRef.current);
34165
34142
  clientRef.current = null;
34166
34143
  currentWsUrlRef.current = "";
34167
34144
  }
34168
34145
  };
34169
- }, [enabled, getNatsWsUrl, acquireClient, releaseClient]);
34170
- useEffect50(() => {
34146
+ }, [enabled, wsUrl]);
34147
+ useEffect51(() => {
34171
34148
  if (!enabled || !dialogId || !isConnected) {
34172
34149
  if (subscriptionRef.current) {
34173
34150
  try {
@@ -34250,7 +34227,7 @@ function useJetStreamDialogSubscription({
34250
34227
  setIsSubscribed(false);
34251
34228
  };
34252
34229
  }, [enabled, dialogId, isConnected, streamName, topic, reconnectionCount]);
34253
- useEffect50(() => {
34230
+ useEffect51(() => {
34254
34231
  highestStreamSeqRef.current = null;
34255
34232
  setCurrentStreamSeq(null);
34256
34233
  }, [dialogId]);
@@ -34258,8 +34235,7 @@ function useJetStreamDialogSubscription({
34258
34235
  }
34259
34236
 
34260
34237
  // src/components/chat/hooks/use-nats-dialog-subscription.ts
34261
- import { useCallback as useCallback32, useEffect as useEffect51, useRef as useRef44, useState as useState74 } from "react";
34262
- var shared2 = null;
34238
+ import { useEffect as useEffect52, useRef as useRef45, useState as useState74 } from "react";
34263
34239
  function useNatsDialogSubscription({
34264
34240
  enabled,
34265
34241
  dialogId,
@@ -34276,84 +34252,44 @@ function useNatsDialogSubscription({
34276
34252
  const [isConnected, setIsConnected] = useState74(false);
34277
34253
  const [isSubscribed, setIsSubscribed] = useState74(false);
34278
34254
  const [reconnectionCount, setReconnectionCount] = useState74(0);
34279
- const clientRef = useRef44(null);
34280
- const subscriptionRefs = useRef44(/* @__PURE__ */ new Map());
34281
- const onEventRef = useRef44(onEvent);
34282
- useEffect51(() => {
34255
+ const clientRef = useRef45(null);
34256
+ const subscriptionRefs = useRef45(/* @__PURE__ */ new Map());
34257
+ const onEventRef = useRef45(onEvent);
34258
+ useEffect52(() => {
34283
34259
  onEventRef.current = onEvent;
34284
34260
  }, [onEvent]);
34285
- const onConnectRef = useRef44(onConnect);
34286
- useEffect51(() => {
34261
+ const onConnectRef = useRef45(onConnect);
34262
+ useEffect52(() => {
34287
34263
  onConnectRef.current = onConnect;
34288
34264
  }, [onConnect]);
34289
- const onDisconnectRef = useRef44(onDisconnect);
34290
- useEffect51(() => {
34265
+ const onDisconnectRef = useRef45(onDisconnect);
34266
+ useEffect52(() => {
34291
34267
  onDisconnectRef.current = onDisconnect;
34292
34268
  }, [onDisconnect]);
34293
- const onSubscribedRef = useRef44(onSubscribed);
34294
- useEffect51(() => {
34269
+ const onSubscribedRef = useRef45(onSubscribed);
34270
+ useEffect52(() => {
34295
34271
  onSubscribedRef.current = onSubscribed;
34296
34272
  }, [onSubscribed]);
34297
- const onBeforeReconnectRef = useRef44(onBeforeReconnect);
34298
- useEffect51(() => {
34273
+ const onBeforeReconnectRef = useRef45(onBeforeReconnect);
34274
+ useEffect52(() => {
34299
34275
  onBeforeReconnectRef.current = onBeforeReconnect;
34300
34276
  }, [onBeforeReconnect]);
34301
- const hadConnectionBeforeRef = useRef44(false);
34302
- const getNatsWsUrlRef = useRef44(getNatsWsUrl);
34303
- useEffect51(() => {
34277
+ const hadConnectionBeforeRef = useRef45(false);
34278
+ const getNatsWsUrlRef = useRef45(getNatsWsUrl);
34279
+ useEffect52(() => {
34304
34280
  getNatsWsUrlRef.current = getNatsWsUrl;
34305
34281
  }, [getNatsWsUrl]);
34306
- const reconnectionBackoffRef = useRef44(reconnectionBackoff);
34307
- useEffect51(() => {
34282
+ const reconnectionBackoffRef = useRef45(reconnectionBackoff);
34283
+ useEffect52(() => {
34308
34284
  reconnectionBackoffRef.current = reconnectionBackoff;
34309
34285
  }, [reconnectionBackoff]);
34310
- const acquireClient = useCallback32((url) => {
34311
- if (shared2?.wsUrl !== url) {
34312
- if (shared2) {
34313
- shared2.closeTimer && clearTimeout(shared2.closeTimer);
34314
- const old = shared2;
34315
- shared2 = null;
34316
- void old.client.close().catch(() => {
34317
- });
34318
- }
34319
- const { name = "openframe-frontend", user = "machine", pass = "" } = clientConfig;
34320
- const client = createNatsClient({
34321
- servers: url,
34322
- name,
34323
- user,
34324
- pass,
34325
- connectTimeoutMs: NETWORK_CONFIG.CONNECT_TIMEOUT_MS,
34326
- reconnect: false,
34327
- pingIntervalMs: NETWORK_CONFIG.PING_INTERVAL_MS,
34328
- maxPingOut: NETWORK_CONFIG.MAX_PING_OUT
34329
- });
34330
- shared2 = { wsUrl: url, client, connectPromise: null, refCount: 0, closeTimer: null, retryTimer: null };
34331
- }
34332
- shared2.refCount += 1;
34333
- shared2.closeTimer && clearTimeout(shared2.closeTimer);
34334
- shared2.closeTimer = null;
34335
- return shared2;
34286
+ const clientConfigRef = useRef45(clientConfig);
34287
+ useEffect52(() => {
34288
+ clientConfigRef.current = clientConfig;
34336
34289
  }, [clientConfig]);
34337
- const releaseClient = useCallback32((url) => {
34338
- if (!shared2 || shared2.wsUrl !== url) return;
34339
- shared2.refCount = Math.max(0, shared2.refCount - 1);
34340
- if (shared2.refCount > 0) return;
34341
- shared2.closeTimer = setTimeout(() => {
34342
- const s = shared2;
34343
- shared2 = null;
34344
- if (s) {
34345
- if (s.retryTimer) {
34346
- clearTimeout(s.retryTimer);
34347
- s.retryTimer = null;
34348
- }
34349
- void s.client.close().catch(() => {
34350
- });
34351
- }
34352
- }, NETWORK_CONFIG.SHARED_CLOSE_DELAY_MS);
34353
- }, []);
34354
- const currentWsUrlRef = useRef44("");
34355
- useEffect51(() => {
34356
- const wsUrl = getNatsWsUrl();
34290
+ const currentWsUrlRef = useRef45("");
34291
+ const wsUrl = getNatsWsUrl();
34292
+ useEffect52(() => {
34357
34293
  if (!enabled || !wsUrl) {
34358
34294
  if (currentWsUrlRef.current && clientRef.current) {
34359
34295
  releaseClient(currentWsUrlRef.current);
@@ -34372,135 +34308,73 @@ function useNatsDialogSubscription({
34372
34308
  setIsConnected(false);
34373
34309
  }
34374
34310
  currentWsUrlRef.current = wsUrl;
34375
- const sharedConn = acquireClient(wsUrl);
34311
+ const cfg = clientConfigRef.current;
34312
+ const sharedConn = acquireClient(wsUrl, {
34313
+ name: cfg.name ?? "openframe-frontend",
34314
+ user: cfg.user ?? "machine",
34315
+ pass: cfg.pass ?? ""
34316
+ });
34376
34317
  const client = sharedConn.client;
34377
34318
  clientRef.current = client;
34378
- setIsConnected(false);
34379
- let closed = false;
34380
- let retryAttempt = 0;
34381
- function scheduleRetry() {
34382
- if (closed) return;
34383
- if (shared2 !== sharedConn) return;
34384
- if (sharedConn.retryTimer) {
34385
- clearTimeout(sharedConn.retryTimer);
34386
- sharedConn.retryTimer = null;
34387
- }
34388
- const cfg = reconnectionBackoffRef.current ?? {};
34389
- const fastRetries = cfg.fastRetries ?? 0;
34390
- const fastDelay = cfg.fastRetryDelayMs ?? NETWORK_CONFIG.RETRY_INITIAL_DELAY_MS;
34391
- const baseDelay = cfg.initialDelayMs ?? NETWORK_CONFIG.RETRY_INITIAL_DELAY_MS;
34392
- const maxDelay = cfg.maxDelayMs ?? NETWORK_CONFIG.RETRY_MAX_DELAY_MS;
34393
- const multiplier = cfg.multiplier ?? NETWORK_CONFIG.RETRY_BACKOFF_MULTIPLIER;
34394
- const delay2 = retryAttempt < fastRetries ? fastDelay : Math.min(baseDelay * multiplier ** (retryAttempt - fastRetries), maxDelay);
34395
- const jitteredDelay = delay2 * (0.5 + Math.random() * 0.5);
34396
- retryAttempt++;
34397
- sharedConn.retryTimer = setTimeout(async () => {
34398
- sharedConn.retryTimer = null;
34399
- if (closed) return;
34400
- if (shared2 !== sharedConn) return;
34401
- try {
34402
- await onBeforeReconnectRef.current?.();
34403
- } catch {
34404
- }
34405
- if (closed) return;
34406
- if (shared2 !== sharedConn) return;
34407
- const freshUrl = getNatsWsUrlRef.current();
34408
- if (freshUrl !== wsUrl) return;
34319
+ setIsConnected(client.isConnected());
34320
+ const tearDownSubscriptions = () => {
34321
+ subscriptionRefs.current.forEach((sub) => {
34409
34322
  try {
34410
- sharedConn.connectPromise = null;
34411
- sharedConn.connectPromise = client.connect();
34412
- await sharedConn.connectPromise;
34413
- if (!closed && shared2 === sharedConn) {
34414
- retryAttempt = 0;
34415
- setIsConnected(true);
34416
- }
34323
+ sub?.unsubscribe();
34417
34324
  } catch {
34418
- sharedConn.connectPromise = null;
34419
- if (!closed && shared2 === sharedConn) {
34420
- scheduleRetry();
34421
- }
34422
- }
34423
- }, jitteredDelay);
34424
- }
34425
- const unsubscribeStatus = client.onStatus((event) => {
34426
- const connected = event.status === "connected";
34427
- const disconnected = ["closed", "disconnected", "error"].includes(event.status);
34428
- if (connected) {
34429
- setIsConnected(true);
34430
- if (hadConnectionBeforeRef.current) {
34431
- setReconnectionCount((c) => c + 1);
34432
34325
  }
34433
- hadConnectionBeforeRef.current = true;
34434
- retryAttempt = 0;
34435
- onConnectRef.current?.();
34436
- }
34437
- if (disconnected) {
34438
- setIsConnected(false);
34439
- setIsSubscribed(false);
34440
- subscriptionRefs.current.forEach((sub) => {
34441
- try {
34442
- sub?.unsubscribe();
34443
- } catch {
34444
- }
34445
- });
34446
- subscriptionRefs.current.clear();
34447
- lastSubscribedDialogIdRef.current = null;
34448
- abortControllerRef.current?.abort();
34449
- abortControllerRef.current = null;
34450
- onDisconnectRef.current?.();
34451
- scheduleRetry();
34452
- }
34453
- });
34454
- (async () => {
34455
- try {
34456
- sharedConn.connectPromise || (sharedConn.connectPromise = client.connect());
34457
- await sharedConn.connectPromise;
34458
- if (!closed) {
34326
+ });
34327
+ subscriptionRefs.current.clear();
34328
+ lastSubscribedDialogIdRef.current = null;
34329
+ abortControllerRef.current?.abort();
34330
+ abortControllerRef.current = null;
34331
+ };
34332
+ const isDisconnectStatus = (status) => status === "closed" || status === "disconnected" || status === "error";
34333
+ const lifecycle = startConnectionLifecycle({
34334
+ conn: sharedConn,
34335
+ wsUrl,
34336
+ onBeforeReconnect: () => onBeforeReconnectRef.current?.(),
34337
+ backoff: reconnectionBackoffRef.current,
34338
+ getFreshUrl: () => getNatsWsUrlRef.current(),
34339
+ shouldRetryOn: isDisconnectStatus,
34340
+ onStatusChange: (status) => {
34341
+ if (status === "connected") {
34459
34342
  setIsConnected(true);
34343
+ if (hadConnectionBeforeRef.current) {
34344
+ setReconnectionCount((c) => c + 1);
34345
+ }
34460
34346
  hadConnectionBeforeRef.current = true;
34347
+ onConnectRef.current?.();
34461
34348
  }
34462
- } catch {
34463
- sharedConn.connectPromise = null;
34464
- if (!closed) {
34349
+ if (isDisconnectStatus(status)) {
34465
34350
  setIsConnected(false);
34351
+ setIsSubscribed(false);
34352
+ tearDownSubscriptions();
34466
34353
  onDisconnectRef.current?.();
34467
- scheduleRetry();
34468
34354
  }
34469
34355
  }
34470
- })();
34356
+ });
34471
34357
  return () => {
34472
- closed = true;
34358
+ lifecycle.stop();
34473
34359
  setIsConnected(false);
34474
34360
  setIsSubscribed(false);
34475
- unsubscribeStatus();
34476
- if (sharedConn.retryTimer) {
34477
- clearTimeout(sharedConn.retryTimer);
34478
- sharedConn.retryTimer = null;
34479
- }
34480
- subscriptionRefs.current.forEach((sub) => {
34481
- try {
34482
- sub?.unsubscribe();
34483
- } catch {
34484
- }
34485
- });
34486
- subscriptionRefs.current.clear();
34487
- lastSubscribedDialogIdRef.current = null;
34361
+ tearDownSubscriptions();
34488
34362
  if (clientRef.current && currentWsUrlRef.current) {
34489
34363
  releaseClient(currentWsUrlRef.current);
34490
34364
  clientRef.current = null;
34491
34365
  currentWsUrlRef.current = "";
34492
34366
  }
34493
34367
  };
34494
- }, [enabled, getNatsWsUrl, acquireClient, releaseClient]);
34368
+ }, [enabled, wsUrl]);
34495
34369
  const topicsKey = topics.join(",");
34496
- const lastSubscribedDialogIdRef = useRef44(null);
34497
- const isConnectedRef = useRef44(isConnected);
34498
- useEffect51(() => {
34370
+ const lastSubscribedDialogIdRef = useRef45(null);
34371
+ const isConnectedRef = useRef45(isConnected);
34372
+ useEffect52(() => {
34499
34373
  isConnectedRef.current = isConnected;
34500
34374
  }, [isConnected]);
34501
- const currentDialogIdRef = useRef44(null);
34502
- const abortControllerRef = useRef44(null);
34503
- useEffect51(() => {
34375
+ const currentDialogIdRef = useRef45(null);
34376
+ const abortControllerRef = useRef45(null);
34377
+ useEffect52(() => {
34504
34378
  currentDialogIdRef.current = dialogId;
34505
34379
  if (!enabled || !dialogId) {
34506
34380
  if (subscriptionRefs.current.size > 0) {
@@ -34581,7 +34455,7 @@ function useNatsDialogSubscription({
34581
34455
  abortControllerRef.current = null;
34582
34456
  };
34583
34457
  }, [enabled, dialogId, topicsKey, topics]);
34584
- useEffect51(() => {
34458
+ useEffect52(() => {
34585
34459
  if (!enabled || !currentDialogIdRef.current || !isConnected) {
34586
34460
  return;
34587
34461
  }
@@ -34631,7 +34505,7 @@ function buildNatsWsUrl(apiBaseUrl, options) {
34631
34505
  }
34632
34506
 
34633
34507
  // src/components/chat/hooks/use-realtime-chunk-processor.ts
34634
- import { useCallback as useCallback33, useRef as useRef45, useEffect as useEffect52 } from "react";
34508
+ import { useCallback as useCallback31, useRef as useRef46, useEffect as useEffect53 } from "react";
34635
34509
 
34636
34510
  // src/components/chat/utils/chunk-parser.ts
34637
34511
  function normalizeToolCalls(raw) {
@@ -35264,14 +35138,14 @@ function useRealtimeChunkProcessor(options) {
35264
35138
  // get the new batch UI; pass `false` explicitly to fall back to legacy.
35265
35139
  batchApprovalsEnabled = true
35266
35140
  } = options;
35267
- const accumulatorRef = useRef45(
35141
+ const accumulatorRef = useRef46(
35268
35142
  createMessageSegmentAccumulator({
35269
35143
  onApprove: callbacks.onApprove,
35270
35144
  onReject: callbacks.onReject
35271
35145
  })
35272
35146
  );
35273
- const hasInitializedWithData = useRef45(false);
35274
- useEffect52(() => {
35147
+ const hasInitializedWithData = useRef46(false);
35148
+ useEffect53(() => {
35275
35149
  if (initialState && !hasInitializedWithData.current) {
35276
35150
  accumulatorRef.current.initializeWithState(initialState);
35277
35151
  if (initialState.escalatedApprovals) {
@@ -35284,10 +35158,10 @@ function useRealtimeChunkProcessor(options) {
35284
35158
  hasInitializedWithData.current = true;
35285
35159
  }
35286
35160
  }, [initialState, callbacks]);
35287
- const isInStreamRef = useRef45(false);
35288
- const hasEverStreamedRef = useRef45(false);
35289
- const pendingEscalatedRef = useRef45(/* @__PURE__ */ new Map());
35290
- const processChunk = useCallback33(
35161
+ const isInStreamRef = useRef46(false);
35162
+ const hasEverStreamedRef = useRef46(false);
35163
+ const pendingEscalatedRef = useRef46(/* @__PURE__ */ new Map());
35164
+ const processChunk = useCallback31(
35291
35165
  (chunk) => {
35292
35166
  if (!enableThinking && chunk && typeof chunk === "object" && chunk.type === MESSAGE_TYPE.THINKING) {
35293
35167
  return;
@@ -35501,21 +35375,21 @@ function useRealtimeChunkProcessor(options) {
35501
35375
  },
35502
35376
  [callbacks, displayApprovalTypes, approvalStatuses, initialState, enableThinking]
35503
35377
  );
35504
- const getSegments = useCallback33(() => {
35378
+ const getSegments = useCallback31(() => {
35505
35379
  return accumulatorRef.current.getSegments();
35506
35380
  }, []);
35507
- const reset = useCallback33(() => {
35381
+ const reset = useCallback31(() => {
35508
35382
  accumulatorRef.current.reset();
35509
35383
  pendingEscalatedRef.current.clear();
35510
35384
  hasInitializedWithData.current = false;
35511
35385
  }, []);
35512
- const updateApprovalStatus = useCallback33(
35386
+ const updateApprovalStatus = useCallback31(
35513
35387
  (requestId, status) => {
35514
35388
  return accumulatorRef.current.updateApprovalStatus(requestId, status);
35515
35389
  },
35516
35390
  []
35517
35391
  );
35518
- const getPendingApprovals = useCallback33(() => {
35392
+ const getPendingApprovals = useCallback31(() => {
35519
35393
  return new Map(pendingEscalatedRef.current);
35520
35394
  }, []);
35521
35395
  return {
@@ -35528,7 +35402,7 @@ function useRealtimeChunkProcessor(options) {
35528
35402
  }
35529
35403
 
35530
35404
  // src/components/chat/hooks/use-slash-commands.ts
35531
- import { useEffect as useEffect53, useState as useState75 } from "react";
35405
+ import { useEffect as useEffect54, useState as useState75 } from "react";
35532
35406
  async function fetchSlashCommands(prefix, signal, commandsUrl) {
35533
35407
  const url = new URL(commandsUrl, window.location.origin);
35534
35408
  if (prefix) url.searchParams.set("q", prefix);
@@ -35540,7 +35414,7 @@ async function fetchSlashCommands(prefix, signal, commandsUrl) {
35540
35414
  function useSlashCommands(prefix, commandsUrl) {
35541
35415
  const [commands, setCommands] = useState75([]);
35542
35416
  const [loading, setLoading] = useState75(false);
35543
- useEffect53(() => {
35417
+ useEffect54(() => {
35544
35418
  if (prefix == null) {
35545
35419
  setCommands([]);
35546
35420
  return;
@@ -35570,7 +35444,7 @@ function useSlashCommands(prefix, commandsUrl) {
35570
35444
  }
35571
35445
 
35572
35446
  // src/components/chat/hooks/use-chat-attachments.ts
35573
- import { useCallback as useCallback34, useMemo as useMemo26, useRef as useRef46, useState as useState76 } from "react";
35447
+ import { useCallback as useCallback32, useMemo as useMemo26, useRef as useRef47, useState as useState76 } from "react";
35574
35448
  import { fileTypeFromBlob } from "file-type";
35575
35449
  var CHAT_ATTACHMENTS_BUCKET = "chat-attachments";
35576
35450
  var CHAT_ATTACHMENTS_FOLDER = "chat";
@@ -35647,11 +35521,11 @@ function useChatAttachments() {
35647
35521
  const runtime = useRequiredChatRuntime();
35648
35522
  const uploadUrlEndpoint = runtime.endpoints.attachmentUploadUrl;
35649
35523
  const [attachments, setAttachments] = useState76([]);
35650
- const controllersRef = useRef46(/* @__PURE__ */ new Map());
35651
- const updateOne = useCallback34((id, patch) => {
35524
+ const controllersRef = useRef47(/* @__PURE__ */ new Map());
35525
+ const updateOne = useCallback32((id, patch) => {
35652
35526
  setAttachments((prev) => prev.map((a) => a.id === id ? { ...a, ...patch } : a));
35653
35527
  }, []);
35654
- const removeAttachment = useCallback34((id) => {
35528
+ const removeAttachment = useCallback32((id) => {
35655
35529
  const ctrl = controllersRef.current.get(id);
35656
35530
  if (ctrl) {
35657
35531
  ctrl.abort();
@@ -35659,12 +35533,12 @@ function useChatAttachments() {
35659
35533
  }
35660
35534
  setAttachments((prev) => prev.filter((a) => a.id !== id));
35661
35535
  }, []);
35662
- const clear = useCallback34(() => {
35536
+ const clear = useCallback32(() => {
35663
35537
  for (const ctrl of controllersRef.current.values()) ctrl.abort();
35664
35538
  controllersRef.current.clear();
35665
35539
  setAttachments([]);
35666
35540
  }, []);
35667
- const uploadOne = useCallback34(
35541
+ const uploadOne = useCallback32(
35668
35542
  async (att) => {
35669
35543
  const ctrl = controllersRef.current.get(att.id);
35670
35544
  try {
@@ -35736,9 +35610,9 @@ function useChatAttachments() {
35736
35610
  },
35737
35611
  [uploadUrlEndpoint, updateOne]
35738
35612
  );
35739
- const attachmentsRef = useRef46([]);
35613
+ const attachmentsRef = useRef47([]);
35740
35614
  attachmentsRef.current = attachments;
35741
- const addFiles = useCallback34(
35615
+ const addFiles = useCallback32(
35742
35616
  (files) => {
35743
35617
  const arr = Array.from(files);
35744
35618
  if (arr.length === 0) return;
@@ -35813,16 +35687,16 @@ function useChatAttachments() {
35813
35687
  }
35814
35688
 
35815
35689
  // src/components/chat/hooks/use-chat-attachment-image-gallery.tsx
35816
- import { useCallback as useCallback35, useEffect as useEffect54, useRef as useRef47, useState as useState77 } from "react";
35690
+ import { useCallback as useCallback33, useEffect as useEffect55, useRef as useRef48, useState as useState77 } from "react";
35817
35691
  import { jsx as jsx271 } from "react/jsx-runtime";
35818
35692
  var CLOSED = { isOpen: false, images: [], initialIndex: 0 };
35819
35693
  function useChatAttachmentImageGallery() {
35820
35694
  const runtime = useRequiredChatRuntime();
35821
35695
  const viewUrlPrefix = runtime.endpoints.attachmentViewUrlPrefix;
35822
- const panelRef = useRef47(null);
35696
+ const panelRef = useRef48(null);
35823
35697
  const [state, setState] = useState77(CLOSED);
35824
- const handleClose = useCallback35(() => setState(CLOSED), []);
35825
- useEffect54(() => {
35698
+ const handleClose = useCallback33(() => setState(CLOSED), []);
35699
+ useEffect55(() => {
35826
35700
  const root = panelRef.current;
35827
35701
  if (!root) return;
35828
35702
  const onClick = (ev) => {
@@ -35868,7 +35742,7 @@ function absolutize(prefix) {
35868
35742
  }
35869
35743
 
35870
35744
  // src/components/chat/hooks/use-chat-identity.ts
35871
- import { useEffect as useEffect55, useState as useState78 } from "react";
35745
+ import { useEffect as useEffect56, useState as useState78 } from "react";
35872
35746
  var ANON_DEFAULTS = {
35873
35747
  authTier: "anon",
35874
35748
  source: null,
@@ -35877,11 +35751,11 @@ var ANON_DEFAULTS = {
35877
35751
  };
35878
35752
  function useChatIdentity() {
35879
35753
  const runtime = useRequiredChatRuntime();
35880
- const url = runtime.endpoints.chatIdentityUrl;
35754
+ const url = runtime.endpoints.identityUrl;
35881
35755
  const proxyEmail = getEmbedProxyAuth()?.email ?? null;
35882
35756
  const [data, setData] = useState78(ANON_DEFAULTS);
35883
35757
  const [isLoading, setIsLoading] = useState78(true);
35884
- useEffect55(() => {
35758
+ useEffect56(() => {
35885
35759
  let cancelled = false;
35886
35760
  const ctrl = new AbortController();
35887
35761
  setIsLoading(true);
@@ -35909,11 +35783,11 @@ function useChatIdentity() {
35909
35783
  }
35910
35784
 
35911
35785
  // src/components/chat/hooks/use-close-on-navigation.ts
35912
- import { useEffect as useEffect56, useRef as useRef48 } from "react";
35786
+ import { useEffect as useEffect57, useRef as useRef49 } from "react";
35913
35787
  function useCloseOnNavigation(close, pathname) {
35914
- const prevPathnameRef = useRef48(null);
35915
- const initializedRef = useRef48(false);
35916
- useEffect56(() => {
35788
+ const prevPathnameRef = useRef49(null);
35789
+ const initializedRef = useRef49(false);
35790
+ useEffect57(() => {
35917
35791
  if (!initializedRef.current) {
35918
35792
  initializedRef.current = true;
35919
35793
  prevPathnameRef.current = pathname;
@@ -35927,20 +35801,20 @@ function useCloseOnNavigation(close, pathname) {
35927
35801
  }
35928
35802
 
35929
35803
  // src/components/chat/hooks/use-chat.ts
35930
- import { useState as useState80, useCallback as useCallback37, useEffect as useEffect57, useRef as useRef50 } from "react";
35804
+ import { useState as useState80, useCallback as useCallback35, useEffect as useEffect58, useRef as useRef51 } from "react";
35931
35805
 
35932
35806
  // src/components/chat/hooks/use-sse.ts
35933
- import { useState as useState79, useCallback as useCallback36, useRef as useRef49 } from "react";
35807
+ import { useState as useState79, useCallback as useCallback34, useRef as useRef50 } from "react";
35934
35808
  function useSSE({ useMock = true, debugMode = false, streamFn } = {}) {
35935
35809
  const [isStreaming, setIsStreaming] = useState79(false);
35936
35810
  const [error, setError] = useState79(null);
35937
- const abortControllerRef = useRef49(null);
35938
- const fallbackStream = useCallback36(async function* () {
35811
+ const abortControllerRef = useRef50(null);
35812
+ const fallbackStream = useCallback34(async function* () {
35939
35813
  throw new Error(
35940
35814
  "[useSSE] No streamFn provided and `useMock: true` is no longer wired into the lib. Supply a `streamFn` (see `createDocStreamFn` in use-embedded-chat) or migrate the mock to your host code."
35941
35815
  );
35942
35816
  }, []);
35943
- const streamMessage = useCallback36(
35817
+ const streamMessage = useCallback34(
35944
35818
  async function* (message2, extra) {
35945
35819
  setIsStreaming(true);
35946
35820
  setError(null);
@@ -35970,13 +35844,13 @@ function useSSE({ useMock = true, debugMode = false, streamFn } = {}) {
35970
35844
  },
35971
35845
  [streamFn, fallbackStream]
35972
35846
  );
35973
- const abort = useCallback36(() => {
35847
+ const abort = useCallback34(() => {
35974
35848
  if (abortControllerRef.current) {
35975
35849
  abortControllerRef.current.abort();
35976
35850
  }
35977
35851
  setIsStreaming(false);
35978
35852
  }, []);
35979
- const reset = useCallback36(() => {
35853
+ const reset = useCallback34(() => {
35980
35854
  }, []);
35981
35855
  return {
35982
35856
  streamMessage,
@@ -36002,10 +35876,10 @@ function useChat({
36002
35876
  } = {}) {
36003
35877
  const [messages, setMessages] = useState80(() => initialMessages ?? []);
36004
35878
  const [isTyping, setIsTyping] = useState80(false);
36005
- const currentAssistantSegmentsRef = useRef50([]);
36006
- const onMessagesChangeRef = useRef50(onMessagesChange);
35879
+ const currentAssistantSegmentsRef = useRef51([]);
35880
+ const onMessagesChangeRef = useRef51(onMessagesChange);
36007
35881
  onMessagesChangeRef.current = onMessagesChange;
36008
- useEffect57(() => {
35882
+ useEffect58(() => {
36009
35883
  onMessagesChangeRef.current?.(messages);
36010
35884
  }, [messages]);
36011
35885
  const {
@@ -36019,10 +35893,10 @@ function useChat({
36019
35893
  debugMode,
36020
35894
  streamFn
36021
35895
  });
36022
- const addMessage = useCallback37((message2) => {
35896
+ const addMessage = useCallback35((message2) => {
36023
35897
  setMessages((prev) => [...prev, message2]);
36024
35898
  }, []);
36025
- const updateLastAssistantMessage = useCallback37((segments) => {
35899
+ const updateLastAssistantMessage = useCallback35((segments) => {
36026
35900
  setMessages((prev) => {
36027
35901
  const newMessages = [...prev];
36028
35902
  const lastMessage = newMessages[newMessages.length - 1];
@@ -36035,7 +35909,7 @@ function useChat({
36035
35909
  return newMessages;
36036
35910
  });
36037
35911
  }, []);
36038
- const sendMessage = useCallback37(
35912
+ const sendMessage = useCallback35(
36039
35913
  async (text, extra, options) => {
36040
35914
  const userMessage = {
36041
35915
  id: `user-${Date.now()}`,
@@ -36265,18 +36139,18 @@ function useChat({
36265
36139
  },
36266
36140
  [streamMessage, addMessage, updateLastAssistantMessage, assistantName, assistantAvatar]
36267
36141
  );
36268
- const handleQuickAction = useCallback37(
36142
+ const handleQuickAction = useCallback35(
36269
36143
  (actionText) => {
36270
36144
  sendMessage(actionText);
36271
36145
  },
36272
36146
  [sendMessage]
36273
36147
  );
36274
- const clearMessages = useCallback37(() => {
36148
+ const clearMessages = useCallback35(() => {
36275
36149
  setMessages([]);
36276
36150
  setIsTyping(false);
36277
36151
  reset();
36278
36152
  }, [reset]);
36279
- const stopMessage = useCallback37(() => {
36153
+ const stopMessage = useCallback35(() => {
36280
36154
  abort();
36281
36155
  setIsTyping(false);
36282
36156
  }, [abort]);
@@ -36294,7 +36168,7 @@ function useChat({
36294
36168
  }
36295
36169
 
36296
36170
  // src/components/chat/hooks/use-sse-chat-adapter.ts
36297
- import { useState as useState81, useEffect as useEffect58, useCallback as useCallback38, useMemo as useMemo27, useRef as useRef51 } from "react";
36171
+ import { useState as useState81, useEffect as useEffect59, useCallback as useCallback36, useMemo as useMemo27, useRef as useRef52 } from "react";
36298
36172
  function createEmptyTurnMeta() {
36299
36173
  return {
36300
36174
  provider: null,
@@ -36618,23 +36492,23 @@ function useSseChatAdapter(options) {
36618
36492
  );
36619
36493
  }
36620
36494
  const tableIdForDocumentType = options?.tableIdForDocumentType ?? defaultTableIdForDocumentType;
36621
- const persistedRef = useRef51(null);
36495
+ const persistedRef = useRef52(null);
36622
36496
  if (persistedRef.current === null) {
36623
36497
  pruneStaleChatStorage(source);
36624
36498
  persistedRef.current = loadPersistedChat(source) || { messages: [], sources: [], sendCount: 0 };
36625
36499
  }
36626
- const sourcesMapRef = useRef51(
36500
+ const sourcesMapRef = useRef52(
36627
36501
  new Map(persistedRef.current.sources)
36628
36502
  );
36629
- const refsMapRef = useRef51(
36503
+ const refsMapRef = useRef52(
36630
36504
  new Map(persistedRef.current.refs ?? [])
36631
36505
  );
36632
- const metaMapRef = useRef51(/* @__PURE__ */ new Map());
36633
- const messagesRef = useRef51(persistedRef.current.messages);
36634
- const sendCountRef = useRef51(persistedRef.current.sendCount);
36506
+ const metaMapRef = useRef52(/* @__PURE__ */ new Map());
36507
+ const messagesRef = useRef52(persistedRef.current.messages);
36508
+ const sendCountRef = useRef52(persistedRef.current.sendCount);
36635
36509
  const [streamingPhase, setStreamingPhase] = useState81("idle");
36636
36510
  const [metaTick, setMetaTick] = useState81(0);
36637
- const bumpMetaTick = useCallback38(() => setMetaTick((t) => t + 1), []);
36511
+ const bumpMetaTick = useCallback36(() => setMetaTick((t) => t + 1), []);
36638
36512
  const streamFn = useMemo27(
36639
36513
  () => createDocStreamFn(
36640
36514
  source,
@@ -36661,7 +36535,7 @@ function useSseChatAdapter(options) {
36661
36535
  () => /* @__PURE__ */ new Map()
36662
36536
  );
36663
36537
  const commandsUrl = runtime.endpoints.commandsUrl;
36664
- useEffect58(() => {
36538
+ useEffect59(() => {
36665
36539
  let cancelled = false;
36666
36540
  const ctrl = new AbortController();
36667
36541
  fetchSlashCommands("", ctrl.signal, commandsUrl).then((commands) => {
@@ -36697,7 +36571,7 @@ function useSseChatAdapter(options) {
36697
36571
  ctrl.abort();
36698
36572
  };
36699
36573
  }, [source, commandsUrl]);
36700
- const persist = useCallback38(
36574
+ const persist = useCallback36(
36701
36575
  (nextMessages) => {
36702
36576
  savePersistedChat(source, {
36703
36577
  messages: nextMessages,
@@ -36751,7 +36625,7 @@ function useSseChatAdapter(options) {
36751
36625
  ...m.hidden ? { hidden: true } : {}
36752
36626
  };
36753
36627
  });
36754
- const sendMessage = useCallback38(
36628
+ const sendMessage = useCallback36(
36755
36629
  async (text, options2) => {
36756
36630
  const {
36757
36631
  hidden,
@@ -36770,7 +36644,7 @@ function useSseChatAdapter(options) {
36770
36644
  },
36771
36645
  [chatSendMessage]
36772
36646
  );
36773
- const displayRef = useCallback38(
36647
+ const displayRef = useCallback36(
36774
36648
  (reference) => {
36775
36649
  const tableId = tableIdForDocumentType(reference.type);
36776
36650
  if (!tableId) {
@@ -36794,7 +36668,7 @@ function useSseChatAdapter(options) {
36794
36668
  },
36795
36669
  [sendMessage, source, cmdIdByTableId, tableIdForDocumentType]
36796
36670
  );
36797
- const discussRef = useCallback38(
36671
+ const discussRef = useCallback36(
36798
36672
  (reference) => {
36799
36673
  const tableId = tableIdForDocumentType(reference.type);
36800
36674
  if (!tableId) {
@@ -36818,11 +36692,11 @@ function useSseChatAdapter(options) {
36818
36692
  },
36819
36693
  [sendMessage, tableIdForDocumentType]
36820
36694
  );
36821
- const stopMessage = useCallback38(() => {
36695
+ const stopMessage = useCallback36(() => {
36822
36696
  chatStopMessage();
36823
36697
  setStreamingPhase("idle");
36824
36698
  }, [chatStopMessage]);
36825
- const clearMessages = useCallback38(() => {
36699
+ const clearMessages = useCallback36(() => {
36826
36700
  sourcesMapRef.current.clear();
36827
36701
  refsMapRef.current.clear();
36828
36702
  metaMapRef.current.clear();
@@ -36837,7 +36711,7 @@ function useSseChatAdapter(options) {
36837
36711
  }
36838
36712
  }
36839
36713
  }, [chatClearMessages, source, bumpMetaTick]);
36840
- useEffect58(() => {
36714
+ useEffect59(() => {
36841
36715
  if (!isTyping && !isStreaming && streamingPhase !== "idle") {
36842
36716
  setStreamingPhase("idle");
36843
36717
  }
@@ -36875,10 +36749,10 @@ function useSseChatAdapter(options) {
36875
36749
 
36876
36750
  // src/components/chat/hooks/use-nats-chat-adapter.ts
36877
36751
  import {
36878
- useCallback as useCallback39,
36879
- useEffect as useEffect59,
36752
+ useCallback as useCallback37,
36753
+ useEffect as useEffect60,
36880
36754
  useMemo as useMemo28,
36881
- useRef as useRef52,
36755
+ useRef as useRef53,
36882
36756
  useState as useState82
36883
36757
  } from "react";
36884
36758
  function nextId(role) {
@@ -36915,7 +36789,7 @@ function useNatsChatAdapter(config, options = {}) {
36915
36789
  } = config;
36916
36790
  const [messages, setMessages] = useState82([]);
36917
36791
  const [streamingPhase, setStreamingPhase] = useState82("idle");
36918
- const callbacksRef = useRef52({
36792
+ const callbacksRef = useRef53({
36919
36793
  onSegmentsUpdate: (segments) => {
36920
36794
  setMessages((prev) => updateTrailingAssistant(prev, segments));
36921
36795
  },
@@ -36941,7 +36815,7 @@ function useNatsChatAdapter(config, options = {}) {
36941
36815
  onChunkReceived: (chunk) => processChunk(chunk),
36942
36816
  fetchChunks
36943
36817
  });
36944
- useEffect59(() => {
36818
+ useEffect60(() => {
36945
36819
  if (!active || !dialogId) return;
36946
36820
  resetChunkTracking();
36947
36821
  startInitialBuffering();
@@ -36958,7 +36832,7 @@ function useNatsChatAdapter(config, options = {}) {
36958
36832
  catchupProcessChunk(payload, messageType);
36959
36833
  }
36960
36834
  });
36961
- const sendMessage = useCallback39(
36835
+ const sendMessage = useCallback37(
36962
36836
  async (text, sendOptions) => {
36963
36837
  const hidden = sendOptions?.hidden ?? false;
36964
36838
  setMessages((prev) => [
@@ -36981,17 +36855,17 @@ function useNatsChatAdapter(config, options = {}) {
36981
36855
  },
36982
36856
  [publishUserMessage, dialogId]
36983
36857
  );
36984
- const stopMessage = useCallback39(() => {
36858
+ const stopMessage = useCallback37(() => {
36985
36859
  setStreamingPhase("idle");
36986
36860
  }, []);
36987
- const clearMessages = useCallback39(() => {
36861
+ const clearMessages = useCallback37(() => {
36988
36862
  setMessages([]);
36989
36863
  resetAccumulator();
36990
36864
  setStreamingPhase("idle");
36991
36865
  }, [resetAccumulator]);
36992
- const discussRef = useCallback39((_ref) => {
36866
+ const discussRef = useCallback37((_ref) => {
36993
36867
  }, []);
36994
- const displayRef = useCallback39((_ref) => {
36868
+ const displayRef = useCallback37((_ref) => {
36995
36869
  }, []);
36996
36870
  const isLoading = streamingPhase !== "idle";
36997
36871
  return useMemo28(
@@ -37027,7 +36901,7 @@ function useNatsChatAdapter(config, options = {}) {
37027
36901
  }
37028
36902
 
37029
36903
  // src/components/chat/hooks/use-unified-chat.ts
37030
- import { useCallback as useCallback40, useMemo as useMemo29, useRef as useRef53 } from "react";
36904
+ import { useCallback as useCallback38, useMemo as useMemo29, useRef as useRef54 } from "react";
37031
36905
  var EMPTY_SSE_OPTIONS = {};
37032
36906
  function createDisabledNatsConfig() {
37033
36907
  return {
@@ -37042,7 +36916,7 @@ function createDisabledNatsConfig() {
37042
36916
  }
37043
36917
  function useUnifiedChat(options) {
37044
36918
  const { modes, activeMode } = options;
37045
- const disabledNatsRef = useRef53(null);
36919
+ const disabledNatsRef = useRef54(null);
37046
36920
  if (disabledNatsRef.current === null) {
37047
36921
  disabledNatsRef.current = createDisabledNatsConfig();
37048
36922
  }
@@ -37055,20 +36929,20 @@ function useUnifiedChat(options) {
37055
36929
  );
37056
36930
  void sseActive;
37057
36931
  const activeState = activeMode === "guide" ? sseState : natsState;
37058
- const stopMessage = useCallback40(() => activeState.stopMessage(), [activeState]);
37059
- const clearMessages = useCallback40(
36932
+ const stopMessage = useCallback38(() => activeState.stopMessage(), [activeState]);
36933
+ const clearMessages = useCallback38(
37060
36934
  () => activeState.clearMessages(),
37061
36935
  [activeState]
37062
36936
  );
37063
- const sendMessage = useCallback40(
36937
+ const sendMessage = useCallback38(
37064
36938
  (text, opts) => activeState.sendMessage(text, opts),
37065
36939
  [activeState]
37066
36940
  );
37067
- const discussRef = useCallback40(
36941
+ const discussRef = useCallback38(
37068
36942
  (ref) => activeState.discussRef(ref),
37069
36943
  [activeState]
37070
36944
  );
37071
- const displayRef = useCallback40(
36945
+ const displayRef = useCallback38(
37072
36946
  (ref) => activeState.displayRef(ref),
37073
36947
  [activeState]
37074
36948
  );
@@ -37586,7 +37460,7 @@ function chatChipClass({ tone, density = "chip", extra }) {
37586
37460
  }
37587
37461
 
37588
37462
  // src/components/chat/embeddable-chat.tsx
37589
- import { useCallback as useCallback42, useEffect as useEffect62, useMemo as useMemo31, useRef as useRef56, useState as useState84 } from "react";
37463
+ import { useCallback as useCallback40, useEffect as useEffect63, useMemo as useMemo31, useRef as useRef57, useState as useState84 } from "react";
37590
37464
 
37591
37465
  // node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
37592
37466
  import * as React109 from "react";
@@ -38013,7 +37887,7 @@ function EmbeddableChatInner({
38013
37887
  const commandsUrl = runtime.endpoints.commandsUrl;
38014
37888
  const { attachmentsEnabled, user: identityUser } = useChatIdentity();
38015
37889
  const viewUrlPrefix = runtime.endpoints.attachmentViewUrlPrefix;
38016
- useEffect62(() => {
37890
+ useEffect63(() => {
38017
37891
  if (process.env.NODE_ENV !== "production") {
38018
37892
  const hasOpen = open !== void 0;
38019
37893
  const hasHandler = onOpenChange !== void 0;
@@ -38034,8 +37908,8 @@ function EmbeddableChatInner({
38034
37908
  return !window.matchMedia("(pointer: coarse)").matches;
38035
37909
  });
38036
37910
  usePreventScroll({ isDisabled: !isOpen });
38037
- const navigatingAwayRef = useRef56(false);
38038
- useEffect62(() => {
37911
+ const navigatingAwayRef = useRef57(false);
37912
+ useEffect63(() => {
38039
37913
  if (!isOpen) return;
38040
37914
  if (typeof window === "undefined") return;
38041
37915
  if (!isIOS()) return;
@@ -38060,12 +37934,12 @@ function EmbeddableChatInner({
38060
37934
  window.scrollTo(0, scrollY);
38061
37935
  };
38062
37936
  }, [isOpen]);
38063
- const chatInputRef = useRef56(null);
37937
+ const chatInputRef = useRef57(null);
38064
37938
  const [commandsById, setCommandsById] = useState84(
38065
37939
  () => /* @__PURE__ */ new Map()
38066
37940
  );
38067
37941
  const [commandsLoaded, setCommandsLoaded] = useState84(false);
38068
- useEffect62(() => {
37942
+ useEffect63(() => {
38069
37943
  if (!isOpen) return;
38070
37944
  let cancelled = false;
38071
37945
  const ctrl = new AbortController();
@@ -38110,7 +37984,7 @@ function EmbeddableChatInner({
38110
37984
  const initialActiveMode = controlledActiveMode ?? defaultActiveMode ?? (effectiveModes.guide ? "guide" : "mingo");
38111
37985
  const [uncontrolledActiveMode, setUncontrolledActiveMode] = useState84(initialActiveMode);
38112
37986
  const activeMode = controlledActiveMode ?? uncontrolledActiveMode;
38113
- const handleActiveModeChange = useCallback42(
37987
+ const handleActiveModeChange = useCallback40(
38114
37988
  (next) => {
38115
37989
  if (controlledActiveMode === void 0) {
38116
37990
  setUncontrolledActiveMode(next);
@@ -38146,8 +38020,8 @@ function EmbeddableChatInner({
38146
38020
  } = useChatAttachments();
38147
38021
  const { panelRef: galleryPanelRef, modal: galleryModal } = useChatAttachmentImageGallery();
38148
38022
  const resolvedBaseRoute = baseRoute || (source === "flamingo" ? "/knowledge-base" : "/data-room");
38149
- const handleClose = useCallback42(() => setIsOpen(false), [setIsOpen]);
38150
- const handleNavigationClose = useCallback42(() => {
38023
+ const handleClose = useCallback40(() => setIsOpen(false), [setIsOpen]);
38024
+ const handleNavigationClose = useCallback40(() => {
38151
38025
  navigatingAwayRef.current = true;
38152
38026
  setIsOpen(false);
38153
38027
  }, [setIsOpen]);
@@ -38155,7 +38029,7 @@ function EmbeddableChatInner({
38155
38029
  () => ({ closeChat: handleNavigationClose }),
38156
38030
  [handleNavigationClose]
38157
38031
  );
38158
- const renderEntityCard = useCallback42(
38032
+ const renderEntityCard = useCallback40(
38159
38033
  (reference) => renderChatInlineEntityCard(reference, {
38160
38034
  onDiscuss: discussRef,
38161
38035
  onDisplay: displayRef,
@@ -38178,7 +38052,7 @@ function EmbeddableChatInner({
38178
38052
  })),
38179
38053
  [rawMessages]
38180
38054
  );
38181
- const handleSend = useCallback42(
38055
+ const handleSend = useCallback40(
38182
38056
  (text) => {
38183
38057
  let augmentedText = text;
38184
38058
  if (readyAttachments.length > 0) {
@@ -38194,12 +38068,12 @@ function EmbeddableChatInner({
38194
38068
  },
38195
38069
  [sendMessage, readyAttachments, viewUrlPrefix, clearAttachments]
38196
38070
  );
38197
- const handleNewChat = useCallback42(() => {
38071
+ const handleNewChat = useCallback40(() => {
38198
38072
  clearMessages();
38199
38073
  }, [clearMessages]);
38200
- const handleOpen = useCallback42(() => setIsOpen(true), [setIsOpen]);
38074
+ const handleOpen = useCallback40(() => setIsOpen(true), [setIsOpen]);
38201
38075
  useCloseOnNavigation(handleNavigationClose, null);
38202
- useEffect62(() => {
38076
+ useEffect63(() => {
38203
38077
  const handler = (e) => {
38204
38078
  const detail = e.detail;
38205
38079
  if (!detail || detail.source !== source) return;
@@ -38999,6 +38873,7 @@ export {
38999
38873
  DELIVERY_TASK_TYPE_OPTIONS,
39000
38874
  TICKET_STATUS_OPTIONS,
39001
38875
  OPENFRAME_DEV_SECTIONS,
38876
+ scrollElementIntoView,
39002
38877
  BenefitCard,
39003
38878
  BenefitCardGrid,
39004
38879
  BrandAssociationCard,
@@ -39212,4 +39087,4 @@ export {
39212
39087
  LogsList,
39213
39088
  assets
39214
39089
  };
39215
- //# sourceMappingURL=chunk-R5RNRH62.js.map
39090
+ //# sourceMappingURL=chunk-ZTJVRSN5.js.map