@flamingo-stack/openframe-frontend-core 0.0.518-1660.4292.1 → 0.0.518-1663.4312.1

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 (331) hide show
  1. package/dist/{chunk-7EFJJMNH.cjs → chunk-25JSVBPR.cjs} +7 -7
  2. package/dist/{chunk-7EFJJMNH.cjs.map → chunk-25JSVBPR.cjs.map} +1 -1
  3. package/dist/{chunk-NJADHL2G.cjs → chunk-3M2MFP2Y.cjs} +30 -2
  4. package/dist/chunk-3M2MFP2Y.cjs.map +1 -0
  5. package/dist/{chunk-QXUMLLYV.cjs → chunk-BQXHC336.cjs} +3 -3
  6. package/dist/{chunk-QXUMLLYV.cjs.map → chunk-BQXHC336.cjs.map} +1 -1
  7. package/dist/{chunk-66GH54DV.cjs → chunk-CHMQCXYO.cjs} +40 -40
  8. package/dist/{chunk-66GH54DV.cjs.map → chunk-CHMQCXYO.cjs.map} +1 -1
  9. package/dist/{chunk-RWYNJC2F.cjs → chunk-DN3GKQ47.cjs} +98 -98
  10. package/dist/{chunk-RWYNJC2F.cjs.map → chunk-DN3GKQ47.cjs.map} +1 -1
  11. package/dist/{chunk-O7L2VJDW.cjs → chunk-GH5YZSQQ.cjs} +12 -12
  12. package/dist/{chunk-O7L2VJDW.cjs.map → chunk-GH5YZSQQ.cjs.map} +1 -1
  13. package/dist/{chunk-XURRAFIB.js → chunk-GJAHN7LH.js} +404 -376
  14. package/dist/chunk-GJAHN7LH.js.map +1 -0
  15. package/dist/{chunk-FS3YSNSU.js → chunk-GS4HJA2G.js} +2 -2
  16. package/dist/{chunk-HIV2GIFP.cjs → chunk-GYONSC3U.cjs} +3 -3
  17. package/dist/{chunk-HIV2GIFP.cjs.map → chunk-GYONSC3U.cjs.map} +1 -1
  18. package/dist/{chunk-XURCARSX.cjs → chunk-I6IWT62M.cjs} +5 -5
  19. package/dist/{chunk-XURCARSX.cjs.map → chunk-I6IWT62M.cjs.map} +1 -1
  20. package/dist/{chunk-43ZZYJ3M.js → chunk-KRBH3PI4.js} +5 -5
  21. package/dist/{chunk-3LMOLDFT.cjs → chunk-KW7GDLSG.cjs} +14 -14
  22. package/dist/{chunk-3LMOLDFT.cjs.map → chunk-KW7GDLSG.cjs.map} +1 -1
  23. package/dist/{chunk-JLO2O5R4.js → chunk-LL4C2NXG.js} +5388 -5249
  24. package/dist/chunk-LL4C2NXG.js.map +1 -0
  25. package/dist/{chunk-DPFQWIZJ.cjs → chunk-LQ2R7IA2.cjs} +32 -32
  26. package/dist/{chunk-DPFQWIZJ.cjs.map → chunk-LQ2R7IA2.cjs.map} +1 -1
  27. package/dist/{chunk-P63LOLTB.js → chunk-MI7WNVWX.js} +6 -6
  28. package/dist/{chunk-BXRB4MQI.cjs → chunk-MKN6S7SU.cjs} +381 -242
  29. package/dist/chunk-MKN6S7SU.cjs.map +1 -0
  30. package/dist/{chunk-ZKVARGSO.js → chunk-MOZUJ7IN.js} +3 -3
  31. package/dist/{chunk-MIFJLUZK.js → chunk-MVY3WDFZ.js} +2 -2
  32. package/dist/{chunk-FXT2OZ5Q.js → chunk-NJJWY7SO.js} +3 -3
  33. package/dist/{chunk-H6K73RK2.cjs → chunk-O4XLTA5G.cjs} +40 -40
  34. package/dist/{chunk-H6K73RK2.cjs.map → chunk-O4XLTA5G.cjs.map} +1 -1
  35. package/dist/{chunk-MEXZZOBO.js → chunk-P6M5MN3L.js} +9 -9
  36. package/dist/{chunk-5KBQECAY.js → chunk-PUBL2NCH.js} +2 -2
  37. package/dist/{chunk-NBJ7L65H.js → chunk-PV3LXEHJ.js} +2 -2
  38. package/dist/{chunk-XZ6WTSVQ.js → chunk-QJHBYNHI.js} +6 -6
  39. package/dist/{chunk-Z3ADCYC5.js → chunk-RCBRCZUF.js} +2 -2
  40. package/dist/{chunk-KP4JRPUE.js → chunk-RJU7YCN3.js} +2 -2
  41. package/dist/{chunk-GA7BHFXD.cjs → chunk-RLVJISO4.cjs} +77 -77
  42. package/dist/{chunk-GA7BHFXD.cjs.map → chunk-RLVJISO4.cjs.map} +1 -1
  43. package/dist/{chunk-OGVIGAMZ.cjs → chunk-SXLEPNY2.cjs} +31 -31
  44. package/dist/{chunk-OGVIGAMZ.cjs.map → chunk-SXLEPNY2.cjs.map} +1 -1
  45. package/dist/{chunk-WI4XHZ2B.js → chunk-TFIPJAA5.js} +3 -3
  46. package/dist/{chunk-HPPCPGBR.cjs → chunk-URU6YKOA.cjs} +29 -29
  47. package/dist/{chunk-HPPCPGBR.cjs.map → chunk-URU6YKOA.cjs.map} +1 -1
  48. package/dist/{chunk-WSRPNLTY.cjs → chunk-WQDDSJWN.cjs} +18 -18
  49. package/dist/{chunk-WSRPNLTY.cjs.map → chunk-WQDDSJWN.cjs.map} +1 -1
  50. package/dist/{chunk-56OUH3UF.js → chunk-XARCNHWZ.js} +2 -2
  51. package/dist/{chunk-J7ZJ4KM2.cjs → chunk-YH627NWE.cjs} +4 -4
  52. package/dist/{chunk-J7ZJ4KM2.cjs.map → chunk-YH627NWE.cjs.map} +1 -1
  53. package/dist/{chunk-AI7WIW4E.js → chunk-YUQNJXSC.js} +4 -4
  54. package/dist/components/about-icon.d.ts +9 -0
  55. package/dist/components/about-icon.d.ts.map +1 -0
  56. package/dist/components/aspect-ratio.d.ts +4 -0
  57. package/dist/components/aspect-ratio.d.ts.map +1 -0
  58. package/dist/components/avatar.d.ts +7 -0
  59. package/dist/components/avatar.d.ts.map +1 -0
  60. package/dist/components/case-studies/index.cjs +14 -14
  61. package/dist/components/case-studies/index.js +4 -4
  62. package/dist/components/chart.d.ts +72 -0
  63. package/dist/components/chart.d.ts.map +1 -0
  64. package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts +7 -1
  65. package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts.map +1 -1
  66. package/dist/components/chat/index.cjs +6 -4
  67. package/dist/components/chat/index.cjs.map +1 -1
  68. package/dist/components/chat/index.js +5 -3
  69. package/dist/components/chat/types/api.types.d.ts +22 -4
  70. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  71. package/dist/components/check-circle-icon.d.ts +7 -0
  72. package/dist/components/check-circle-icon.d.ts.map +1 -0
  73. package/dist/components/checkbox.d.ts +5 -0
  74. package/dist/components/checkbox.d.ts.map +1 -0
  75. package/dist/components/claude-icon.d.ts +6 -0
  76. package/dist/components/claude-icon.d.ts.map +1 -0
  77. package/dist/components/coins-icon.d.ts +9 -0
  78. package/dist/components/coins-icon.d.ts.map +1 -0
  79. package/dist/components/command.d.ts +81 -0
  80. package/dist/components/command.d.ts.map +1 -0
  81. package/dist/components/community-hub-icon.d.ts +9 -0
  82. package/dist/components/community-hub-icon.d.ts.map +1 -0
  83. package/dist/components/community-icon.d.ts +9 -0
  84. package/dist/components/community-icon.d.ts.map +1 -0
  85. package/dist/components/compare-icon.d.ts +9 -0
  86. package/dist/components/compare-icon.d.ts.map +1 -0
  87. package/dist/components/contact/index.cjs +5 -5
  88. package/dist/components/contact/index.js +4 -4
  89. package/dist/components/context-menu.d.ts +28 -0
  90. package/dist/components/context-menu.d.ts.map +1 -0
  91. package/dist/components/custom-external-link-icon.d.ts +9 -0
  92. package/dist/components/custom-external-link-icon.d.ts.map +1 -0
  93. package/dist/components/custom-fork-icon.d.ts +9 -0
  94. package/dist/components/custom-fork-icon.d.ts.map +1 -0
  95. package/dist/components/custom-icons.d.ts +8 -0
  96. package/dist/components/custom-icons.d.ts.map +1 -0
  97. package/dist/components/custom-license-icon.d.ts +9 -0
  98. package/dist/components/custom-license-icon.d.ts.map +1 -0
  99. package/dist/components/custom-star-icon.d.ts +9 -0
  100. package/dist/components/custom-star-icon.d.ts.map +1 -0
  101. package/dist/components/custom-time-icon.d.ts +9 -0
  102. package/dist/components/custom-time-icon.d.ts.map +1 -0
  103. package/dist/components/docs/index.cjs +7 -7
  104. package/dist/components/docs/index.js +6 -6
  105. package/dist/components/donut-icon.d.ts +4 -0
  106. package/dist/components/donut-icon.d.ts.map +1 -0
  107. package/dist/components/edit-profile-icon.d.ts +7 -0
  108. package/dist/components/edit-profile-icon.d.ts.map +1 -0
  109. package/dist/components/elestio-logo.d.ts +9 -0
  110. package/dist/components/elestio-logo.d.ts.map +1 -0
  111. package/dist/components/embeds/index.cjs +5 -5
  112. package/dist/components/embeds/index.js +4 -4
  113. package/dist/components/empty-vendor-icon.d.ts +7 -0
  114. package/dist/components/empty-vendor-icon.d.ts.map +1 -0
  115. package/dist/components/faq/index.cjs +6 -6
  116. package/dist/components/faq/index.js +5 -5
  117. package/dist/components/features/index.cjs +4 -4
  118. package/dist/components/features/index.js +3 -3
  119. package/dist/components/features/provider-button.d.ts +1 -1
  120. package/dist/components/features/provider-button.d.ts.map +1 -1
  121. package/dist/components/flamingo-logo.d.ts +9 -0
  122. package/dist/components/flamingo-logo.d.ts.map +1 -0
  123. package/dist/components/form.d.ts +26 -0
  124. package/dist/components/form.d.ts.map +1 -0
  125. package/dist/components/github-icon.d.ts +9 -0
  126. package/dist/components/github-icon.d.ts.map +1 -0
  127. package/dist/components/google-logo.d.ts +5 -0
  128. package/dist/components/google-logo.d.ts.map +1 -0
  129. package/dist/components/hamburger-icon.d.ts +9 -0
  130. package/dist/components/hamburger-icon.d.ts.map +1 -0
  131. package/dist/components/help-center-pages/index.cjs +25 -25
  132. package/dist/components/help-center-pages/index.js +16 -16
  133. package/dist/components/hubspot-icon.d.ts +7 -0
  134. package/dist/components/hubspot-icon.d.ts.map +1 -0
  135. package/dist/components/icon-utils.d.ts +7 -0
  136. package/dist/components/icon-utils.d.ts.map +1 -0
  137. package/dist/components/icons/apple-icon.d.ts +10 -0
  138. package/dist/components/icons/apple-icon.d.ts.map +1 -0
  139. package/dist/components/icons/index.cjs +4 -2
  140. package/dist/components/icons/index.cjs.map +1 -1
  141. package/dist/components/icons/index.d.ts +1 -0
  142. package/dist/components/icons/index.d.ts.map +1 -1
  143. package/dist/components/icons/index.js +3 -1
  144. package/dist/components/index.cjs +222 -266
  145. package/dist/components/index.cjs.map +1 -1
  146. package/dist/components/index.js +374 -418
  147. package/dist/components/index.js.map +1 -1
  148. package/dist/components/interactive-wrapper.d.ts +84 -0
  149. package/dist/components/interactive-wrapper.d.ts.map +1 -0
  150. package/dist/components/join-waitlist-button-stub.d.ts +10 -0
  151. package/dist/components/join-waitlist-button-stub.d.ts.map +1 -0
  152. package/dist/components/made-with-love.d.ts.map +1 -1
  153. package/dist/components/meeting-scheduler/index.cjs +41 -41
  154. package/dist/components/meeting-scheduler/index.js +5 -5
  155. package/dist/components/menu-icon.d.ts +9 -0
  156. package/dist/components/menu-icon.d.ts.map +1 -0
  157. package/dist/components/minus-circle-icon.d.ts +7 -0
  158. package/dist/components/minus-circle-icon.d.ts.map +1 -0
  159. package/dist/components/moon-icon.d.ts +9 -0
  160. package/dist/components/moon-icon.d.ts.map +1 -0
  161. package/dist/components/ms-icon.d.ts +9 -0
  162. package/dist/components/ms-icon.d.ts.map +1 -0
  163. package/dist/components/navigation/index.cjs +4 -4
  164. package/dist/components/navigation/index.js +3 -3
  165. package/dist/components/onboarding-guides/index.cjs +8 -8
  166. package/dist/components/onboarding-guides/index.js +7 -7
  167. package/dist/components/open-source-features.d.ts +1 -1
  168. package/dist/components/open-source-features.d.ts.map +1 -1
  169. package/dist/components/open-source-icon.d.ts +9 -0
  170. package/dist/components/open-source-icon.d.ts.map +1 -0
  171. package/dist/components/openframe-logo.d.ts +7 -0
  172. package/dist/components/openframe-logo.d.ts.map +1 -0
  173. package/dist/components/openmsp-logo.d.ts +11 -0
  174. package/dist/components/openmsp-logo.d.ts.map +1 -0
  175. package/dist/components/plus-circle-icon.d.ts +9 -0
  176. package/dist/components/plus-circle-icon.d.ts.map +1 -0
  177. package/dist/components/progress.d.ts +7 -0
  178. package/dist/components/progress.d.ts.map +1 -0
  179. package/dist/components/provider-button.d.ts +10 -0
  180. package/dist/components/provider-button.d.ts.map +1 -0
  181. package/dist/components/reddit-icon.d.ts +10 -0
  182. package/dist/components/reddit-icon.d.ts.map +1 -0
  183. package/dist/components/related-content/index.cjs +6 -6
  184. package/dist/components/related-content/index.js +5 -5
  185. package/dist/components/resizable.d.ts +24 -0
  186. package/dist/components/resizable.d.ts.map +1 -0
  187. package/dist/components/scroll-area.d.ts +13 -0
  188. package/dist/components/scroll-area.d.ts.map +1 -0
  189. package/dist/components/send-icon.d.ts +7 -0
  190. package/dist/components/send-icon.d.ts.map +1 -0
  191. package/dist/components/separator.d.ts +5 -0
  192. package/dist/components/separator.d.ts.map +1 -0
  193. package/dist/components/skeleton.d.ts +4 -0
  194. package/dist/components/skeleton.d.ts.map +1 -0
  195. package/dist/components/slack-icon.d.ts +9 -0
  196. package/dist/components/slack-icon.d.ts.map +1 -0
  197. package/dist/components/slider.d.ts +5 -0
  198. package/dist/components/slider.d.ts.map +1 -0
  199. package/dist/components/smooth-accordion.d.ts +12 -0
  200. package/dist/components/smooth-accordion.d.ts.map +1 -0
  201. package/dist/components/steps.d.ts +17 -0
  202. package/dist/components/steps.d.ts.map +1 -0
  203. package/dist/components/sun-icon.d.ts +9 -0
  204. package/dist/components/sun-icon.d.ts.map +1 -0
  205. package/dist/components/switch.d.ts +5 -0
  206. package/dist/components/switch.d.ts.map +1 -0
  207. package/dist/components/textarea.d.ts +6 -0
  208. package/dist/components/textarea.d.ts.map +1 -0
  209. package/dist/components/tickets/index.cjs +8 -8
  210. package/dist/components/tickets/index.js +7 -7
  211. package/dist/components/ui/index.cjs +6 -4
  212. package/dist/components/ui/index.cjs.map +1 -1
  213. package/dist/components/ui/index.js +5 -3
  214. package/dist/components/ui/pagination-stub.d.ts +6 -0
  215. package/dist/components/ui/pagination-stub.d.ts.map +1 -0
  216. package/dist/components/ui/responsive-icons-block-stub.d.ts +7 -0
  217. package/dist/components/ui/responsive-icons-block-stub.d.ts.map +1 -0
  218. package/dist/components/user-icon.d.ts +9 -0
  219. package/dist/components/user-icon.d.ts.map +1 -0
  220. package/dist/components/vendor-directory-icon.d.ts +9 -0
  221. package/dist/components/vendor-directory-icon.d.ts.map +1 -0
  222. package/dist/components/vendors-icon.d.ts +9 -0
  223. package/dist/components/vendors-icon.d.ts.map +1 -0
  224. package/dist/components/why-it-matters.d.ts +1 -1
  225. package/dist/components/why-it-matters.d.ts.map +1 -1
  226. package/dist/components/x-icon.d.ts +9 -0
  227. package/dist/components/x-icon.d.ts.map +1 -0
  228. package/dist/components/x-logo.d.ts +7 -0
  229. package/dist/components/x-logo.d.ts.map +1 -0
  230. package/dist/hooks/index.cjs +3 -3
  231. package/dist/hooks/index.js +2 -2
  232. package/dist/index.cjs +8 -4
  233. package/dist/index.cjs.map +1 -1
  234. package/dist/index.js +7 -3
  235. package/package.json +1 -1
  236. package/src/components/about-icon.tsx +29 -0
  237. package/src/components/aspect-ratio.tsx +7 -0
  238. package/src/components/avatar.tsx +40 -0
  239. package/src/components/chart.tsx +364 -0
  240. package/src/components/chat/chat-container.tsx +1 -1
  241. package/src/components/chat/hooks/.use-jetstream-dialog-subscription.md +11 -4
  242. package/src/components/chat/hooks/use-jetstream-dialog-subscription.ts +71 -6
  243. package/src/components/chat/types/api.types.ts +22 -4
  244. package/src/components/chat/utils/__tests__/history-merge.test.ts +99 -0
  245. package/src/components/check-circle-icon.tsx +29 -0
  246. package/src/components/checkbox.tsx +30 -0
  247. package/src/components/claude-icon.tsx +24 -0
  248. package/src/components/coins-icon.tsx +29 -0
  249. package/src/components/command.tsx +153 -0
  250. package/src/components/community-hub-icon.tsx +27 -0
  251. package/src/components/community-icon.tsx +27 -0
  252. package/src/components/compare-icon.tsx +27 -0
  253. package/src/components/context-menu.tsx +200 -0
  254. package/src/components/custom-external-link-icon.tsx +33 -0
  255. package/src/components/custom-fork-icon.tsx +33 -0
  256. package/src/components/custom-icons.tsx +47 -0
  257. package/src/components/custom-license-icon.tsx +33 -0
  258. package/src/components/custom-star-icon.tsx +29 -0
  259. package/src/components/custom-time-icon.tsx +33 -0
  260. package/src/components/donut-icon.tsx +21 -0
  261. package/src/components/edit-profile-icon.tsx +23 -0
  262. package/src/components/elestio-logo.tsx +67 -0
  263. package/src/components/empty-vendor-icon.tsx +44 -0
  264. package/src/components/features/auth-providers-list.tsx +1 -1
  265. package/src/components/features/platform-badge.tsx +2 -2
  266. package/src/components/features/provider-button.tsx +6 -2
  267. package/src/components/flamingo-logo.tsx +27 -0
  268. package/src/components/form.tsx +138 -0
  269. package/src/components/github-icon.tsx +26 -0
  270. package/src/components/google-logo.tsx +32 -0
  271. package/src/components/hamburger-icon.tsx +29 -0
  272. package/src/components/hubspot-icon.tsx +20 -0
  273. package/src/components/icon-utils.tsx +36 -0
  274. package/src/components/icons/apple-icon.tsx +30 -0
  275. package/src/components/icons/index.ts +1 -0
  276. package/src/components/interactive-wrapper.tsx +336 -0
  277. package/src/components/join-waitlist-button-stub.tsx +30 -0
  278. package/src/components/loading/openmsp-heartbeat.tsx +1 -1
  279. package/src/components/made-with-love.tsx +3 -4
  280. package/src/components/menu-icon.tsx +22 -0
  281. package/src/components/minus-circle-icon.tsx +28 -0
  282. package/src/components/moon-icon.tsx +26 -0
  283. package/src/components/ms-icon.tsx +31 -0
  284. package/src/components/open-source-features.tsx +1 -1
  285. package/src/components/open-source-icon.tsx +27 -0
  286. package/src/components/openframe-logo.tsx +46 -0
  287. package/src/components/openmsp-logo.tsx +36 -0
  288. package/src/components/plus-circle-icon.tsx +30 -0
  289. package/src/components/progress.tsx +27 -0
  290. package/src/components/provider-button.tsx +40 -0
  291. package/src/components/reddit-icon.tsx +50 -0
  292. package/src/components/resizable.tsx +45 -0
  293. package/src/components/scroll-area.tsx +49 -0
  294. package/src/components/send-icon.tsx +26 -0
  295. package/src/components/separator.tsx +22 -0
  296. package/src/components/skeleton.tsx +8 -0
  297. package/src/components/slack-icon.tsx +43 -0
  298. package/src/components/slider.tsx +28 -0
  299. package/src/components/smooth-accordion.tsx +124 -0
  300. package/src/components/steps.tsx +98 -0
  301. package/src/components/sun-icon.tsx +27 -0
  302. package/src/components/switch.tsx +29 -0
  303. package/src/components/textarea.tsx +22 -0
  304. package/src/components/ui/pagination-stub.tsx +38 -0
  305. package/src/components/ui/responsive-icons-block-stub.tsx +14 -0
  306. package/src/components/user-icon.tsx +33 -0
  307. package/src/components/vendor-directory-icon.tsx +27 -0
  308. package/src/components/vendor-tag.tsx +1 -1
  309. package/src/components/vendors-icon.tsx +27 -0
  310. package/src/components/why-it-matters.tsx +1 -1
  311. package/src/components/x-icon.tsx +29 -0
  312. package/src/components/x-logo.tsx +22 -0
  313. package/dist/chunk-BXRB4MQI.cjs.map +0 -1
  314. package/dist/chunk-JLO2O5R4.js.map +0 -1
  315. package/dist/chunk-NJADHL2G.cjs.map +0 -1
  316. package/dist/chunk-XURRAFIB.js.map +0 -1
  317. /package/dist/{chunk-FS3YSNSU.js.map → chunk-GS4HJA2G.js.map} +0 -0
  318. /package/dist/{chunk-43ZZYJ3M.js.map → chunk-KRBH3PI4.js.map} +0 -0
  319. /package/dist/{chunk-P63LOLTB.js.map → chunk-MI7WNVWX.js.map} +0 -0
  320. /package/dist/{chunk-ZKVARGSO.js.map → chunk-MOZUJ7IN.js.map} +0 -0
  321. /package/dist/{chunk-MIFJLUZK.js.map → chunk-MVY3WDFZ.js.map} +0 -0
  322. /package/dist/{chunk-FXT2OZ5Q.js.map → chunk-NJJWY7SO.js.map} +0 -0
  323. /package/dist/{chunk-MEXZZOBO.js.map → chunk-P6M5MN3L.js.map} +0 -0
  324. /package/dist/{chunk-5KBQECAY.js.map → chunk-PUBL2NCH.js.map} +0 -0
  325. /package/dist/{chunk-NBJ7L65H.js.map → chunk-PV3LXEHJ.js.map} +0 -0
  326. /package/dist/{chunk-XZ6WTSVQ.js.map → chunk-QJHBYNHI.js.map} +0 -0
  327. /package/dist/{chunk-Z3ADCYC5.js.map → chunk-RCBRCZUF.js.map} +0 -0
  328. /package/dist/{chunk-KP4JRPUE.js.map → chunk-RJU7YCN3.js.map} +0 -0
  329. /package/dist/{chunk-WI4XHZ2B.js.map → chunk-TFIPJAA5.js.map} +0 -0
  330. /package/dist/{chunk-56OUH3UF.js.map → chunk-XARCNHWZ.js.map} +0 -0
  331. /package/dist/{chunk-AI7WIW4E.js.map → chunk-YUQNJXSC.js.map} +0 -0
@@ -0,0 +1,40 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar"
5
+
6
+ import { cn } from "../utils/cn"
7
+
8
+ const Avatar = React.forwardRef<
9
+ React.ElementRef<typeof AvatarPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
11
+ >(({ className, ...props }, ref) => (
12
+ <AvatarPrimitive.Root
13
+ ref={ref}
14
+ className={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
15
+ {...props}
16
+ />
17
+ ))
18
+ Avatar.displayName = AvatarPrimitive.Root.displayName
19
+
20
+ const AvatarImage = React.forwardRef<
21
+ React.ElementRef<typeof AvatarPrimitive.Image>,
22
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
23
+ >(({ className, ...props }, ref) => (
24
+ <AvatarPrimitive.Image ref={ref} className={cn("aspect-square h-full w-full", className)} {...props} />
25
+ ))
26
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName
27
+
28
+ const AvatarFallback = React.forwardRef<
29
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
30
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
31
+ >(({ className, ...props }, ref) => (
32
+ <AvatarPrimitive.Fallback
33
+ ref={ref}
34
+ className={cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className)}
35
+ {...props}
36
+ />
37
+ ))
38
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
39
+
40
+ export { Avatar, AvatarImage, AvatarFallback }
@@ -0,0 +1,364 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as RechartsPrimitive from "recharts"
5
+
6
+ import { cn } from "../utils/cn"
7
+
8
+ // Format: { THEME_NAME: CSS_SELECTOR }
9
+ const THEMES = { light: "", dark: ".dark" } as const
10
+
11
+ export type ChartConfig = {
12
+ [k in string]: {
13
+ label?: React.ReactNode
14
+ icon?: React.ComponentType
15
+ } & (
16
+ | { color?: string; theme?: never }
17
+ | { color?: never; theme: Record<keyof typeof THEMES, string> }
18
+ )
19
+ }
20
+
21
+ type ChartContextProps = {
22
+ config: ChartConfig
23
+ }
24
+
25
+ const ChartContext = React.createContext<ChartContextProps | null>(null)
26
+
27
+ function useChart() {
28
+ const context = React.useContext(ChartContext)
29
+
30
+ if (!context) {
31
+ throw new Error("useChart must be used within a <ChartContainer />")
32
+ }
33
+
34
+ return context
35
+ }
36
+
37
+ const ChartContainer = React.forwardRef<
38
+ HTMLDivElement,
39
+ React.ComponentProps<"div"> & {
40
+ config: ChartConfig
41
+ children: React.ComponentProps<
42
+ typeof RechartsPrimitive.ResponsiveContainer
43
+ >["children"]
44
+ }
45
+ >(({ id, className, children, config, ...props }, ref) => {
46
+ const uniqueId = React.useId()
47
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
48
+
49
+ return (
50
+ <ChartContext.Provider value={{ config }}>
51
+ <div
52
+ data-chart={chartId}
53
+ ref={ref}
54
+ className={cn(
55
+ "flex aspect-video justify-center text-h6 [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
56
+ className
57
+ )}
58
+ {...props}
59
+ >
60
+ <ChartStyle id={chartId} config={config} />
61
+ <RechartsPrimitive.ResponsiveContainer>
62
+ {children}
63
+ </RechartsPrimitive.ResponsiveContainer>
64
+ </div>
65
+ </ChartContext.Provider>
66
+ )
67
+ })
68
+ ChartContainer.displayName = "Chart"
69
+
70
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
71
+ const colorConfig = Object.entries(config).filter(
72
+ ([_, config]) => config.theme || config.color
73
+ )
74
+
75
+ if (!colorConfig.length) {
76
+ return null
77
+ }
78
+
79
+ return (
80
+ <style
81
+ dangerouslySetInnerHTML={{
82
+ __html: Object.entries(THEMES)
83
+ .map(
84
+ ([theme, prefix]) => `
85
+ ${prefix} [data-chart=${id}] {
86
+ ${colorConfig
87
+ .map(([key, itemConfig]) => {
88
+ const color =
89
+ itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
90
+ itemConfig.color
91
+ return color ? ` --color-${key}: ${color};` : null
92
+ })
93
+ .join("\n")}
94
+ }
95
+ `
96
+ )
97
+ .join("\n"),
98
+ }}
99
+ />
100
+ )
101
+ }
102
+
103
+ const ChartTooltip = RechartsPrimitive.Tooltip
104
+
105
+ const ChartTooltipContent = React.forwardRef<
106
+ HTMLDivElement,
107
+ React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
108
+ React.ComponentProps<"div"> & {
109
+ hideLabel?: boolean
110
+ hideIndicator?: boolean
111
+ indicator?: "line" | "dot" | "dashed"
112
+ nameKey?: string
113
+ labelKey?: string
114
+ }
115
+ >(
116
+ (props: any, ref: any) => {
117
+ const {
118
+ active,
119
+ payload,
120
+ className,
121
+ indicator = "dot",
122
+ hideLabel = false,
123
+ hideIndicator = false,
124
+ label,
125
+ labelFormatter,
126
+ labelClassName,
127
+ formatter,
128
+ color,
129
+ nameKey,
130
+ labelKey,
131
+ ...rest
132
+ } = props;
133
+ const { config } = useChart()
134
+
135
+ const tooltipLabel = React.useMemo(() => {
136
+ if (hideLabel || !payload?.length) {
137
+ return null
138
+ }
139
+
140
+ const [item] = payload
141
+ const key = `${labelKey || item.dataKey || item.name || "value"}`
142
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
143
+ const value =
144
+ !labelKey && typeof label === "string"
145
+ ? config[label as keyof typeof config]?.label || label
146
+ : itemConfig?.label
147
+
148
+ if (labelFormatter) {
149
+ return (
150
+ <div className={cn("font-medium", labelClassName)}>
151
+ {labelFormatter(value, payload)}
152
+ </div>
153
+ )
154
+ }
155
+
156
+ if (!value) {
157
+ return null
158
+ }
159
+
160
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
161
+ }, [
162
+ label,
163
+ labelFormatter,
164
+ payload,
165
+ hideLabel,
166
+ labelClassName,
167
+ config,
168
+ labelKey,
169
+ ])
170
+
171
+ if (!active || !payload?.length) {
172
+ return null
173
+ }
174
+
175
+ const nestLabel = payload.length === 1 && indicator !== "dot"
176
+
177
+ return (
178
+ <div
179
+ ref={ref}
180
+ className={cn(
181
+ "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-h6 shadow-xl",
182
+ className
183
+ )}
184
+ >
185
+ {!nestLabel ? tooltipLabel : null}
186
+ <div className="grid gap-1.5">
187
+ {payload?.map((item: any, index: number) => {
188
+ const key = `${nameKey || item.name || item.dataKey || "value"}`
189
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
190
+ const indicatorColor = color || item.payload.fill || item.color
191
+
192
+ return (
193
+ <div
194
+ key={item.dataKey}
195
+ className={cn(
196
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
197
+ indicator === "dot" && "items-center"
198
+ )}
199
+ >
200
+ {formatter && item?.value !== undefined && item.name ? (
201
+ formatter(item.value, item.name, item, index, item.payload)
202
+ ) : (
203
+ <>
204
+ {itemConfig?.icon ? (
205
+ <itemConfig.icon />
206
+ ) : (
207
+ !hideIndicator && (
208
+ <div
209
+ className={cn(
210
+ "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
211
+ {
212
+ "h-2.5 w-2.5": indicator === "dot",
213
+ "w-1": indicator === "line",
214
+ "w-0 border-[1.5px] border-dashed bg-transparent":
215
+ indicator === "dashed",
216
+ "my-0.5": nestLabel && indicator === "dashed",
217
+ }
218
+ )}
219
+ style={
220
+ {
221
+ "--color-bg": indicatorColor,
222
+ "--color-border": indicatorColor,
223
+ } as React.CSSProperties
224
+ }
225
+ />
226
+ )
227
+ )}
228
+ <div
229
+ className={cn(
230
+ "flex flex-1 justify-between leading-none",
231
+ nestLabel ? "items-end" : "items-center"
232
+ )}
233
+ >
234
+ <div className="grid gap-1.5">
235
+ {nestLabel ? tooltipLabel : null}
236
+ <span className="text-muted-foreground">
237
+ {itemConfig?.label || item.name}
238
+ </span>
239
+ </div>
240
+ {item.value && (
241
+ <span className="text-code tabular-nums text-foreground">
242
+ {item.value.toLocaleString()}
243
+ </span>
244
+ )}
245
+ </div>
246
+ </>
247
+ )}
248
+ </div>
249
+ )
250
+ })}
251
+ </div>
252
+ </div>
253
+ )
254
+ }
255
+ )
256
+ ChartTooltipContent.displayName = "ChartTooltip"
257
+
258
+ const ChartLegend = RechartsPrimitive.Legend
259
+
260
+ const ChartLegendContent = React.forwardRef<
261
+ HTMLDivElement,
262
+ React.ComponentProps<"div"> &
263
+ { payload?: any; verticalAlign?: any } & {
264
+ hideIcon?: boolean
265
+ nameKey?: string
266
+ }
267
+ >(
268
+ (
269
+ { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
270
+ ref
271
+ ) => {
272
+ const { config } = useChart()
273
+
274
+ if (!payload?.length) {
275
+ return null
276
+ }
277
+
278
+ return (
279
+ <div
280
+ ref={ref}
281
+ className={cn(
282
+ "flex items-center justify-center gap-4",
283
+ verticalAlign === "top" ? "pb-3" : "pt-3",
284
+ className
285
+ )}
286
+ >
287
+ {payload?.map((item: any) => {
288
+ const key = `${nameKey || item.dataKey || "value"}`
289
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
290
+
291
+ return (
292
+ <div
293
+ key={item.value}
294
+ className={cn(
295
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
296
+ )}
297
+ >
298
+ {itemConfig?.icon && !hideIcon ? (
299
+ <itemConfig.icon />
300
+ ) : (
301
+ <div
302
+ className="h-2 w-2 shrink-0 rounded-[2px]"
303
+ style={{
304
+ backgroundColor: item.color,
305
+ }}
306
+ />
307
+ )}
308
+ {itemConfig?.label}
309
+ </div>
310
+ )
311
+ })}
312
+ </div>
313
+ )
314
+ }
315
+ )
316
+ ChartLegendContent.displayName = "ChartLegend"
317
+
318
+ // Helper to extract item config from a payload.
319
+ function getPayloadConfigFromPayload(
320
+ config: ChartConfig,
321
+ payload: unknown,
322
+ key: string
323
+ ) {
324
+ if (typeof payload !== "object" || payload === null) {
325
+ return undefined
326
+ }
327
+
328
+ const payloadPayload =
329
+ "payload" in payload &&
330
+ typeof payload.payload === "object" &&
331
+ payload.payload !== null
332
+ ? payload.payload
333
+ : undefined
334
+
335
+ let configLabelKey: string = key
336
+
337
+ if (
338
+ key in payload &&
339
+ typeof payload[key as keyof typeof payload] === "string"
340
+ ) {
341
+ configLabelKey = payload[key as keyof typeof payload] as string
342
+ } else if (
343
+ payloadPayload &&
344
+ key in payloadPayload &&
345
+ typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
346
+ ) {
347
+ configLabelKey = payloadPayload[
348
+ key as keyof typeof payloadPayload
349
+ ] as string
350
+ }
351
+
352
+ return configLabelKey in config
353
+ ? config[configLabelKey]
354
+ : config[key as keyof typeof config]
355
+ }
356
+
357
+ export {
358
+ ChartContainer,
359
+ ChartTooltip,
360
+ ChartTooltipContent,
361
+ ChartLegend,
362
+ ChartLegendContent,
363
+ ChartStyle,
364
+ }
@@ -2,7 +2,7 @@ import * as React from "react"
2
2
  import { cn } from "../../utils/cn"
3
3
  import { SquareAvatar as Avatar } from "../ui/square-avatar"
4
4
  import { Button } from "../ui/button"
5
- import { PlusCircleIcon } from "../icons/plus-circle-icon"
5
+ import { PlusCircleIcon } from "../plus-circle-icon"
6
6
  import { XmarkIcon } from "../icons-v2-generated/signs-and-symbols/xmark-icon"
7
7
  import { Chevron02LeftIcon } from "../icons-v2-generated"
8
8
  import { TicketStatusTag, resolveStatusTagProps } from "../ui/ticket-status-tag"
@@ -13,22 +13,29 @@ The single exported hook. Accepts `UseJetStreamDialogSubscriptionOptions` and re
13
13
  |---|---|
14
14
  | `isConnected` | Whether the NATS WebSocket connection is live |
15
15
  | `isSubscribed` | Whether the JetStream consumer is active |
16
- | `reconnectionCount` | Increments whenever the live tail is re-established: a NATS reconnect, a JetStream ordered-consumer recreation, or a resync after the page was hidden. Callers refetch persisted history on every increment |
16
+ | `reconnectionCount` | Increments whenever the live tail is re-established: a NATS reconnect, a JetStream ordered-consumer recreation, a resync after the page was hidden, or a host reporting either via `resyncSignal`. Callers refetch persisted history on every increment; one absence counts once even when two sources report it |
17
17
  | `currentStreamSeq` | Highest stream sequence number observed |
18
18
 
19
+ **Host-supplied resync (`resyncSignal` option):**
20
+
21
+ A counter the embedder bumps when it knows, from outside the page, that the tail may have missed something — an absence the page could not observe (a native shell whose window visibility never reaches `document.visibilityState`), or a write made on the page's behalf while it was away. Any increase is treated exactly like a reconnect. The value at mount is a baseline, rebased on every `dialogId` change so switching to a conversation with a lower count cannot swallow later resyncs.
22
+
19
23
  **Internal refs (stable across renders):**
20
24
 
21
25
  - `clientRef` — shared `NatsClient` instance
22
26
  - `lastRecoveryReportRef` — timestamp floor so a flapping consumer cannot storm callers with refetches
27
+ - `resyncTimerRef` — trailing-edge timer collapsing resync requests within `RESYNC_COALESCE_MS`; cleared on dialog change and unmount so a request never crosses a conversation boundary
28
+ - `lastResyncSignalRef` — baseline for `resyncSignal`, rebased per dialog
23
29
  - `subscriptionRef` — active `JetStreamSubscriptionHandle`
24
30
  - `highestStreamSeqRef` — tracks max stream sequence for gap-free resume
25
31
 
26
32
  **Effect order (declaration order matters):**
27
33
 
28
34
  1. **Connection effect** — acquires/releases the shared NATS client when `enabled` or `wsUrl` changes; drives the `startConnectionLifecycle` which emits status events.
29
- 2. **Dialog reset effect** — resets `highestStreamSeqRef` when `dialogId` changes so a new dialog never inherits a stale start sequence.
30
- 3. **Visibility effect** — after the page has been hidden longer than `RESYNC_AFTER_HIDDEN_MS`, returning to view bumps the counter: a hidden page can stop receiving without the socket ever closing, and nothing else reports that.
31
- 4. **Subscription effect** — creates or recreates the ephemeral consumer when `isConnected`, `dialogId`, `topic`, `streamName`, or the reconnect counter change.
35
+ 2. **Dialog reset effect** — resets `highestStreamSeqRef`, rebases the `resyncSignal` baseline, and drops any pending resync when `dialogId` changes, so a new dialog never inherits a stale start sequence or the previous dialog's refetch.
36
+ 3. **Visibility effect** — after the page has been hidden longer than `RESYNC_AFTER_HIDDEN_MS`, returning to view requests a resync: a hidden page can stop receiving without the socket ever closing, and nothing else reports that.
37
+ 4. **Host-signal effect** — an increase in `resyncSignal` requests a resync on the same path, for absences and out-of-band writes the page cannot see.
38
+ 5. **Subscription effect** — creates or recreates the ephemeral consumer when `isConnected`, `dialogId`, `topic`, `streamName`, or the reconnect counter change.
32
39
 
33
40
  **Deliver policy logic:**
34
41
 
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useRef, useState } from 'react'
3
+ import { useCallback, useEffect, useRef, useState } from 'react'
4
4
  import {
5
5
  acquireClient as acquireSharedClient,
6
6
  releaseClient as releaseSharedClient,
@@ -20,7 +20,24 @@ const DEFAULT_STREAM_NAME = 'CHAT_CHUNKS'
20
20
  * absence worth resyncing for. Alt-tabbing must not churn the consumer; a
21
21
  * window that sat in the tray must not come back showing a stale conversation.
22
22
  */
23
- const RESYNC_AFTER_HIDDEN_MS = 10_000
23
+ export const RESYNC_AFTER_HIDDEN_MS = 10_000
24
+ /**
25
+ * How long resync requests are gathered before one is acted on.
26
+ *
27
+ * A single reveal can be reported twice: the page sees `visibilitychange`, and
28
+ * a host that knows the window was away reports it too (`resyncSignal`),
29
+ * neither able to tell whether the other noticed. Both land within a frame or
30
+ * two of each other, being driven by the same OS event, and acting on both
31
+ * rebuilds the consumer and refetches history twice for one reveal.
32
+ *
33
+ * Gathered on the TRAILING edge, so a request is deferred and never dropped.
34
+ * Two reports of one reveal collapse into one rebuild; two genuinely different
35
+ * signals — a notification reply landing just before the user opens the window
36
+ * — also collapse into one, which is correct, because a single refetch after
37
+ * the last of them covers both. The cost is a second of latency on a path whose
38
+ * next step is a network round trip.
39
+ */
40
+ const RESYNC_COALESCE_MS = 1_000
24
41
  /**
25
42
  * Floor between two reported recoveries. Every recovery costs the caller a
26
43
  * history refetch, and a consumer that cannot hold its sequence — gap, reset,
@@ -60,6 +77,7 @@ export function useJetStreamDialogSubscription({
60
77
  clientConfig = {},
61
78
  reconnectionBackoff,
62
79
  inactiveThresholdMs,
80
+ resyncSignal = 0,
63
81
  }: UseJetStreamDialogSubscriptionOptions): UseJetStreamDialogSubscriptionReturn {
64
82
  const [isConnected, setIsConnected] = useState(false)
65
83
  const [isSubscribed, setIsSubscribed] = useState(false)
@@ -73,6 +91,8 @@ export function useJetStreamDialogSubscription({
73
91
  const [currentStreamSeq, setCurrentStreamSeq] = useState<number | null>(null)
74
92
 
75
93
  const lastRecoveryReportRef = useRef(0)
94
+ const resyncTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
95
+ const lastResyncSignalRef = useRef(resyncSignal)
76
96
  const clientRef = useRef<NatsClient | null>(null)
77
97
  const subscriptionRef = useRef<JetStreamSubscriptionHandle | null>(null)
78
98
  const highestStreamSeqRef = useRef<number | null>(null)
@@ -245,7 +265,26 @@ export function useJetStreamDialogSubscription({
245
265
  // ignoring optStartSeq).
246
266
  useEffect(() => {
247
267
  highestStreamSeqRef.current = null
268
+ // A host's signal counts per dialog (it can carry a per-conversation term),
269
+ // so the baseline has to move with the dialog or a switch to one with a
270
+ // LOWER count would swallow every later resync for it.
271
+ lastResyncSignalRef.current = resyncSignal
248
272
  setCurrentStreamSeq(null)
273
+ // A resync gathered for the previous dialog must not land on this one: the
274
+ // counter says nothing about which conversation it meant, so callers would
275
+ // refetch the wrong one. The dialog change supersedes it — the new dialog
276
+ // loads its own history regardless. As cleanup, so it covers unmount too,
277
+ // which is the same rule.
278
+ return () => {
279
+ if (resyncTimerRef.current !== null) {
280
+ clearTimeout(resyncTimerRef.current)
281
+ resyncTimerRef.current = null
282
+ }
283
+ }
284
+ // `resyncSignal` is read as the new baseline, not depended on: reacting to
285
+ // it here would reset the baseline on the very change meant to trigger a
286
+ // resync, and the effect below owns that.
287
+ // eslint-disable-next-line react-hooks/exhaustive-deps
249
288
  }, [dialogId])
250
289
 
251
290
  // Coming back into view after a real absence is treated exactly like a
@@ -256,8 +295,20 @@ export function useJetStreamDialogSubscription({
256
295
  // report that: the tail simply stays quiet, and the conversation on screen
257
296
  // stays frozen at whatever was there when the window went away (the user's
258
297
  // manual fix is a page refresh, which is exactly the history refetch this
259
- // triggers). Bumping the counter rebuilds the consumer from the last sequence
260
- // seen AND tells callers to refetch history.
298
+ // triggers). Rebuilds the consumer from the last sequence seen AND tells
299
+ // callers to refetch history.
300
+ //
301
+ // Every source funnels through here (see `RESYNC_COALESCE_MS`). Restarting
302
+ // the timer rather than dropping is what makes that safe: a request is only
303
+ // ever folded into the one that follows it, never discarded.
304
+ const requestResync = useCallback(() => {
305
+ if (resyncTimerRef.current !== null) clearTimeout(resyncTimerRef.current)
306
+ resyncTimerRef.current = setTimeout(() => {
307
+ resyncTimerRef.current = null
308
+ setReconnectionCount((c) => c + 1)
309
+ }, RESYNC_COALESCE_MS)
310
+ }, [])
311
+
261
312
  useEffect(() => {
262
313
  if (!enabled) return
263
314
  let hiddenSince = document.visibilityState === 'hidden' ? Date.now() : 0
@@ -270,13 +321,27 @@ export function useJetStreamDialogSubscription({
270
321
  const awayMs = hiddenSince === 0 ? 0 : Date.now() - hiddenSince
271
322
  hiddenSince = 0
272
323
  if (awayMs >= RESYNC_AFTER_HIDDEN_MS) {
273
- setReconnectionCount((c) => c + 1)
324
+ requestResync()
274
325
  }
275
326
  }
276
327
 
277
328
  document.addEventListener('visibilitychange', onVisibilityChange)
278
329
  return () => document.removeEventListener('visibilitychange', onVisibilityChange)
279
- }, [enabled])
330
+ }, [enabled, requestResync])
331
+
332
+ useEffect(() => {
333
+ // Held, not consumed, while disabled: it fires once on enable instead.
334
+ // A host reports a signal against the conversation, not against this hook's
335
+ // readiness, so one arriving while the caller is still assembling the
336
+ // subscription describes a gap in the history the caller is fetching right
337
+ // now. Dropping it would leave that fetch's result stale with nothing left
338
+ // to say so.
339
+ if (!enabled) return
340
+ // The mount value is a baseline, not a signal.
341
+ if (resyncSignal <= lastResyncSignalRef.current) return
342
+ lastResyncSignalRef.current = resyncSignal
343
+ requestResync()
344
+ }, [enabled, resyncSignal, requestResync])
280
345
 
281
346
  // Subscription lifecycle: (re)create the ephemeral JetStream consumer whenever
282
347
  // we transition into a connected state for a dialog, and whenever the dialog
@@ -131,6 +131,22 @@ export interface UseJetStreamDialogSubscriptionOptions {
131
131
  /** Consumer inactivity threshold in ms before NATS auto-cleans it. Defaults to the
132
132
  * client's, and applies only to the first consumer — recreations use nats.ws's. */
133
133
  inactiveThresholdMs?: number
134
+ /**
135
+ * A counter the host bumps when it knows, from outside the page, that the tail
136
+ * may have missed something.
137
+ *
138
+ * The hook's own detector is `visibilitychange`, which a browser tab reports
139
+ * honestly and an embedding shell may not — and which says nothing at all
140
+ * about a write made on the page's behalf while it was away. A host holding
141
+ * either kind of knowledge bumps this instead of hoping the page noticed.
142
+ *
143
+ * Treated exactly like a reconnect: the consumer is rebuilt from the highest
144
+ * sequence already seen, and `reconnectionCount` moves so callers refetch
145
+ * persisted history. Any increase counts; the value itself means nothing, and
146
+ * an increase arriving alongside a `visibilitychange` costs one rebuild, not
147
+ * two.
148
+ */
149
+ resyncSignal?: number
134
150
  }
135
151
 
136
152
  export interface UseJetStreamDialogSubscriptionReturn {
@@ -138,10 +154,12 @@ export interface UseJetStreamDialogSubscriptionReturn {
138
154
  isSubscribed: boolean
139
155
  /**
140
156
  * Incremented each time the live tail is re-established: a NATS reconnect, a
141
- * JetStream ordered-consumer recreation, or the page returning to view after
142
- * being hidden long enough to have missed something. All three mean the same
143
- * thing to the caller — the tail may have skipped messages, so persisted
144
- * history has to be refetched. Starts at 0.
157
+ * JetStream ordered-consumer recreation, the page returning to view after
158
+ * being hidden long enough to have missed something, or a host reporting the
159
+ * same via `resyncSignal`. All of them mean the same thing to the caller —
160
+ * the tail may have skipped messages, so persisted history has to be
161
+ * refetched. One absence counts once even when two sources report it.
162
+ * Starts at 0.
145
163
  */
146
164
  reconnectionCount: number
147
165
  /** Highest JetStream stream sequence observed so far (null before first delivery). */