@athenaintel/react 0.57.2 → 0.60.0

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 (852) hide show
  1. package/README.md +795 -12
  2. package/dist/agent-runtime/src/addressed-agents.cjs +16 -0
  3. package/dist/agent-runtime/src/addressed-agents.cjs.map +1 -0
  4. package/dist/agent-runtime/src/addressed-agents.d.ts +30 -0
  5. package/dist/agent-runtime/src/addressed-agents.js +16 -0
  6. package/dist/agent-runtime/src/addressed-agents.js.map +1 -0
  7. package/dist/agent-runtime/src/answer-label.cjs +4 -3
  8. package/dist/agent-runtime/src/answer-label.cjs.map +1 -1
  9. package/dist/agent-runtime/src/answer-label.d.ts +13 -6
  10. package/dist/agent-runtime/src/answer-label.js +4 -3
  11. package/dist/agent-runtime/src/answer-label.js.map +1 -1
  12. package/dist/agent-runtime/src/chat-outbox-attachments.cjs.map +1 -1
  13. package/dist/agent-runtime/src/chat-outbox-attachments.d.ts +1 -1
  14. package/dist/agent-runtime/src/chat-outbox-attachments.js.map +1 -1
  15. package/dist/agent-runtime/src/chat-outbox-entry.cjs +101 -0
  16. package/dist/agent-runtime/src/chat-outbox-entry.cjs.map +1 -0
  17. package/dist/agent-runtime/src/chat-outbox-entry.d.ts +99 -0
  18. package/dist/agent-runtime/src/chat-outbox-entry.js +101 -0
  19. package/dist/agent-runtime/src/chat-outbox-entry.js.map +1 -0
  20. package/dist/agent-runtime/src/chat-outbox-legacy.cjs +252 -0
  21. package/dist/agent-runtime/src/chat-outbox-legacy.cjs.map +1 -0
  22. package/dist/agent-runtime/src/chat-outbox-legacy.d.ts +96 -0
  23. package/dist/agent-runtime/src/chat-outbox-legacy.js +252 -0
  24. package/dist/agent-runtime/src/chat-outbox-legacy.js.map +1 -0
  25. package/dist/agent-runtime/src/chat-outbox-policy.cjs +30 -0
  26. package/dist/agent-runtime/src/chat-outbox-policy.cjs.map +1 -0
  27. package/dist/agent-runtime/src/chat-outbox-policy.d.ts +42 -0
  28. package/dist/agent-runtime/src/chat-outbox-policy.js +30 -0
  29. package/dist/agent-runtime/src/chat-outbox-policy.js.map +1 -0
  30. package/dist/agent-runtime/src/chat-outbox-storage.cjs +306 -0
  31. package/dist/agent-runtime/src/chat-outbox-storage.cjs.map +1 -0
  32. package/dist/agent-runtime/src/chat-outbox-storage.d.ts +194 -0
  33. package/dist/agent-runtime/src/chat-outbox-storage.js +306 -0
  34. package/dist/agent-runtime/src/chat-outbox-storage.js.map +1 -0
  35. package/dist/agent-runtime/src/chat-outbox-thread.cjs +21 -94
  36. package/dist/agent-runtime/src/chat-outbox-thread.cjs.map +1 -1
  37. package/dist/agent-runtime/src/chat-outbox-thread.d.ts +22 -18
  38. package/dist/agent-runtime/src/chat-outbox-thread.js +21 -94
  39. package/dist/agent-runtime/src/chat-outbox-thread.js.map +1 -1
  40. package/dist/agent-runtime/src/chat-outbox.cjs +492 -547
  41. package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
  42. package/dist/agent-runtime/src/chat-outbox.d.ts +110 -142
  43. package/dist/agent-runtime/src/chat-outbox.js +492 -547
  44. package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
  45. package/dist/agent-runtime/src/composer-markdown.cjs +0 -16
  46. package/dist/agent-runtime/src/composer-markdown.cjs.map +1 -1
  47. package/dist/agent-runtime/src/composer-markdown.d.ts +1 -1
  48. package/dist/agent-runtime/src/composer-markdown.js +1 -17
  49. package/dist/agent-runtime/src/composer-markdown.js.map +1 -1
  50. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +3 -1
  51. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  52. package/dist/agent-runtime/src/deep-agent-transport-recipe.d.ts +8 -1
  53. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +3 -1
  54. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  55. package/dist/agent-runtime/src/dictation-preferences.d.ts +356 -0
  56. package/dist/agent-runtime/src/dictation-record.d.ts +279 -0
  57. package/dist/agent-runtime/src/dictation-session.d.ts +106 -7
  58. package/dist/agent-runtime/src/dictation-snippets.d.ts +9 -0
  59. package/dist/agent-runtime/src/dictation-transfer.d.ts +142 -0
  60. package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
  61. package/dist/agent-runtime/src/edit-command.d.ts +1 -1
  62. package/dist/agent-runtime/src/edit-command.js.map +1 -1
  63. package/dist/agent-runtime/src/errors.cjs +1 -0
  64. package/dist/agent-runtime/src/errors.cjs.map +1 -1
  65. package/dist/agent-runtime/src/errors.js +1 -0
  66. package/dist/agent-runtime/src/errors.js.map +1 -1
  67. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +24 -0
  68. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  69. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +3 -3
  70. package/dist/agent-runtime/src/generated/runconfig-contract.js +24 -0
  71. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  72. package/dist/agent-runtime/src/index.d.ts +14 -8
  73. package/dist/agent-runtime/src/lane-follow.cjs +289 -0
  74. package/dist/agent-runtime/src/lane-follow.cjs.map +1 -0
  75. package/dist/agent-runtime/src/lane-follow.js +289 -0
  76. package/dist/agent-runtime/src/lane-follow.js.map +1 -0
  77. package/dist/agent-runtime/src/lane-images.cjs +387 -0
  78. package/dist/agent-runtime/src/lane-images.cjs.map +1 -0
  79. package/dist/agent-runtime/src/lane-images.js +387 -0
  80. package/dist/agent-runtime/src/lane-images.js.map +1 -0
  81. package/dist/agent-runtime/src/message-window.js +1 -1
  82. package/dist/agent-runtime/src/messages.cjs +19 -1
  83. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  84. package/dist/agent-runtime/src/messages.d.ts +8 -0
  85. package/dist/agent-runtime/src/messages.js +21 -3
  86. package/dist/agent-runtime/src/messages.js.map +1 -1
  87. package/dist/agent-runtime/src/named-agents.cjs +301 -0
  88. package/dist/agent-runtime/src/named-agents.cjs.map +1 -0
  89. package/dist/agent-runtime/src/named-agents.d.ts +246 -0
  90. package/dist/agent-runtime/src/named-agents.js +301 -0
  91. package/dist/agent-runtime/src/named-agents.js.map +1 -0
  92. package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
  93. package/dist/agent-runtime/src/offline-status.d.ts +93 -2
  94. package/dist/agent-runtime/src/offline-status.js.map +1 -1
  95. package/dist/agent-runtime/src/ptc-subcalls.cjs +41 -0
  96. package/dist/agent-runtime/src/ptc-subcalls.cjs.map +1 -0
  97. package/dist/agent-runtime/src/ptc-subcalls.js +41 -0
  98. package/dist/agent-runtime/src/ptc-subcalls.js.map +1 -0
  99. package/dist/agent-runtime/src/queue.cjs +2 -2
  100. package/dist/agent-runtime/src/queue.cjs.map +1 -1
  101. package/dist/agent-runtime/src/queue.d.ts +20 -25
  102. package/dist/agent-runtime/src/queue.js +2 -2
  103. package/dist/agent-runtime/src/queue.js.map +1 -1
  104. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +314 -84
  105. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  106. package/dist/agent-runtime/src/quota-safe-local-storage-session.d.ts +137 -40
  107. package/dist/agent-runtime/src/quota-safe-local-storage-session.js +318 -88
  108. package/dist/agent-runtime/src/quota-safe-local-storage-session.js.map +1 -1
  109. package/dist/agent-runtime/src/run-send.cjs +54 -0
  110. package/dist/agent-runtime/src/run-send.cjs.map +1 -0
  111. package/dist/agent-runtime/src/run-send.d.ts +51 -0
  112. package/dist/agent-runtime/src/run-send.js +54 -0
  113. package/dist/agent-runtime/src/run-send.js.map +1 -0
  114. package/dist/agent-runtime/src/running-tool-placeholder.cjs +6 -0
  115. package/dist/agent-runtime/src/running-tool-placeholder.cjs.map +1 -1
  116. package/dist/agent-runtime/src/running-tool-placeholder.js +6 -0
  117. package/dist/agent-runtime/src/running-tool-placeholder.js.map +1 -1
  118. package/dist/agent-runtime/src/runtime.d.ts +9 -5
  119. package/dist/agent-runtime/src/sealed-idb.cjs +64 -0
  120. package/dist/agent-runtime/src/sealed-idb.cjs.map +1 -1
  121. package/dist/agent-runtime/src/sealed-idb.d.ts +16 -0
  122. package/dist/agent-runtime/src/sealed-idb.js +64 -0
  123. package/dist/agent-runtime/src/sealed-idb.js.map +1 -1
  124. package/dist/agent-runtime/src/send-recovery.cjs +90 -118
  125. package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
  126. package/dist/agent-runtime/src/send-recovery.d.ts +25 -29
  127. package/dist/agent-runtime/src/send-recovery.js +90 -118
  128. package/dist/agent-runtime/src/send-recovery.js.map +1 -1
  129. package/dist/agent-runtime/src/statewire-diagnostics.d.ts +4 -1
  130. package/dist/agent-runtime/src/statewire-held-sends.cjs +191 -0
  131. package/dist/agent-runtime/src/statewire-held-sends.cjs.map +1 -0
  132. package/dist/agent-runtime/src/statewire-held-sends.d.ts +119 -0
  133. package/dist/agent-runtime/src/statewire-held-sends.js +191 -0
  134. package/dist/agent-runtime/src/statewire-held-sends.js.map +1 -0
  135. package/dist/agent-runtime/src/statewire-state.cjs +4 -0
  136. package/dist/agent-runtime/src/statewire-state.cjs.map +1 -1
  137. package/dist/agent-runtime/src/statewire-state.js +4 -0
  138. package/dist/agent-runtime/src/statewire-state.js.map +1 -1
  139. package/dist/agent-runtime/src/statewire-transport.cjs +8 -2
  140. package/dist/agent-runtime/src/statewire-transport.cjs.map +1 -1
  141. package/dist/agent-runtime/src/statewire-transport.d.ts +14 -5
  142. package/dist/agent-runtime/src/statewire-transport.js +8 -2
  143. package/dist/agent-runtime/src/statewire-transport.js.map +1 -1
  144. package/dist/agent-runtime/src/subagent-transcripts.cjs +1 -23
  145. package/dist/agent-runtime/src/subagent-transcripts.cjs.map +1 -1
  146. package/dist/agent-runtime/src/subagent-transcripts.js +3 -25
  147. package/dist/agent-runtime/src/subagent-transcripts.js.map +1 -1
  148. package/dist/agent-runtime/src/subagents.cjs +22 -29
  149. package/dist/agent-runtime/src/subagents.cjs.map +1 -1
  150. package/dist/agent-runtime/src/subagents.js +23 -30
  151. package/dist/agent-runtime/src/subagents.js.map +1 -1
  152. package/dist/agent-runtime/src/thread-extras.cjs +27 -19
  153. package/dist/agent-runtime/src/thread-extras.cjs.map +1 -1
  154. package/dist/agent-runtime/src/thread-extras.d.ts +19 -6
  155. package/dist/agent-runtime/src/thread-extras.js +27 -19
  156. package/dist/agent-runtime/src/thread-extras.js.map +1 -1
  157. package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +8 -8
  158. package/dist/agent-runtime/src/tool-metadata.cjs +19 -0
  159. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  160. package/dist/agent-runtime/src/tool-metadata.js +19 -0
  161. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  162. package/dist/agent-runtime/src/tool-names.cjs +21 -0
  163. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  164. package/dist/agent-runtime/src/tool-names.d.ts +8 -0
  165. package/dist/agent-runtime/src/tool-names.js +21 -0
  166. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  167. package/dist/agent-runtime/src/typed-interrupt-kinds.cjs +247 -0
  168. package/dist/agent-runtime/src/typed-interrupt-kinds.cjs.map +1 -0
  169. package/dist/agent-runtime/src/typed-interrupt-kinds.d.ts +173 -0
  170. package/dist/agent-runtime/src/typed-interrupt-kinds.js +247 -0
  171. package/dist/agent-runtime/src/typed-interrupt-kinds.js.map +1 -0
  172. package/dist/agent-runtime/src/typed-interrupts.cjs +48 -0
  173. package/dist/agent-runtime/src/typed-interrupts.cjs.map +1 -0
  174. package/dist/agent-runtime/src/typed-interrupts.d.ts +75 -0
  175. package/dist/agent-runtime/src/typed-interrupts.js +48 -0
  176. package/dist/agent-runtime/src/typed-interrupts.js.map +1 -0
  177. package/dist/agent-runtime/src/types.d.ts +1 -1
  178. package/dist/agent-runtime/src/use-conversation-list.cjs +1 -0
  179. package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
  180. package/dist/agent-runtime/src/use-conversation-list.d.ts +7 -0
  181. package/dist/agent-runtime/src/use-conversation-list.js +1 -0
  182. package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
  183. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +46 -29
  184. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
  185. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +14 -22
  186. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +46 -29
  187. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
  188. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +78 -14
  189. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  190. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +34 -7
  191. package/dist/agent-runtime/src/use-deep-agent-runtime.js +79 -15
  192. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  193. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +16 -1
  194. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  195. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +7 -2
  196. package/dist/agent-runtime/src/use-deep-agent-thread.js +16 -1
  197. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  198. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +30 -4
  199. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  200. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +22 -4
  201. package/dist/agent-runtime/src/use-deep-agent-voice.js +30 -4
  202. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  203. package/dist/agent-runtime/src/withdrawn-turns.d.ts +5 -4
  204. package/dist/agent-runtime/src/word-device-fit.d.ts +174 -0
  205. package/dist/agent-runtime/src/work-in.d.ts +127 -0
  206. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  207. package/dist/assets/AthenaAssetEmbed.d.ts +6 -1
  208. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  209. package/dist/assets/asset-panel-store.cjs +13 -5
  210. package/dist/assets/asset-panel-store.cjs.map +1 -1
  211. package/dist/assets/asset-panel-store.d.ts +33 -2
  212. package/dist/assets/asset-panel-store.js +13 -5
  213. package/dist/assets/asset-panel-store.js.map +1 -1
  214. package/dist/auth/AthenaCredentialSourceContext.cjs +11 -0
  215. package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
  216. package/dist/auth/AthenaCredentialSourceContext.d.ts +6 -0
  217. package/dist/auth/AthenaCredentialSourceContext.js +11 -0
  218. package/dist/auth/AthenaCredentialSourceContext.js.map +1 -1
  219. package/dist/auth/account-identity.cjs +13 -2
  220. package/dist/auth/account-identity.cjs.map +1 -1
  221. package/dist/auth/account-identity.d.ts +9 -0
  222. package/dist/auth/account-identity.js +13 -2
  223. package/dist/auth/account-identity.js.map +1 -1
  224. package/dist/auth/credential-source.cjs +20 -4
  225. package/dist/auth/credential-source.cjs.map +1 -1
  226. package/dist/auth/credential-source.d.ts +9 -0
  227. package/dist/auth/credential-source.js +20 -4
  228. package/dist/auth/credential-source.js.map +1 -1
  229. package/dist/catalog/chat-pickers.cjs +31 -0
  230. package/dist/catalog/chat-pickers.cjs.map +1 -1
  231. package/dist/catalog/chat-pickers.d.ts +17 -0
  232. package/dist/catalog/chat-pickers.js +33 -2
  233. package/dist/catalog/chat-pickers.js.map +1 -1
  234. package/dist/catalog/runtime-catalog.cjs +63 -3
  235. package/dist/catalog/runtime-catalog.cjs.map +1 -1
  236. package/dist/catalog/runtime-catalog.d.ts +63 -3
  237. package/dist/catalog/runtime-catalog.js +64 -4
  238. package/dist/catalog/runtime-catalog.js.map +1 -1
  239. package/dist/chat/AthenaChat.cjs +301 -98
  240. package/dist/chat/AthenaChat.cjs.map +1 -1
  241. package/dist/chat/AthenaChat.d.ts +80 -4
  242. package/dist/chat/AthenaChat.js +302 -99
  243. package/dist/chat/AthenaChat.js.map +1 -1
  244. package/dist/chat/StatewireApprovalCard.cjs +35 -5
  245. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  246. package/dist/chat/StatewireApprovalCard.d.ts +55 -2
  247. package/dist/chat/StatewireApprovalCard.js +37 -7
  248. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  249. package/dist/chat/StatewireQueuedMessages.cjs +17 -2
  250. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  251. package/dist/chat/StatewireQueuedMessages.d.ts +8 -45
  252. package/dist/chat/StatewireQueuedMessages.js +18 -3
  253. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  254. package/dist/chat/chat-agent-mentions.cjs +70 -0
  255. package/dist/chat/chat-agent-mentions.cjs.map +1 -0
  256. package/dist/chat/chat-agent-mentions.d.ts +13 -0
  257. package/dist/chat/chat-agent-mentions.js +70 -0
  258. package/dist/chat/chat-agent-mentions.js.map +1 -0
  259. package/dist/chat/composer-actions.cjs +12 -0
  260. package/dist/chat/composer-actions.cjs.map +1 -0
  261. package/dist/chat/composer-actions.d.ts +22 -0
  262. package/dist/chat/composer-actions.js +12 -0
  263. package/dist/chat/composer-actions.js.map +1 -0
  264. package/dist/chat/follow-up-suggestions.cjs +185 -0
  265. package/dist/chat/follow-up-suggestions.cjs.map +1 -0
  266. package/dist/chat/follow-up-suggestions.d.ts +64 -0
  267. package/dist/chat/follow-up-suggestions.js +185 -0
  268. package/dist/chat/follow-up-suggestions.js.map +1 -0
  269. package/dist/chat/super-grouping/ToolTimeline.cjs +4 -3
  270. package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
  271. package/dist/chat/super-grouping/ToolTimeline.d.ts +7 -3
  272. package/dist/chat/super-grouping/ToolTimeline.js +4 -3
  273. package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
  274. package/dist/chat/turn-changes.cjs +284 -0
  275. package/dist/chat/turn-changes.cjs.map +1 -0
  276. package/dist/chat/turn-changes.d.ts +130 -0
  277. package/dist/chat/turn-changes.js +284 -0
  278. package/dist/chat/turn-changes.js.map +1 -0
  279. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.cjs +31 -0
  280. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.cjs.map +1 -0
  281. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.d.ts +31 -0
  282. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.js +31 -0
  283. package/dist/chat/typed-interrupts/StatewireTypedInterruptCard.js.map +1 -0
  284. package/dist/chat/typed-interrupts/approval-cards.cjs +250 -0
  285. package/dist/chat/typed-interrupts/approval-cards.cjs.map +1 -0
  286. package/dist/chat/typed-interrupts/approval-cards.d.ts +22 -0
  287. package/dist/chat/typed-interrupts/approval-cards.js +250 -0
  288. package/dist/chat/typed-interrupts/approval-cards.js.map +1 -0
  289. package/dist/chat/typed-interrupts/form-cards.cjs +289 -0
  290. package/dist/chat/typed-interrupts/form-cards.cjs.map +1 -0
  291. package/dist/chat/typed-interrupts/form-cards.d.ts +6 -0
  292. package/dist/chat/typed-interrupts/form-cards.js +289 -0
  293. package/dist/chat/typed-interrupts/form-cards.js.map +1 -0
  294. package/dist/chat/typed-interrupts/interrupt-card-shell.cjs +182 -0
  295. package/dist/chat/typed-interrupts/interrupt-card-shell.cjs.map +1 -0
  296. package/dist/chat/typed-interrupts/interrupt-card-shell.d.ts +47 -0
  297. package/dist/chat/typed-interrupts/interrupt-card-shell.js +182 -0
  298. package/dist/chat/typed-interrupts/interrupt-card-shell.js.map +1 -0
  299. package/dist/chat/typed-interrupts/json-schema-form.cjs +388 -0
  300. package/dist/chat/typed-interrupts/json-schema-form.cjs.map +1 -0
  301. package/dist/chat/typed-interrupts/json-schema-form.d.ts +33 -0
  302. package/dist/chat/typed-interrupts/json-schema-form.js +388 -0
  303. package/dist/chat/typed-interrupts/json-schema-form.js.map +1 -0
  304. package/dist/chat/typed-interrupts/questionnaire-card.cjs +449 -0
  305. package/dist/chat/typed-interrupts/questionnaire-card.cjs.map +1 -0
  306. package/dist/chat/typed-interrupts/questionnaire-card.d.ts +20 -0
  307. package/dist/chat/typed-interrupts/questionnaire-card.js +449 -0
  308. package/dist/chat/typed-interrupts/questionnaire-card.js.map +1 -0
  309. package/dist/chat/typed-interrupts/request-file-card.cjs +159 -0
  310. package/dist/chat/typed-interrupts/request-file-card.cjs.map +1 -0
  311. package/dist/chat/typed-interrupts/request-file-card.d.ts +2 -0
  312. package/dist/chat/typed-interrupts/request-file-card.js +159 -0
  313. package/dist/chat/typed-interrupts/request-file-card.js.map +1 -0
  314. package/dist/chat/typed-interrupts/toolkit-selection-card.cjs +189 -0
  315. package/dist/chat/typed-interrupts/toolkit-selection-card.cjs.map +1 -0
  316. package/dist/chat/typed-interrupts/toolkit-selection-card.d.ts +23 -0
  317. package/dist/chat/typed-interrupts/toolkit-selection-card.js +189 -0
  318. package/dist/chat/typed-interrupts/toolkit-selection-card.js.map +1 -0
  319. package/dist/chat/typed-interrupts/typed-interrupt-body.cjs +26 -0
  320. package/dist/chat/typed-interrupts/typed-interrupt-body.cjs.map +1 -0
  321. package/dist/chat/typed-interrupts/typed-interrupt-body.d.ts +3 -0
  322. package/dist/chat/typed-interrupts/typed-interrupt-body.js +26 -0
  323. package/dist/chat/typed-interrupts/typed-interrupt-body.js.map +1 -0
  324. package/dist/chat/typed-interrupts/typed-interrupt-graphql.cjs +105 -0
  325. package/dist/chat/typed-interrupts/typed-interrupt-graphql.cjs.map +1 -0
  326. package/dist/chat/typed-interrupts/typed-interrupt-graphql.d.ts +29 -0
  327. package/dist/chat/typed-interrupts/typed-interrupt-graphql.js +105 -0
  328. package/dist/chat/typed-interrupts/typed-interrupt-graphql.js.map +1 -0
  329. package/dist/chat/typed-interrupts/typed-interrupt-notice.cjs +70 -0
  330. package/dist/chat/typed-interrupts/typed-interrupt-notice.cjs.map +1 -0
  331. package/dist/chat/typed-interrupts/typed-interrupt-notice.d.ts +45 -0
  332. package/dist/chat/typed-interrupts/typed-interrupt-notice.js +70 -0
  333. package/dist/chat/typed-interrupts/typed-interrupt-notice.js.map +1 -0
  334. package/dist/chat/typed-interrupts/typed-interrupt-panel.cjs +76 -0
  335. package/dist/chat/typed-interrupts/typed-interrupt-panel.cjs.map +1 -0
  336. package/dist/chat/typed-interrupts/typed-interrupt-panel.d.ts +11 -0
  337. package/dist/chat/typed-interrupts/typed-interrupt-panel.js +76 -0
  338. package/dist/chat/typed-interrupts/typed-interrupt-panel.js.map +1 -0
  339. package/dist/chat/typed-interrupts/typed-interrupt-types.d.ts +46 -0
  340. package/dist/chat/typed-interrupts/use-interrupt-draft.cjs +106 -0
  341. package/dist/chat/typed-interrupts/use-interrupt-draft.cjs.map +1 -0
  342. package/dist/chat/typed-interrupts/use-interrupt-draft.d.ts +29 -0
  343. package/dist/chat/typed-interrupts/use-interrupt-draft.js +106 -0
  344. package/dist/chat/typed-interrupts/use-interrupt-draft.js.map +1 -0
  345. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.cjs +231 -0
  346. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.cjs.map +1 -0
  347. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.d.ts +66 -0
  348. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.js +231 -0
  349. package/dist/chat/typed-interrupts/use-statewire-typed-interrupt.js.map +1 -0
  350. package/dist/chat-ui/composer/composer-named-agents.cjs +13 -0
  351. package/dist/chat-ui/composer/composer-named-agents.cjs.map +1 -0
  352. package/dist/chat-ui/composer/composer-named-agents.d.ts +20 -0
  353. package/dist/chat-ui/composer/composer-named-agents.js +13 -0
  354. package/dist/chat-ui/composer/composer-named-agents.js.map +1 -0
  355. package/dist/chat-ui/composer/slash-command-menu.cjs +143 -0
  356. package/dist/chat-ui/composer/slash-command-menu.cjs.map +1 -0
  357. package/dist/chat-ui/composer/slash-command-menu.d.ts +19 -0
  358. package/dist/chat-ui/composer/slash-command-menu.js +143 -0
  359. package/dist/chat-ui/composer/slash-command-menu.js.map +1 -0
  360. package/dist/chat-ui/composer/slash-commands-extension.cjs +51 -0
  361. package/dist/chat-ui/composer/slash-commands-extension.cjs.map +1 -0
  362. package/dist/chat-ui/composer/slash-commands-extension.d.ts +39 -0
  363. package/dist/chat-ui/composer/slash-commands-extension.js +51 -0
  364. package/dist/chat-ui/composer/slash-commands-extension.js.map +1 -0
  365. package/dist/chat-ui/composer/slash-commands.cjs +74 -0
  366. package/dist/chat-ui/composer/slash-commands.cjs.map +1 -0
  367. package/dist/chat-ui/composer/slash-commands.d.ts +82 -0
  368. package/dist/chat-ui/composer/slash-commands.js +74 -0
  369. package/dist/chat-ui/composer/slash-commands.js.map +1 -0
  370. package/dist/chat-ui/composer/tiptap-composer.cjs +135 -9
  371. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  372. package/dist/chat-ui/composer/tiptap-composer.d.ts +61 -2
  373. package/dist/chat-ui/composer/tiptap-composer.js +135 -9
  374. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  375. package/dist/chat-ui/index.cjs +5 -0
  376. package/dist/chat-ui/index.cjs.map +1 -1
  377. package/dist/chat-ui/index.d.ts +4 -2
  378. package/dist/chat-ui/index.js +5 -0
  379. package/dist/chat-ui/index.js.map +1 -1
  380. package/dist/chat-ui/mentions/mention-chip.cjs +10 -4
  381. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  382. package/dist/chat-ui/mentions/mention-chip.js +11 -5
  383. package/dist/chat-ui/mentions/mention-chip.js.map +1 -1
  384. package/dist/chat-ui/mentions/mention-extension.cjs +8 -1
  385. package/dist/chat-ui/mentions/mention-extension.cjs.map +1 -1
  386. package/dist/chat-ui/mentions/mention-extension.js +8 -1
  387. package/dist/chat-ui/mentions/mention-extension.js.map +1 -1
  388. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.cjs +1 -0
  389. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.cjs.map +1 -1
  390. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.js +1 -0
  391. package/dist/chat-ui/mentions/suggestions/components/get-scope-name.js.map +1 -1
  392. package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs +20 -2
  393. package/dist/chat-ui/mentions/suggestions/components/mention-icon.cjs.map +1 -1
  394. package/dist/chat-ui/mentions/suggestions/components/mention-icon.d.ts +10 -1
  395. package/dist/chat-ui/mentions/suggestions/components/mention-icon.js +22 -4
  396. package/dist/chat-ui/mentions/suggestions/components/mention-icon.js.map +1 -1
  397. package/dist/chat-ui/mentions/suggestions/components/menu-item.cjs +1 -1
  398. package/dist/chat-ui/mentions/suggestions/components/menu-item.cjs.map +1 -1
  399. package/dist/chat-ui/mentions/suggestions/components/menu-item.js +1 -1
  400. package/dist/chat-ui/mentions/suggestions/components/menu-item.js.map +1 -1
  401. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +45 -0
  402. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  403. package/dist/chat-ui/mentions/suggestions/data/api-client.d.ts +48 -0
  404. package/dist/chat-ui/mentions/suggestions/data/api-client.js +45 -0
  405. package/dist/chat-ui/mentions/suggestions/data/api-client.js.map +1 -1
  406. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.cjs +89 -0
  407. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.cjs.map +1 -0
  408. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.d.ts +8 -0
  409. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.js +89 -0
  410. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icon-names.generated.js.map +1 -0
  411. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs +140 -116
  412. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.cjs.map +1 -1
  413. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.d.ts +46 -12
  414. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js +141 -117
  415. package/dist/chat-ui/mentions/suggestions/data/sources/asset-type-icons.js.map +1 -1
  416. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +272 -25
  417. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  418. package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +88 -10
  419. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +274 -27
  420. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  421. package/dist/chat-ui/mentions/suggestions/data/types.cjs.map +1 -1
  422. package/dist/chat-ui/mentions/suggestions/data/types.d.ts +27 -1
  423. package/dist/chat-ui/mentions/suggestions/data/types.js.map +1 -1
  424. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +56 -5
  425. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
  426. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +26 -6
  427. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +57 -6
  428. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
  429. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.cjs +34 -17
  430. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.cjs.map +1 -1
  431. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.d.ts +19 -1
  432. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.js +35 -18
  433. package/dist/chat-ui/mentions/suggestions/mention-suggestions.extension.js.map +1 -1
  434. package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs +12 -0
  435. package/dist/chat-ui/mentions/use-asset-icon-app-url.cjs.map +1 -0
  436. package/dist/chat-ui/mentions/use-asset-icon-app-url.d.ts +8 -0
  437. package/dist/chat-ui/mentions/use-asset-icon-app-url.js +12 -0
  438. package/dist/chat-ui/mentions/use-asset-icon-app-url.js.map +1 -0
  439. package/dist/chat-ui/statewire.d.ts +1 -1
  440. package/dist/chat-ui/thread/statewire-history-edge.cjs +15 -0
  441. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  442. package/dist/chat-ui/thread/statewire-history-edge.d.ts +4 -1
  443. package/dist/chat-ui/thread/statewire-history-edge.js +15 -0
  444. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  445. package/dist/collab/client.cjs +41 -6
  446. package/dist/collab/client.cjs.map +1 -1
  447. package/dist/collab/client.d.ts +38 -7
  448. package/dist/collab/client.js +41 -6
  449. package/dist/collab/client.js.map +1 -1
  450. package/dist/composer/ComposerAttachedReferences.cjs +119 -0
  451. package/dist/composer/ComposerAttachedReferences.cjs.map +1 -0
  452. package/dist/composer/ComposerAttachedReferences.d.ts +26 -0
  453. package/dist/composer/ComposerAttachedReferences.js +119 -0
  454. package/dist/composer/ComposerAttachedReferences.js.map +1 -0
  455. package/dist/composer/ComposerNamedAgents.cjs +63 -0
  456. package/dist/composer/ComposerNamedAgents.cjs.map +1 -0
  457. package/dist/composer/ComposerNamedAgents.d.ts +16 -0
  458. package/dist/composer/ComposerNamedAgents.js +63 -0
  459. package/dist/composer/ComposerNamedAgents.js.map +1 -0
  460. package/dist/composer/attached-references.cjs +159 -0
  461. package/dist/composer/attached-references.cjs.map +1 -0
  462. package/dist/composer/attached-references.d.ts +86 -0
  463. package/dist/composer/attached-references.js +159 -0
  464. package/dist/composer/attached-references.js.map +1 -0
  465. package/dist/composer/build-composed-message.cjs +14 -7
  466. package/dist/composer/build-composed-message.cjs.map +1 -1
  467. package/dist/composer/build-composed-message.d.ts +6 -1
  468. package/dist/composer/build-composed-message.js +14 -7
  469. package/dist/composer/build-composed-message.js.map +1 -1
  470. package/dist/composer/composer-handoff.cjs +6 -2
  471. package/dist/composer/composer-handoff.cjs.map +1 -1
  472. package/dist/composer/composer-handoff.d.ts +7 -1
  473. package/dist/composer/composer-handoff.js +6 -2
  474. package/dist/composer/composer-handoff.js.map +1 -1
  475. package/dist/composer/folder-upload.cjs +149 -0
  476. package/dist/composer/folder-upload.cjs.map +1 -0
  477. package/dist/composer/folder-upload.d.ts +79 -0
  478. package/dist/composer/folder-upload.js +149 -0
  479. package/dist/composer/folder-upload.js.map +1 -0
  480. package/dist/composer/index.d.ts +1 -1
  481. package/dist/composer/staged-message-metadata.cjs +12 -0
  482. package/dist/composer/staged-message-metadata.cjs.map +1 -0
  483. package/dist/composer/staged-message-metadata.d.ts +15 -0
  484. package/dist/composer/staged-message-metadata.js +12 -0
  485. package/dist/composer/staged-message-metadata.js.map +1 -0
  486. package/dist/composer/useAttachToChat.cjs +35 -0
  487. package/dist/composer/useAttachToChat.cjs.map +1 -0
  488. package/dist/composer/useAttachToChat.d.ts +54 -0
  489. package/dist/composer/useAttachToChat.js +35 -0
  490. package/dist/composer/useAttachToChat.js.map +1 -0
  491. package/dist/composer/useAttachedReferencesComposerProps.cjs +19 -0
  492. package/dist/composer/useAttachedReferencesComposerProps.cjs.map +1 -0
  493. package/dist/composer/useAttachedReferencesComposerProps.d.ts +12 -0
  494. package/dist/composer/useAttachedReferencesComposerProps.js +19 -0
  495. package/dist/composer/useAttachedReferencesComposerProps.js.map +1 -0
  496. package/dist/composer/useFileUpload.cjs +95 -7
  497. package/dist/composer/useFileUpload.cjs.map +1 -1
  498. package/dist/composer/useFileUpload.d.ts +21 -2
  499. package/dist/composer/useFileUpload.js +95 -7
  500. package/dist/composer/useFileUpload.js.map +1 -1
  501. package/dist/data/athena-api-error.cjs +125 -0
  502. package/dist/data/athena-api-error.cjs.map +1 -0
  503. package/dist/data/athena-api-error.d.ts +96 -0
  504. package/dist/data/athena-api-error.js +125 -0
  505. package/dist/data/athena-api-error.js.map +1 -0
  506. package/dist/data/athena-data-client.cjs +106 -0
  507. package/dist/data/athena-data-client.cjs.map +1 -0
  508. package/dist/data/athena-data-client.d.ts +74 -0
  509. package/dist/data/athena-data-client.js +106 -0
  510. package/dist/data/athena-data-client.js.map +1 -0
  511. package/dist/data/athena-member.cjs +93 -0
  512. package/dist/data/athena-member.cjs.map +1 -0
  513. package/dist/data/athena-member.d.ts +125 -0
  514. package/dist/data/athena-member.js +93 -0
  515. package/dist/data/athena-member.js.map +1 -0
  516. package/dist/data/athena-request.cjs +460 -0
  517. package/dist/data/athena-request.cjs.map +1 -0
  518. package/dist/data/athena-request.d.ts +120 -0
  519. package/dist/data/athena-request.js +460 -0
  520. package/dist/data/athena-request.js.map +1 -0
  521. package/dist/data/use-athena-fetch.cjs +14 -0
  522. package/dist/data/use-athena-fetch.cjs.map +1 -0
  523. package/dist/data/use-athena-fetch.d.ts +19 -0
  524. package/dist/data/use-athena-fetch.js +14 -0
  525. package/dist/data/use-athena-fetch.js.map +1 -0
  526. package/dist/data/use-athena-graphql.cjs +66 -0
  527. package/dist/data/use-athena-graphql.cjs.map +1 -0
  528. package/dist/data/use-athena-graphql.d.ts +56 -0
  529. package/dist/data/use-athena-graphql.js +66 -0
  530. package/dist/data/use-athena-graphql.js.map +1 -0
  531. package/dist/data/use-athena-rest.cjs +33 -0
  532. package/dist/data/use-athena-rest.cjs.map +1 -0
  533. package/dist/data/use-athena-rest.d.ts +21 -0
  534. package/dist/data/use-athena-rest.js +33 -0
  535. package/dist/data/use-athena-rest.js.map +1 -0
  536. package/dist/data/use-semantic-query.cjs +44 -0
  537. package/dist/data/use-semantic-query.cjs.map +1 -0
  538. package/dist/data/use-semantic-query.d.ts +92 -0
  539. package/dist/data/use-semantic-query.js +44 -0
  540. package/dist/data/use-semantic-query.js.map +1 -0
  541. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  542. package/dist/diagnostics/athena-diagnostics.d.ts +5 -1
  543. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  544. package/dist/diagnostics/errors.cjs +7 -0
  545. package/dist/diagnostics/errors.cjs.map +1 -1
  546. package/dist/diagnostics/errors.d.ts +7 -0
  547. package/dist/diagnostics/errors.js +7 -0
  548. package/dist/diagnostics/errors.js.map +1 -1
  549. package/dist/index.cjs +155 -11
  550. package/dist/index.cjs.map +1 -1
  551. package/dist/index.d.ts +72 -13
  552. package/dist/index.js +148 -4
  553. package/dist/index.js.map +1 -1
  554. package/dist/keryx-http/src/initial-sync.cjs +64 -16
  555. package/dist/keryx-http/src/initial-sync.cjs.map +1 -1
  556. package/dist/keryx-http/src/initial-sync.d.ts +31 -1
  557. package/dist/keryx-http/src/initial-sync.js +64 -16
  558. package/dist/keryx-http/src/initial-sync.js.map +1 -1
  559. package/dist/keryx-http/src/own-awareness.cjs +20 -0
  560. package/dist/keryx-http/src/own-awareness.cjs.map +1 -0
  561. package/dist/keryx-http/src/own-awareness.d.ts +50 -0
  562. package/dist/keryx-http/src/own-awareness.js +20 -0
  563. package/dist/keryx-http/src/own-awareness.js.map +1 -0
  564. package/dist/keryx-http/src/update-attributions.cjs +26 -1
  565. package/dist/keryx-http/src/update-attributions.cjs.map +1 -1
  566. package/dist/keryx-http/src/update-attributions.d.ts +10 -1
  567. package/dist/keryx-http/src/update-attributions.js +26 -1
  568. package/dist/keryx-http/src/update-attributions.js.map +1 -1
  569. package/dist/offline/chat-outbox.cjs +262 -26
  570. package/dist/offline/chat-outbox.cjs.map +1 -1
  571. package/dist/offline/chat-outbox.d.ts +90 -12
  572. package/dist/offline/chat-outbox.js +263 -27
  573. package/dist/offline/chat-outbox.js.map +1 -1
  574. package/dist/provider/AthenaProvider.cjs +60 -22
  575. package/dist/provider/AthenaProvider.cjs.map +1 -1
  576. package/dist/provider/AthenaProvider.d.ts +24 -8
  577. package/dist/provider/AthenaProvider.js +61 -23
  578. package/dist/provider/AthenaProvider.js.map +1 -1
  579. package/dist/react/package.json.cjs +1 -1
  580. package/dist/react/package.json.js +1 -1
  581. package/dist/references/src/anchors/parse.cjs +11 -1
  582. package/dist/references/src/anchors/parse.cjs.map +1 -1
  583. package/dist/references/src/anchors/parse.js +11 -1
  584. package/dist/references/src/anchors/parse.js.map +1 -1
  585. package/dist/references/src/anchors/schemas.d.ts +1 -0
  586. package/dist/references/src/anchors/serialize.cjs +1 -0
  587. package/dist/references/src/anchors/serialize.cjs.map +1 -1
  588. package/dist/references/src/anchors/serialize.js +1 -0
  589. package/dist/references/src/anchors/serialize.js.map +1 -1
  590. package/dist/references/src/anchors/types.cjs +5 -0
  591. package/dist/references/src/anchors/types.cjs.map +1 -1
  592. package/dist/references/src/anchors/types.d.ts +9 -0
  593. package/dist/references/src/anchors/types.js +5 -0
  594. package/dist/references/src/anchors/types.js.map +1 -1
  595. package/dist/references/src/attachable.cjs +149 -0
  596. package/dist/references/src/attachable.cjs.map +1 -0
  597. package/dist/references/src/attachable.d.ts +87 -0
  598. package/dist/references/src/attachable.js +149 -0
  599. package/dist/references/src/attachable.js.map +1 -0
  600. package/dist/references/src/schemas.d.ts +2 -0
  601. package/dist/runtime/StatewirePlanModeLaneSync.cjs +93 -0
  602. package/dist/runtime/StatewirePlanModeLaneSync.cjs.map +1 -0
  603. package/dist/runtime/StatewirePlanModeLaneSync.d.ts +34 -0
  604. package/dist/runtime/StatewirePlanModeLaneSync.js +93 -0
  605. package/dist/runtime/StatewirePlanModeLaneSync.js.map +1 -0
  606. package/dist/runtime/StatewireThreadConfigLaneSync.cjs +2 -0
  607. package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
  608. package/dist/runtime/StatewireThreadConfigLaneSync.d.ts +4 -0
  609. package/dist/runtime/StatewireThreadConfigLaneSync.js +2 -0
  610. package/dist/runtime/StatewireThreadConfigLaneSync.js.map +1 -1
  611. package/dist/runtime/statewire-plan-mode.cjs +71 -0
  612. package/dist/runtime/statewire-plan-mode.cjs.map +1 -0
  613. package/dist/runtime/statewire-plan-mode.d.ts +88 -0
  614. package/dist/runtime/statewire-plan-mode.js +71 -0
  615. package/dist/runtime/statewire-plan-mode.js.map +1 -0
  616. package/dist/runtime/statewire-run-config.cjs +3 -1
  617. package/dist/runtime/statewire-run-config.cjs.map +1 -1
  618. package/dist/runtime/statewire-run-config.d.ts +7 -0
  619. package/dist/runtime/statewire-run-config.js +3 -1
  620. package/dist/runtime/statewire-run-config.js.map +1 -1
  621. package/dist/runtime/statewire-session-key.cjs +11 -5
  622. package/dist/runtime/statewire-session-key.cjs.map +1 -1
  623. package/dist/runtime/statewire-session-key.d.ts +22 -10
  624. package/dist/runtime/statewire-session-key.js +11 -5
  625. package/dist/runtime/statewire-session-key.js.map +1 -1
  626. package/dist/runtime/useAthenaStatewireRuntime.cjs +64 -9
  627. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  628. package/dist/runtime/useAthenaStatewireRuntime.d.ts +26 -10
  629. package/dist/runtime/useAthenaStatewireRuntime.js +66 -11
  630. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  631. package/dist/search/useAthenaAssets.cjs +394 -0
  632. package/dist/search/useAthenaAssets.cjs.map +1 -0
  633. package/dist/search/useAthenaAssets.d.ts +186 -0
  634. package/dist/search/useAthenaAssets.js +394 -0
  635. package/dist/search/useAthenaAssets.js.map +1 -0
  636. package/dist/sheet-range/index.cjs +4 -0
  637. package/dist/sheet-range/index.cjs.map +1 -1
  638. package/dist/sheet-range/index.d.ts +4 -2
  639. package/dist/sheet-range/index.js +4 -0
  640. package/dist/sheet-range/index.js.map +1 -1
  641. package/dist/sheet-range/query-range.cjs +102 -0
  642. package/dist/sheet-range/query-range.cjs.map +1 -0
  643. package/dist/sheet-range/query-range.d.ts +46 -0
  644. package/dist/sheet-range/query-range.js +102 -0
  645. package/dist/sheet-range/query-range.js.map +1 -0
  646. package/dist/styles.css +1 -1
  647. package/dist/subagents/index.cjs +49 -0
  648. package/dist/subagents/index.cjs.map +1 -0
  649. package/dist/subagents/index.d.ts +16 -0
  650. package/dist/subagents/index.js +49 -0
  651. package/dist/subagents/index.js.map +1 -0
  652. package/dist/subagents/lane-follow.cjs +19 -0
  653. package/dist/subagents/lane-follow.cjs.map +1 -0
  654. package/dist/subagents/lane-follow.d.ts +9 -0
  655. package/dist/subagents/lane-follow.js +19 -0
  656. package/dist/subagents/lane-follow.js.map +1 -0
  657. package/dist/subagents/lane-model.cjs +178 -0
  658. package/dist/subagents/lane-model.cjs.map +1 -0
  659. package/dist/subagents/lane-model.d.ts +140 -0
  660. package/dist/subagents/lane-model.js +178 -0
  661. package/dist/subagents/lane-model.js.map +1 -0
  662. package/dist/subagents/lane-parts.cjs +517 -0
  663. package/dist/subagents/lane-parts.cjs.map +1 -0
  664. package/dist/subagents/lane-parts.d.ts +130 -0
  665. package/dist/subagents/lane-parts.js +517 -0
  666. package/dist/subagents/lane-parts.js.map +1 -0
  667. package/dist/subagents/subagent-lane-group.cjs +215 -0
  668. package/dist/subagents/subagent-lane-group.cjs.map +1 -0
  669. package/dist/subagents/subagent-lane-group.d.ts +67 -0
  670. package/dist/subagents/subagent-lane-group.js +215 -0
  671. package/dist/subagents/subagent-lane-group.js.map +1 -0
  672. package/dist/subagents/subagent-transcript-drawer.cjs +431 -0
  673. package/dist/subagents/subagent-transcript-drawer.cjs.map +1 -0
  674. package/dist/subagents/subagent-transcript-drawer.d.ts +78 -0
  675. package/dist/subagents/subagent-transcript-drawer.js +431 -0
  676. package/dist/subagents/subagent-transcript-drawer.js.map +1 -0
  677. package/dist/subagents/task-subagent-group.cjs +115 -0
  678. package/dist/subagents/task-subagent-group.cjs.map +1 -0
  679. package/dist/subagents/task-subagent-group.d.ts +36 -0
  680. package/dist/subagents/task-subagent-group.js +115 -0
  681. package/dist/subagents/task-subagent-group.js.map +1 -0
  682. package/dist/subagents/use-omitted-images-in-view.cjs +68 -0
  683. package/dist/subagents/use-omitted-images-in-view.cjs.map +1 -0
  684. package/dist/subagents/use-omitted-images-in-view.d.ts +21 -0
  685. package/dist/subagents/use-omitted-images-in-view.js +68 -0
  686. package/dist/subagents/use-omitted-images-in-view.js.map +1 -0
  687. package/dist/threads/Inbox.cjs +2 -2
  688. package/dist/threads/Inbox.cjs.map +1 -1
  689. package/dist/threads/SessionList.cjs +6 -6
  690. package/dist/threads/SessionList.cjs.map +1 -1
  691. package/dist/threads/SessionsPage.cjs +13 -7
  692. package/dist/threads/SessionsPage.cjs.map +1 -1
  693. package/dist/threads/SessionsPage.d.ts +10 -1
  694. package/dist/threads/SessionsPage.js +9 -3
  695. package/dist/threads/SessionsPage.js.map +1 -1
  696. package/dist/threads/session-list-model.cjs.map +1 -1
  697. package/dist/threads/session-list-model.d.ts +2 -1
  698. package/dist/threads/session-list-model.js.map +1 -1
  699. package/dist/threads/session-row-parts.cjs +3 -3
  700. package/dist/threads/session-row-parts.cjs.map +1 -1
  701. package/dist/threads/sessions-page-model.cjs +13 -5
  702. package/dist/threads/sessions-page-model.cjs.map +1 -1
  703. package/dist/threads/sessions-page-model.d.ts +7 -0
  704. package/dist/threads/sessions-page-model.js +11 -3
  705. package/dist/threads/sessions-page-model.js.map +1 -1
  706. package/dist/threads/sessions-page-storage.cjs +8 -8
  707. package/dist/threads/sessions-page-storage.cjs.map +1 -1
  708. package/dist/threads/sessions-page-storage.d.ts +5 -1
  709. package/dist/threads/sessions-page-storage.js +8 -8
  710. package/dist/threads/sessions-page-storage.js.map +1 -1
  711. package/dist/threads/statewire-thread-list.cjs +14 -2
  712. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  713. package/dist/threads/statewire-thread-list.d.ts +11 -2
  714. package/dist/threads/statewire-thread-list.js +14 -2
  715. package/dist/threads/statewire-thread-list.js.map +1 -1
  716. package/dist/threads/use-athena-sessions.cjs +1 -0
  717. package/dist/threads/use-athena-sessions.cjs.map +1 -1
  718. package/dist/threads/use-athena-sessions.d.ts +7 -0
  719. package/dist/threads/use-athena-sessions.js +1 -0
  720. package/dist/threads/use-athena-sessions.js.map +1 -1
  721. package/dist/threads/use-athena-thread-agent.cjs +31 -0
  722. package/dist/threads/use-athena-thread-agent.cjs.map +1 -0
  723. package/dist/threads/use-athena-thread-agent.d.ts +38 -0
  724. package/dist/threads/use-athena-thread-agent.js +31 -0
  725. package/dist/threads/use-athena-thread-agent.js.map +1 -0
  726. package/dist/threads/use-athena-thread-plan-mode.cjs +18 -0
  727. package/dist/threads/use-athena-thread-plan-mode.cjs.map +1 -0
  728. package/dist/threads/use-athena-thread-plan-mode.d.ts +18 -0
  729. package/dist/threads/use-athena-thread-plan-mode.js +18 -0
  730. package/dist/threads/use-athena-thread-plan-mode.js.map +1 -0
  731. package/dist/threads/use-rest-conversation-history.d.ts +1 -0
  732. package/dist/tools/agent-creations.cjs +97 -0
  733. package/dist/tools/agent-creations.cjs.map +1 -0
  734. package/dist/tools/agent-creations.d.ts +38 -0
  735. package/dist/tools/agent-creations.js +97 -0
  736. package/dist/tools/agent-creations.js.map +1 -0
  737. package/dist/tools/agent-highlights.cjs +100 -0
  738. package/dist/tools/agent-highlights.cjs.map +1 -0
  739. package/dist/tools/agent-highlights.d.ts +57 -0
  740. package/dist/tools/agent-highlights.js +100 -0
  741. package/dist/tools/agent-highlights.js.map +1 -0
  742. package/dist/tools/append-document-tool-ui.cjs +1 -0
  743. package/dist/tools/append-document-tool-ui.cjs.map +1 -1
  744. package/dist/tools/append-document-tool-ui.d.ts +7 -0
  745. package/dist/tools/append-document-tool-ui.js +2 -1
  746. package/dist/tools/append-document-tool-ui.js.map +1 -1
  747. package/dist/tools/auto-open-tools.cjs +144 -71
  748. package/dist/tools/auto-open-tools.cjs.map +1 -1
  749. package/dist/tools/auto-open-tools.d.ts +131 -1
  750. package/dist/tools/auto-open-tools.js +145 -72
  751. package/dist/tools/auto-open-tools.js.map +1 -1
  752. package/dist/tools/browser-tool-uis.cjs +594 -0
  753. package/dist/tools/browser-tool-uis.cjs.map +1 -0
  754. package/dist/tools/browser-tool-uis.d.ts +8 -0
  755. package/dist/tools/browser-tool-uis.js +594 -0
  756. package/dist/tools/browser-tool-uis.js.map +1 -0
  757. package/dist/tools/computer-asset-tool-uis.cjs +313 -0
  758. package/dist/tools/computer-asset-tool-uis.cjs.map +1 -0
  759. package/dist/tools/computer-asset-tool-uis.d.ts +5 -0
  760. package/dist/tools/computer-asset-tool-uis.js +313 -0
  761. package/dist/tools/computer-asset-tool-uis.js.map +1 -0
  762. package/dist/tools/document-edit-tool-uis.cjs +218 -0
  763. package/dist/tools/document-edit-tool-uis.cjs.map +1 -0
  764. package/dist/tools/document-edit-tool-uis.d.ts +40 -0
  765. package/dist/tools/document-edit-tool-uis.js +218 -0
  766. package/dist/tools/document-edit-tool-uis.js.map +1 -0
  767. package/dist/tools/drive-tool-uis.cjs +429 -0
  768. package/dist/tools/drive-tool-uis.cjs.map +1 -0
  769. package/dist/tools/drive-tool-uis.d.ts +121 -0
  770. package/dist/tools/drive-tool-uis.js +429 -0
  771. package/dist/tools/drive-tool-uis.js.map +1 -0
  772. package/dist/tools/email-calendar-tool-uis.cjs +789 -0
  773. package/dist/tools/email-calendar-tool-uis.cjs.map +1 -0
  774. package/dist/tools/email-calendar-tool-uis.d.ts +129 -0
  775. package/dist/tools/email-calendar-tool-uis.js +789 -0
  776. package/dist/tools/email-calendar-tool-uis.js.map +1 -0
  777. package/dist/tools/ontology-tool-uis.cjs +83 -0
  778. package/dist/tools/ontology-tool-uis.cjs.map +1 -0
  779. package/dist/tools/ontology-tool-uis.d.ts +9 -0
  780. package/dist/tools/ontology-tool-uis.js +83 -0
  781. package/dist/tools/ontology-tool-uis.js.map +1 -0
  782. package/dist/tools/orchestration-tool-uis.cjs +586 -0
  783. package/dist/tools/orchestration-tool-uis.cjs.map +1 -0
  784. package/dist/tools/orchestration-tool-uis.d.ts +141 -0
  785. package/dist/tools/orchestration-tool-uis.js +586 -0
  786. package/dist/tools/orchestration-tool-uis.js.map +1 -0
  787. package/dist/tools/presentation-edit-tool-uis.cjs +516 -0
  788. package/dist/tools/presentation-edit-tool-uis.cjs.map +1 -0
  789. package/dist/tools/presentation-edit-tool-uis.d.ts +73 -0
  790. package/dist/tools/presentation-edit-tool-uis.js +516 -0
  791. package/dist/tools/presentation-edit-tool-uis.js.map +1 -0
  792. package/dist/tools/project-tool-uis.cjs +213 -0
  793. package/dist/tools/project-tool-uis.cjs.map +1 -0
  794. package/dist/tools/project-tool-uis.d.ts +14 -0
  795. package/dist/tools/project-tool-uis.js +213 -0
  796. package/dist/tools/project-tool-uis.js.map +1 -0
  797. package/dist/tools/sandbox-tool-uis.cjs +491 -0
  798. package/dist/tools/sandbox-tool-uis.cjs.map +1 -0
  799. package/dist/tools/sandbox-tool-uis.d.ts +116 -0
  800. package/dist/tools/sandbox-tool-uis.js +491 -0
  801. package/dist/tools/sandbox-tool-uis.js.map +1 -0
  802. package/dist/tools/sheet-query-tool-ui.cjs +138 -0
  803. package/dist/tools/sheet-query-tool-ui.cjs.map +1 -0
  804. package/dist/tools/sheet-query-tool-ui.d.ts +15 -0
  805. package/dist/tools/sheet-query-tool-ui.js +138 -0
  806. package/dist/tools/sheet-query-tool-ui.js.map +1 -0
  807. package/dist/tools/studio-screenshot-tool-uis.cjs +262 -0
  808. package/dist/tools/studio-screenshot-tool-uis.cjs.map +1 -0
  809. package/dist/tools/studio-screenshot-tool-uis.d.ts +52 -0
  810. package/dist/tools/studio-screenshot-tool-uis.js +262 -0
  811. package/dist/tools/studio-screenshot-tool-uis.js.map +1 -0
  812. package/dist/tools/subagent-task-tool-ui.cjs +24 -475
  813. package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
  814. package/dist/tools/subagent-task-tool-ui.d.ts +19 -103
  815. package/dist/tools/subagent-task-tool-ui.js +28 -479
  816. package/dist/tools/subagent-task-tool-ui.js.map +1 -1
  817. package/dist/tools/tool-summary.cjs +36 -0
  818. package/dist/tools/tool-summary.cjs.map +1 -1
  819. package/dist/tools/tool-summary.js +36 -0
  820. package/dist/tools/tool-summary.js.map +1 -1
  821. package/dist/tools/tool-uis.cjs +181 -53
  822. package/dist/tools/tool-uis.cjs.map +1 -1
  823. package/dist/tools/tool-uis.d.ts +40 -0
  824. package/dist/tools/tool-uis.js +183 -55
  825. package/dist/tools/tool-uis.js.map +1 -1
  826. package/dist/typed-interrupts/index.cjs +15 -0
  827. package/dist/typed-interrupts/index.cjs.map +1 -0
  828. package/dist/typed-interrupts/index.d.ts +20 -0
  829. package/dist/typed-interrupts/index.js +15 -0
  830. package/dist/typed-interrupts/index.js.map +1 -0
  831. package/dist/version.cjs +4 -0
  832. package/dist/version.cjs.map +1 -1
  833. package/dist/version.d.ts +9 -0
  834. package/dist/version.js +4 -0
  835. package/dist/version.js.map +1 -1
  836. package/dist/workbench/live-desktop-api.cjs +2 -1
  837. package/dist/workbench/live-desktop-api.cjs.map +1 -1
  838. package/dist/workbench/live-desktop-api.js +2 -1
  839. package/dist/workbench/live-desktop-api.js.map +1 -1
  840. package/dist/workbench/session-workbench-panes.cjs +6 -6
  841. package/dist/workbench/session-workbench-panes.cjs.map +1 -1
  842. package/dist/workbench/session-workspace-api.cjs +7 -2
  843. package/dist/workbench/session-workspace-api.cjs.map +1 -1
  844. package/dist/workbench/session-workspace-api.d.ts +10 -0
  845. package/dist/workbench/session-workspace-api.js +7 -2
  846. package/dist/workbench/session-workspace-api.js.map +1 -1
  847. package/package.json +28 -6
  848. package/dist/agent-runtime/src/chat-outbox-store.cjs +0 -510
  849. package/dist/agent-runtime/src/chat-outbox-store.cjs.map +0 -1
  850. package/dist/agent-runtime/src/chat-outbox-store.d.ts +0 -210
  851. package/dist/agent-runtime/src/chat-outbox-store.js +0 -510
  852. package/dist/agent-runtime/src/chat-outbox-store.js.map +0 -1
@@ -3,9 +3,11 @@ import { useAuiState, useThreadViewportStore, useThreadViewport, getExternalStor
3
3
  import { useContext, useState, useRef, useEffect, useMemo, Component } from "react";
4
4
  import { StatewireHistoryContext, NO_STATEWIRE_HISTORY } from "../../provider/statewire-history-context.js";
5
5
  import { useStatewireToolOutputs } from "../../provider/statewire-window-context.js";
6
+ import { useDeepAgentLaneFollowRegistry } from "../../subagents/lane-follow.js";
6
7
  import { AthenaStatewireThreadIdContext } from "../../threads/thread-id-context.js";
7
8
  import { useDeepAgentWindowSync } from "../../agent-runtime/src/use-deep-agent-window-sync.js";
8
9
  import { isStatewireChannelTeardown } from "../../agent-runtime/src/errors.js";
10
+ import { useDeepAgentLaneFollowSync } from "../../agent-runtime/src/lane-follow.js";
9
11
  import { cn } from "cnfast";
10
12
  const THREAD_VIEWPORT_ATTR = "data-aui-thread-viewport";
11
13
  const THREAD_VIEWPORT_FOOTER_ATTR = "data-aui-thread-viewport-footer";
@@ -157,6 +159,17 @@ const HistoryEdgeRow = ({
157
159
  }
158
160
  );
159
161
  };
162
+ function LaneFollowSync({ registry, paused }) {
163
+ useDeepAgentLaneFollowSync({
164
+ registry,
165
+ paused,
166
+ onError: (error) => {
167
+ if (error instanceof Error && isStatewireChannelTeardown(error)) return;
168
+ console.warn("[StatewireHistoryEdge] following a subagent lane failed:", error);
169
+ }
170
+ });
171
+ return null;
172
+ }
160
173
  const StatewireHistoryEdge = ({
161
174
  toolOutputs: toolOutputsProp,
162
175
  className,
@@ -182,6 +195,7 @@ const StatewireHistoryEdge = ({
182
195
  messages
183
196
  });
184
197
  const historyStore = useContext(StatewireHistoryContext);
198
+ const laneFollows = useDeepAgentLaneFollowRegistry();
185
199
  const { hasOlder, canLoadOlder, loading, loadOlder } = useDeepAgentWindowSync({
186
200
  messages,
187
201
  toolOutputs,
@@ -231,6 +245,7 @@ const StatewireHistoryEdge = ({
231
245
  };
232
246
  }, [rowEl, hasOlder, viewport]);
233
247
  return /* @__PURE__ */ jsxs(Fragment, { children: [
248
+ laneFollows === null ? null : /* @__PURE__ */ jsx(LaneFollowSync, { registry: laneFollows, paused: loading }),
234
249
  /* @__PURE__ */ jsx(KeepReadingPlace, { viewport, threadId, messages }),
235
250
  /* @__PURE__ */ jsx(
236
251
  HistoryEdgeRow,
@@ -1 +1 @@
1
- {"version":3,"file":"statewire-history-edge.js","sources":["../../../src/chat-ui/thread/statewire-history-edge.tsx"],"sourcesContent":["import {\n getExternalStoreMessages,\n type ThreadMessage,\n type ThreadViewportState,\n useAuiState,\n useThreadViewport,\n useThreadViewportStore,\n} from \"@assistant-ui/react\";\nimport {\n type DeepAgentHistoryLoadEvent,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n useDeepAgentWindowSync,\n} from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { Component, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n NO_STATEWIRE_HISTORY,\n StatewireHistoryContext,\n} from \"../../provider/statewire-history-context\";\nimport { useStatewireToolOutputs } from \"../../provider/statewire-window-context\";\nimport { AthenaStatewireThreadIdContext } from \"../../threads/thread-id-context\";\n\n/** The attribute `ChatThreadShell` stamps on the scroll viewport. */\nexport const THREAD_VIEWPORT_ATTR = \"data-aui-thread-viewport\";\n/** The attribute `ChatThreadShell` stamps on its sticky viewport footer (the composer dock). */\nexport const THREAD_VIEWPORT_FOOTER_ATTR = \"data-aui-thread-viewport-footer\";\n\n/**\n * How far above the viewport the edge row counts as near: the row sits above\n * the first loaded message, so reaching it means the user has scrolled past\n * everything loaded and the next page should already be on its way. Messages\n * this close to the viewport also count as on screen for cut tool outputs.\n */\nexport const HISTORY_EDGE_NEAR_MARGIN_PX = 1500;\n\n/**\n * Cut tool outputs a transcript reads at once. The reads share the session's\n * command lane with everything the person sends, so a long transcript must\n * not queue dozens of them ahead of a message or a Stop.\n */\nexport const HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY = 2;\n\n/** What assistant-ui's `MessagePrimitive.Root` stamps on every message. */\nconst MESSAGE_SELECTOR = \"[data-message-id]\";\n\nconst NO_MESSAGE_IDS: ReadonlySet<string> = new Set();\n\nfunction sameIds({ a, b }: { a: ReadonlySet<string>; b: ReadonlySet<string> }): boolean {\n if (a.size !== b.size) return false;\n for (const id of a) if (!b.has(id)) return false;\n return true;\n}\n\n/**\n * Which messages sit within {@link HISTORY_EDGE_NEAR_MARGIN_PX} of the\n * viewport, so cut tool outputs are read for what the person can reach. A\n * thread opens at its newest turn; reading every loaded step's output up\n * front sent dozens of reads, each re-rendering the transcript, for steps\n * nobody had scrolled to.\n *\n * `undefined` (every message counts) where nothing can be observed: no\n * viewport around the row, or no `IntersectionObserver`. A message rendered\n * without a `data-message-id` root (a host's own renderer) cannot be observed\n * either, so it counts as before.\n */\nfunction useMessagesNearViewport({\n viewport,\n hasViewport,\n messages,\n}: {\n viewport: HTMLElement | null;\n /** A viewport is (or will be) registered around the row. */\n hasViewport: boolean;\n /** The converted thread: every change may have mounted or remounted a message. */\n messages: readonly ThreadMessage[];\n}): ((messageId: string) => boolean) | undefined {\n const [nearIds, setNearIds] = useState<ReadonlySet<string>>(NO_MESSAGE_IDS);\n const observable = hasViewport && typeof IntersectionObserver !== \"undefined\";\n const trackRef = useRef<(() => void) | null>(null);\n // Every id a rendered element carries, as of the last scan.\n const renderedIdsRef = useRef<ReadonlySet<string>>(NO_MESSAGE_IDS);\n\n useEffect(() => {\n if (!viewport || !observable) return undefined;\n const near = new Set<Element>();\n const observed = new Set<Element>();\n const publish = () => {\n const ids = new Set<string>();\n for (const element of near) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) ids.add(id);\n }\n setNearIds((previous) => (sameIds({ a: previous, b: ids }) ? previous : ids));\n };\n const intersections = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target.isConnected) near.add(entry.target);\n else near.delete(entry.target);\n }\n publish();\n },\n { root: viewport, rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px` },\n );\n // A page that folds into a turn gives it a new id: a host keyed by id\n // remounts the turn's element, a host keyed by row (`ChatThreadShell`)\n // keeps it and the element's id changes. So what is observed follows the\n // rendered elements, not the message list, and the near ids are read off\n // those elements again on every scan.\n const track = () => {\n for (const element of observed) {\n if (element.isConnected) continue;\n intersections.unobserve(element);\n observed.delete(element);\n near.delete(element);\n }\n const rendered = new Set<string>();\n for (const element of viewport.querySelectorAll(MESSAGE_SELECTOR)) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) rendered.add(id);\n if (observed.has(element)) continue;\n observed.add(element);\n intersections.observe(element);\n }\n renderedIdsRef.current = rendered;\n publish();\n };\n trackRef.current = track;\n track();\n return () => {\n trackRef.current = null;\n renderedIdsRef.current = NO_MESSAGE_IDS;\n intersections.disconnect();\n setNearIds(NO_MESSAGE_IDS);\n };\n }, [viewport, observable]);\n\n // A changed message list is the trigger to re-scan: its messages render in\n // the same commit, so their elements are in the DOM by this effect (a\n // query, no layout read).\n useEffect(() => {\n trackRef.current?.();\n }, [messages]);\n\n return useMemo(() => {\n if (!observable) return undefined;\n return (messageId: string) => {\n // Not registered yet: nothing is on screen to read for.\n if (viewport === null) return false;\n return nearIds.has(messageId) || !renderedIdsRef.current.has(messageId);\n };\n }, [nearIds, observable, viewport]);\n}\n\n/** The wire message a converted message was built from first (its oldest source). */\nfunction oldestSourceId(message: ThreadMessage): string | undefined {\n const source = getExternalStoreMessages<{ id?: unknown }>(message)[0];\n return typeof source?.id === \"string\" ? source.id : undefined;\n}\n\n/**\n * Whether older history landed ahead of what was loaded: the old first\n * message now sits further down (a page ahead of it), or the first message's\n * old oldest wire message now follows earlier ones (a page that folded into\n * the first loaded turn). A first message replaced in place — a branch picked\n * on it, an edit — is neither, and a run streaming at the tail never touches\n * the first message.\n */\nfunction prependedOlderHistory({\n previous,\n next,\n}: {\n previous: readonly ThreadMessage[];\n next: readonly ThreadMessage[];\n}): boolean {\n const previousFirst = previous[0];\n const nextFirst = next[0];\n if (previousFirst === undefined || nextFirst === undefined || previousFirst === nextFirst) return false;\n if (previousFirst.id !== nextFirst.id && next.some((message, index) => index > 0 && message.id === previousFirst.id)) {\n return true;\n }\n const previousOldest = oldestSourceId(previousFirst);\n if (previousOldest === undefined || previousOldest === oldestSourceId(nextFirst)) return false;\n return getExternalStoreMessages<{ id?: unknown }>(nextFirst).some(\n (source, index) => index > 0 && source?.id === previousOldest,\n );\n}\n\ninterface KeepReadingPlaceProps {\n viewport: HTMLElement | null;\n threadId: string | null;\n /** The converted thread. */\n messages: readonly ThreadMessage[];\n}\n\n/**\n * Keeps the reader's place when older history lands. Everything a page adds\n * sits above what the person is reading, so their distance from the bottom of\n * the transcript is what must survive. A class for `getSnapshotBeforeUpdate`:\n * the distance is read right before React applies the commit that renders the\n * page — the one moment it is exact, even for a scroll the browser has not\n * reported yet — and restored after it, instantly (never through the\n * viewport's smooth scrolling). Other commits read no layout.\n *\n * The browser's scroll anchoring and assistant-ui's prepend anchor aim at the\n * same position, so whichever ran first leaves this nothing to do; on its own\n * it covers what they miss: a reader at the very top (browsers never anchor\n * at scroll offset 0) and a page that folds into the first loaded turn of a\n * host that keys rows by message id (that message remounts under a new id,\n * taking the browser's anchor node with it; `ChatThreadShell` keeps the row).\n */\nclass KeepReadingPlace extends Component<KeepReadingPlaceProps> {\n getSnapshotBeforeUpdate(previous: Readonly<KeepReadingPlaceProps>): number | null {\n const { viewport, threadId, messages } = this.props;\n if (\n viewport === null ||\n viewport !== previous.viewport ||\n threadId !== previous.threadId ||\n messages === previous.messages ||\n !prependedOlderHistory({ previous: previous.messages, next: messages })\n ) {\n return null;\n }\n return viewport.scrollHeight - viewport.scrollTop;\n }\n\n componentDidUpdate(\n _previous: Readonly<KeepReadingPlaceProps>,\n _state: unknown,\n fromBottom: number | null,\n ): void {\n const { viewport } = this.props;\n if (viewport === null || fromBottom === null) return;\n const top = viewport.scrollHeight - fromBottom;\n if (Math.abs(viewport.scrollTop - top) >= 1) viewport.scrollTo({ top, behavior: \"instant\" });\n }\n\n render(): null {\n return null;\n }\n}\n\nexport interface HistoryEdgeRowProps {\n /** Whether the server holds messages older than the loaded window. */\n hasOlder: boolean;\n /** Whether the next page can be asked for; `false` with `hasOlder` is the connection's loading depth spent. Defaults to `hasOlder`. */\n canLoadOlder?: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n onLoadOlder: () => void;\n className?: string;\n /** The row element, for the viewport observer. */\n rowRef?: (element: HTMLElement | null) => void;\n}\n\n/**\n * The top edge of the LOADED history: a manual way to load the next page of\n * older messages, and the in-flight state. Renders nothing when the whole\n * transcript is loaded (or the head interest has not resolved).\n */\nexport const HistoryEdgeRow: FC<HistoryEdgeRowProps> = ({\n hasOlder,\n canLoadOlder = hasOlder,\n loading,\n onLoadOlder,\n className,\n rowRef,\n}) => {\n if (!hasOlder) return null;\n return (\n <div\n ref={rowRef}\n data-testid=\"thread-history-edge\"\n className={cn(\n \"mx-auto flex w-full max-w-(--thread-max-width) items-center justify-center py-1 text-xs text-muted-foreground\",\n className,\n )}\n >\n {loading ? (\n <span data-testid=\"thread-history-edge-loading\">Loading earlier messages…</span>\n ) : canLoadOlder ? (\n <button\n type=\"button\"\n data-testid=\"thread-history-edge-load\"\n onClick={onLoadOlder}\n className=\"rounded-lg px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n Load earlier messages\n </button>\n ) : (\n <span data-testid=\"thread-history-edge-limit\">Earlier messages can't be loaded here</span>\n )}\n </div>\n );\n};\n\nexport interface StatewireHistoryEdgeProps {\n /**\n * The thread's tool-output store (the one its converter substitutes from).\n * Defaults to `AthenaProvider`'s; hosts mounting the runtime themselves pass\n * the store they gave `useDeepAgentRuntime({ toolOutputs })`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /**\n * @deprecated Ignored. Older history pages by command (`history/page`) on\n * every host that serves it, into the conversation's own store, which the\n * thread joins. A host that mounts the runtime itself provides the steps\n * control through `TurnStepsControlContext` (`EarlierStepsButton`), so a\n * summarized turn's rows can open its steps.\n */\n historyPages?: unknown;\n className?: string;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: (event: DeepAgentHistoryLoadEvent) => void;\n}\n\n/**\n * The client half of the interest window for a DOM thread — mounted once per\n * thread, inside the scroll viewport above the messages (`ChatThreadShell`'s\n * `beforeMessages` slot):\n *\n * - renders the \"Load earlier messages\" edge row and loads the next page when\n * the row comes near the viewport (scrolling up) or on its button, keeping\n * the reading position when the page lands above the view;\n * - fetches cut tool outputs whole for the cards near the viewport, a few at\n * a time, so they re-render complete through the converter (`toolOutputs`).\n *\n * Inert until the head interest resolves: no row, no reads.\n */\nexport const StatewireHistoryEdge: FC<StatewireHistoryEdgeProps> = ({\n toolOutputs: toolOutputsProp,\n className,\n onHistoryLoad,\n}) => {\n const providerToolOutputs = useStatewireToolOutputs();\n const toolOutputs = toolOutputsProp ?? providerToolOutputs ?? undefined;\n const messages = useAuiState((s) => s.thread.messages);\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const [nearTop, setNearTop] = useState(false);\n const [nearTopEpoch, setNearTopEpoch] = useState(0);\n const nearTopRef = useRef(false);\n const [rowEl, setRowEl] = useState<HTMLElement | null>(null);\n // The scroll viewport the thread registered (assistant-ui's viewport store),\n // known even while the row renders nothing; the row's ancestor otherwise.\n const hasViewportStore = useThreadViewportStore({ optional: true }) !== null;\n const registeredViewport = useThreadViewport({\n optional: true,\n selector: (state: ThreadViewportState) => state.element.viewport,\n });\n const viewport =\n registeredViewport ?? rowEl?.closest<HTMLElement>(`[${THREAD_VIEWPORT_ATTR}]`) ?? null;\n const isMessageMounted = useMessagesNearViewport({\n viewport,\n hasViewport: hasViewportStore || viewport !== null,\n messages,\n });\n const historyStore = useContext(StatewireHistoryContext);\n const { hasOlder, canLoadOlder, loading, loadOlder } = useDeepAgentWindowSync({\n messages,\n toolOutputs,\n nearTop,\n nearTopEpoch,\n isMessageMounted,\n maxConcurrentToolOutputs: HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY,\n onHistoryLoad,\n onError: (error, command) => {\n // Leaving the thread settles an in-flight read as lost: lifecycle, not a failure.\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn(`[StatewireHistoryEdge] ${command} failed:`, error);\n },\n });\n\n // Other surfaces of the provider (the workbench's Shell pane) read where the\n // history stands; leaving the thread or unmounting withdraws the report.\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n historyStore.set({ threadId, hasOlder, canLoadOlder, loading, loadOlder });\n return undefined;\n }, [historyStore, threadId, hasOlder, canLoadOlder, loading, loadOlder]);\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n return () => {\n if (historyStore.get().threadId === threadId) historyStore.set(NO_STATEWIRE_HISTORY);\n };\n }, [historyStore, threadId]);\n\n // The row's own visibility is the near-top level: a level, not an edge, so\n // pages chain while the user stays at the top and stop once the prepended\n // content has pushed the row away again.\n useEffect(() => {\n if (!rowEl || !hasOlder || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const near = entry.isIntersecting;\n if (nearTopRef.current === near) continue;\n nearTopRef.current = near;\n setNearTop(near);\n if (near) setNearTopEpoch((epoch) => epoch + 1);\n }\n },\n {\n root: viewport,\n rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px`,\n },\n );\n observer.observe(rowEl);\n return () => {\n observer.disconnect();\n nearTopRef.current = false;\n setNearTop(false);\n };\n }, [rowEl, hasOlder, viewport]);\n\n return (\n <>\n <KeepReadingPlace viewport={viewport} threadId={threadId} messages={messages} />\n <HistoryEdgeRow\n rowRef={setRowEl}\n hasOlder={hasOlder}\n canLoadOlder={canLoadOlder}\n loading={loading}\n onLoadOlder={loadOlder}\n className={className}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"statewire-history-edge.js","sources":["../../../src/chat-ui/thread/statewire-history-edge.tsx"],"sourcesContent":["import {\n getExternalStoreMessages,\n type ThreadMessage,\n type ThreadViewportState,\n useAuiState,\n useThreadViewport,\n useThreadViewportStore,\n} from \"@assistant-ui/react\";\nimport {\n type DeepAgentHistoryLoadEvent,\n type DeepAgentLaneFollowRegistry,\n type DeepAgentToolOutputStore,\n isStatewireChannelTeardown,\n useDeepAgentLaneFollowSync,\n useDeepAgentWindowSync,\n} from \"@athenaintel/agent-runtime\";\nimport type { FC } from \"react\";\nimport { Component, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n NO_STATEWIRE_HISTORY,\n StatewireHistoryContext,\n} from \"../../provider/statewire-history-context\";\nimport { useStatewireToolOutputs } from \"../../provider/statewire-window-context\";\nimport { useDeepAgentLaneFollowRegistry } from \"../../subagents/lane-follow\";\nimport { AthenaStatewireThreadIdContext } from \"../../threads/thread-id-context\";\n\n/** The attribute `ChatThreadShell` stamps on the scroll viewport. */\nexport const THREAD_VIEWPORT_ATTR = \"data-aui-thread-viewport\";\n/** The attribute `ChatThreadShell` stamps on its sticky viewport footer (the composer dock). */\nexport const THREAD_VIEWPORT_FOOTER_ATTR = \"data-aui-thread-viewport-footer\";\n\n/**\n * How far above the viewport the edge row counts as near: the row sits above\n * the first loaded message, so reaching it means the user has scrolled past\n * everything loaded and the next page should already be on its way. Messages\n * this close to the viewport also count as on screen for cut tool outputs.\n */\nexport const HISTORY_EDGE_NEAR_MARGIN_PX = 1500;\n\n/**\n * Cut tool outputs a transcript reads at once. The reads share the session's\n * command lane with everything the person sends, so a long transcript must\n * not queue dozens of them ahead of a message or a Stop.\n */\nexport const HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY = 2;\n\n/** What assistant-ui's `MessagePrimitive.Root` stamps on every message. */\nconst MESSAGE_SELECTOR = \"[data-message-id]\";\n\nconst NO_MESSAGE_IDS: ReadonlySet<string> = new Set();\n\nfunction sameIds({ a, b }: { a: ReadonlySet<string>; b: ReadonlySet<string> }): boolean {\n if (a.size !== b.size) return false;\n for (const id of a) if (!b.has(id)) return false;\n return true;\n}\n\n/**\n * Which messages sit within {@link HISTORY_EDGE_NEAR_MARGIN_PX} of the\n * viewport, so cut tool outputs are read for what the person can reach. A\n * thread opens at its newest turn; reading every loaded step's output up\n * front sent dozens of reads, each re-rendering the transcript, for steps\n * nobody had scrolled to.\n *\n * `undefined` (every message counts) where nothing can be observed: no\n * viewport around the row, or no `IntersectionObserver`. A message rendered\n * without a `data-message-id` root (a host's own renderer) cannot be observed\n * either, so it counts as before.\n */\nfunction useMessagesNearViewport({\n viewport,\n hasViewport,\n messages,\n}: {\n viewport: HTMLElement | null;\n /** A viewport is (or will be) registered around the row. */\n hasViewport: boolean;\n /** The converted thread: every change may have mounted or remounted a message. */\n messages: readonly ThreadMessage[];\n}): ((messageId: string) => boolean) | undefined {\n const [nearIds, setNearIds] = useState<ReadonlySet<string>>(NO_MESSAGE_IDS);\n const observable = hasViewport && typeof IntersectionObserver !== \"undefined\";\n const trackRef = useRef<(() => void) | null>(null);\n // Every id a rendered element carries, as of the last scan.\n const renderedIdsRef = useRef<ReadonlySet<string>>(NO_MESSAGE_IDS);\n\n useEffect(() => {\n if (!viewport || !observable) return undefined;\n const near = new Set<Element>();\n const observed = new Set<Element>();\n const publish = () => {\n const ids = new Set<string>();\n for (const element of near) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) ids.add(id);\n }\n setNearIds((previous) => (sameIds({ a: previous, b: ids }) ? previous : ids));\n };\n const intersections = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target.isConnected) near.add(entry.target);\n else near.delete(entry.target);\n }\n publish();\n },\n { root: viewport, rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px` },\n );\n // A page that folds into a turn gives it a new id: a host keyed by id\n // remounts the turn's element, a host keyed by row (`ChatThreadShell`)\n // keeps it and the element's id changes. So what is observed follows the\n // rendered elements, not the message list, and the near ids are read off\n // those elements again on every scan.\n const track = () => {\n for (const element of observed) {\n if (element.isConnected) continue;\n intersections.unobserve(element);\n observed.delete(element);\n near.delete(element);\n }\n const rendered = new Set<string>();\n for (const element of viewport.querySelectorAll(MESSAGE_SELECTOR)) {\n const id = element.getAttribute(\"data-message-id\");\n if (id) rendered.add(id);\n if (observed.has(element)) continue;\n observed.add(element);\n intersections.observe(element);\n }\n renderedIdsRef.current = rendered;\n publish();\n };\n trackRef.current = track;\n track();\n return () => {\n trackRef.current = null;\n renderedIdsRef.current = NO_MESSAGE_IDS;\n intersections.disconnect();\n setNearIds(NO_MESSAGE_IDS);\n };\n }, [viewport, observable]);\n\n // A changed message list is the trigger to re-scan: its messages render in\n // the same commit, so their elements are in the DOM by this effect (a\n // query, no layout read).\n useEffect(() => {\n trackRef.current?.();\n }, [messages]);\n\n return useMemo(() => {\n if (!observable) return undefined;\n return (messageId: string) => {\n // Not registered yet: nothing is on screen to read for.\n if (viewport === null) return false;\n return nearIds.has(messageId) || !renderedIdsRef.current.has(messageId);\n };\n }, [nearIds, observable, viewport]);\n}\n\n/** The wire message a converted message was built from first (its oldest source). */\nfunction oldestSourceId(message: ThreadMessage): string | undefined {\n const source = getExternalStoreMessages<{ id?: unknown }>(message)[0];\n return typeof source?.id === \"string\" ? source.id : undefined;\n}\n\n/**\n * Whether older history landed ahead of what was loaded: the old first\n * message now sits further down (a page ahead of it), or the first message's\n * old oldest wire message now follows earlier ones (a page that folded into\n * the first loaded turn). A first message replaced in place — a branch picked\n * on it, an edit — is neither, and a run streaming at the tail never touches\n * the first message.\n */\nfunction prependedOlderHistory({\n previous,\n next,\n}: {\n previous: readonly ThreadMessage[];\n next: readonly ThreadMessage[];\n}): boolean {\n const previousFirst = previous[0];\n const nextFirst = next[0];\n if (previousFirst === undefined || nextFirst === undefined || previousFirst === nextFirst) return false;\n if (previousFirst.id !== nextFirst.id && next.some((message, index) => index > 0 && message.id === previousFirst.id)) {\n return true;\n }\n const previousOldest = oldestSourceId(previousFirst);\n if (previousOldest === undefined || previousOldest === oldestSourceId(nextFirst)) return false;\n return getExternalStoreMessages<{ id?: unknown }>(nextFirst).some(\n (source, index) => index > 0 && source?.id === previousOldest,\n );\n}\n\ninterface KeepReadingPlaceProps {\n viewport: HTMLElement | null;\n threadId: string | null;\n /** The converted thread. */\n messages: readonly ThreadMessage[];\n}\n\n/**\n * Keeps the reader's place when older history lands. Everything a page adds\n * sits above what the person is reading, so their distance from the bottom of\n * the transcript is what must survive. A class for `getSnapshotBeforeUpdate`:\n * the distance is read right before React applies the commit that renders the\n * page — the one moment it is exact, even for a scroll the browser has not\n * reported yet — and restored after it, instantly (never through the\n * viewport's smooth scrolling). Other commits read no layout.\n *\n * The browser's scroll anchoring and assistant-ui's prepend anchor aim at the\n * same position, so whichever ran first leaves this nothing to do; on its own\n * it covers what they miss: a reader at the very top (browsers never anchor\n * at scroll offset 0) and a page that folds into the first loaded turn of a\n * host that keys rows by message id (that message remounts under a new id,\n * taking the browser's anchor node with it; `ChatThreadShell` keeps the row).\n */\nclass KeepReadingPlace extends Component<KeepReadingPlaceProps> {\n getSnapshotBeforeUpdate(previous: Readonly<KeepReadingPlaceProps>): number | null {\n const { viewport, threadId, messages } = this.props;\n if (\n viewport === null ||\n viewport !== previous.viewport ||\n threadId !== previous.threadId ||\n messages === previous.messages ||\n !prependedOlderHistory({ previous: previous.messages, next: messages })\n ) {\n return null;\n }\n return viewport.scrollHeight - viewport.scrollTop;\n }\n\n componentDidUpdate(\n _previous: Readonly<KeepReadingPlaceProps>,\n _state: unknown,\n fromBottom: number | null,\n ): void {\n const { viewport } = this.props;\n if (viewport === null || fromBottom === null) return;\n const top = viewport.scrollHeight - fromBottom;\n if (Math.abs(viewport.scrollTop - top) >= 1) viewport.scrollTo({ top, behavior: \"instant\" });\n }\n\n render(): null {\n return null;\n }\n}\n\nexport interface HistoryEdgeRowProps {\n /** Whether the server holds messages older than the loaded window. */\n hasOlder: boolean;\n /** Whether the next page can be asked for; `false` with `hasOlder` is the connection's loading depth spent. Defaults to `hasOlder`. */\n canLoadOlder?: boolean;\n /** A page of older history is in flight. */\n loading: boolean;\n onLoadOlder: () => void;\n className?: string;\n /** The row element, for the viewport observer. */\n rowRef?: (element: HTMLElement | null) => void;\n}\n\n/**\n * The top edge of the LOADED history: a manual way to load the next page of\n * older messages, and the in-flight state. Renders nothing when the whole\n * transcript is loaded (or the head interest has not resolved).\n */\nexport const HistoryEdgeRow: FC<HistoryEdgeRowProps> = ({\n hasOlder,\n canLoadOlder = hasOlder,\n loading,\n onLoadOlder,\n className,\n rowRef,\n}) => {\n if (!hasOlder) return null;\n return (\n <div\n ref={rowRef}\n data-testid=\"thread-history-edge\"\n className={cn(\n \"mx-auto flex w-full max-w-(--thread-max-width) items-center justify-center py-1 text-xs text-muted-foreground\",\n className,\n )}\n >\n {loading ? (\n <span data-testid=\"thread-history-edge-loading\">Loading earlier messages…</span>\n ) : canLoadOlder ? (\n <button\n type=\"button\"\n data-testid=\"thread-history-edge-load\"\n onClick={onLoadOlder}\n className=\"rounded-lg px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n Load earlier messages\n </button>\n ) : (\n <span data-testid=\"thread-history-edge-limit\">Earlier messages can't be loaded here</span>\n )}\n </div>\n );\n};\n\nexport interface StatewireHistoryEdgeProps {\n /**\n * The thread's tool-output store (the one its converter substitutes from).\n * Defaults to `AthenaProvider`'s; hosts mounting the runtime themselves pass\n * the store they gave `useDeepAgentRuntime({ toolOutputs })`.\n */\n toolOutputs?: DeepAgentToolOutputStore;\n /**\n * @deprecated Ignored. Older history pages by command (`history/page`) on\n * every host that serves it, into the conversation's own store, which the\n * thread joins. A host that mounts the runtime itself provides the steps\n * control through `TurnStepsControlContext` (`EarlierStepsButton`), so a\n * summarized turn's rows can open its steps.\n */\n historyPages?: unknown;\n className?: string;\n /** A page interest resolved (telemetry). */\n onHistoryLoad?: (event: DeepAgentHistoryLoadEvent) => void;\n}\n\n/**\n * Keeps the attach following the running subagent lanes an open transcript\n * drawer shows (`useDeepAgentLaneFollowSync`), so a followed lane's card\n * carries every step; never while a page of older history is being read (the\n * two statements share the attach's interest lane). A host that does not\n * serve `follow` keeps the cards' own steps.\n */\nfunction LaneFollowSync({ registry, paused }: { registry: DeepAgentLaneFollowRegistry; paused: boolean }) {\n useDeepAgentLaneFollowSync({\n registry,\n paused,\n onError: (error) => {\n // Leaving the thread settles an in-flight statement as lost: lifecycle, not a failure.\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn(\"[StatewireHistoryEdge] following a subagent lane failed:\", error);\n },\n });\n return null;\n}\n\n/**\n * The client half of the interest window for a DOM thread — mounted once per\n * thread, inside the scroll viewport above the messages (`ChatThreadShell`'s\n * `beforeMessages` slot):\n *\n * - renders the \"Load earlier messages\" edge row and loads the next page when\n * the row comes near the viewport (scrolling up) or on its button, keeping\n * the reading position when the page lands above the view;\n * - fetches cut tool outputs whole for the cards near the viewport, a few at\n * a time, so they re-render complete through the converter (`toolOutputs`);\n * - inside a lane-follow scope (`DeepAgentLaneFollowScope`, which `AthenaChat`\n * mounts), follows the running subagent lanes an open transcript drawer\n * shows.\n *\n * Inert until the head interest resolves: no row, no reads.\n */\nexport const StatewireHistoryEdge: FC<StatewireHistoryEdgeProps> = ({\n toolOutputs: toolOutputsProp,\n className,\n onHistoryLoad,\n}) => {\n const providerToolOutputs = useStatewireToolOutputs();\n const toolOutputs = toolOutputsProp ?? providerToolOutputs ?? undefined;\n const messages = useAuiState((s) => s.thread.messages);\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const [nearTop, setNearTop] = useState(false);\n const [nearTopEpoch, setNearTopEpoch] = useState(0);\n const nearTopRef = useRef(false);\n const [rowEl, setRowEl] = useState<HTMLElement | null>(null);\n // The scroll viewport the thread registered (assistant-ui's viewport store),\n // known even while the row renders nothing; the row's ancestor otherwise.\n const hasViewportStore = useThreadViewportStore({ optional: true }) !== null;\n const registeredViewport = useThreadViewport({\n optional: true,\n selector: (state: ThreadViewportState) => state.element.viewport,\n });\n const viewport =\n registeredViewport ?? rowEl?.closest<HTMLElement>(`[${THREAD_VIEWPORT_ATTR}]`) ?? null;\n const isMessageMounted = useMessagesNearViewport({\n viewport,\n hasViewport: hasViewportStore || viewport !== null,\n messages,\n });\n const historyStore = useContext(StatewireHistoryContext);\n const laneFollows = useDeepAgentLaneFollowRegistry();\n const { hasOlder, canLoadOlder, loading, loadOlder } = useDeepAgentWindowSync({\n messages,\n toolOutputs,\n nearTop,\n nearTopEpoch,\n isMessageMounted,\n maxConcurrentToolOutputs: HISTORY_EDGE_TOOL_OUTPUT_CONCURRENCY,\n onHistoryLoad,\n onError: (error, command) => {\n // Leaving the thread settles an in-flight read as lost: lifecycle, not a failure.\n if (error instanceof Error && isStatewireChannelTeardown(error)) return;\n console.warn(`[StatewireHistoryEdge] ${command} failed:`, error);\n },\n });\n\n // Other surfaces of the provider (the workbench's Shell pane) read where the\n // history stands; leaving the thread or unmounting withdraws the report.\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n historyStore.set({ threadId, hasOlder, canLoadOlder, loading, loadOlder });\n return undefined;\n }, [historyStore, threadId, hasOlder, canLoadOlder, loading, loadOlder]);\n useEffect(() => {\n if (!historyStore || !threadId) return undefined;\n return () => {\n if (historyStore.get().threadId === threadId) historyStore.set(NO_STATEWIRE_HISTORY);\n };\n }, [historyStore, threadId]);\n\n // The row's own visibility is the near-top level: a level, not an edge, so\n // pages chain while the user stays at the top and stop once the prepended\n // content has pushed the row away again.\n useEffect(() => {\n if (!rowEl || !hasOlder || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const near = entry.isIntersecting;\n if (nearTopRef.current === near) continue;\n nearTopRef.current = near;\n setNearTop(near);\n if (near) setNearTopEpoch((epoch) => epoch + 1);\n }\n },\n {\n root: viewport,\n rootMargin: `${HISTORY_EDGE_NEAR_MARGIN_PX}px 0px`,\n },\n );\n observer.observe(rowEl);\n return () => {\n observer.disconnect();\n nearTopRef.current = false;\n setNearTop(false);\n };\n }, [rowEl, hasOlder, viewport]);\n\n return (\n <>\n {laneFollows === null ? null : <LaneFollowSync registry={laneFollows} paused={loading} />}\n <KeepReadingPlace viewport={viewport} threadId={threadId} messages={messages} />\n <HistoryEdgeRow\n rowRef={setRowEl}\n hasOlder={hasOlder}\n canLoadOlder={canLoadOlder}\n loading={loading}\n onLoadOlder={loadOlder}\n className={className}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const initialSync = require("../keryx-http/src/initial-sync.cjs");
4
+ const ownAwareness = require("../keryx-http/src/own-awareness.cjs");
4
5
  const receiveOnlySocket = require("../keryx-http/src/receive-only-socket.cjs");
5
6
  const unconfirmedUpdateAttributions = require("../keryx-http/src/unconfirmed-update-attributions.cjs");
6
7
  const updateAttributions = require("../keryx-http/src/update-attributions.cjs");
@@ -54,7 +55,6 @@ function socketFor({
54
55
  unconfirmed
55
56
  });
56
57
  }
57
- const HTTP_FIRST_READ_TIMEOUT_MS = 6e4;
58
58
  function browserStorage() {
59
59
  try {
60
60
  return typeof window !== "undefined" && window.localStorage ? window.localStorage : null;
@@ -103,6 +103,8 @@ function connectGenericDoc(args) {
103
103
  let accessRecheckPending = false;
104
104
  let keryxAnswersSyncStep1 = false;
105
105
  let httpFirstRead = null;
106
+ let keptHttpFirstRead = null;
107
+ let applyingHttpFirstRead = false;
106
108
  const notify = () => {
107
109
  version += 1;
108
110
  for (const listener of listeners) listener();
@@ -137,6 +139,9 @@ function connectGenericDoc(args) {
137
139
  transportChanged();
138
140
  if (changed) notify();
139
141
  };
142
+ doc.on("update", () => {
143
+ if (!applyingHttpFirstRead) keptHttpFirstRead = null;
144
+ });
140
145
  doc.on("update", (update, origin) => {
141
146
  if (!prepared || provider !== null || destroyed || origin instanceof websocket.WebsocketProvider) return;
142
147
  carriedUpdates = [
@@ -328,6 +333,7 @@ function connectGenericDoc(args) {
328
333
  connect: httpFirstUrl === null,
329
334
  ...socket && { WebSocketPolyfill: socket }
330
335
  });
336
+ ownAwareness.publishOwnAwarenessOnly({ transport: nextProvider });
331
337
  provider = nextProvider;
332
338
  liveGrant = grant;
333
339
  nextProvider.unconfirmedUpdates = [...carriedUpdates, ...nextProvider.unconfirmedUpdates];
@@ -403,8 +409,13 @@ function connectGenericDoc(args) {
403
409
  scheduleRefresh(grant);
404
410
  if (httpFirstUrl !== null) void openOverHttp({ target: nextProvider, url: httpFirstUrl, roomUrl });
405
411
  };
406
- function asksForDiffedSync({ roomUrl, unconfirmed }) {
412
+ function asksForDiffedSync({
413
+ roomUrl,
414
+ unconfirmed,
415
+ afterRead = false
416
+ }) {
407
417
  if (args.httpFirstOpen !== true) return false;
418
+ if (args.diffedInitialSync === "after-read" && !afterRead) return false;
408
419
  const origin = initialSync.keryxOriginOf(roomUrl);
409
420
  const known = keryxAnswersSyncStep1 || origin !== null && initialSync.knownInitialSyncSupport({ storage: browserStorage(), origin }) === true;
410
421
  return known && doc.store.clients.size > 0 && unconfirmed === 0 && !unconfirmedAttributions.keepsWrites;
@@ -419,6 +430,7 @@ function connectGenericDoc(args) {
419
430
  const origin = initialSync.keryxOriginOf(roomUrl);
420
431
  const storage = browserStorage();
421
432
  let event;
433
+ let applied = false;
422
434
  if (origin !== null && initialSync.knownInitialSyncSupport({ storage, origin }) === false) {
423
435
  event = { outcome: "skipped", durationMs: 0 };
424
436
  } else {
@@ -426,14 +438,19 @@ function connectGenericDoc(args) {
426
438
  httpFirstRead = { target, controller };
427
439
  const timeout = setTimeout(
428
440
  () => controller.abort(new DOMException("The HTTP-first read timed out", "TimeoutError")),
429
- HTTP_FIRST_READ_TIMEOUT_MS
441
+ initialSync.HTTP_FIRST_READ_TIMEOUT_MS
430
442
  );
431
443
  try {
432
- const read = await initialSync.readRoomOverHttp({ url, signal: controller.signal });
444
+ const read = await initialSync.readRoomOverHttp({
445
+ url,
446
+ signal: controller.signal,
447
+ idleTimeoutMs: initialSync.HTTP_FIRST_READ_IDLE_TIMEOUT_MS
448
+ });
433
449
  if (origin !== null) initialSync.rememberInitialSyncSupport({ storage, origin, supported: read.answersSyncStep1 });
434
450
  if (read.answersSyncStep1 && provider === target && !destroyed) {
435
- if (read.update.byteLength > 2) Y__namespace.applyUpdate(doc, read.update, target);
451
+ if (read.update.byteLength > 2) applyHttpFirstRead({ update: read.update, target });
436
452
  keryxAnswersSyncStep1 = true;
453
+ applied = true;
437
454
  }
438
455
  event = {
439
456
  outcome: read.answersSyncStep1 ? "read" : "unsupported",
@@ -456,13 +473,25 @@ function connectGenericDoc(args) {
456
473
  } catch {
457
474
  }
458
475
  if (destroyed || provider !== target) return;
459
- if (asksForDiffedSync({ roomUrl, unconfirmed: target.unconfirmedUpdates.length })) {
476
+ if (asksForDiffedSync({ roomUrl, unconfirmed: target.unconfirmedUpdates.length, afterRead: applied })) {
460
477
  target.params[initialSync.INITIAL_SYNC_PARAM] = initialSync.INITIAL_SYNC_DIFF;
461
478
  } else {
462
479
  delete target.params[initialSync.INITIAL_SYNC_PARAM];
463
480
  }
464
481
  target.connect();
465
482
  }
483
+ function applyHttpFirstRead({
484
+ update,
485
+ target
486
+ }) {
487
+ if (args.keepHttpFirstRead === true && doc.store.clients.size === 0) keptHttpFirstRead = update;
488
+ applyingHttpFirstRead = true;
489
+ try {
490
+ Y__namespace.applyUpdate(doc, update, target);
491
+ } finally {
492
+ applyingHttpFirstRead = false;
493
+ }
494
+ }
466
495
  const preparing = localCopy ? localCopy.prepare({ doc, transport }).catch(() => ({ unsyncedEdits: null })).then(({ unsyncedEdits }) => {
467
496
  if (destroyed) return;
468
497
  if (unsyncedEdits && !(unsyncedEdits.inserts.isEmpty() && unsyncedEdits.deletes.isEmpty())) {
@@ -612,6 +641,11 @@ function connectGenericDoc(args) {
612
641
  get writesRefused() {
613
642
  return (documentStatus$1 == null ? void 0 : documentStatus$1.writesRefused) ?? false;
614
643
  },
644
+ takeHttpFirstRead: () => {
645
+ const kept = keptHttpFirstRead;
646
+ keptHttpFirstRead = null;
647
+ return kept;
648
+ },
615
649
  waitForSync,
616
650
  waitForAcknowledged,
617
651
  getPresence: () => {
@@ -668,6 +702,7 @@ function connectGenericDoc(args) {
668
702
  destroy: () => {
669
703
  if (destroyed) return;
670
704
  destroyed = true;
705
+ keptHttpFirstRead = null;
671
706
  documentStatus$1 == null ? void 0 : documentStatus$1.destroy();
672
707
  teardownProvider();
673
708
  clearRetryTimer();
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","sources":["../../src/collab/client.ts"],"sourcesContent":["/**\n * Vanilla (framework-agnostic) live client for Generic Doc assets.\n *\n * `connectGenericDoc` owns the full connection lifecycle: mint a room-bound\n * token via the public API, open the Keryx WebSocket with the v14 provider\n * (`@y/websocket` + `@y/y`), re-mint before expiry, apply the close-code\n * policy (4401 → one fresh mint, other 44xx → permanent stop, everything\n * else → provider backoff), and expose presence from awareness. React apps\n * use `useGenericDoc` from `@athenaintel/react/collab` instead of calling\n * this directly.\n *\n * A host that keeps a local copy of the document (`localCopy`) gets it applied\n * before the first connection, keeps its unacknowledged edits waiting across\n * sessions, and can hold a connection that would send edits made without one\n * until it has checked them against the server (`beforeConnect`). Offline, a\n * mint that fails for want of the network is retried (`retryMintError`)\n * instead of ending the handle, and past `offlineGateAfterMs` without a socket\n * the handle reconnects itself, re-minting each time, so every reconnect after\n * a real outage re-checks access and passes the host's gate.\n *\n * A write the host makes on its own (an editor's housekeeping, a restored value)\n * goes out as housekeeping when it is made inside `runWithDocUpdateAttributions`\n * for `handle.doc` with `BACKGROUND_UPDATE_ATTRIBUTIONS`: the socket appends the\n * scope's attributions to the update, which Keryx counts as system work instead\n * of the person's edit (`socketFor`). One made while no socket is open is kept\n * until Keryx acknowledges it and sent the same way, ahead of the next\n * connection's sync (`UnconfirmedUpdateAttributions`). On a read-only grant\n * nothing that carries document content leaves the socket.\n *\n * A host that can read Keryx's document status with the room's grant\n * (`readDocumentStatus`) learns whether Keryx takes the room's writes for now\n * (`handle.writesRefused`): a quarantined room takes none, and its socket drops\n * every edit unconfirmed without a word (`document-status.ts`).\n */\n\nimport {\n INITIAL_SYNC_DIFF,\n INITIAL_SYNC_PARAM,\n type InitialSyncSupportStorage,\n keryxOriginOf,\n keryxRoomReadUrl,\n knownInitialSyncSupport,\n readRoomOverHttp,\n rememberInitialSyncSupport,\n} from '@athenaintel/keryx-http/initial-sync';\nimport { receiveOnlyWebSocket } from '@athenaintel/keryx-http/receive-only-socket';\nimport { UnconfirmedUpdateAttributions } from '@athenaintel/keryx-http/unconfirmed-update-attributions';\nimport {\n attributingWebSocket,\n docUpdateAttributions,\n} from '@athenaintel/keryx-http/update-attributions';\nimport { WebsocketProvider } from '@y/websocket';\nimport * as Y from '@y/y';\nimport { classifyClose } from './close-policy';\nimport { type ReadDocumentStatus, watchDocumentStatus } from './document-status';\nimport {\n type CollabAuth,\n type CollabTokenResponse,\n CollabTokenError,\n mintCollabToken,\n} from './mint';\nimport { MAX_CONSECUTIVE_REMINTS, MIN_REFRESH_DELAY_MS, refreshDelayMs } from './token-refresh';\n\nexport type GenericDocStatus =\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'closed'\n | 'error';\n\nexport interface PresenceEntry {\n clientId: number;\n state: Record<string, unknown>;\n}\n\nexport interface GenericDocHandle {\n /** The live shared document. Owned by the handle; destroyed with it. */\n readonly doc: Y.Doc;\n readonly status: GenericDocStatus;\n /**\n * Whether the initial server sync has completed for the current connection.\n * `status === 'connected'` fires before the server state arrives, so a doc\n * read immediately after connect can still be empty — gate first reads on\n * this (or `waitForSync`).\n */\n readonly synced: boolean;\n /**\n * Whether every change made to this document has reached the server: `false` from a local edit\n * until the server sends it back (`@y/websocket`'s `syncStatus.localUpdatesSynced`; yhub echoes\n * every update to its sender). Kept across reconnects and re-mints: a replaced provider hands its\n * unconfirmed edits to the next, and an edit made between providers waits for one. A host that\n * closes the document while this is `false` loses those edits, unless a local copy keeps them.\n */\n readonly localChangesSynced: boolean;\n /** Granted access from the last successful mint. */\n readonly accessType: 'r' | 'rw' | null;\n /** Terminal error, when status is 'error' or 'closed'. */\n readonly error: Error | null;\n /**\n * Whether the document holds what the host's local copy stored (always `true` without one).\n * Mount readers after it: until then the document is still empty.\n */\n readonly prepared: boolean;\n /** Whether this host allows a live connection. Disabled documents remain editable locally. */\n readonly connectionEnabled: boolean;\n /**\n * A connection the host's `beforeConnect` held: the handle waits, sending nothing, until the\n * host calls `resume()` (or destroys the handle).\n */\n readonly held: boolean;\n /** Monotonic change counter — bumps on every status/presence notification. */\n readonly version: number;\n /**\n * Resolve once the initial server sync completes; reject on timeout, on a\n * terminal connection state, or if the handle is destroyed first.\n */\n waitForSync: (timeoutMs?: number) => Promise<void>;\n /**\n * Resolve once connected, initially synced, and every local change has been acknowledged,\n * including any edits the local-copy hook restores after sync. The host must prevent further\n * editing while saving a checkpoint. Reject on timeout, a disabled connection, or a terminal state.\n */\n waitForAcknowledged: (timeoutMs?: number) => Promise<void>;\n getPresence: () => PresenceEntry[];\n /** Broadcast this client's presence state (requires a live connection). */\n setPresence: (state: Record<string, unknown> | null) => void;\n /**\n * Force an early token refresh. Session-preserving: the live connection\n * stays up until the fresh token is minted; a failed mint retries on a\n * short timer instead of dropping the session. Without a connection it\n * reconnects now.\n */\n refreshNow: () => Promise<void>;\n /**\n * Asks for a grant now, reconnecting only when it edits: the host has reason to think the person\n * may edit again (their access rose while the document was open, which no socket close tells:\n * Keryx closes nothing on a widening). A grant that edits reconnects the live room with it, or\n * asks the host's `beforeConnect` again for a room it held on a grant that only read; a grant\n * that still only reads changes nothing. One at a time. Resolves `true` when the room was handed a\n * grant that edits (a held room's `beforeConnect` still decides), `false` when the mint failed or\n * was refused, the grant still only reads, or the room is neither live nor held on a grant that\n * only read (a room on its way back mints its own).\n */\n refreshGrant: () => Promise<boolean>;\n /**\n * Disable all connections without losing the document or its pending edits. Enabling mints a\n * fresh grant and runs the host's beforeConnect gate; it never bypasses a permission or review.\n */\n setConnectionEnabled: (enabled: boolean) => void;\n /** Connect past a hold, without asking `beforeConnect` again. */\n resume: () => void;\n /** Local edits the server has not echoed yet (handed between providers too), or `null`. */\n unconfirmedEdits: () => Y.ContentIds | null;\n /**\n * Keryx's document status, as last read with the room's grant, says the room takes no writes for\n * now: it is quarantined while it is repaired, and its socket drops every edit unconfirmed until\n * it is released. Always `false` without `readDocumentStatus`, on a read-only grant, and whenever\n * the last read could not answer.\n */\n readonly writesRefused: boolean;\n onChange: (listener: () => void) => () => void;\n destroy: () => void;\n}\n\n/**\n * Issues a room-bound Keryx token for one asset. The default calls the public\n * `/collab-token` route with the handle's `auth`; a host with its own trusted\n * mint (a desktop app's main process holding the user's key) passes one\n * instead, and the handle uses it for the first mint and every re-mint.\n */\nexport type CollabMint = (params: {\n assetId: string;\n access: 'view' | 'edit';\n}) => Promise<CollabTokenResponse>;\n\n/** What a host's local copy reads of the handle's transport. */\nexport interface GenericDocTransportView {\n /** True for a transaction the transport applied (the server's state, a peer's edit). */\n isRemoteOrigin: (origin: unknown) => boolean;\n /** Local edits the server has not echoed yet, or `null`. */\n getUnconfirmed: () => Y.ContentIds | null;\n /** Connected, past the initial sync, and nothing unconfirmed. */\n isFullySynced: () => boolean;\n}\n\n/** What `beforeConnect` is asked about. */\nexport interface GenericDocConnectGate {\n /** The grant the connection would use (its access is the server's current verdict). */\n grant: CollabTokenResponse;\n /** The handle has not connected yet. */\n firstConnection: boolean;\n /** How long the handle had been without a connection, when it had one before. */\n offlineForMs: number | null;\n /** Local edits made without a connection (or inherited from an earlier session) wait to be sent. */\n hasUnsyncedEdits: boolean;\n /**\n * The connection follows Keryx's re-check of the room's grant (it closed the live socket with\n * 4401: a share narrowed or removed, a quarantine or its release), not an outage: whatever the\n * grant says now changed while the document was connected and open. Absent otherwise.\n */\n accessRechecked?: boolean;\n}\n\n/** A host's local copy of the document (`@athenaintel/local-copy` behind a host's glue). */\nexport interface GenericDocLocalCopy {\n /**\n * Called once, before the first mint: apply the stored copy to `doc` and return the local edits\n * it holds that the server never acknowledged. The handle sends them and waits for their echo\n * like its own. A failure here must resolve `{ unsyncedEdits: null }`: the handle then runs\n * without a copy.\n */\n prepare: (params: {\n doc: Y.Doc;\n transport: GenericDocTransportView;\n }) => Promise<{ unsyncedEdits: Y.ContentIds | null }>;\n /** The handle's unconfirmed edits or sync state changed. */\n transportChanged: () => void;\n /**\n * An explicit host pause/resume policy changed. Invalidate decisions that must be checked afresh\n * before a later manual save. A pause runs after its provider is destroyed and its status is\n * disconnected, so edits restored by the hook stay local. A resume runs before minting.\n * Network retries and an immediate conflict `resume()` do not call it.\n */\n connectionPolicyChanged?: (enabled: boolean) => void;\n /**\n * Asked after each mint and before the connection it would open: the first connection, a\n * reconnect after an outage longer than `offlineGateAfterMs`, and a re-mint after a revocation\n * (never a scheduled token refresh of a live connection, never past `resume()`). The host\n * checks what it must before anything is sent (the document still opens here; access; edits\n * made without a connection against the server's). `'hold'` keeps the handle from connecting\n * until `resume()`; a throw counts as \"not yet\" and is asked again on the next attempt.\n */\n beforeConnect?: (gate: GenericDocConnectGate) => Promise<'connect' | 'hold'>;\n}\n\n/** After this long without a socket, the handle reconnects itself (re-mint, gate) instead of the provider. */\nexport const DEFAULT_OFFLINE_GATE_AFTER_MS = 15_000;\n\n/** Retry delays for a mint that failed for want of the network. */\nconst MINT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 15_000, 30_000, 60_000];\n\n/**\n * The default `retryMintError`: a network failure, a timeout, a rate limit or a server error is\n * worth retrying; a refusal (401/403/404) is the server's verdict and ends the handle.\n */\nexport function isRetryableMintError(error: unknown): boolean {\n if (error instanceof CollabTokenError) {\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n return error instanceof TypeError || (error instanceof DOMException && error.name === 'TimeoutError');\n}\n\nfunction resolveMint({ auth, mint }: { auth?: CollabAuth; mint?: CollabMint }): CollabMint {\n if (mint) return mint;\n if (!auth) throw new Error('connectGenericDoc needs `auth` or `mint`');\n return ({ assetId, access }) => mintCollabToken({ auth, assetId, access });\n}\n\n/**\n * The socket a provider for `grant` opens (`@athenaintel/keryx-http`'s wrappers, the ones\n * Olympus's rooms use). On a read-write grant, each sync update a write made inside a\n * `runWithDocUpdateAttributions` scope for `doc` sends carries the scope's attributions, which\n * Keryx reads after the update (`origin: background` counts as system work; a Keryx that predates\n * the trailer ignores it), and its sync step 2 goes out behind such writes made while no socket\n * was open, each as its own marked update (`unconfirmed`). On a read-only grant no frame that\n * carries document content leaves: a sync step 2 or an update is dropped (Keryx ignores them on\n * such a grant anyway), awareness passes. Read when each provider is built, as `@y/websocket` reads\n * `WebSocket`; `undefined` where there is none, and the provider fails at connect as it always did.\n */\nfunction socketFor({\n grant,\n doc,\n unconfirmed,\n}: {\n grant: CollabTokenResponse;\n doc: Y.Doc;\n unconfirmed: UnconfirmedUpdateAttributions;\n}): typeof WebSocket | undefined {\n const Base: typeof WebSocket | undefined = globalThis.WebSocket;\n if (typeof Base !== 'function') return undefined;\n if (grant.access_type === 'r') return receiveOnlyWebSocket({ Base });\n return attributingWebSocket({\n Base,\n attributionsFor: () => docUpdateAttributions(doc),\n unconfirmed,\n });\n}\n\n/** How an HTTP-first read went (`connectGenericDoc`'s `httpFirstOpen`). */\nexport interface GenericDocHttpFirstOpenEvent {\n /**\n * `read`: read over HTTP and applied; the socket asks for the diff. `unsupported`: Keryx answered\n * without saying it answers a socket's sync step 1; its document was not used. `failed`: the read\n * failed (`error` says why). `skipped`: Keryx is known not to answer, so nothing was read.\n * `aborted`: the room replaced or closed the provider during the read, which it stopped.\n */\n outcome: 'read' | 'unsupported' | 'failed' | 'skipped' | 'aborted';\n /** The decoded body's size (`read`, `unsupported`). */\n bytes?: number;\n /** From the request to the socket's connect. */\n durationMs: number;\n /** Why the read failed (`failed`): the error's name and message. */\n error?: string;\n}\n\n/** How long an HTTP-first read may take before the room falls back to the socket's whole-document sync. */\nconst HTTP_FIRST_READ_TIMEOUT_MS = 60_000;\n\n/** `localStorage`, when the host has one (a browser, Electron's renderer, the phone's editor page). */\nfunction browserStorage(): InitialSyncSupportStorage | null {\n try {\n return typeof window !== 'undefined' && window.localStorage ? window.localStorage : null;\n } catch {\n return null;\n }\n}\n\nexport function connectGenericDoc(args: {\n assetId: string;\n /** Credentials for the default mint; not used when `mint` is given. */\n auth?: CollabAuth;\n access?: 'view' | 'edit';\n mint?: CollabMint;\n /** A local copy of the document the host keeps (see {@link GenericDocLocalCopy}). */\n localCopy?: GenericDocLocalCopy;\n /** Whether a failed mint is worth retrying; defaults to {@link isRetryableMintError}. */\n retryMintError?: (error: unknown) => boolean;\n /** See {@link DEFAULT_OFFLINE_GATE_AFTER_MS}. */\n offlineGateAfterMs?: number;\n /** Start without connecting or minting (for a host's manual-save mode). Defaults to true. */\n connectionEnabled?: boolean;\n /**\n * Reads Keryx's document status with the room's grant (see `ReadDocumentStatus`), for\n * `handle.writesRefused`. A host that cannot read it leaves it out.\n */\n readDocumentStatus?: ReadDocumentStatus;\n /**\n * Open the room HTTP-first (Word at scale), as Olympus opens a Word room: a document that holds\n * nothing yet is read over `GET /ydoc` (compressed, decoded as it downloads), applied as Keryx's\n * own state, and the socket asks Keryx for only what it still lacks (`?initialSync=diff`) - when\n * Keryx says it answers that way (`@athenaintel/keryx-http/initial-sync`). Every later socket of\n * the room asks for the diff too while Keryx is known to answer and the room holds no write Keryx\n * has not echoed. For rooms whose documents can be large (Word documents).\n */\n httpFirstOpen?: boolean;\n /** Hears how each HTTP-first read went (`httpFirstOpen`), for the host's telemetry. */\n onHttpFirstOpen?: (event: GenericDocHttpFirstOpenEvent) => void;\n}): GenericDocHandle {\n const access = args.access ?? 'view';\n const mint = resolveMint({ auth: args.auth, mint: args.mint });\n const localCopy = args.localCopy;\n const retryMintError = args.retryMintError ?? isRetryableMintError;\n const offlineGateAfterMs = args.offlineGateAfterMs ?? DEFAULT_OFFLINE_GATE_AFTER_MS;\n const doc = new Y.Doc();\n // Writes made in a `runWithDocUpdateAttributions` scope, until Keryx acknowledges them: the\n // sockets every provider opens send those made while no socket was open ahead of their sync.\n const unconfirmedAttributions = new UnconfirmedUpdateAttributions({\n doc,\n attributionsFor: () => docUpdateAttributions(doc),\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n });\n const listeners = new Set<() => void>();\n\n let provider: WebsocketProvider | null = null;\n let refreshTimer: ReturnType<typeof setTimeout> | null = null;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n let offlineTimer: ReturnType<typeof setTimeout> | null = null;\n /** The provider whose socket was still opening, with nothing to send, at the threshold. */\n let openingPastThreshold: WebsocketProvider | null = null;\n let mintRetries = 0;\n let destroyed = false;\n let connectionEnabled = args.connectionEnabled ?? true;\n let status: GenericDocStatus = connectionEnabled ? 'connecting' : 'disconnected';\n let synced = false;\n let accessType: 'r' | 'rw' | null = null;\n let error: Error | null = null;\n let lastPresence: Record<string, unknown> | null = null;\n let version = 0;\n let consecutiveRemints = 0;\n let prepared = localCopy === undefined;\n let held = false;\n let heldGrant: CollabTokenResponse | null = null;\n let everConnected = false;\n let disconnectedSince: number | null = null;\n /** Bumped by every connect attempt: an attempt that finds it changed after an await stops. */\n let connectSeq = 0;\n /** Local edits no provider holds: handed on by a replaced provider, or made with none. */\n let carriedUpdates: WebsocketProvider['unconfirmedUpdates'] = [];\n let localChangesSynced = true;\n /** The grant the current provider connects with. */\n let liveGrant: CollabTokenResponse | null = null;\n /** Keryx's auth re-check closed the socket (4401): the next connection reads the document status. */\n let readStatusOnConnect = false;\n /**\n * Keryx's auth re-check closed the socket (4401): the gate asked before the next connection hears\n * that the grant changed while the document was connected (`accessRechecked`), until it answers.\n */\n let accessRecheckPending = false;\n /** This room saw its Keryx say it answers a socket's sync step 1 (its HTTP-first read). */\n let keryxAnswersSyncStep1 = false;\n /**\n * The HTTP-first read of a provider's document, while it runs: that provider is opening, and\n * replacing it (a re-mint, the offline takeover, `setConnectionEnabled(false)`, `destroy()`) stops\n * the download.\n */\n let httpFirstRead: { target: WebsocketProvider; controller: AbortController } | null = null;\n\n const notify = () => {\n version += 1;\n for (const listener of listeners) listener();\n };\n\n const documentStatus = args.readDocumentStatus\n ? watchDocumentStatus({\n read: args.readDocumentStatus,\n currentGrant: () => liveGrant,\n onChange: () => {\n if (!destroyed) notify();\n },\n })\n : null;\n\n const unconfirmedEdits = (): Y.ContentIds | null => {\n const all = [...carriedUpdates, ...(provider?.unconfirmedUpdates ?? [])].map(\n (entry) => entry.ids as Y.ContentIds\n );\n if (all.length === 0) return null;\n return all.length === 1 ? (all[0] as Y.ContentIds) : Y.mergeContentIds(all);\n };\n\n const transport: GenericDocTransportView = {\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n getUnconfirmed: unconfirmedEdits,\n isFullySynced: () => status === 'connected' && synced && localChangesSynced,\n };\n\n const transportChanged = () => {\n localCopy?.transportChanged();\n };\n\n const refreshLocalChangesSynced = () => {\n const next = carriedUpdates.length === 0 && (provider?.unconfirmedUpdates.length ?? 0) === 0;\n const changed = next !== localChangesSynced;\n localChangesSynced = next;\n documentStatus?.unconfirmedChanged(!next);\n // After the flag: the copy reads `isFullySynced()` in its callback.\n // Before notifying: the callback can restore values and create more unconfirmed edits.\n transportChanged();\n if (changed) notify();\n };\n\n // An edit made while no provider exists (a re-mint in flight, offline) is sent by the next one,\n // which takes it as unconfirmed. The local copy's own load is not an edit.\n doc.on('update', (update: Uint8Array, origin: unknown) => {\n if (!prepared || provider !== null || destroyed || origin instanceof WebsocketProvider) return;\n carriedUpdates = [\n ...carriedUpdates,\n { created: Date.now(), ids: Y.createContentIdsFromUpdate(update) },\n ];\n refreshLocalChangesSynced();\n });\n\n const setStatus = (next: GenericDocStatus, err: Error | null = null) => {\n if (destroyed && next !== 'closed') return;\n const wasConnected = status === 'connected';\n status = next;\n error = err;\n if (next === 'connected') {\n everConnected = true;\n disconnectedSince = null;\n clearOfflineTimer();\n } else {\n if (wasConnected || (everConnected && disconnectedSince === null)) {\n disconnectedSince = Date.now();\n }\n documentStatus?.disconnected();\n }\n transportChanged();\n notify();\n };\n\n const clearRefreshTimer = () => {\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer);\n refreshTimer = null;\n }\n };\n\n const clearRetryTimer = () => {\n if (retryTimer !== null) {\n clearTimeout(retryTimer);\n retryTimer = null;\n }\n };\n\n function clearOfflineTimer() {\n if (offlineTimer !== null) {\n clearTimeout(offlineTimer);\n offlineTimer = null;\n }\n }\n\n const teardownProvider = () => {\n clearRefreshTimer();\n // A future provider must complete its own initial sync; the doc keeps its\n // content either way. Subscribers must observe the flip immediately —\n // waiting for the next provider event would let them act on synced=true\n // across the replacement gap.\n if (synced) {\n synced = false;\n notify();\n }\n if (provider) {\n // Its unconfirmed edits outlive it: the next provider sends them and waits for their echo.\n const previous = provider;\n provider = null;\n if (httpFirstRead?.target === previous) {\n httpFirstRead.controller.abort(new DOMException('The room closed', 'AbortError'));\n httpFirstRead = null;\n }\n carriedUpdates = [...carriedUpdates, ...previous.unconfirmedUpdates];\n previous.destroy();\n }\n };\n\n const scheduleRefresh = (grant: CollabTokenResponse) => {\n clearRefreshTimer();\n const delay = refreshDelayMs({ expiresAtMs: grant.expires_at_ms, now: Date.now() });\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, delay);\n };\n\n /** A failed attempt that is worth retrying: try again later, or as soon as the network returns. */\n const scheduleRetry = () => {\n clearRetryTimer();\n const delay = MINT_RETRY_DELAYS_MS[Math.min(mintRetries, MINT_RETRY_DELAYS_MS.length - 1)];\n mintRetries += 1;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void connect();\n }, delay);\n };\n\n const onBrowserOnline = () => {\n // Only a handle waiting to retry: a refused or permanently closed one stays stopped.\n if (\n destroyed || !connectionEnabled || status === 'closed' || status === 'error' ||\n provider !== null || held\n ) return;\n mintRetries = 0;\n clearRetryTimer();\n void connect();\n };\n if (typeof window !== 'undefined') window.addEventListener('online', onBrowserOnline);\n\n /**\n * Past the gate's threshold without a socket, the handle reconnects itself (re-mint, gate). A\n * socket still being opened with nothing waiting to be sent is left to finish (a slow network\n * is not restarted every threshold), and the handle looks again a threshold later; if it opens\n * holding edits made since, they go through the gate first (`status`).\n */\n const armOfflineTakeover = () => {\n if (!connectionEnabled || offlineTimer !== null || !localCopy?.beforeConnect) return;\n offlineTimer = setTimeout(() => {\n offlineTimer = null;\n if (destroyed || !connectionEnabled || status === 'connected' || provider === null) return;\n // A provider reading its document over HTTP first is opening too (a long report, a slow link)\n if ((provider.wsconnecting || httpFirstRead?.target === provider) && !hasUnsyncedLocalEdits()) {\n openingPastThreshold = provider;\n armOfflineTakeover();\n return;\n }\n teardownProvider();\n void connect();\n }, offlineGateAfterMs);\n };\n\n const hasUnsyncedLocalEdits = () =>\n carriedUpdates.length > 0 || (provider?.unconfirmedUpdates.length ?? 0) > 0;\n\n\n const connect = async (opts?: {\n scheduledRefresh?: boolean;\n skipGate?: boolean;\n grant?: CollabTokenResponse;\n }): Promise<void> => {\n if (destroyed || !connectionEnabled) return;\n const seq = ++connectSeq;\n await preparing;\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n // Only a live connection is refreshed in place (and skips the host's gate); a refresh while the\n // socket is down is a reconnect like any other.\n const scheduledRefresh = opts?.scheduledRefresh === true && status === 'connected';\n // A scheduled refresh mints FIRST and keeps the live session up: the old\n // token has ~5 minutes of headroom, so a transient mint failure retries\n // on a short timer instead of dropping a healthy connection.\n if (!scheduledRefresh) {\n teardownProvider();\n } else {\n clearRefreshTimer();\n }\n clearRetryTimer();\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n let grant: CollabTokenResponse;\n if (opts?.grant && opts.grant.expires_at_ms - Date.now() > MIN_REFRESH_DELAY_MS) {\n grant = opts.grant;\n } else {\n try {\n grant = await mint({ assetId: args.assetId, access });\n } catch (err) {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (scheduledRefresh) {\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, MIN_REFRESH_DELAY_MS);\n return;\n }\n if (retryMintError(err)) {\n // Offline (or the mint's server is): keep the document and try again.\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n // A denied mint is authoritative (revoked / not shared / not eligible).\n setStatus('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n mintRetries = 0;\n accessType = grant.access_type;\n const beforeConnect = localCopy?.beforeConnect;\n if (beforeConnect && !scheduledRefresh && !opts?.skipGate) {\n const firstConnection = !everConnected;\n const offlineForMs = disconnectedSince === null ? null : Date.now() - disconnectedSince;\n let decision: 'connect' | 'hold';\n try {\n decision = await beforeConnect({\n grant,\n firstConnection,\n offlineForMs,\n hasUnsyncedEdits: hasUnsyncedLocalEdits(),\n ...(accessRecheckPending ? { accessRechecked: true } : {}),\n });\n } catch {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n accessRecheckPending = false;\n if (decision === 'hold') {\n held = true;\n heldGrant = grant;\n if (status !== 'disconnected') setStatus('disconnected');\n else notify();\n return;\n }\n }\n if (scheduledRefresh) {\n teardownProvider();\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n\n const socket = socketFor({ grant, doc, unconfirmed: unconfirmedAttributions });\n const roomUrl = `${grant.ws_url}/${grant.org}/${grant.doc_id}`;\n // Word at scale: a document that holds nothing yet is read over HTTP first, then the socket connects\n const httpFirstUrl =\n args.httpFirstOpen === true && doc.store.clients.size === 0 && carriedUpdates.length === 0\n ? keryxRoomReadUrl({ wsUrl: roomUrl, token: grant.token, branch: grant.branch })\n : null;\n const params: Record<string, string> = {\n yauth: grant.token,\n branch: grant.branch,\n gc: 'true',\n };\n if (httpFirstUrl === null && asksForDiffedSync({ roomUrl, unconfirmed: carriedUpdates.length })) {\n params[INITIAL_SYNC_PARAM] = INITIAL_SYNC_DIFF;\n }\n const nextProvider = new WebsocketProvider(grant.ws_url, `${grant.org}/${grant.doc_id}`, doc, {\n params,\n // BroadcastChannel would sync same-origin clients locally, bypassing the\n // server's permission enforcement (a read-only tab could write into an\n // editor tab's doc). Permissioned docs must round-trip the server.\n disableBc: true,\n connect: httpFirstUrl === null,\n ...(socket && { WebSocketPolyfill: socket }),\n });\n provider = nextProvider;\n liveGrant = grant;\n nextProvider.unconfirmedUpdates = [...carriedUpdates, ...nextProvider.unconfirmedUpdates];\n carriedUpdates = [];\n refreshLocalChangesSynced();\n\n nextProvider.on('sync-status', () => {\n if (provider !== nextProvider) return;\n refreshLocalChangesSynced();\n });\n\n nextProvider.on('status', (event: { status: 'connecting' | 'connected' | 'disconnected' }) => {\n if (provider !== nextProvider) return;\n if (\n event.status === 'connected' &&\n openingPastThreshold === nextProvider &&\n hasUnsyncedLocalEdits()\n ) {\n // Opened after the threshold holding edits made meanwhile: before its handshake sends\n // them (`@y/websocket` reports `connected` first), they go through the gate.\n teardownProvider();\n void connect();\n return;\n }\n // The connections that read Keryx's document status at once: the first, the one after an auth\n // re-check close, and one after an outage the handle treats as real. Never an ordinary\n // reconnect (a Keryx deploy reconnects every room at once).\n const readStatusNow =\n event.status === 'connected' &&\n (!everConnected ||\n readStatusOnConnect ||\n (disconnectedSince !== null && Date.now() - disconnectedSince >= offlineGateAfterMs));\n if (event.status === 'connected') {\n consecutiveRemints = 0;\n readStatusOnConnect = false;\n accessRecheckPending = false;\n }\n setStatus(event.status);\n if (event.status === 'connected') documentStatus?.connected({ readNow: readStatusNow });\n if (event.status === 'connected' && lastPresence !== null) {\n nextProvider.awareness.setLocalState(lastPresence);\n }\n // `@y/websocket` reports `disconnected` only for a socket that had opened: one that never\n // opens (the server unreachable while the mint goes through) only ever reports `connecting`,\n // and is just as offline.\n if (event.status !== 'connected') armOfflineTakeover();\n });\n // Its first `connecting` came from its constructor, before this listener existed.\n if (!nextProvider.wsconnected) armOfflineTakeover();\n\n nextProvider.on('sync', (state: boolean) => {\n if (provider !== nextProvider) return;\n if (synced !== state) {\n synced = state;\n transportChanged();\n notify();\n }\n });\n\n nextProvider.on('connection-close', (event: CloseEvent | null) => {\n if (provider !== nextProvider) return;\n // The next socket asks for a diffed initial sync only while nothing it holds needs Keryx's whole document\n if (asksForDiffedSync({ roomUrl, unconfirmed: nextProvider.unconfirmedUpdates.length })) {\n nextProvider.params[INITIAL_SYNC_PARAM] = INITIAL_SYNC_DIFF;\n } else {\n delete nextProvider.params[INITIAL_SYNC_PARAM];\n }\n const action = classifyClose(event?.code);\n if (action === 'remint') {\n // Revoked mid-session: a fresh mint re-runs the server-side permission\n // check. If access is truly gone the mint 403s and we land in 'error'.\n // Bounded: repeated 4401s without an intervening successful connect\n // mean the server keeps rejecting freshly minted tokens — stop rather\n // than loop mint→connect→kick.\n consecutiveRemints += 1;\n // A quarantine and a release both close the room's sockets this way, once Keryx has written\n // or cleared the marker: the reconnected socket learns which. Until then nothing is read\n // (the handle stays `connected` through the re-mint, on a grant Keryx just bounced).\n readStatusOnConnect = true;\n // The host's gate hears that the grant changed while the document was open: a view-only\n // grant now holds the edits it never sent, in words that don't blame being offline.\n accessRecheckPending = true;\n documentStatus?.disconnected();\n teardownProvider();\n if (consecutiveRemints > MAX_CONSECUTIVE_REMINTS) {\n setStatus(\n 'closed',\n new Error('Access repeatedly revoked mid-session (4401); giving up.')\n );\n return;\n }\n void connect();\n } else if (action === 'stop') {\n teardownProvider();\n setStatus(\n 'closed',\n new Error(`Connection closed permanently (code ${event?.code ?? 'unknown'})`)\n );\n }\n // 'retry': the provider's exponential backoff handles it, until the offline takeover.\n });\n\n nextProvider.awareness.on('change', () => {\n if (provider !== nextProvider) return;\n notify();\n });\n\n scheduleRefresh(grant);\n if (httpFirstUrl !== null) void openOverHttp({ target: nextProvider, url: httpFirstUrl, roomUrl });\n };\n\n /**\n * Word at scale: whether a socket of this room asks for a diffed initial sync - a room that opens\n * HTTP-first, whose Keryx is known to answer it, whose document holds something, and that holds no\n * write Keryx may hold without having echoed it (an unconfirmed update, a kept attributed write):\n * those are confirmed by the whole document Keryx sends when a socket opens.\n */\n function asksForDiffedSync({ roomUrl, unconfirmed }: { roomUrl: string; unconfirmed: number }): boolean {\n if (args.httpFirstOpen !== true) return false;\n const origin = keryxOriginOf(roomUrl);\n const known =\n keryxAnswersSyncStep1 ||\n (origin !== null && knownInitialSyncSupport({ storage: browserStorage(), origin }) === true);\n return known && doc.store.clients.size > 0 && unconfirmed === 0 && !unconfirmedAttributions.keepsWrites;\n }\n\n /**\n * Word at scale: read the room over HTTP, apply it as Keryx's own state (the provider's origin, so\n * nothing treats it as a local edit), then connect the provider's socket, asking for the diff when\n * Keryx said it answers that way. A Keryx that did not, a failed read, or a provider replaced\n * meanwhile: the document is left as it was and the socket connects as every room's does.\n */\n async function openOverHttp({\n target,\n url,\n roomUrl,\n }: {\n target: WebsocketProvider;\n url: string;\n roomUrl: string;\n }): Promise<void> {\n const started = performance.now();\n const origin = keryxOriginOf(roomUrl);\n const storage = browserStorage();\n let event: GenericDocHttpFirstOpenEvent;\n if (origin !== null && knownInitialSyncSupport({ storage, origin }) === false) {\n event = { outcome: 'skipped', durationMs: 0 };\n } else {\n const controller = new AbortController();\n httpFirstRead = { target, controller };\n const timeout = setTimeout(\n () => controller.abort(new DOMException('The HTTP-first read timed out', 'TimeoutError')),\n HTTP_FIRST_READ_TIMEOUT_MS\n );\n try {\n const read = await readRoomOverHttp({ url, signal: controller.signal });\n if (origin !== null) rememberInitialSyncSupport({ storage, origin, supported: read.answersSyncStep1 });\n if (read.answersSyncStep1 && provider === target && !destroyed) {\n if (read.update.byteLength > 2) Y.applyUpdate(doc, read.update, target);\n keryxAnswersSyncStep1 = true;\n }\n event = {\n outcome: read.answersSyncStep1 ? 'read' : 'unsupported',\n bytes: read.bytes,\n durationMs: performance.now() - started,\n };\n } catch (err) {\n // the socket's whole-document sync, as before; a read the room stopped is no failure\n event =\n controller.signal.aborted && (destroyed || provider !== target)\n ? { outcome: 'aborted', durationMs: performance.now() - started }\n : {\n outcome: 'failed',\n durationMs: performance.now() - started,\n error: err instanceof Error ? `${err.name}: ${err.message}` : String(err),\n };\n } finally {\n clearTimeout(timeout);\n if (httpFirstRead?.controller === controller) httpFirstRead = null;\n }\n }\n try {\n args.onHttpFirstOpen?.(event);\n } catch {\n // a host's telemetry never keeps the room from opening its socket\n }\n if (destroyed || provider !== target) return;\n if (asksForDiffedSync({ roomUrl, unconfirmed: target.unconfirmedUpdates.length })) {\n target.params[INITIAL_SYNC_PARAM] = INITIAL_SYNC_DIFF;\n } else {\n delete target.params[INITIAL_SYNC_PARAM];\n }\n target.connect();\n }\n\n const preparing: Promise<void> = localCopy\n ? localCopy\n .prepare({ doc, transport })\n .catch(() => ({ unsyncedEdits: null }))\n .then(({ unsyncedEdits }) => {\n if (destroyed) return;\n if (unsyncedEdits && !(unsyncedEdits.inserts.isEmpty() && unsyncedEdits.deletes.isEmpty())) {\n carriedUpdates = [...carriedUpdates, { created: Date.now(), ids: unsyncedEdits }];\n }\n prepared = true;\n refreshLocalChangesSynced();\n notify();\n })\n : Promise.resolve();\n\n void connect();\n\n const waitForSync = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n const terminal = (): Error | null => {\n if (destroyed) return new Error('Handle destroyed before initial sync');\n if (status === 'closed' || status === 'error') {\n return error ?? new Error(`Connection ${status} before initial sync`);\n }\n return null;\n };\n if (synced) {\n resolve();\n return;\n }\n const immediate = terminal();\n if (immediate) {\n reject(immediate);\n return;\n }\n const cleanup = () => {\n clearTimeout(timer);\n listeners.delete(listener);\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`Timed out after ${timeoutMs}ms waiting for initial sync`));\n }, timeoutMs);\n const listener = () => {\n if (synced) {\n cleanup();\n resolve();\n return;\n }\n const err = terminal();\n if (err) {\n cleanup();\n reject(err);\n }\n };\n listeners.add(listener);\n });\n\n const waitForAcknowledged = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n let finished = false;\n let checkQueued = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const finish = (failure?: Error) => {\n if (finished) return;\n finished = true;\n if (timer !== null) clearTimeout(timer);\n listeners.delete(check);\n if (failure) reject(failure);\n else resolve();\n };\n const check = () => {\n if (finished || checkQueued) return;\n checkQueued = true;\n // All synchronous transport hooks and change listeners finish before a save settles.\n queueMicrotask(() => {\n checkQueued = false;\n if (finished) return;\n if (destroyed) {\n finish(new Error('Handle destroyed before local changes were acknowledged'));\n } else if (!connectionEnabled) {\n finish(new Error('Connection disabled before local changes were acknowledged'));\n } else if (status === 'closed' || status === 'error') {\n finish(error ?? new Error(`Connection ${status} before local changes were acknowledged`));\n } else if (prepared && status === 'connected' && synced && localChangesSynced) {\n finish();\n }\n });\n };\n timer = setTimeout(() => {\n finish(new Error(`Timed out after ${timeoutMs}ms waiting for local changes to be acknowledged`));\n }, timeoutMs);\n listeners.add(check);\n check();\n });\n\n /** A grant asked for by `refreshGrant`, while it runs. */\n let grantRefresh: Promise<boolean> | null = null;\n const askForGrant = async (): Promise<boolean> => {\n try {\n const grant = await mint({ assetId: args.assetId, access });\n if (destroyed || !connectionEnabled || grant.access_type !== 'rw') return false;\n if (held) {\n // Held meanwhile on a grant that edits (an overlap to review): the host's decision stands.\n if (heldGrant?.access_type !== 'r') return false;\n held = false;\n heldGrant = null;\n notify();\n void connect({ grant });\n return true;\n }\n if (status !== 'connected') return false;\n if (accessType === 'rw') return true;\n // Keryx reads a socket's grant when it opens: the live room reconnects on the new one.\n void connect({ scheduledRefresh: true, grant });\n return true;\n } catch {\n return false;\n }\n };\n const refreshGrant = (): Promise<boolean> => {\n if (destroyed || !connectionEnabled) return Promise.resolve(false);\n if (grantRefresh) return grantRefresh;\n const heldOnRead = held && heldGrant?.access_type === 'r';\n // A room on its way back mints its own grant; one live on a grant that edits needs none.\n if (!heldOnRead && status !== 'connected') return Promise.resolve(false);\n if (!heldOnRead && accessType === 'rw') return Promise.resolve(true);\n const asked = askForGrant().finally(() => {\n grantRefresh = null;\n });\n grantRefresh = asked;\n return asked;\n };\n\n return {\n doc,\n get status() {\n return status;\n },\n get synced() {\n return synced;\n },\n get localChangesSynced() {\n return localChangesSynced;\n },\n get accessType() {\n return accessType;\n },\n get error() {\n return error;\n },\n get prepared() {\n return prepared;\n },\n get connectionEnabled() {\n return connectionEnabled;\n },\n get held() {\n return held;\n },\n get version() {\n return version;\n },\n get writesRefused() {\n return documentStatus?.writesRefused ?? false;\n },\n waitForSync,\n waitForAcknowledged,\n getPresence: () => {\n if (!provider) return [];\n const entries: PresenceEntry[] = [];\n provider.awareness.getStates().forEach((state, clientId) => {\n entries.push({ clientId, state: state as Record<string, unknown> });\n });\n return entries;\n },\n setPresence: (state) => {\n lastPresence = state;\n provider?.awareness.setLocalState(state);\n },\n refreshNow: () => {\n if (!connectionEnabled || held) return Promise.resolve();\n return provider ? connect({ scheduledRefresh: true }) : connect();\n },\n refreshGrant,\n setConnectionEnabled: (enabled) => {\n if (destroyed || enabled === connectionEnabled) return;\n connectionEnabled = enabled;\n if (!enabled) {\n // Invalidate every mint/gate already in flight before tearing down the live provider.\n connectSeq += 1;\n clearRetryTimer();\n clearOfflineTimer();\n teardownProvider();\n setStatus('disconnected');\n localCopy?.connectionPolicyChanged?.(false);\n return;\n }\n localCopy?.connectionPolicyChanged?.(true);\n held = false;\n heldGrant = null;\n setStatus('connecting');\n void connect();\n },\n resume: () => {\n if (!held || destroyed || !connectionEnabled) return;\n held = false;\n const grant = heldGrant;\n heldGrant = null;\n notify();\n void connect({ skipGate: true, grant: grant ?? undefined });\n },\n unconfirmedEdits,\n onChange: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n destroy: () => {\n if (destroyed) return;\n destroyed = true;\n documentStatus?.destroy();\n teardownProvider();\n clearRetryTimer();\n clearOfflineTimer();\n if (typeof window !== 'undefined') window.removeEventListener('online', onBrowserOnline);\n status = 'closed';\n // Final notification so pending waitForSync callers reject instead of\n // hanging on listeners that are about to be dropped.\n for (const listener of [...listeners]) listener();\n listeners.clear();\n unconfirmedAttributions.destroy();\n doc.destroy();\n },\n };\n}\n\nexport { CollabTokenError };\nexport type { CollabAuth, CollabTokenResponse };\n"],"names":["CollabTokenError","mint","mintCollabToken","receiveOnlyWebSocket","attributingWebSocket","docUpdateAttributions","Y","UnconfirmedUpdateAttributions","WebsocketProvider","documentStatus","watchDocumentStatus","refreshDelayMs","MIN_REFRESH_DELAY_MS","keryxRoomReadUrl","INITIAL_SYNC_PARAM","INITIAL_SYNC_DIFF","classifyClose","MAX_CONSECUTIVE_REMINTS","keryxOriginOf","knownInitialSyncSupport","readRoomOverHttp","rememberInitialSyncSupport"],"mappings":"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"}
1
+ {"version":3,"file":"client.cjs","sources":["../../src/collab/client.ts"],"sourcesContent":["/**\n * Vanilla (framework-agnostic) live client for Generic Doc assets.\n *\n * `connectGenericDoc` owns the full connection lifecycle: mint a room-bound\n * token via the public API, open the Keryx WebSocket with the v14 provider\n * (`@y/websocket` + `@y/y`), re-mint before expiry, apply the close-code\n * policy (4401 → one fresh mint, other 44xx → permanent stop, everything\n * else → provider backoff), and expose presence from awareness. React apps\n * use `useGenericDoc` from `@athenaintel/react/collab` instead of calling\n * this directly.\n *\n * A host that keeps a local copy of the document (`localCopy`) gets it applied\n * before the first connection, keeps its unacknowledged edits waiting across\n * sessions, and can hold a connection that would send edits made without one\n * until it has checked them against the server (`beforeConnect`). Offline, a\n * mint that fails for want of the network is retried (`retryMintError`)\n * instead of ending the handle, and past `offlineGateAfterMs` without a socket\n * the handle reconnects itself, re-minting each time, so every reconnect after\n * a real outage re-checks access and passes the host's gate.\n *\n * A write the host makes on its own (an editor's housekeeping, a restored value)\n * goes out as housekeeping when it is made inside `runWithDocUpdateAttributions`\n * for `handle.doc` with `BACKGROUND_UPDATE_ATTRIBUTIONS`: the socket appends the\n * scope's attributions to the update, which Keryx counts as system work instead\n * of the person's edit (`socketFor`). One made while no socket is open is kept\n * until Keryx acknowledges it and sent the same way, ahead of the next\n * connection's sync (`UnconfirmedUpdateAttributions`). On a read-only grant\n * nothing that carries document content leaves the socket.\n *\n * The socket sends the handle's own presence and never a collaborator's\n * (`publishOwnAwarenessOnly`): Keryx already holds and relays every other\n * client's entry, and drops a re-sent agent slot or departure.\n *\n * A host that can read Keryx's document status with the room's grant\n * (`readDocumentStatus`) learns whether Keryx takes the room's writes for now\n * (`handle.writesRefused`): a quarantined room takes none, and its socket drops\n * every edit unconfirmed without a word (`document-status.ts`).\n */\n\nimport {\n type DiffedInitialSync,\n HTTP_FIRST_READ_IDLE_TIMEOUT_MS,\n HTTP_FIRST_READ_TIMEOUT_MS,\n INITIAL_SYNC_DIFF,\n INITIAL_SYNC_PARAM,\n type InitialSyncSupportStorage,\n keryxOriginOf,\n keryxRoomReadUrl,\n knownInitialSyncSupport,\n readRoomOverHttp,\n rememberInitialSyncSupport,\n} from '@athenaintel/keryx-http/initial-sync';\nimport { publishOwnAwarenessOnly } from '@athenaintel/keryx-http/own-awareness';\nimport { receiveOnlyWebSocket } from '@athenaintel/keryx-http/receive-only-socket';\nimport { UnconfirmedUpdateAttributions } from '@athenaintel/keryx-http/unconfirmed-update-attributions';\nimport {\n attributingWebSocket,\n docUpdateAttributions,\n} from '@athenaintel/keryx-http/update-attributions';\nimport { WebsocketProvider } from '@y/websocket';\nimport * as Y from '@y/y';\nimport { classifyClose } from './close-policy';\nimport { type ReadDocumentStatus, watchDocumentStatus } from './document-status';\nimport {\n type CollabAuth,\n type CollabTokenResponse,\n CollabTokenError,\n mintCollabToken,\n} from './mint';\nimport { MAX_CONSECUTIVE_REMINTS, MIN_REFRESH_DELAY_MS, refreshDelayMs } from './token-refresh';\n\nexport type GenericDocStatus =\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'closed'\n | 'error';\n\nexport interface PresenceEntry {\n clientId: number;\n state: Record<string, unknown>;\n}\n\nexport interface GenericDocHandle {\n /** The live shared document. Owned by the handle; destroyed with it. */\n readonly doc: Y.Doc;\n readonly status: GenericDocStatus;\n /**\n * Whether the initial server sync has completed for the current connection.\n * `status === 'connected'` fires before the server state arrives, so a doc\n * read immediately after connect can still be empty — gate first reads on\n * this (or `waitForSync`).\n */\n readonly synced: boolean;\n /**\n * Whether every change made to this document has reached the server: `false` from a local edit\n * until the server sends it back (`@y/websocket`'s `syncStatus.localUpdatesSynced`; yhub echoes\n * every update to its sender). Kept across reconnects and re-mints: a replaced provider hands its\n * unconfirmed edits to the next, and an edit made between providers waits for one. A host that\n * closes the document while this is `false` loses those edits, unless a local copy keeps them.\n */\n readonly localChangesSynced: boolean;\n /** Granted access from the last successful mint. */\n readonly accessType: 'r' | 'rw' | null;\n /** Terminal error, when status is 'error' or 'closed'. */\n readonly error: Error | null;\n /**\n * Whether the document holds what the host's local copy stored (always `true` without one).\n * Mount readers after it: until then the document is still empty.\n */\n readonly prepared: boolean;\n /** Whether this host allows a live connection. Disabled documents remain editable locally. */\n readonly connectionEnabled: boolean;\n /**\n * A connection the host's `beforeConnect` held: the handle waits, sending nothing, until the\n * host calls `resume()` (or destroys the handle).\n */\n readonly held: boolean;\n /** Monotonic change counter — bumps on every status/presence notification. */\n readonly version: number;\n /**\n * Resolve once the initial server sync completes; reject on timeout, on a\n * terminal connection state, or if the handle is destroyed first.\n */\n waitForSync: (timeoutMs?: number) => Promise<void>;\n /**\n * Resolve once connected, initially synced, and every local change has been acknowledged,\n * including any edits the local-copy hook restores after sync. The host must prevent further\n * editing while saving a checkpoint. Reject on timeout, a disabled connection, or a terminal state.\n */\n waitForAcknowledged: (timeoutMs?: number) => Promise<void>;\n getPresence: () => PresenceEntry[];\n /** Broadcast this client's presence state (requires a live connection). */\n setPresence: (state: Record<string, unknown> | null) => void;\n /**\n * Force an early token refresh. Session-preserving: the live connection\n * stays up until the fresh token is minted; a failed mint retries on a\n * short timer instead of dropping the session. Without a connection it\n * reconnects now.\n */\n refreshNow: () => Promise<void>;\n /**\n * Asks for a grant now, reconnecting only when it edits: the host has reason to think the person\n * may edit again (their access rose while the document was open). A live socket hears of a\n * widening itself: Keryx closes a read-only socket of someone Agora lets edit again (4401) and the\n * handle re-mints. This is for what that signal misses: a room held with no socket, or an older\n * Keryx. A grant that edits reconnects the live room with it, or asks the host's\n * `beforeConnect` again for a room it held on a grant that only read; a grant that still only\n * reads changes nothing. One at a time. Resolves `true` when the room was handed a\n * grant that edits (a held room's `beforeConnect` still decides), `false` when the mint failed or\n * was refused, the grant still only reads, or the room is neither live nor held on a grant that\n * only read (a room on its way back mints its own).\n */\n refreshGrant: () => Promise<boolean>;\n /**\n * Disable all connections without losing the document or its pending edits. Enabling mints a\n * fresh grant and runs the host's beforeConnect gate; it never bypasses a permission or review.\n */\n setConnectionEnabled: (enabled: boolean) => void;\n /** Connect past a hold, without asking `beforeConnect` again. */\n resume: () => void;\n /** Local edits the server has not echoed yet (handed between providers too), or `null`. */\n unconfirmedEdits: () => Y.ContentIds | null;\n /**\n * Keryx's document status, as last read with the room's grant, says the room takes no writes for\n * now: it is quarantined while it is repaired, and its socket drops every edit unconfirmed until\n * it is released. Always `false` without `readDocumentStatus`, on a read-only grant, and whenever\n * the last read could not answer.\n */\n readonly writesRefused: boolean;\n /**\n * The update the room's HTTP-first read applied, handed over once (`keepHttpFirstRead`): the\n * document's whole state as Keryx served it, so an engine that hydrates from the document can take\n * these bytes instead of encoding the document again. `null` without `keepHttpFirstRead`, when the\n * room read nothing that way (a document its local copy filled, a Keryx that does not answer), once\n * taken, and once the document has changed since the read (a peer's edit, a local one, the socket's\n * sync), when the document itself is the only complete source. Optional: a host's own handle (a\n * relayed document, a test's) keeps none.\n */\n takeHttpFirstRead?: () => Uint8Array | null;\n onChange: (listener: () => void) => () => void;\n destroy: () => void;\n}\n\n/**\n * Issues a room-bound Keryx token for one asset. The default calls the public\n * `/collab-token` route with the handle's `auth`; a host with its own trusted\n * mint (a desktop app's main process holding the user's key) passes one\n * instead, and the handle uses it for the first mint and every re-mint.\n */\nexport type CollabMint = (params: {\n assetId: string;\n access: 'view' | 'edit';\n}) => Promise<CollabTokenResponse>;\n\n/** What a host's local copy reads of the handle's transport. */\nexport interface GenericDocTransportView {\n /** True for a transaction the transport applied (the server's state, a peer's edit). */\n isRemoteOrigin: (origin: unknown) => boolean;\n /** Local edits the server has not echoed yet, or `null`. */\n getUnconfirmed: () => Y.ContentIds | null;\n /** Connected, past the initial sync, and nothing unconfirmed. */\n isFullySynced: () => boolean;\n}\n\n/** What `beforeConnect` is asked about. */\nexport interface GenericDocConnectGate {\n /** The grant the connection would use (its access is the server's current verdict). */\n grant: CollabTokenResponse;\n /** The handle has not connected yet. */\n firstConnection: boolean;\n /** How long the handle had been without a connection, when it had one before. */\n offlineForMs: number | null;\n /** Local edits made without a connection (or inherited from an earlier session) wait to be sent. */\n hasUnsyncedEdits: boolean;\n /**\n * The connection follows Keryx's re-check of the room's grant (it closed the live socket with\n * 4401: a share narrowed or removed, a quarantine or its release), not an outage: whatever the\n * grant says now changed while the document was connected and open. Absent otherwise.\n */\n accessRechecked?: boolean;\n}\n\n/** A host's local copy of the document (`@athenaintel/local-copy` behind a host's glue). */\nexport interface GenericDocLocalCopy {\n /**\n * Called once, before the first mint: apply the stored copy to `doc` and return the local edits\n * it holds that the server never acknowledged. The handle sends them and waits for their echo\n * like its own. A failure here must resolve `{ unsyncedEdits: null }`: the handle then runs\n * without a copy.\n */\n prepare: (params: {\n doc: Y.Doc;\n transport: GenericDocTransportView;\n }) => Promise<{ unsyncedEdits: Y.ContentIds | null }>;\n /** The handle's unconfirmed edits or sync state changed. */\n transportChanged: () => void;\n /**\n * An explicit host pause/resume policy changed. Invalidate decisions that must be checked afresh\n * before a later manual save. A pause runs after its provider is destroyed and its status is\n * disconnected, so edits restored by the hook stay local. A resume runs before minting.\n * Network retries and an immediate conflict `resume()` do not call it.\n */\n connectionPolicyChanged?: (enabled: boolean) => void;\n /**\n * Asked after each mint and before the connection it would open: the first connection, a\n * reconnect after an outage longer than `offlineGateAfterMs`, and a re-mint after a revocation\n * (never a scheduled token refresh of a live connection, never past `resume()`). The host\n * checks what it must before anything is sent (the document still opens here; access; edits\n * made without a connection against the server's). `'hold'` keeps the handle from connecting\n * until `resume()`; a throw counts as \"not yet\" and is asked again on the next attempt.\n */\n beforeConnect?: (gate: GenericDocConnectGate) => Promise<'connect' | 'hold'>;\n}\n\n/** After this long without a socket, the handle reconnects itself (re-mint, gate) instead of the provider. */\nexport const DEFAULT_OFFLINE_GATE_AFTER_MS = 15_000;\n\n/** Retry delays for a mint that failed for want of the network. */\nconst MINT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 15_000, 30_000, 60_000];\n\n/**\n * The default `retryMintError`: a network failure, a timeout, a rate limit or a server error is\n * worth retrying; a refusal (401/403/404) is the server's verdict and ends the handle.\n */\nexport function isRetryableMintError(error: unknown): boolean {\n if (error instanceof CollabTokenError) {\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n return error instanceof TypeError || (error instanceof DOMException && error.name === 'TimeoutError');\n}\n\nfunction resolveMint({ auth, mint }: { auth?: CollabAuth; mint?: CollabMint }): CollabMint {\n if (mint) return mint;\n if (!auth) throw new Error('connectGenericDoc needs `auth` or `mint`');\n return ({ assetId, access }) => mintCollabToken({ auth, assetId, access });\n}\n\n/**\n * The socket a provider for `grant` opens (`@athenaintel/keryx-http`'s wrappers, the ones\n * Olympus's rooms use). On a read-write grant, each sync update a write made inside a\n * `runWithDocUpdateAttributions` scope for `doc` sends carries the scope's attributions, which\n * Keryx reads after the update (`origin: background` counts as system work; a Keryx that predates\n * the trailer ignores it), and its sync step 2 goes out behind such writes made while no socket\n * was open, each as its own marked update (`unconfirmed`). On a read-only grant no frame that\n * carries document content leaves: a sync step 2 or an update is dropped (Keryx ignores them on\n * such a grant anyway), awareness passes. Read when each provider is built, as `@y/websocket` reads\n * `WebSocket`; `undefined` where there is none, and the provider fails at connect as it always did.\n */\nfunction socketFor({\n grant,\n doc,\n unconfirmed,\n}: {\n grant: CollabTokenResponse;\n doc: Y.Doc;\n unconfirmed: UnconfirmedUpdateAttributions;\n}): typeof WebSocket | undefined {\n const Base: typeof WebSocket | undefined = globalThis.WebSocket;\n if (typeof Base !== 'function') return undefined;\n if (grant.access_type === 'r') return receiveOnlyWebSocket({ Base });\n return attributingWebSocket({\n Base,\n attributionsFor: () => docUpdateAttributions(doc),\n unconfirmed,\n });\n}\n\n/** How an HTTP-first read went (`connectGenericDoc`'s `httpFirstOpen`). */\nexport interface GenericDocHttpFirstOpenEvent {\n /**\n * `read`: read over HTTP and applied; the socket asks for the diff. `unsupported`: Keryx answered\n * without saying it answers a socket's sync step 1; its document was not used. `failed`: the read\n * failed (`error` says why). `skipped`: Keryx is known not to answer, so nothing was read.\n * `aborted`: the room replaced or closed the provider during the read, which it stopped.\n */\n outcome: 'read' | 'unsupported' | 'failed' | 'skipped' | 'aborted';\n /** The decoded body's size (`read`, `unsupported`). */\n bytes?: number;\n /** From the request to the socket's connect. */\n durationMs: number;\n /** Why the read failed (`failed`): the error's name and message. */\n error?: string;\n}\n\n/** `localStorage`, when the host has one (a browser, Electron's renderer, the phone's editor page). */\nfunction browserStorage(): InitialSyncSupportStorage | null {\n try {\n return typeof window !== 'undefined' && window.localStorage ? window.localStorage : null;\n } catch {\n return null;\n }\n}\n\nexport function connectGenericDoc(args: {\n assetId: string;\n /** Credentials for the default mint; not used when `mint` is given. */\n auth?: CollabAuth;\n access?: 'view' | 'edit';\n mint?: CollabMint;\n /** A local copy of the document the host keeps (see {@link GenericDocLocalCopy}). */\n localCopy?: GenericDocLocalCopy;\n /** Whether a failed mint is worth retrying; defaults to {@link isRetryableMintError}. */\n retryMintError?: (error: unknown) => boolean;\n /** See {@link DEFAULT_OFFLINE_GATE_AFTER_MS}. */\n offlineGateAfterMs?: number;\n /** Start without connecting or minting (for a host's manual-save mode). Defaults to true. */\n connectionEnabled?: boolean;\n /**\n * Reads Keryx's document status with the room's grant (see `ReadDocumentStatus`), for\n * `handle.writesRefused`. A host that cannot read it leaves it out.\n */\n readDocumentStatus?: ReadDocumentStatus;\n /**\n * Open the room HTTP-first (Word at scale), as Olympus opens a Word room: a document that holds\n * nothing yet is read over `GET /ydoc` (compressed, decoded as it downloads), applied as Keryx's\n * own state, and the socket asks Keryx for only what it still lacks (`?initialSync=diff`) - when\n * Keryx says it answers that way (`@athenaintel/keryx-http/initial-sync`). Which later sockets ask\n * for the diff too is `diffedInitialSync`'s choice. A read whose bytes keep coming runs on; one\n * that receives nothing for a minute is given up for the socket's whole-document sync. For rooms\n * whose documents can be large (Word documents, decks).\n */\n httpFirstOpen?: boolean;\n /**\n * With `httpFirstOpen`: which sockets ask for the diff (`DiffedInitialSync`). `every-socket` (the\n * default, a Word document's room): every socket while Keryx is known to answer and the room holds\n * no write Keryx has not echoed. `after-read` (a deck's room): only the socket that follows the\n * room's own read.\n */\n diffedInitialSync?: DiffedInitialSync;\n /** Hears how each HTTP-first read went (`httpFirstOpen`), for the host's telemetry. */\n onHttpFirstOpen?: (event: GenericDocHttpFirstOpenEvent) => void;\n /**\n * With `httpFirstOpen`: keep the update the room's read applied to an empty document until\n * `takeHttpFirstRead()` takes it or the document changes (a workbook's room: the sheet engine\n * hydrates from those bytes instead of a full re-encode of the document).\n */\n keepHttpFirstRead?: boolean;\n}): GenericDocHandle {\n const access = args.access ?? 'view';\n const mint = resolveMint({ auth: args.auth, mint: args.mint });\n const localCopy = args.localCopy;\n const retryMintError = args.retryMintError ?? isRetryableMintError;\n const offlineGateAfterMs = args.offlineGateAfterMs ?? DEFAULT_OFFLINE_GATE_AFTER_MS;\n const doc = new Y.Doc();\n // Writes made in a `runWithDocUpdateAttributions` scope, until Keryx acknowledges them: the\n // sockets every provider opens send those made while no socket was open ahead of their sync.\n const unconfirmedAttributions = new UnconfirmedUpdateAttributions({\n doc,\n attributionsFor: () => docUpdateAttributions(doc),\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n });\n const listeners = new Set<() => void>();\n\n let provider: WebsocketProvider | null = null;\n let refreshTimer: ReturnType<typeof setTimeout> | null = null;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n let offlineTimer: ReturnType<typeof setTimeout> | null = null;\n /** The provider whose socket was still opening, with nothing to send, at the threshold. */\n let openingPastThreshold: WebsocketProvider | null = null;\n let mintRetries = 0;\n let destroyed = false;\n let connectionEnabled = args.connectionEnabled ?? true;\n let status: GenericDocStatus = connectionEnabled ? 'connecting' : 'disconnected';\n let synced = false;\n let accessType: 'r' | 'rw' | null = null;\n let error: Error | null = null;\n let lastPresence: Record<string, unknown> | null = null;\n let version = 0;\n let consecutiveRemints = 0;\n let prepared = localCopy === undefined;\n let held = false;\n let heldGrant: CollabTokenResponse | null = null;\n let everConnected = false;\n let disconnectedSince: number | null = null;\n /** Bumped by every connect attempt: an attempt that finds it changed after an await stops. */\n let connectSeq = 0;\n /** Local edits no provider holds: handed on by a replaced provider, or made with none. */\n let carriedUpdates: WebsocketProvider['unconfirmedUpdates'] = [];\n let localChangesSynced = true;\n /** The grant the current provider connects with. */\n let liveGrant: CollabTokenResponse | null = null;\n /** Keryx's auth re-check closed the socket (4401): the next connection reads the document status. */\n let readStatusOnConnect = false;\n /**\n * Keryx's auth re-check closed the socket (4401): the gate asked before the next connection hears\n * that the grant changed while the document was connected (`accessRechecked`), until it answers.\n */\n let accessRecheckPending = false;\n /** This room saw its Keryx say it answers a socket's sync step 1 (its HTTP-first read). */\n let keryxAnswersSyncStep1 = false;\n /**\n * The HTTP-first read of a provider's document, while it runs: that provider is opening, and\n * replacing it (a re-mint, the offline takeover, `setConnectionEnabled(false)`, `destroy()`) stops\n * the download.\n */\n let httpFirstRead: { target: WebsocketProvider; controller: AbortController } | null = null;\n /** See `takeHttpFirstRead` (`keepHttpFirstRead`). */\n let keptHttpFirstRead: Uint8Array | null = null;\n /** The read's own update is being applied: the one document change that keeps `keptHttpFirstRead`. */\n let applyingHttpFirstRead = false;\n\n const notify = () => {\n version += 1;\n for (const listener of listeners) listener();\n };\n\n const documentStatus = args.readDocumentStatus\n ? watchDocumentStatus({\n read: args.readDocumentStatus,\n currentGrant: () => liveGrant,\n onChange: () => {\n if (!destroyed) notify();\n },\n })\n : null;\n\n const unconfirmedEdits = (): Y.ContentIds | null => {\n const all = [...carriedUpdates, ...(provider?.unconfirmedUpdates ?? [])].map(\n (entry) => entry.ids as Y.ContentIds\n );\n if (all.length === 0) return null;\n return all.length === 1 ? (all[0] as Y.ContentIds) : Y.mergeContentIds(all);\n };\n\n const transport: GenericDocTransportView = {\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n getUnconfirmed: unconfirmedEdits,\n isFullySynced: () => status === 'connected' && synced && localChangesSynced,\n };\n\n const transportChanged = () => {\n localCopy?.transportChanged();\n };\n\n const refreshLocalChangesSynced = () => {\n const next = carriedUpdates.length === 0 && (provider?.unconfirmedUpdates.length ?? 0) === 0;\n const changed = next !== localChangesSynced;\n localChangesSynced = next;\n documentStatus?.unconfirmedChanged(!next);\n // After the flag: the copy reads `isFullySynced()` in its callback.\n // Before notifying: the callback can restore values and create more unconfirmed edits.\n transportChanged();\n if (changed) notify();\n };\n\n // Any change but the read's own leaves the kept read short of the document's whole state.\n doc.on('update', () => {\n if (!applyingHttpFirstRead) keptHttpFirstRead = null;\n });\n\n // An edit made while no provider exists (a re-mint in flight, offline) is sent by the next one,\n // which takes it as unconfirmed. The local copy's own load is not an edit.\n doc.on('update', (update: Uint8Array, origin: unknown) => {\n if (!prepared || provider !== null || destroyed || origin instanceof WebsocketProvider) return;\n carriedUpdates = [\n ...carriedUpdates,\n { created: Date.now(), ids: Y.createContentIdsFromUpdate(update) },\n ];\n refreshLocalChangesSynced();\n });\n\n const setStatus = (next: GenericDocStatus, err: Error | null = null) => {\n if (destroyed && next !== 'closed') return;\n const wasConnected = status === 'connected';\n status = next;\n error = err;\n if (next === 'connected') {\n everConnected = true;\n disconnectedSince = null;\n clearOfflineTimer();\n } else {\n if (wasConnected || (everConnected && disconnectedSince === null)) {\n disconnectedSince = Date.now();\n }\n documentStatus?.disconnected();\n }\n transportChanged();\n notify();\n };\n\n const clearRefreshTimer = () => {\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer);\n refreshTimer = null;\n }\n };\n\n const clearRetryTimer = () => {\n if (retryTimer !== null) {\n clearTimeout(retryTimer);\n retryTimer = null;\n }\n };\n\n function clearOfflineTimer() {\n if (offlineTimer !== null) {\n clearTimeout(offlineTimer);\n offlineTimer = null;\n }\n }\n\n const teardownProvider = () => {\n clearRefreshTimer();\n // A future provider must complete its own initial sync; the doc keeps its\n // content either way. Subscribers must observe the flip immediately —\n // waiting for the next provider event would let them act on synced=true\n // across the replacement gap.\n if (synced) {\n synced = false;\n notify();\n }\n if (provider) {\n // Its unconfirmed edits outlive it: the next provider sends them and waits for their echo.\n const previous = provider;\n provider = null;\n if (httpFirstRead?.target === previous) {\n httpFirstRead.controller.abort(new DOMException('The room closed', 'AbortError'));\n httpFirstRead = null;\n }\n carriedUpdates = [...carriedUpdates, ...previous.unconfirmedUpdates];\n previous.destroy();\n }\n };\n\n const scheduleRefresh = (grant: CollabTokenResponse) => {\n clearRefreshTimer();\n const delay = refreshDelayMs({ expiresAtMs: grant.expires_at_ms, now: Date.now() });\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, delay);\n };\n\n /** A failed attempt that is worth retrying: try again later, or as soon as the network returns. */\n const scheduleRetry = () => {\n clearRetryTimer();\n const delay = MINT_RETRY_DELAYS_MS[Math.min(mintRetries, MINT_RETRY_DELAYS_MS.length - 1)];\n mintRetries += 1;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void connect();\n }, delay);\n };\n\n const onBrowserOnline = () => {\n // Only a handle waiting to retry: a refused or permanently closed one stays stopped.\n if (\n destroyed || !connectionEnabled || status === 'closed' || status === 'error' ||\n provider !== null || held\n ) return;\n mintRetries = 0;\n clearRetryTimer();\n void connect();\n };\n if (typeof window !== 'undefined') window.addEventListener('online', onBrowserOnline);\n\n /**\n * Past the gate's threshold without a socket, the handle reconnects itself (re-mint, gate). A\n * socket still being opened with nothing waiting to be sent is left to finish (a slow network\n * is not restarted every threshold), and the handle looks again a threshold later; if it opens\n * holding edits made since, they go through the gate first (`status`).\n */\n const armOfflineTakeover = () => {\n if (!connectionEnabled || offlineTimer !== null || !localCopy?.beforeConnect) return;\n offlineTimer = setTimeout(() => {\n offlineTimer = null;\n if (destroyed || !connectionEnabled || status === 'connected' || provider === null) return;\n // A provider reading its document over HTTP first is opening too (a long report, a slow link)\n if ((provider.wsconnecting || httpFirstRead?.target === provider) && !hasUnsyncedLocalEdits()) {\n openingPastThreshold = provider;\n armOfflineTakeover();\n return;\n }\n teardownProvider();\n void connect();\n }, offlineGateAfterMs);\n };\n\n const hasUnsyncedLocalEdits = () =>\n carriedUpdates.length > 0 || (provider?.unconfirmedUpdates.length ?? 0) > 0;\n\n\n const connect = async (opts?: {\n scheduledRefresh?: boolean;\n skipGate?: boolean;\n grant?: CollabTokenResponse;\n }): Promise<void> => {\n if (destroyed || !connectionEnabled) return;\n const seq = ++connectSeq;\n await preparing;\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n // Only a live connection is refreshed in place (and skips the host's gate); a refresh while the\n // socket is down is a reconnect like any other.\n const scheduledRefresh = opts?.scheduledRefresh === true && status === 'connected';\n // A scheduled refresh mints FIRST and keeps the live session up: the old\n // token has ~5 minutes of headroom, so a transient mint failure retries\n // on a short timer instead of dropping a healthy connection.\n if (!scheduledRefresh) {\n teardownProvider();\n } else {\n clearRefreshTimer();\n }\n clearRetryTimer();\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n let grant: CollabTokenResponse;\n if (opts?.grant && opts.grant.expires_at_ms - Date.now() > MIN_REFRESH_DELAY_MS) {\n grant = opts.grant;\n } else {\n try {\n grant = await mint({ assetId: args.assetId, access });\n } catch (err) {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (scheduledRefresh) {\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, MIN_REFRESH_DELAY_MS);\n return;\n }\n if (retryMintError(err)) {\n // Offline (or the mint's server is): keep the document and try again.\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n // A denied mint is authoritative (revoked / not shared / not eligible).\n setStatus('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n mintRetries = 0;\n accessType = grant.access_type;\n const beforeConnect = localCopy?.beforeConnect;\n if (beforeConnect && !scheduledRefresh && !opts?.skipGate) {\n const firstConnection = !everConnected;\n const offlineForMs = disconnectedSince === null ? null : Date.now() - disconnectedSince;\n let decision: 'connect' | 'hold';\n try {\n decision = await beforeConnect({\n grant,\n firstConnection,\n offlineForMs,\n hasUnsyncedEdits: hasUnsyncedLocalEdits(),\n ...(accessRecheckPending ? { accessRechecked: true } : {}),\n });\n } catch {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n accessRecheckPending = false;\n if (decision === 'hold') {\n held = true;\n heldGrant = grant;\n if (status !== 'disconnected') setStatus('disconnected');\n else notify();\n return;\n }\n }\n if (scheduledRefresh) {\n teardownProvider();\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n\n const socket = socketFor({ grant, doc, unconfirmed: unconfirmedAttributions });\n const roomUrl = `${grant.ws_url}/${grant.org}/${grant.doc_id}`;\n // Word at scale: a document that holds nothing yet is read over HTTP first, then the socket connects\n const httpFirstUrl =\n args.httpFirstOpen === true && doc.store.clients.size === 0 && carriedUpdates.length === 0\n ? keryxRoomReadUrl({ wsUrl: roomUrl, token: grant.token, branch: grant.branch })\n : null;\n const params: Record<string, string> = {\n yauth: grant.token,\n branch: grant.branch,\n gc: 'true',\n };\n if (httpFirstUrl === null && asksForDiffedSync({ roomUrl, unconfirmed: carriedUpdates.length })) {\n params[INITIAL_SYNC_PARAM] = INITIAL_SYNC_DIFF;\n }\n const nextProvider = new WebsocketProvider(grant.ws_url, `${grant.org}/${grant.doc_id}`, doc, {\n params,\n // BroadcastChannel would sync same-origin clients locally, bypassing the\n // server's permission enforcement (a read-only tab could write into an\n // editor tab's doc). Permissioned docs must round-trip the server.\n disableBc: true,\n connect: httpFirstUrl === null,\n ...(socket && { WebSocketPolyfill: socket }),\n });\n publishOwnAwarenessOnly({ transport: nextProvider });\n provider = nextProvider;\n liveGrant = grant;\n nextProvider.unconfirmedUpdates = [...carriedUpdates, ...nextProvider.unconfirmedUpdates];\n carriedUpdates = [];\n refreshLocalChangesSynced();\n\n nextProvider.on('sync-status', () => {\n if (provider !== nextProvider) return;\n refreshLocalChangesSynced();\n });\n\n nextProvider.on('status', (event: { status: 'connecting' | 'connected' | 'disconnected' }) => {\n if (provider !== nextProvider) return;\n if (\n event.status === 'connected' &&\n openingPastThreshold === nextProvider &&\n hasUnsyncedLocalEdits()\n ) {\n // Opened after the threshold holding edits made meanwhile: before its handshake sends\n // them (`@y/websocket` reports `connected` first), they go through the gate.\n teardownProvider();\n void connect();\n return;\n }\n // The connections that read Keryx's document status at once: the first, the one after an auth\n // re-check close, and one after an outage the handle treats as real. Never an ordinary\n // reconnect (a Keryx deploy reconnects every room at once).\n const readStatusNow =\n event.status === 'connected' &&\n (!everConnected ||\n readStatusOnConnect ||\n (disconnectedSince !== null && Date.now() - disconnectedSince >= offlineGateAfterMs));\n if (event.status === 'connected') {\n consecutiveRemints = 0;\n readStatusOnConnect = false;\n accessRecheckPending = false;\n }\n setStatus(event.status);\n if (event.status === 'connected') documentStatus?.connected({ readNow: readStatusNow });\n if (event.status === 'connected' && lastPresence !== null) {\n nextProvider.awareness.setLocalState(lastPresence);\n }\n // `@y/websocket` reports `disconnected` only for a socket that had opened: one that never\n // opens (the server unreachable while the mint goes through) only ever reports `connecting`,\n // and is just as offline.\n if (event.status !== 'connected') armOfflineTakeover();\n });\n // Its first `connecting` came from its constructor, before this listener existed.\n if (!nextProvider.wsconnected) armOfflineTakeover();\n\n nextProvider.on('sync', (state: boolean) => {\n if (provider !== nextProvider) return;\n if (synced !== state) {\n synced = state;\n transportChanged();\n notify();\n }\n });\n\n nextProvider.on('connection-close', (event: CloseEvent | null) => {\n if (provider !== nextProvider) return;\n // The next socket asks for a diffed initial sync only while nothing it holds needs Keryx's whole document\n if (asksForDiffedSync({ roomUrl, unconfirmed: nextProvider.unconfirmedUpdates.length })) {\n nextProvider.params[INITIAL_SYNC_PARAM] = INITIAL_SYNC_DIFF;\n } else {\n delete nextProvider.params[INITIAL_SYNC_PARAM];\n }\n const action = classifyClose(event?.code);\n if (action === 'remint') {\n // Revoked mid-session: a fresh mint re-runs the server-side permission\n // check. If access is truly gone the mint 403s and we land in 'error'.\n // Bounded: repeated 4401s without an intervening successful connect\n // mean the server keeps rejecting freshly minted tokens — stop rather\n // than loop mint→connect→kick.\n consecutiveRemints += 1;\n // A quarantine and a release both close the room's sockets this way, once Keryx has written\n // or cleared the marker: the reconnected socket learns which. Until then nothing is read\n // (the handle stays `connected` through the re-mint, on a grant Keryx just bounced).\n readStatusOnConnect = true;\n // The host's gate hears that the grant changed while the document was open: a view-only\n // grant now holds the edits it never sent, in words that don't blame being offline.\n accessRecheckPending = true;\n documentStatus?.disconnected();\n teardownProvider();\n if (consecutiveRemints > MAX_CONSECUTIVE_REMINTS) {\n setStatus(\n 'closed',\n new Error('Access repeatedly revoked mid-session (4401); giving up.')\n );\n return;\n }\n void connect();\n } else if (action === 'stop') {\n teardownProvider();\n setStatus(\n 'closed',\n new Error(`Connection closed permanently (code ${event?.code ?? 'unknown'})`)\n );\n }\n // 'retry': the provider's exponential backoff handles it, until the offline takeover.\n });\n\n nextProvider.awareness.on('change', () => {\n if (provider !== nextProvider) return;\n notify();\n });\n\n scheduleRefresh(grant);\n if (httpFirstUrl !== null) void openOverHttp({ target: nextProvider, url: httpFirstUrl, roomUrl });\n };\n\n /**\n * Word at scale: whether a socket of this room asks for a diffed initial sync - a room that opens\n * HTTP-first, whose Keryx is known to answer it, whose document holds something, and that holds no\n * write Keryx may hold without having echoed it (an unconfirmed update, a kept attributed write):\n * those are confirmed by the whole document Keryx sends when a socket opens. A deck's room\n * (`diffedInitialSync: 'after-read'`) asks only on the socket that follows its own read\n * (`afterRead`).\n */\n function asksForDiffedSync({\n roomUrl,\n unconfirmed,\n afterRead = false,\n }: {\n roomUrl: string;\n unconfirmed: number;\n afterRead?: boolean;\n }): boolean {\n if (args.httpFirstOpen !== true) return false;\n if (args.diffedInitialSync === 'after-read' && !afterRead) return false;\n const origin = keryxOriginOf(roomUrl);\n const known =\n keryxAnswersSyncStep1 ||\n (origin !== null && knownInitialSyncSupport({ storage: browserStorage(), origin }) === true);\n return known && doc.store.clients.size > 0 && unconfirmed === 0 && !unconfirmedAttributions.keepsWrites;\n }\n\n /**\n * Word at scale: read the room over HTTP, apply it as Keryx's own state (the provider's origin, so\n * nothing treats it as a local edit), then connect the provider's socket, asking for the diff when\n * Keryx said it answers that way. A Keryx that did not, a failed read, or a provider replaced\n * meanwhile: the document is left as it was and the socket connects as every room's does.\n */\n async function openOverHttp({\n target,\n url,\n roomUrl,\n }: {\n target: WebsocketProvider;\n url: string;\n roomUrl: string;\n }): Promise<void> {\n const started = performance.now();\n const origin = keryxOriginOf(roomUrl);\n const storage = browserStorage();\n let event: GenericDocHttpFirstOpenEvent;\n // The read landed and the document holds Keryx's state from it: the socket after it may ask\n let applied = false;\n if (origin !== null && knownInitialSyncSupport({ storage, origin }) === false) {\n event = { outcome: 'skipped', durationMs: 0 };\n } else {\n const controller = new AbortController();\n httpFirstRead = { target, controller };\n const timeout = setTimeout(\n () => controller.abort(new DOMException('The HTTP-first read timed out', 'TimeoutError')),\n HTTP_FIRST_READ_TIMEOUT_MS\n );\n try {\n // A read still downloading runs on (a large deck on a slow link); one that receives nothing\n // for the idle timeout is given up and the socket syncs instead.\n const read = await readRoomOverHttp({\n url,\n signal: controller.signal,\n idleTimeoutMs: HTTP_FIRST_READ_IDLE_TIMEOUT_MS,\n });\n if (origin !== null) rememberInitialSyncSupport({ storage, origin, supported: read.answersSyncStep1 });\n if (read.answersSyncStep1 && provider === target && !destroyed) {\n if (read.update.byteLength > 2) applyHttpFirstRead({ update: read.update, target });\n keryxAnswersSyncStep1 = true;\n applied = true;\n }\n event = {\n outcome: read.answersSyncStep1 ? 'read' : 'unsupported',\n bytes: read.bytes,\n durationMs: performance.now() - started,\n };\n } catch (err) {\n // the socket's whole-document sync, as before; a read the room stopped is no failure\n event =\n controller.signal.aborted && (destroyed || provider !== target)\n ? { outcome: 'aborted', durationMs: performance.now() - started }\n : {\n outcome: 'failed',\n durationMs: performance.now() - started,\n error: err instanceof Error ? `${err.name}: ${err.message}` : String(err),\n };\n } finally {\n clearTimeout(timeout);\n if (httpFirstRead?.controller === controller) httpFirstRead = null;\n }\n }\n try {\n args.onHttpFirstOpen?.(event);\n } catch {\n // a host's telemetry never keeps the room from opening its socket\n }\n if (destroyed || provider !== target) return;\n if (asksForDiffedSync({ roomUrl, unconfirmed: target.unconfirmedUpdates.length, afterRead: applied })) {\n target.params[INITIAL_SYNC_PARAM] = INITIAL_SYNC_DIFF;\n } else {\n delete target.params[INITIAL_SYNC_PARAM];\n }\n target.connect();\n }\n\n /**\n * Applies the read's update as Keryx's own state (the provider's origin). With `keepHttpFirstRead`\n * the update is kept from before the apply, so a listener of the document's `update` event can\n * already take it, and only when the document held nothing: the kept update is then its whole state.\n */\n function applyHttpFirstRead({\n update,\n target,\n }: {\n update: Uint8Array;\n target: WebsocketProvider;\n }): void {\n if (args.keepHttpFirstRead === true && doc.store.clients.size === 0) keptHttpFirstRead = update;\n applyingHttpFirstRead = true;\n try {\n Y.applyUpdate(doc, update, target);\n } finally {\n applyingHttpFirstRead = false;\n }\n }\n\n const preparing: Promise<void> = localCopy\n ? localCopy\n .prepare({ doc, transport })\n .catch(() => ({ unsyncedEdits: null }))\n .then(({ unsyncedEdits }) => {\n if (destroyed) return;\n if (unsyncedEdits && !(unsyncedEdits.inserts.isEmpty() && unsyncedEdits.deletes.isEmpty())) {\n carriedUpdates = [...carriedUpdates, { created: Date.now(), ids: unsyncedEdits }];\n }\n prepared = true;\n refreshLocalChangesSynced();\n notify();\n })\n : Promise.resolve();\n\n void connect();\n\n const waitForSync = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n const terminal = (): Error | null => {\n if (destroyed) return new Error('Handle destroyed before initial sync');\n if (status === 'closed' || status === 'error') {\n return error ?? new Error(`Connection ${status} before initial sync`);\n }\n return null;\n };\n if (synced) {\n resolve();\n return;\n }\n const immediate = terminal();\n if (immediate) {\n reject(immediate);\n return;\n }\n const cleanup = () => {\n clearTimeout(timer);\n listeners.delete(listener);\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`Timed out after ${timeoutMs}ms waiting for initial sync`));\n }, timeoutMs);\n const listener = () => {\n if (synced) {\n cleanup();\n resolve();\n return;\n }\n const err = terminal();\n if (err) {\n cleanup();\n reject(err);\n }\n };\n listeners.add(listener);\n });\n\n const waitForAcknowledged = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n let finished = false;\n let checkQueued = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const finish = (failure?: Error) => {\n if (finished) return;\n finished = true;\n if (timer !== null) clearTimeout(timer);\n listeners.delete(check);\n if (failure) reject(failure);\n else resolve();\n };\n const check = () => {\n if (finished || checkQueued) return;\n checkQueued = true;\n // All synchronous transport hooks and change listeners finish before a save settles.\n queueMicrotask(() => {\n checkQueued = false;\n if (finished) return;\n if (destroyed) {\n finish(new Error('Handle destroyed before local changes were acknowledged'));\n } else if (!connectionEnabled) {\n finish(new Error('Connection disabled before local changes were acknowledged'));\n } else if (status === 'closed' || status === 'error') {\n finish(error ?? new Error(`Connection ${status} before local changes were acknowledged`));\n } else if (prepared && status === 'connected' && synced && localChangesSynced) {\n finish();\n }\n });\n };\n timer = setTimeout(() => {\n finish(new Error(`Timed out after ${timeoutMs}ms waiting for local changes to be acknowledged`));\n }, timeoutMs);\n listeners.add(check);\n check();\n });\n\n /** A grant asked for by `refreshGrant`, while it runs. */\n let grantRefresh: Promise<boolean> | null = null;\n const askForGrant = async (): Promise<boolean> => {\n try {\n const grant = await mint({ assetId: args.assetId, access });\n if (destroyed || !connectionEnabled || grant.access_type !== 'rw') return false;\n if (held) {\n // Held meanwhile on a grant that edits (an overlap to review): the host's decision stands.\n if (heldGrant?.access_type !== 'r') return false;\n held = false;\n heldGrant = null;\n notify();\n void connect({ grant });\n return true;\n }\n if (status !== 'connected') return false;\n if (accessType === 'rw') return true;\n // Keryx reads a socket's grant when it opens: the live room reconnects on the new one.\n void connect({ scheduledRefresh: true, grant });\n return true;\n } catch {\n return false;\n }\n };\n const refreshGrant = (): Promise<boolean> => {\n if (destroyed || !connectionEnabled) return Promise.resolve(false);\n if (grantRefresh) return grantRefresh;\n const heldOnRead = held && heldGrant?.access_type === 'r';\n // A room on its way back mints its own grant; one live on a grant that edits needs none.\n if (!heldOnRead && status !== 'connected') return Promise.resolve(false);\n if (!heldOnRead && accessType === 'rw') return Promise.resolve(true);\n const asked = askForGrant().finally(() => {\n grantRefresh = null;\n });\n grantRefresh = asked;\n return asked;\n };\n\n return {\n doc,\n get status() {\n return status;\n },\n get synced() {\n return synced;\n },\n get localChangesSynced() {\n return localChangesSynced;\n },\n get accessType() {\n return accessType;\n },\n get error() {\n return error;\n },\n get prepared() {\n return prepared;\n },\n get connectionEnabled() {\n return connectionEnabled;\n },\n get held() {\n return held;\n },\n get version() {\n return version;\n },\n get writesRefused() {\n return documentStatus?.writesRefused ?? false;\n },\n takeHttpFirstRead: () => {\n const kept = keptHttpFirstRead;\n keptHttpFirstRead = null;\n return kept;\n },\n waitForSync,\n waitForAcknowledged,\n getPresence: () => {\n if (!provider) return [];\n const entries: PresenceEntry[] = [];\n provider.awareness.getStates().forEach((state, clientId) => {\n entries.push({ clientId, state: state as Record<string, unknown> });\n });\n return entries;\n },\n setPresence: (state) => {\n lastPresence = state;\n provider?.awareness.setLocalState(state);\n },\n refreshNow: () => {\n if (!connectionEnabled || held) return Promise.resolve();\n return provider ? connect({ scheduledRefresh: true }) : connect();\n },\n refreshGrant,\n setConnectionEnabled: (enabled) => {\n if (destroyed || enabled === connectionEnabled) return;\n connectionEnabled = enabled;\n if (!enabled) {\n // Invalidate every mint/gate already in flight before tearing down the live provider.\n connectSeq += 1;\n clearRetryTimer();\n clearOfflineTimer();\n teardownProvider();\n setStatus('disconnected');\n localCopy?.connectionPolicyChanged?.(false);\n return;\n }\n localCopy?.connectionPolicyChanged?.(true);\n held = false;\n heldGrant = null;\n setStatus('connecting');\n void connect();\n },\n resume: () => {\n if (!held || destroyed || !connectionEnabled) return;\n held = false;\n const grant = heldGrant;\n heldGrant = null;\n notify();\n void connect({ skipGate: true, grant: grant ?? undefined });\n },\n unconfirmedEdits,\n onChange: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n destroy: () => {\n if (destroyed) return;\n destroyed = true;\n keptHttpFirstRead = null;\n documentStatus?.destroy();\n teardownProvider();\n clearRetryTimer();\n clearOfflineTimer();\n if (typeof window !== 'undefined') window.removeEventListener('online', onBrowserOnline);\n status = 'closed';\n // Final notification so pending waitForSync callers reject instead of\n // hanging on listeners that are about to be dropped.\n for (const listener of [...listeners]) listener();\n listeners.clear();\n unconfirmedAttributions.destroy();\n doc.destroy();\n },\n };\n}\n\nexport { CollabTokenError };\nexport type { CollabAuth, CollabTokenResponse };\n"],"names":["CollabTokenError","mint","mintCollabToken","receiveOnlyWebSocket","attributingWebSocket","docUpdateAttributions","Y","UnconfirmedUpdateAttributions","WebsocketProvider","documentStatus","watchDocumentStatus","refreshDelayMs","MIN_REFRESH_DELAY_MS","keryxRoomReadUrl","INITIAL_SYNC_PARAM","INITIAL_SYNC_DIFF","publishOwnAwarenessOnly","classifyClose","MAX_CONSECUTIVE_REMINTS","keryxOriginOf","knownInitialSyncSupport","HTTP_FIRST_READ_TIMEOUT_MS","readRoomOverHttp","HTTP_FIRST_READ_IDLE_TIMEOUT_MS","rememberInitialSyncSupport"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgQO,MAAM,gCAAgC;AAG7C,MAAM,uBAAuB,CAAC,KAAO,KAAO,KAAO,KAAO,MAAQ,KAAQ,GAAM;AAMzE,SAAS,qBAAqB,OAAyB;AAC5D,MAAI,iBAAiBA,KAAAA,kBAAkB;AACrC,WAAO,MAAM,UAAU,OAAO,MAAM,WAAW,OAAO,MAAM,WAAW;AAAA,EACzE;AACA,SAAO,iBAAiB,aAAc,iBAAiB,gBAAgB,MAAM,SAAS;AACxF;AAEA,SAAS,YAAY,EAAE,MAAA,MAAMC,UAA8D;AACzF,MAAIA,OAAM,QAAOA;AACjB,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,0CAA0C;AACrE,SAAO,CAAC,EAAE,SAAS,OAAA,MAAaC,KAAAA,gBAAgB,EAAE,MAAM,SAAS,QAAQ;AAC3E;AAaA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAIiC;AAC/B,QAAM,OAAqC,WAAW;AACtD,MAAI,OAAO,SAAS,WAAY,QAAO;AACvC,MAAI,MAAM,gBAAgB,YAAYC,kBAAAA,qBAAqB,EAAE,MAAM;AACnE,SAAOC,wCAAqB;AAAA,IAC1B;AAAA,IACA,iBAAiB,MAAMC,mBAAAA,sBAAsB,GAAG;AAAA,IAChD;AAAA,EAAA,CACD;AACH;AAoBA,SAAS,iBAAmD;AAC1D,MAAI;AACF,WAAO,OAAO,WAAW,eAAe,OAAO,eAAe,OAAO,eAAe;AAAA,EACtF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,kBAAkB,MA4Cb;AACnB,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAMJ,QAAO,YAAY,EAAE,MAAM,KAAK,MAAM,MAAM,KAAK,MAAM;AAC7D,QAAM,YAAY,KAAK;AACvB,QAAM,iBAAiB,KAAK,kBAAkB;AAC9C,QAAM,qBAAqB,KAAK,sBAAsB;AACtD,QAAM,MAAM,IAAIK,aAAE,IAAA;AAGlB,QAAM,0BAA0B,IAAIC,4DAA8B;AAAA,IAChE;AAAA,IACA,iBAAiB,MAAMF,mBAAAA,sBAAsB,GAAG;AAAA,IAChD,gBAAgB,CAAC,WAAW,kBAAkBG,UAAAA;AAAAA,EAAA,CAC/C;AACD,QAAM,gCAAgB,IAAA;AAEtB,MAAI,WAAqC;AACzC,MAAI,eAAqD;AACzD,MAAI,aAAmD;AACvD,MAAI,eAAqD;AAEzD,MAAI,uBAAiD;AACrD,MAAI,cAAc;AAClB,MAAI,YAAY;AAChB,MAAI,oBAAoB,KAAK,qBAAqB;AAClD,MAAI,SAA2B,oBAAoB,eAAe;AAClE,MAAI,SAAS;AACb,MAAI,aAAgC;AACpC,MAAI,QAAsB;AAC1B,MAAI,eAA+C;AACnD,MAAI,UAAU;AACd,MAAI,qBAAqB;AACzB,MAAI,WAAW,cAAc;AAC7B,MAAI,OAAO;AACX,MAAI,YAAwC;AAC5C,MAAI,gBAAgB;AACpB,MAAI,oBAAmC;AAEvC,MAAI,aAAa;AAEjB,MAAI,iBAA0D,CAAA;AAC9D,MAAI,qBAAqB;AAEzB,MAAI,YAAwC;AAE5C,MAAI,sBAAsB;AAK1B,MAAI,uBAAuB;AAE3B,MAAI,wBAAwB;AAM5B,MAAI,gBAAmF;AAEvF,MAAI,oBAAuC;AAE3C,MAAI,wBAAwB;AAE5B,QAAM,SAAS,MAAM;AACnB,eAAW;AACX,eAAW,YAAY,UAAW,UAAA;AAAA,EACpC;AAEA,QAAMC,mBAAiB,KAAK,qBACxBC,mCAAoB;AAAA,IAClB,MAAM,KAAK;AAAA,IACX,cAAc,MAAM;AAAA,IACpB,UAAU,MAAM;AACd,UAAI,CAAC,UAAW,QAAA;AAAA,IAClB;AAAA,EAAA,CACD,IACD;AAEJ,QAAM,mBAAmB,MAA2B;AAClD,UAAM,MAAM,CAAC,GAAG,gBAAgB,IAAI,qCAAU,uBAAsB,CAAA,CAAG,EAAE;AAAA,MACvE,CAAC,UAAU,MAAM;AAAA,IAAA;AAEnB,QAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,WAAO,IAAI,WAAW,IAAK,IAAI,CAAC,IAAqBJ,aAAE,gBAAgB,GAAG;AAAA,EAC5E;AAEA,QAAM,YAAqC;AAAA,IACzC,gBAAgB,CAAC,WAAW,kBAAkBE,UAAAA;AAAAA,IAC9C,gBAAgB;AAAA,IAChB,eAAe,MAAM,WAAW,eAAe,UAAU;AAAA,EAAA;AAG3D,QAAM,mBAAmB,MAAM;AAC7B,2CAAW;AAAA,EACb;AAEA,QAAM,4BAA4B,MAAM;AACtC,UAAM,OAAO,eAAe,WAAW,OAAM,qCAAU,mBAAmB,WAAU,OAAO;AAC3F,UAAM,UAAU,SAAS;AACzB,yBAAqB;AACrBC,yDAAgB,mBAAmB,CAAC;AAGpC,qBAAA;AACA,QAAI,QAAS,QAAA;AAAA,EACf;AAGA,MAAI,GAAG,UAAU,MAAM;AACrB,QAAI,CAAC,sBAAuB,qBAAoB;AAAA,EAClD,CAAC;AAID,MAAI,GAAG,UAAU,CAAC,QAAoB,WAAoB;AACxD,QAAI,CAAC,YAAY,aAAa,QAAQ,aAAa,kBAAkBD,4BAAmB;AACxF,qBAAiB;AAAA,MACf,GAAG;AAAA,MACH,EAAE,SAAS,KAAK,IAAA,GAAO,KAAKF,aAAE,2BAA2B,MAAM,EAAA;AAAA,IAAE;AAEnE,8BAAA;AAAA,EACF,CAAC;AAED,QAAM,YAAY,CAAC,MAAwB,MAAoB,SAAS;AACtE,QAAI,aAAa,SAAS,SAAU;AACpC,UAAM,eAAe,WAAW;AAChC,aAAS;AACT,YAAQ;AACR,QAAI,SAAS,aAAa;AACxB,sBAAgB;AAChB,0BAAoB;AACpB,wBAAA;AAAA,IACF,OAAO;AACL,UAAI,gBAAiB,iBAAiB,sBAAsB,MAAO;AACjE,4BAAoB,KAAK,IAAA;AAAA,MAC3B;AACAG,2DAAgB;AAAA,IAClB;AACA,qBAAA;AACA,WAAA;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAM;AAC9B,QAAI,iBAAiB,MAAM;AACzB,mBAAa,YAAY;AACzB,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,kBAAkB,MAAM;AAC5B,QAAI,eAAe,MAAM;AACvB,mBAAa,UAAU;AACvB,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,WAAS,oBAAoB;AAC3B,QAAI,iBAAiB,MAAM;AACzB,mBAAa,YAAY;AACzB,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,mBAAmB,MAAM;AAC7B,sBAAA;AAKA,QAAI,QAAQ;AACV,eAAS;AACT,aAAA;AAAA,IACF;AACA,QAAI,UAAU;AAEZ,YAAM,WAAW;AACjB,iBAAW;AACX,WAAI,+CAAe,YAAW,UAAU;AACtC,sBAAc,WAAW,MAAM,IAAI,aAAa,mBAAmB,YAAY,CAAC;AAChF,wBAAgB;AAAA,MAClB;AACA,uBAAiB,CAAC,GAAG,gBAAgB,GAAG,SAAS,kBAAkB;AACnE,eAAS,QAAA;AAAA,IACX;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,UAA+B;AACtD,sBAAA;AACA,UAAM,QAAQE,4BAAe,EAAE,aAAa,MAAM,eAAe,KAAK,KAAK,IAAA,GAAO;AAClF,mBAAe,WAAW,MAAM;AAC9B,WAAK,QAAQ,EAAE,kBAAkB,MAAM;AAAA,IACzC,GAAG,KAAK;AAAA,EACV;AAGA,QAAM,gBAAgB,MAAM;AAC1B,oBAAA;AACA,UAAM,QAAQ,qBAAqB,KAAK,IAAI,aAAa,qBAAqB,SAAS,CAAC,CAAC;AACzF,mBAAe;AACf,iBAAa,WAAW,MAAM;AAC5B,mBAAa;AACb,WAAK,QAAA;AAAA,IACP,GAAG,KAAK;AAAA,EACV;AAEA,QAAM,kBAAkB,MAAM;AAE5B,QACE,aAAa,CAAC,qBAAqB,WAAW,YAAY,WAAW,WACrE,aAAa,QAAQ,KACrB;AACF,kBAAc;AACd,oBAAA;AACA,SAAK,QAAA;AAAA,EACP;AACA,MAAI,OAAO,WAAW,YAAa,QAAO,iBAAiB,UAAU,eAAe;AAQpF,QAAM,qBAAqB,MAAM;AAC/B,QAAI,CAAC,qBAAqB,iBAAiB,QAAQ,EAAC,uCAAW,eAAe;AAC9E,mBAAe,WAAW,MAAM;AAC9B,qBAAe;AACf,UAAI,aAAa,CAAC,qBAAqB,WAAW,eAAe,aAAa,KAAM;AAEpF,WAAK,SAAS,iBAAgB,+CAAe,YAAW,aAAa,CAAC,yBAAyB;AAC7F,+BAAuB;AACvB,2BAAA;AACA;AAAA,MACF;AACA,uBAAA;AACA,WAAK,QAAA;AAAA,IACP,GAAG,kBAAkB;AAAA,EACvB;AAEA,QAAM,wBAAwB,MAC5B,eAAe,SAAS,OAAM,qCAAU,mBAAmB,WAAU,KAAK;AAG5E,QAAM,UAAU,OAAO,SAIF;AACnB,QAAI,aAAa,CAAC,kBAAmB;AACrC,UAAM,MAAM,EAAE;AACd,UAAM;AACN,QAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAG3D,UAAM,oBAAmB,6BAAM,sBAAqB,QAAQ,WAAW;AAIvE,QAAI,CAAC,kBAAkB;AACrB,uBAAA;AAAA,IACF,OAAO;AACL,wBAAA;AAAA,IACF;AACA,oBAAA;AACA,QAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAC3D,QAAI;AACJ,SAAI,6BAAM,UAAS,KAAK,MAAM,gBAAgB,KAAK,IAAA,IAAQC,mCAAsB;AAC/E,cAAQ,KAAK;AAAA,IACf,OAAO;AACL,UAAI;AACF,gBAAQ,MAAMX,MAAK,EAAE,SAAS,KAAK,SAAS,QAAQ;AAAA,MACtD,SAAS,KAAK;AACZ,YAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAC3D,YAAI,kBAAkB;AACpB,yBAAe,WAAW,MAAM;AAC9B,iBAAK,QAAQ,EAAE,kBAAkB,MAAM;AAAA,UACzC,GAAGW,aAAAA,oBAAoB;AACvB;AAAA,QACF;AACA,YAAI,eAAe,GAAG,GAAG;AAEvB,cAAI,WAAW,eAAgB,WAAU,cAAc;AACvD,wBAAA;AACA;AAAA,QACF;AAEA,kBAAU,SAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AACtE;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAC3D,kBAAc;AACd,iBAAa,MAAM;AACnB,UAAM,gBAAgB,uCAAW;AACjC,QAAI,iBAAiB,CAAC,oBAAoB,EAAC,6BAAM,WAAU;AACzD,YAAM,kBAAkB,CAAC;AACzB,YAAM,eAAe,sBAAsB,OAAO,OAAO,KAAK,QAAQ;AACtE,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,cAAc;AAAA,UAC7B;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB,sBAAA;AAAA,UAClB,GAAI,uBAAuB,EAAE,iBAAiB,SAAS,CAAA;AAAA,QAAC,CACzD;AAAA,MACH,QAAQ;AACN,YAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAC3D,YAAI,WAAW,eAAgB,WAAU,cAAc;AACvD,sBAAA;AACA;AAAA,MACF;AACA,UAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAC3D,6BAAuB;AACvB,UAAI,aAAa,QAAQ;AACvB,eAAO;AACP,oBAAY;AACZ,YAAI,WAAW,eAAgB,WAAU,cAAc;AAAA,YAClD,QAAA;AACL;AAAA,MACF;AAAA,IACF;AACA,QAAI,kBAAkB;AACpB,uBAAA;AAAA,IACF;AACA,QAAI,aAAa,CAAC,qBAAqB,QAAQ,WAAY;AAE3D,UAAM,SAAS,UAAU,EAAE,OAAO,KAAK,aAAa,yBAAyB;AAC7E,UAAM,UAAU,GAAG,MAAM,MAAM,IAAI,MAAM,GAAG,IAAI,MAAM,MAAM;AAE5D,UAAM,eACJ,KAAK,kBAAkB,QAAQ,IAAI,MAAM,QAAQ,SAAS,KAAK,eAAe,WAAW,IACrFC,YAAAA,iBAAiB,EAAE,OAAO,SAAS,OAAO,MAAM,OAAO,QAAQ,MAAM,OAAA,CAAQ,IAC7E;AACN,UAAM,SAAiC;AAAA,MACrC,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,IAAI;AAAA,IAAA;AAEN,QAAI,iBAAiB,QAAQ,kBAAkB,EAAE,SAAS,aAAa,eAAe,OAAA,CAAQ,GAAG;AAC/F,aAAOC,YAAAA,kBAAkB,IAAIC,YAAAA;AAAAA,IAC/B;AACA,UAAM,eAAe,IAAIP,UAAAA,kBAAkB,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,MAAM,MAAM,IAAI,KAAK;AAAA,MAC5F;AAAA;AAAA;AAAA;AAAA,MAIA,WAAW;AAAA,MACX,SAAS,iBAAiB;AAAA,MAC1B,GAAI,UAAU,EAAE,mBAAmB,OAAA;AAAA,IAAO,CAC3C;AACDQ,yCAAwB,EAAE,WAAW,cAAc;AACnD,eAAW;AACX,gBAAY;AACZ,iBAAa,qBAAqB,CAAC,GAAG,gBAAgB,GAAG,aAAa,kBAAkB;AACxF,qBAAiB,CAAA;AACjB,8BAAA;AAEA,iBAAa,GAAG,eAAe,MAAM;AACnC,UAAI,aAAa,aAAc;AAC/B,gCAAA;AAAA,IACF,CAAC;AAED,iBAAa,GAAG,UAAU,CAAC,UAAmE;AAC5F,UAAI,aAAa,aAAc;AAC/B,UACE,MAAM,WAAW,eACjB,yBAAyB,gBACzB,yBACA;AAGA,yBAAA;AACA,aAAK,QAAA;AACL;AAAA,MACF;AAIA,YAAM,gBACJ,MAAM,WAAW,gBAChB,CAAC,iBACA,uBACC,sBAAsB,QAAQ,KAAK,IAAA,IAAQ,qBAAqB;AACrE,UAAI,MAAM,WAAW,aAAa;AAChC,6BAAqB;AACrB,8BAAsB;AACtB,+BAAuB;AAAA,MACzB;AACA,gBAAU,MAAM,MAAM;AACtB,UAAI,MAAM,WAAW,YAAaP,sDAAgB,UAAU,EAAE,SAAS;AACvE,UAAI,MAAM,WAAW,eAAe,iBAAiB,MAAM;AACzD,qBAAa,UAAU,cAAc,YAAY;AAAA,MACnD;AAIA,UAAI,MAAM,WAAW,YAAa,oBAAA;AAAA,IACpC,CAAC;AAED,QAAI,CAAC,aAAa,YAAa,oBAAA;AAE/B,iBAAa,GAAG,QAAQ,CAAC,UAAmB;AAC1C,UAAI,aAAa,aAAc;AAC/B,UAAI,WAAW,OAAO;AACpB,iBAAS;AACT,yBAAA;AACA,eAAA;AAAA,MACF;AAAA,IACF,CAAC;AAED,iBAAa,GAAG,oBAAoB,CAAC,UAA6B;AAChE,UAAI,aAAa,aAAc;AAE/B,UAAI,kBAAkB,EAAE,SAAS,aAAa,aAAa,mBAAmB,OAAA,CAAQ,GAAG;AACvF,qBAAa,OAAOK,YAAAA,kBAAkB,IAAIC,YAAAA;AAAAA,MAC5C,OAAO;AACL,eAAO,aAAa,OAAOD,8BAAkB;AAAA,MAC/C;AACA,YAAM,SAASG,YAAAA,cAAc,+BAAO,IAAI;AACxC,UAAI,WAAW,UAAU;AAMvB,8BAAsB;AAItB,8BAAsB;AAGtB,+BAAuB;AACvBR,6DAAgB;AAChB,yBAAA;AACA,YAAI,qBAAqBS,aAAAA,yBAAyB;AAChD;AAAA,YACE;AAAA,YACA,IAAI,MAAM,0DAA0D;AAAA,UAAA;AAEtE;AAAA,QACF;AACA,aAAK,QAAA;AAAA,MACP,WAAW,WAAW,QAAQ;AAC5B,yBAAA;AACA;AAAA,UACE;AAAA,UACA,IAAI,MAAM,wCAAuC,+BAAO,SAAQ,SAAS,GAAG;AAAA,QAAA;AAAA,MAEhF;AAAA,IAEF,CAAC;AAED,iBAAa,UAAU,GAAG,UAAU,MAAM;AACxC,UAAI,aAAa,aAAc;AAC/B,aAAA;AAAA,IACF,CAAC;AAED,oBAAgB,KAAK;AACrB,QAAI,iBAAiB,KAAM,MAAK,aAAa,EAAE,QAAQ,cAAc,KAAK,cAAc,SAAS;AAAA,EACnG;AAUA,WAAS,kBAAkB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EAAA,GAKF;AACV,QAAI,KAAK,kBAAkB,KAAM,QAAO;AACxC,QAAI,KAAK,sBAAsB,gBAAgB,CAAC,UAAW,QAAO;AAClE,UAAM,SAASC,YAAAA,cAAc,OAAO;AACpC,UAAM,QACJ,yBACC,WAAW,QAAQC,YAAAA,wBAAwB,EAAE,SAAS,eAAA,GAAkB,OAAA,CAAQ,MAAM;AACzF,WAAO,SAAS,IAAI,MAAM,QAAQ,OAAO,KAAK,gBAAgB,KAAK,CAAC,wBAAwB;AAAA,EAC9F;AAQA,iBAAe,aAAa;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,EAAA,GAKgB;;AAChB,UAAM,UAAU,YAAY,IAAA;AAC5B,UAAM,SAASD,YAAAA,cAAc,OAAO;AACpC,UAAM,UAAU,eAAA;AAChB,QAAI;AAEJ,QAAI,UAAU;AACd,QAAI,WAAW,QAAQC,YAAAA,wBAAwB,EAAE,SAAS,OAAA,CAAQ,MAAM,OAAO;AAC7E,cAAQ,EAAE,SAAS,WAAW,YAAY,EAAA;AAAA,IAC5C,OAAO;AACL,YAAM,aAAa,IAAI,gBAAA;AACvB,sBAAgB,EAAE,QAAQ,WAAA;AAC1B,YAAM,UAAU;AAAA,QACd,MAAM,WAAW,MAAM,IAAI,aAAa,iCAAiC,cAAc,CAAC;AAAA,QACxFC,YAAAA;AAAAA,MAAA;AAEF,UAAI;AAGF,cAAM,OAAO,MAAMC,6BAAiB;AAAA,UAClC;AAAA,UACA,QAAQ,WAAW;AAAA,UACnB,eAAeC,YAAAA;AAAAA,QAAA,CAChB;AACD,YAAI,WAAW,KAAMC,aAAAA,2BAA2B,EAAE,SAAS,QAAQ,WAAW,KAAK,kBAAkB;AACrG,YAAI,KAAK,oBAAoB,aAAa,UAAU,CAAC,WAAW;AAC9D,cAAI,KAAK,OAAO,aAAa,EAAG,oBAAmB,EAAE,QAAQ,KAAK,QAAQ,QAAQ;AAClF,kCAAwB;AACxB,oBAAU;AAAA,QACZ;AACA,gBAAQ;AAAA,UACN,SAAS,KAAK,mBAAmB,SAAS;AAAA,UAC1C,OAAO,KAAK;AAAA,UACZ,YAAY,YAAY,QAAQ;AAAA,QAAA;AAAA,MAEpC,SAAS,KAAK;AAEZ,gBACE,WAAW,OAAO,YAAY,aAAa,aAAa,UACpD,EAAE,SAAS,WAAW,YAAY,YAAY,IAAA,IAAQ,YACtD;AAAA,UACE,SAAS;AAAA,UACT,YAAY,YAAY,IAAA,IAAQ;AAAA,UAChC,OAAO,eAAe,QAAQ,GAAG,IAAI,IAAI,KAAK,IAAI,OAAO,KAAK,OAAO,GAAG;AAAA,QAAA;AAAA,MAElF,UAAA;AACE,qBAAa,OAAO;AACpB,aAAI,+CAAe,gBAAe,WAAY,iBAAgB;AAAA,MAChE;AAAA,IACF;AACA,QAAI;AACF,iBAAK,oBAAL,8BAAuB;AAAA,IACzB,QAAQ;AAAA,IAER;AACA,QAAI,aAAa,aAAa,OAAQ;AACtC,QAAI,kBAAkB,EAAE,SAAS,aAAa,OAAO,mBAAmB,QAAQ,WAAW,QAAA,CAAS,GAAG;AACrG,aAAO,OAAOV,YAAAA,kBAAkB,IAAIC,YAAAA;AAAAA,IACtC,OAAO;AACL,aAAO,OAAO,OAAOD,8BAAkB;AAAA,IACzC;AACA,WAAO,QAAA;AAAA,EACT;AAOA,WAAS,mBAAmB;AAAA,IAC1B;AAAA,IACA;AAAA,EAAA,GAIO;AACP,QAAI,KAAK,sBAAsB,QAAQ,IAAI,MAAM,QAAQ,SAAS,EAAG,qBAAoB;AACzF,4BAAwB;AACxB,QAAI;AACFR,mBAAE,YAAY,KAAK,QAAQ,MAAM;AAAA,IACnC,UAAA;AACE,8BAAwB;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,YAA2B,YAC7B,UACG,QAAQ,EAAE,KAAK,WAAW,EAC1B,MAAM,OAAO,EAAE,eAAe,OAAO,EACrC,KAAK,CAAC,EAAE,oBAAoB;AAC3B,QAAI,UAAW;AACf,QAAI,iBAAiB,EAAE,cAAc,QAAQ,aAAa,cAAc,QAAQ,QAAA,IAAY;AAC1F,uBAAiB,CAAC,GAAG,gBAAgB,EAAE,SAAS,KAAK,IAAA,GAAO,KAAK,eAAe;AAAA,IAClF;AACA,eAAW;AACX,8BAAA;AACA,WAAA;AAAA,EACF,CAAC,IACH,QAAQ,QAAA;AAEZ,OAAK,QAAA;AAEL,QAAM,cAAc,CAAC,YAAY,SAC/B,IAAI,QAAc,CAAC,SAAS,WAAW;AACrC,UAAM,WAAW,MAAoB;AACnC,UAAI,UAAW,QAAO,IAAI,MAAM,sCAAsC;AACtE,UAAI,WAAW,YAAY,WAAW,SAAS;AAC7C,eAAO,SAAS,IAAI,MAAM,cAAc,MAAM,sBAAsB;AAAA,MACtE;AACA,aAAO;AAAA,IACT;AACA,QAAI,QAAQ;AACV,cAAA;AACA;AAAA,IACF;AACA,UAAM,YAAY,SAAA;AAClB,QAAI,WAAW;AACb,aAAO,SAAS;AAChB;AAAA,IACF;AACA,UAAM,UAAU,MAAM;AACpB,mBAAa,KAAK;AAClB,gBAAU,OAAO,QAAQ;AAAA,IAC3B;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAA;AACA,aAAO,IAAI,MAAM,mBAAmB,SAAS,6BAA6B,CAAC;AAAA,IAC7E,GAAG,SAAS;AACZ,UAAM,WAAW,MAAM;AACrB,UAAI,QAAQ;AACV,gBAAA;AACA,gBAAA;AACA;AAAA,MACF;AACA,YAAM,MAAM,SAAA;AACZ,UAAI,KAAK;AACP,gBAAA;AACA,eAAO,GAAG;AAAA,MACZ;AAAA,IACF;AACA,cAAU,IAAI,QAAQ;AAAA,EACxB,CAAC;AAEH,QAAM,sBAAsB,CAAC,YAAY,SACvC,IAAI,QAAc,CAAC,SAAS,WAAW;AACrC,QAAI,WAAW;AACf,QAAI,cAAc;AAClB,QAAI,QAA8C;AAClD,UAAM,SAAS,CAAC,YAAoB;AAClC,UAAI,SAAU;AACd,iBAAW;AACX,UAAI,UAAU,KAAM,cAAa,KAAK;AACtC,gBAAU,OAAO,KAAK;AACtB,UAAI,gBAAgB,OAAO;AAAA,UACtB,SAAA;AAAA,IACP;AACA,UAAM,QAAQ,MAAM;AAClB,UAAI,YAAY,YAAa;AAC7B,oBAAc;AAEd,qBAAe,MAAM;AACnB,sBAAc;AACd,YAAI,SAAU;AACd,YAAI,WAAW;AACb,iBAAO,IAAI,MAAM,yDAAyD,CAAC;AAAA,QAC7E,WAAW,CAAC,mBAAmB;AAC7B,iBAAO,IAAI,MAAM,4DAA4D,CAAC;AAAA,QAChF,WAAW,WAAW,YAAY,WAAW,SAAS;AACpD,iBAAO,SAAS,IAAI,MAAM,cAAc,MAAM,yCAAyC,CAAC;AAAA,QAC1F,WAAW,YAAY,WAAW,eAAe,UAAU,oBAAoB;AAC7E,iBAAA;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AACA,YAAQ,WAAW,MAAM;AACvB,aAAO,IAAI,MAAM,mBAAmB,SAAS,iDAAiD,CAAC;AAAA,IACjG,GAAG,SAAS;AACZ,cAAU,IAAI,KAAK;AACnB,UAAA;AAAA,EACF,CAAC;AAGH,MAAI,eAAwC;AAC5C,QAAM,cAAc,YAA8B;AAChD,QAAI;AACF,YAAM,QAAQ,MAAML,MAAK,EAAE,SAAS,KAAK,SAAS,QAAQ;AAC1D,UAAI,aAAa,CAAC,qBAAqB,MAAM,gBAAgB,KAAM,QAAO;AAC1E,UAAI,MAAM;AAER,aAAI,uCAAW,iBAAgB,IAAK,QAAO;AAC3C,eAAO;AACP,oBAAY;AACZ,eAAA;AACA,aAAK,QAAQ,EAAE,OAAO;AACtB,eAAO;AAAA,MACT;AACA,UAAI,WAAW,YAAa,QAAO;AACnC,UAAI,eAAe,KAAM,QAAO;AAEhC,WAAK,QAAQ,EAAE,kBAAkB,MAAM,OAAO;AAC9C,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,eAAe,MAAwB;AAC3C,QAAI,aAAa,CAAC,kBAAmB,QAAO,QAAQ,QAAQ,KAAK;AACjE,QAAI,aAAc,QAAO;AACzB,UAAM,aAAa,SAAQ,uCAAW,iBAAgB;AAEtD,QAAI,CAAC,cAAc,WAAW,YAAa,QAAO,QAAQ,QAAQ,KAAK;AACvE,QAAI,CAAC,cAAc,eAAe,KAAM,QAAO,QAAQ,QAAQ,IAAI;AACnE,UAAM,QAAQ,cAAc,QAAQ,MAAM;AACxC,qBAAe;AAAA,IACjB,CAAC;AACD,mBAAe;AACf,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,IAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,IACA,IAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,IACA,IAAI,qBAAqB;AACvB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,aAAa;AACf,aAAO;AAAA,IACT;AAAA,IACA,IAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAAA,IACA,IAAI,WAAW;AACb,aAAO;AAAA,IACT;AAAA,IACA,IAAI,oBAAoB;AACtB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,OAAO;AACT,aAAO;AAAA,IACT;AAAA,IACA,IAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAAA,IACA,IAAI,gBAAgB;AAClB,cAAOQ,qDAAgB,kBAAiB;AAAA,IAC1C;AAAA,IACA,mBAAmB,MAAM;AACvB,YAAM,OAAO;AACb,0BAAoB;AACpB,aAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,MAAM;AACjB,UAAI,CAAC,SAAU,QAAO,CAAA;AACtB,YAAM,UAA2B,CAAA;AACjC,eAAS,UAAU,UAAA,EAAY,QAAQ,CAAC,OAAO,aAAa;AAC1D,gBAAQ,KAAK,EAAE,UAAU,MAAA,CAAyC;AAAA,MACpE,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,aAAa,CAAC,UAAU;AACtB,qBAAe;AACf,2CAAU,UAAU,cAAc;AAAA,IACpC;AAAA,IACA,YAAY,MAAM;AAChB,UAAI,CAAC,qBAAqB,KAAM,QAAO,QAAQ,QAAA;AAC/C,aAAO,WAAW,QAAQ,EAAE,kBAAkB,KAAA,CAAM,IAAI,QAAA;AAAA,IAC1D;AAAA,IACA;AAAA,IACA,sBAAsB,CAAC,YAAY;;AACjC,UAAI,aAAa,YAAY,kBAAmB;AAChD,0BAAoB;AACpB,UAAI,CAAC,SAAS;AAEZ,sBAAc;AACd,wBAAA;AACA,0BAAA;AACA,yBAAA;AACA,kBAAU,cAAc;AACxB,qDAAW,4BAAX,mCAAqC;AACrC;AAAA,MACF;AACA,mDAAW,4BAAX,mCAAqC;AACrC,aAAO;AACP,kBAAY;AACZ,gBAAU,YAAY;AACtB,WAAK,QAAA;AAAA,IACP;AAAA,IACA,QAAQ,MAAM;AACZ,UAAI,CAAC,QAAQ,aAAa,CAAC,kBAAmB;AAC9C,aAAO;AACP,YAAM,QAAQ;AACd,kBAAY;AACZ,aAAA;AACA,WAAK,QAAQ,EAAE,UAAU,MAAM,OAAO,SAAS,QAAW;AAAA,IAC5D;AAAA,IACA;AAAA,IACA,UAAU,CAAC,aAAa;AACtB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,SAAS,MAAM;AACb,UAAI,UAAW;AACf,kBAAY;AACZ,0BAAoB;AACpBA,2DAAgB;AAChB,uBAAA;AACA,sBAAA;AACA,wBAAA;AACA,UAAI,OAAO,WAAW,YAAa,QAAO,oBAAoB,UAAU,eAAe;AACvF,eAAS;AAGT,iBAAW,YAAY,CAAC,GAAG,SAAS,EAAG,UAAA;AACvC,gBAAU,MAAA;AACV,8BAAwB,QAAA;AACxB,UAAI,QAAA;AAAA,IACN;AAAA,EAAA;AAEJ;;;;;"}