@opengeni/react 0.57.0 → 1.0.2-canary.37191796234001

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 (629) hide show
  1. package/README.md +654 -22
  2. package/dist/accounts.d.ts +64 -0
  3. package/dist/accounts.js +822 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/approvals.d.ts +2 -1
  6. package/dist/artifacts-document.js +3 -2
  7. package/dist/artifacts-presentation.js +3 -2
  8. package/dist/artifacts-spreadsheet.js +2 -2
  9. package/dist/artifacts.d.ts +4 -1
  10. package/dist/artifacts.js +518 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-GTR5XQ7X.js +16 -0
  13. package/dist/capability-catalog-row.d.ts +20 -0
  14. package/dist/capability-logo-fallback.d.ts +3 -0
  15. package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
  16. package/dist/chat-interactive-block-UGBTNB3L.js.map +1 -0
  17. package/dist/{chunk-5UQPNLIO.js → chunk-23J2ZNXT.js} +4117 -3896
  18. package/dist/chunk-23J2ZNXT.js.map +1 -0
  19. package/dist/chunk-447JLCBU.js +209 -0
  20. package/dist/chunk-447JLCBU.js.map +1 -0
  21. package/dist/chunk-4RVYOY4O.js +379 -0
  22. package/dist/chunk-4RVYOY4O.js.map +1 -0
  23. package/dist/chunk-5CVXZA3Y.js +292 -0
  24. package/dist/chunk-5CVXZA3Y.js.map +1 -0
  25. package/dist/chunk-5J4FOW6Q.js +108 -0
  26. package/dist/chunk-5J4FOW6Q.js.map +1 -0
  27. package/dist/chunk-A2PI6UMY.js +41 -0
  28. package/dist/chunk-A2PI6UMY.js.map +1 -0
  29. package/dist/{chunk-7WCLAEFV.js → chunk-A4UJB2MM.js} +37 -27
  30. package/dist/chunk-A4UJB2MM.js.map +1 -0
  31. package/dist/chunk-B3V6TG77.js +41 -0
  32. package/dist/chunk-B3V6TG77.js.map +1 -0
  33. package/dist/chunk-BRM6FVZA.js +302 -0
  34. package/dist/chunk-BRM6FVZA.js.map +1 -0
  35. package/dist/chunk-C5X5AJXK.js +182 -0
  36. package/dist/chunk-C5X5AJXK.js.map +1 -0
  37. package/dist/chunk-CR7U7HAR.js +453 -0
  38. package/dist/chunk-CR7U7HAR.js.map +1 -0
  39. package/dist/{chunk-R3AZOAB5.js → chunk-DYWBUX5Q.js} +29 -123
  40. package/dist/chunk-DYWBUX5Q.js.map +1 -0
  41. package/dist/chunk-E3G7SAYZ.js +3124 -0
  42. package/dist/chunk-E3G7SAYZ.js.map +1 -0
  43. package/dist/chunk-ELCE5SXV.js +359 -0
  44. package/dist/chunk-ELCE5SXV.js.map +1 -0
  45. package/dist/chunk-ERGYJIBB.js +21 -0
  46. package/dist/chunk-ERGYJIBB.js.map +1 -0
  47. package/dist/chunk-FFA2OVOV.js +319 -0
  48. package/dist/chunk-FFA2OVOV.js.map +1 -0
  49. package/dist/chunk-FZCP527Y.js +116 -0
  50. package/dist/chunk-FZCP527Y.js.map +1 -0
  51. package/dist/chunk-GIMRELBW.js +14 -0
  52. package/dist/chunk-GIMRELBW.js.map +1 -0
  53. package/dist/{chunk-6KLX2RH5.js → chunk-H2NJQORO.js} +1069 -79
  54. package/dist/chunk-H2NJQORO.js.map +1 -0
  55. package/dist/chunk-I7IWRQLN.js +1608 -0
  56. package/dist/chunk-I7IWRQLN.js.map +1 -0
  57. package/dist/{chunk-HA46CYQK.js → chunk-IQUCRAT7.js} +792 -537
  58. package/dist/chunk-IQUCRAT7.js.map +1 -0
  59. package/dist/chunk-IWIDV7SB.js +1 -0
  60. package/dist/chunk-IWIDV7SB.js.map +1 -0
  61. package/dist/chunk-J2QWVSQY.js +312 -0
  62. package/dist/chunk-J2QWVSQY.js.map +1 -0
  63. package/dist/chunk-JFNEV4LU.js +2733 -0
  64. package/dist/chunk-JFNEV4LU.js.map +1 -0
  65. package/dist/chunk-JT4JW7BC.js +54 -0
  66. package/dist/chunk-JT4JW7BC.js.map +1 -0
  67. package/dist/chunk-K3HQAKQX.js +24 -0
  68. package/dist/chunk-K3HQAKQX.js.map +1 -0
  69. package/dist/{chunk-C5ZPSSS5.js → chunk-NEXLLTP4.js} +2 -1
  70. package/dist/{chunk-C5ZPSSS5.js.map → chunk-NEXLLTP4.js.map} +1 -1
  71. package/dist/chunk-NZUI76EM.js +371 -0
  72. package/dist/chunk-NZUI76EM.js.map +1 -0
  73. package/dist/{chunk-PEI6RANI.js → chunk-PNY3JKBJ.js} +309 -74
  74. package/dist/chunk-PNY3JKBJ.js.map +1 -0
  75. package/dist/{chunk-IGC6A2ZI.js → chunk-Q5QBEZIQ.js} +777 -246
  76. package/dist/chunk-Q5QBEZIQ.js.map +1 -0
  77. package/dist/chunk-RHREZ7BO.js +11 -0
  78. package/dist/chunk-RHREZ7BO.js.map +1 -0
  79. package/dist/chunk-SCOTPE2I.js +589 -0
  80. package/dist/chunk-SCOTPE2I.js.map +1 -0
  81. package/dist/{chunk-B6WPZSTT.js → chunk-SJZDKVW2.js} +1331 -1163
  82. package/dist/chunk-SJZDKVW2.js.map +1 -0
  83. package/dist/chunk-TMJRG4YC.js +12803 -0
  84. package/dist/chunk-TMJRG4YC.js.map +1 -0
  85. package/dist/chunk-TMYGL6X5.js +742 -0
  86. package/dist/chunk-TMYGL6X5.js.map +1 -0
  87. package/dist/chunk-UGLEYEMP.js +33 -0
  88. package/dist/chunk-UGLEYEMP.js.map +1 -0
  89. package/dist/chunk-UK4TINKT.js +27 -0
  90. package/dist/chunk-UK4TINKT.js.map +1 -0
  91. package/dist/chunk-UTRTG6LH.js +220 -0
  92. package/dist/chunk-UTRTG6LH.js.map +1 -0
  93. package/dist/chunk-WEHMPOXK.js +39 -0
  94. package/dist/chunk-WEHMPOXK.js.map +1 -0
  95. package/dist/chunk-WRHIZYZF.js +988 -0
  96. package/dist/chunk-WRHIZYZF.js.map +1 -0
  97. package/dist/{chunk-HUIKIDM5.js → chunk-WUISZ3WU.js} +223 -115
  98. package/dist/chunk-WUISZ3WU.js.map +1 -0
  99. package/dist/chunk-XCHWDJ22.js +107 -0
  100. package/dist/chunk-XCHWDJ22.js.map +1 -0
  101. package/dist/chunk-XOAMRDDK.js +481 -0
  102. package/dist/chunk-XOAMRDDK.js.map +1 -0
  103. package/dist/chunk-XUW2UWQM.js +299 -0
  104. package/dist/chunk-XUW2UWQM.js.map +1 -0
  105. package/dist/{chunk-KCGXPP5V.js → chunk-Y2PRMYLC.js} +11 -6
  106. package/dist/chunk-Y2PRMYLC.js.map +1 -0
  107. package/dist/chunk-YBXQDQFX.js +1772 -0
  108. package/dist/chunk-YBXQDQFX.js.map +1 -0
  109. package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
  110. package/dist/chunk-YQEAA6LT.js.map +1 -0
  111. package/dist/chunk-YV4L3ILF.js +9 -0
  112. package/dist/chunk-YV4L3ILF.js.map +1 -0
  113. package/dist/{chunk-LLOLUHVG.js → chunk-YWFG7ZX7.js} +1358 -2746
  114. package/dist/chunk-YWFG7ZX7.js.map +1 -0
  115. package/dist/chunk-ZYRGEKWS.js +216 -0
  116. package/dist/chunk-ZYRGEKWS.js.map +1 -0
  117. package/dist/client.d.ts +7 -4
  118. package/dist/clipboard.js +1 -0
  119. package/dist/commands/types.d.ts +2 -0
  120. package/dist/components/anthropic-mark.d.ts +3 -0
  121. package/dist/components/approval-surface.d.ts +15 -0
  122. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  123. package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
  124. package/dist/components/artifacts/artifact-surface.d.ts +3 -1
  125. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  126. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  127. package/dist/components/artifacts/document-editor.d.ts +4 -2
  128. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  129. package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
  130. package/dist/components/artifacts/editable-document.d.ts +1 -1
  131. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  132. package/dist/components/artifacts/editable-spreadsheet.d.ts +2 -1
  133. package/dist/components/artifacts/index.d.ts +8 -1
  134. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  135. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  136. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  137. package/dist/components/artifacts/published-html-artifact-frame.d.ts +48 -3
  138. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  139. package/dist/components/artifacts/site-view.d.ts +23 -0
  140. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  141. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  142. package/dist/components/browser-select-control.d.ts +16 -0
  143. package/dist/components/browser-viewer.d.ts +10 -1
  144. package/dist/components/chat-composer.d.ts +21 -3
  145. package/dist/components/child-session-link.d.ts +5 -0
  146. package/dist/components/claude-mark.d.ts +3 -0
  147. package/dist/components/code-editor.d.ts +1 -4
  148. package/dist/components/composer.d.ts +45 -4
  149. package/dist/components/computer-viewer.d.ts +4 -1
  150. package/dist/components/copy-button.d.ts +3 -1
  151. package/dist/components/desktop-viewer.d.ts +1 -1
  152. package/dist/components/enrollment-consent.d.ts +6 -3
  153. package/dist/components/file-browser.d.ts +10 -1
  154. package/dist/components/fleet-tile.d.ts +2 -2
  155. package/dist/components/grok-mark.d.ts +26 -0
  156. package/dist/components/human-input-form.d.ts +21 -2
  157. package/dist/components/human-input-surface.d.ts +6 -3
  158. package/dist/components/machine-card.d.ts +4 -1
  159. package/dist/components/machines/machine-detail.d.ts +4 -1
  160. package/dist/components/machines/machine-operation-policy.d.ts +11 -0
  161. package/dist/components/machines-dashboard.d.ts +3 -1
  162. package/dist/components/markdown-table-layout.d.ts +12 -0
  163. package/dist/components/markdown.d.ts +47 -3
  164. package/dist/components/message-timeline.d.ts +72 -9
  165. package/dist/components/model-mark.d.ts +29 -0
  166. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  167. package/dist/components/model-policy-picker.d.ts +62 -13
  168. package/dist/components/open-geni-chat.d.ts +55 -0
  169. package/dist/components/open-geni-links.d.ts +68 -0
  170. package/dist/components/openrouter-mark.d.ts +6 -0
  171. package/dist/components/pierre-file.d.ts +1 -1
  172. package/dist/components/preview-loading.d.ts +2 -0
  173. package/dist/components/queue-item-content.d.ts +9 -0
  174. package/dist/components/sandbox-files.d.ts +13 -2
  175. package/dist/components/sandbox-workspace.d.ts +43 -3
  176. package/dist/components/session-capability-frame.d.ts +35 -0
  177. package/dist/components/session-chrome.d.ts +66 -8
  178. package/dist/components/session-commands-panel.d.ts +6 -0
  179. package/dist/components/session-commands.d.ts +6 -0
  180. package/dist/components/session-connection-request.d.ts +8 -0
  181. package/dist/components/session-conversation.d.ts +86 -0
  182. package/dist/components/session-list.d.ts +36 -0
  183. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  184. package/dist/components/timeline-anchor.d.ts +24 -0
  185. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  186. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  187. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  188. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  189. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  190. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  191. package/dist/components/timeline-annotations.d.ts +13 -3
  192. package/dist/components/timeline-reading-progress.d.ts +11 -0
  193. package/dist/components/timeline-search.d.ts +34 -0
  194. package/dist/components/timeline-settlement.d.ts +16 -0
  195. package/dist/components/tip-follow.d.ts +16 -0
  196. package/dist/components/usage-limit-notice.d.ts +49 -0
  197. package/dist/components/usage-member-list.d.ts +91 -0
  198. package/dist/components/usage-meter.d.ts +73 -0
  199. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  200. package/dist/components/user-message-body.d.ts +10 -1
  201. package/dist/components/workspace-dock.d.ts +6 -2
  202. package/dist/composer.d.ts +5 -4
  203. package/dist/composer.js +15 -9
  204. package/dist/computer-viewer-ENHVAZ2Q.js +19 -0
  205. package/dist/computer-viewer-ENHVAZ2Q.js.map +1 -0
  206. package/dist/connect-account-identity.d.ts +8 -0
  207. package/dist/connect-accounts.d.ts +15 -0
  208. package/dist/connect-chooser.d.ts +18 -0
  209. package/dist/connect-panel.d.ts +18 -0
  210. package/dist/connect-setup.d.ts +16 -0
  211. package/dist/connect.d.ts +21 -0
  212. package/dist/connect.js +2129 -0
  213. package/dist/connect.js.map +1 -0
  214. package/dist/connection-catalog.d.ts +38 -0
  215. package/dist/connection-discovery.d.ts +12 -0
  216. package/dist/connection-installed.d.ts +17 -0
  217. package/dist/connection-logo.d.ts +9 -0
  218. package/dist/connection-service-logo.d.ts +8 -0
  219. package/dist/connection-service-presentation.d.ts +13 -0
  220. package/dist/connection-skeleton.d.ts +5 -0
  221. package/dist/connection-type-picker.d.ts +6 -0
  222. package/dist/conversation-timeline.d.ts +5 -0
  223. package/dist/desktop.d.ts +7 -0
  224. package/dist/desktop.js +26 -0
  225. package/dist/desktop.js.map +1 -0
  226. package/dist/device-authorization.d.ts +23 -0
  227. package/dist/diffs.d.ts +8 -0
  228. package/dist/diffs.js +14 -0
  229. package/dist/diffs.js.map +1 -0
  230. package/dist/discovery-cache.d.ts +5 -0
  231. package/dist/editor.d.ts +7 -0
  232. package/dist/editor.js +21 -0
  233. package/dist/editor.js.map +1 -0
  234. package/dist/embedded-session-client.d.ts +23 -0
  235. package/dist/file-node-visibility.d.ts +15 -0
  236. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-YZ3ZKWMM.js} +2 -1
  237. package/dist/fleet-decision-row-YZ3ZKWMM.js.map +1 -0
  238. package/dist/hooks/channel-cache.d.ts +23 -0
  239. package/dist/hooks/latest-question.d.ts +25 -0
  240. package/dist/hooks/shared-machines-list.d.ts +14 -0
  241. package/dist/hooks/use-attached-browsers.d.ts +2 -1
  242. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  243. package/dist/hooks/use-browser-session.d.ts +12 -1
  244. package/dist/hooks/use-channels.d.ts +1 -0
  245. package/dist/hooks/use-codex-accounts.d.ts +25 -7
  246. package/dist/hooks/use-composer.d.ts +45 -9
  247. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  248. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  249. package/dist/hooks/use-computer-session.d.ts +2 -0
  250. package/dist/hooks/use-connect.d.ts +22 -0
  251. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  252. package/dist/hooks/use-file-attachments.d.ts +21 -2
  253. package/dist/hooks/use-machine-chip.d.ts +3 -3
  254. package/dist/hooks/use-machines.d.ts +19 -1
  255. package/dist/hooks/use-sandbox-files.d.ts +5 -1
  256. package/dist/hooks/use-session-background-commands.d.ts +14 -0
  257. package/dist/hooks/use-session-events.d.ts +30 -8
  258. package/dist/hooks/use-session-lineage.d.ts +4 -0
  259. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  260. package/dist/hooks/use-session.d.ts +6 -0
  261. package/dist/hooks/use-turn-queue.d.ts +12 -0
  262. package/dist/hooks/use-usage.d.ts +40 -0
  263. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  264. package/dist/hooks/use-workspace-sessions.d.ts +27 -5
  265. package/dist/human-input.d.ts +3 -1
  266. package/dist/identity-link-accounts.d.ts +11 -0
  267. package/dist/identity-link-consent.d.ts +18 -0
  268. package/dist/index.d.ts +60 -17
  269. package/dist/index.js +2237 -6200
  270. package/dist/index.js.map +1 -1
  271. package/dist/interaction.d.ts +1 -1
  272. package/dist/interaction.js +35 -184
  273. package/dist/interaction.js.map +1 -1
  274. package/dist/latest-question-755OW5DS.js +117 -0
  275. package/dist/latest-question-755OW5DS.js.map +1 -0
  276. package/dist/lib/error-message.d.ts +7 -0
  277. package/dist/lib/format.d.ts +36 -2
  278. package/dist/lib/host-theme.d.ts +70 -0
  279. package/dist/lib/interaction-errors.d.ts +6 -0
  280. package/dist/lib/menu-styles.d.ts +22 -0
  281. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  282. package/dist/lib/workbench-peers.d.ts +36 -0
  283. package/dist/lib/xterm-theme.d.ts +7 -5
  284. package/dist/machines.d.ts +4 -2
  285. package/dist/machines.js +14 -4
  286. package/dist/markdown-table-layout-QXSLK4BY.js +106 -0
  287. package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
  288. package/dist/mcp-connection-status.d.ts +14 -0
  289. package/dist/model-policy-picker-menu-PWRI7R2X.js +14 -0
  290. package/dist/model-policy-picker-menu-PWRI7R2X.js.map +1 -0
  291. package/dist/model-policy.d.ts +19 -3
  292. package/dist/model-policy.js +9 -1
  293. package/dist/older-history.d.ts +30 -0
  294. package/dist/platform-activity-row-627BFZ46.js +182 -0
  295. package/dist/platform-activity-row-627BFZ46.js.map +1 -0
  296. package/dist/plugin-details.d.ts +14 -0
  297. package/dist/plugin-discovery.d.ts +25 -0
  298. package/dist/provider.d.ts +13 -1
  299. package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-ZHFI5JBP.js} +131 -44
  300. package/dist/queue-surface-implementation-ZHFI5JBP.js.map +1 -0
  301. package/dist/realtime/realtime-control.d.ts +10 -3
  302. package/dist/realtime.js +229 -83
  303. package/dist/realtime.js.map +1 -1
  304. package/dist/sandbox-files-BBC47SLD.js +20 -0
  305. package/dist/sandbox-files-BBC47SLD.js.map +1 -0
  306. package/dist/session-auth-recommendation.d.ts +5 -0
  307. package/dist/session-capability-policy.d.ts +12 -0
  308. package/dist/session-ui.d.ts +30 -2
  309. package/dist/session-ui.js +85 -7
  310. package/dist/session-ui.js.map +1 -1
  311. package/dist/session.d.ts +8 -2
  312. package/dist/session.js +30 -19
  313. package/dist/sites-ui.d.ts +34 -0
  314. package/dist/sites.d.ts +3 -0
  315. package/dist/sites.js +11 -0
  316. package/dist/sites.js.map +1 -0
  317. package/dist/skill-discovery.d.ts +47 -0
  318. package/dist/terminal.d.ts +8 -0
  319. package/dist/terminal.js +31 -0
  320. package/dist/terminal.js.map +1 -0
  321. package/dist/timeline/activity-rail.d.ts +11 -2
  322. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  323. package/dist/timeline/compaction-copy.d.ts +10 -0
  324. package/dist/timeline/entrance.d.ts +13 -1
  325. package/dist/timeline/genie-loading.d.ts +34 -0
  326. package/dist/timeline/index.d.ts +6 -2
  327. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  328. package/dist/timeline/platform-activity-row.d.ts +14 -0
  329. package/dist/timeline/presented-image.d.ts +6 -0
  330. package/dist/timeline/projection.d.ts +31 -2
  331. package/dist/timeline/registry.d.ts +2 -0
  332. package/dist/timeline/retained-image.d.ts +18 -0
  333. package/dist/timeline/rolling-activity.d.ts +11 -0
  334. package/dist/timeline/screenshot-lightbox.d.ts +16 -1
  335. package/dist/timeline/shared.d.ts +8 -3
  336. package/dist/timeline/startup-preference.d.ts +3 -0
  337. package/dist/timeline/startup-timings.d.ts +4 -0
  338. package/dist/timeline/tool-display-name.d.ts +2 -1
  339. package/dist/timeline/turn-summary.d.ts +32 -3
  340. package/dist/timeline/types.d.ts +141 -7
  341. package/dist/timeline-annotation-markers-GNDHTGBD.js +165 -0
  342. package/dist/timeline-annotation-markers-GNDHTGBD.js.map +1 -0
  343. package/dist/timeline-annotation-selection-DMLMM2TX.js +241 -0
  344. package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
  345. package/dist/timeline-annotations-dialog-ELRDBHTS.js +273 -0
  346. package/dist/timeline-annotations-dialog-ELRDBHTS.js.map +1 -0
  347. package/dist/types/machines.d.ts +2 -2
  348. package/dist/usage/allowance-copy.d.ts +25 -0
  349. package/dist/usage/summary.d.ts +35 -0
  350. package/dist/usage.d.ts +13 -0
  351. package/dist/usage.js +1074 -0
  352. package/dist/usage.js.map +1 -0
  353. package/package.json +44 -4
  354. package/src/accounts.tsx +1072 -0
  355. package/src/approvals.ts +8 -1
  356. package/src/artifacts.ts +42 -0
  357. package/src/assets/README.md +8 -0
  358. package/src/assets/gmail.ico +0 -0
  359. package/src/assets/outlook.ico +0 -0
  360. package/src/capability-catalog-row.tsx +94 -0
  361. package/src/capability-logo-fallback.ts +22 -0
  362. package/src/client.ts +22 -13
  363. package/src/commands/registry.ts +18 -15
  364. package/src/commands/types.ts +2 -0
  365. package/src/components/anthropic-mark.tsx +10 -0
  366. package/src/components/approval-surface.tsx +171 -37
  367. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  368. package/src/components/artifacts/artifact-sandbox.tsx +185 -0
  369. package/src/components/artifacts/artifact-surface.tsx +39 -19
  370. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  371. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  372. package/src/components/artifacts/document-editor.tsx +141 -16
  373. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  374. package/src/components/artifacts/editable-artifact-view.tsx +187 -0
  375. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  376. package/src/components/artifacts/editable-document.tsx +37 -36
  377. package/src/components/artifacts/editable-presentation.tsx +36 -18
  378. package/src/components/artifacts/editable-spreadsheet.tsx +5 -2
  379. package/src/components/artifacts/index.ts +44 -0
  380. package/src/components/artifacts/inline-html-document.ts +24 -0
  381. package/src/components/artifacts/latest-task-runner.ts +49 -0
  382. package/src/components/artifacts/presentation-editor.tsx +323 -67
  383. package/src/components/artifacts/published-html-artifact-frame.tsx +338 -5
  384. package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
  385. package/src/components/artifacts/site-view.tsx +116 -0
  386. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  387. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  388. package/src/components/artifacts/spreadsheet-grid.tsx +12 -13
  389. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  390. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  391. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  392. package/src/components/browser-select-control.tsx +312 -0
  393. package/src/components/browser-viewer.tsx +1054 -314
  394. package/src/components/chat-composer.tsx +131 -85
  395. package/src/components/child-session-link.tsx +27 -0
  396. package/src/components/claude-mark.tsx +10 -0
  397. package/src/components/code-editor.tsx +13 -16
  398. package/src/components/composer-transcription-control.tsx +7 -5
  399. package/src/components/composer.tsx +376 -49
  400. package/src/components/computer-viewer.tsx +1041 -329
  401. package/src/components/copy-button.tsx +13 -5
  402. package/src/components/desktop-viewer.tsx +1 -1
  403. package/src/components/enrollment-consent.tsx +65 -7
  404. package/src/components/enrollment-device-flow.tsx +1 -1
  405. package/src/components/file-browser.tsx +158 -34
  406. package/src/components/fleet-tile.tsx +8 -16
  407. package/src/components/generated-video-player.tsx +4 -2
  408. package/src/components/grok-mark.tsx +33 -0
  409. package/src/components/human-input-form.tsx +455 -114
  410. package/src/components/human-input-surface.tsx +18 -7
  411. package/src/components/interaction-intervention-banner.tsx +2 -2
  412. package/src/components/machine-card.tsx +119 -4
  413. package/src/components/machine-dock-bar.tsx +1 -1
  414. package/src/components/machine-input-display.ts +23 -2
  415. package/src/components/machines/machine-detail.tsx +52 -2
  416. package/src/components/machines/machine-operation-policy.tsx +179 -0
  417. package/src/components/machines-dashboard.tsx +8 -17
  418. package/src/components/markdown-table-layout.ts +132 -0
  419. package/src/components/markdown.tsx +473 -44
  420. package/src/components/message-timeline.tsx +2498 -663
  421. package/src/components/model-mark.tsx +90 -0
  422. package/src/components/model-picker.tsx +15 -4
  423. package/src/components/model-policy-picker-menu.tsx +424 -0
  424. package/src/components/model-policy-picker.tsx +337 -381
  425. package/src/components/open-geni-chat.tsx +319 -0
  426. package/src/components/open-geni-links.tsx +179 -0
  427. package/src/components/openrouter-mark.tsx +13 -0
  428. package/src/components/pierre-diff.tsx +41 -16
  429. package/src/components/pierre-file.tsx +36 -11
  430. package/src/components/preview-loading.tsx +154 -0
  431. package/src/components/queue-item-content.ts +14 -0
  432. package/src/components/queue-surface-implementation.tsx +132 -42
  433. package/src/components/queue-surface-state.tsx +3 -1
  434. package/src/components/sandbox-files.tsx +267 -35
  435. package/src/components/sandbox-terminal.tsx +48 -11
  436. package/src/components/sandbox-workspace.tsx +337 -135
  437. package/src/components/session-capability-frame.tsx +192 -0
  438. package/src/components/session-chrome.tsx +1027 -328
  439. package/src/components/session-commands-panel.tsx +126 -0
  440. package/src/components/session-commands.tsx +18 -0
  441. package/src/components/session-connection-request.tsx +97 -0
  442. package/src/components/session-conversation.tsx +512 -0
  443. package/src/components/session-list.tsx +250 -0
  444. package/src/components/session-mcp-capability-card.tsx +680 -0
  445. package/src/components/session-status.tsx +1 -1
  446. package/src/components/timeline-anchor.tsx +119 -0
  447. package/src/components/timeline-annotation-chrome.tsx +196 -0
  448. package/src/components/timeline-annotation-layout.ts +268 -0
  449. package/src/components/timeline-annotation-markers.tsx +185 -0
  450. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  451. package/src/components/timeline-annotation-selection.tsx +106 -54
  452. package/src/components/timeline-annotation-shared.ts +245 -0
  453. package/src/components/timeline-annotations-dialog.tsx +185 -128
  454. package/src/components/timeline-annotations.tsx +189 -45
  455. package/src/components/timeline-reading-progress.ts +80 -0
  456. package/src/components/timeline-search.tsx +168 -0
  457. package/src/components/timeline-settlement.ts +60 -0
  458. package/src/components/tip-follow.ts +70 -7
  459. package/src/components/tooltip.tsx +38 -5
  460. package/src/components/usage-limit-notice.tsx +179 -0
  461. package/src/components/usage-member-list.tsx +792 -0
  462. package/src/components/usage-meter.tsx +382 -0
  463. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  464. package/src/components/user-message-body.tsx +194 -49
  465. package/src/components/workspace-dock.tsx +141 -175
  466. package/src/composer.ts +6 -1
  467. package/src/connect-account-identity.tsx +34 -0
  468. package/src/connect-accounts.tsx +233 -0
  469. package/src/connect-chooser.tsx +336 -0
  470. package/src/connect-panel.tsx +99 -0
  471. package/src/connect-setup.tsx +307 -0
  472. package/src/connect.ts +60 -0
  473. package/src/connection-assets.d.ts +4 -0
  474. package/src/connection-catalog.tsx +162 -0
  475. package/src/connection-discovery.tsx +235 -0
  476. package/src/connection-installed.tsx +51 -0
  477. package/src/connection-logo.tsx +37 -0
  478. package/src/connection-service-logo.tsx +55 -0
  479. package/src/connection-service-presentation.ts +46 -0
  480. package/src/connection-skeleton.tsx +16 -0
  481. package/src/connection-type-picker.tsx +36 -0
  482. package/src/conversation-timeline.ts +92 -0
  483. package/src/desktop.ts +24 -0
  484. package/src/device-authorization.tsx +98 -0
  485. package/src/diffs.ts +16 -0
  486. package/src/discovery-cache.ts +42 -0
  487. package/src/editor.ts +13 -0
  488. package/src/embedded-session-client.ts +104 -0
  489. package/src/file-node-visibility.ts +66 -0
  490. package/src/hooks/channel-cache.ts +104 -0
  491. package/src/hooks/internal.ts +3 -2
  492. package/src/hooks/latest-question.ts +164 -0
  493. package/src/hooks/shared-machines-list.ts +239 -0
  494. package/src/hooks/use-attached-browsers.ts +5 -1
  495. package/src/hooks/use-available-models.ts +20 -14
  496. package/src/hooks/use-browser-frame-stream.ts +25 -3
  497. package/src/hooks/use-browser-session.ts +271 -71
  498. package/src/hooks/use-browser-sessions.ts +7 -1
  499. package/src/hooks/use-channels.ts +32 -10
  500. package/src/hooks/use-codex-accounts.ts +78 -21
  501. package/src/hooks/use-composer.ts +1034 -320
  502. package/src/hooks/use-computer-frame-stream.ts +39 -16
  503. package/src/hooks/use-computer-input-posture.ts +94 -0
  504. package/src/hooks/use-computer-session.ts +110 -32
  505. package/src/hooks/use-computer-sessions.ts +8 -1
  506. package/src/hooks/use-connect.ts +23 -0
  507. package/src/hooks/use-desktop-stream.ts +19 -28
  508. package/src/hooks/use-file-attachments.ts +118 -10
  509. package/src/hooks/use-goal.ts +36 -9
  510. package/src/hooks/use-human-input.ts +31 -4
  511. package/src/hooks/use-last-started-turn-policy.ts +15 -13
  512. package/src/hooks/use-machine-chip.ts +23 -6
  513. package/src/hooks/use-machines.ts +104 -6
  514. package/src/hooks/use-sandbox-files.ts +253 -150
  515. package/src/hooks/use-sandbox-git.ts +58 -29
  516. package/src/hooks/use-session-background-commands.ts +67 -0
  517. package/src/hooks/use-session-capabilities.ts +21 -2
  518. package/src/hooks/use-session-events.ts +759 -433
  519. package/src/hooks/use-session-lineage.ts +28 -6
  520. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  521. package/src/hooks/use-session.ts +75 -16
  522. package/src/hooks/use-slash-commands.ts +6 -11
  523. package/src/hooks/use-turn-queue.ts +113 -13
  524. package/src/hooks/use-usage.ts +100 -0
  525. package/src/hooks/use-voice-input.ts +12 -1
  526. package/src/hooks/use-workspace-capture.ts +3 -2
  527. package/src/hooks/use-workspace-edit.ts +23 -5
  528. package/src/hooks/use-workspace-sessions.ts +99 -11
  529. package/src/human-input.ts +12 -1
  530. package/src/identity-link-accounts.tsx +148 -0
  531. package/src/identity-link-consent.tsx +192 -0
  532. package/src/index.ts +157 -12
  533. package/src/interaction.ts +1 -0
  534. package/src/lib/error-message.ts +37 -0
  535. package/src/lib/format.ts +150 -14
  536. package/src/lib/host-theme.ts +511 -0
  537. package/src/lib/interaction-errors.ts +33 -0
  538. package/src/lib/menu-styles.ts +44 -0
  539. package/src/lib/pierre-diffs-loader.ts +53 -0
  540. package/src/lib/workbench-peers.ts +62 -0
  541. package/src/lib/xterm-theme.ts +23 -21
  542. package/src/machines.ts +9 -1
  543. package/src/mcp-connection-status.ts +35 -0
  544. package/src/model-policy.ts +223 -69
  545. package/src/older-history.ts +87 -0
  546. package/src/plugin-details.tsx +185 -0
  547. package/src/plugin-discovery.tsx +196 -0
  548. package/src/provider.tsx +55 -14
  549. package/src/realtime/dropdown-menu.tsx +19 -12
  550. package/src/realtime/realtime-control.tsx +274 -60
  551. package/src/session-auth-recommendation.ts +48 -0
  552. package/src/session-capability-policy.ts +83 -0
  553. package/src/session-context.ts +1 -0
  554. package/src/session-ui.ts +66 -2
  555. package/src/session.ts +18 -1
  556. package/src/sites-ui.tsx +402 -0
  557. package/src/sites.ts +3 -0
  558. package/src/skill-discovery.tsx +208 -0
  559. package/src/terminal.ts +26 -0
  560. package/src/timeline/activity-rail.tsx +171 -80
  561. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  562. package/src/timeline/compaction-copy.ts +42 -0
  563. package/src/timeline/entrance.tsx +28 -3
  564. package/src/timeline/fleet-decision-projection.ts +2 -1
  565. package/src/timeline/fleet-decision-row.tsx +1 -0
  566. package/src/timeline/genie-loading.tsx +136 -0
  567. package/src/timeline/index.ts +11 -0
  568. package/src/timeline/knowledge-receipt.tsx +100 -0
  569. package/src/timeline/parsers.ts +2 -2
  570. package/src/timeline/platform-activity-row.tsx +216 -0
  571. package/src/timeline/presented-image.ts +49 -0
  572. package/src/timeline/projection.ts +1600 -84
  573. package/src/timeline/registry.ts +15 -3
  574. package/src/timeline/retained-image.ts +97 -0
  575. package/src/timeline/rolling-activity.tsx +92 -0
  576. package/src/timeline/screenshot-lightbox.tsx +115 -17
  577. package/src/timeline/shared.tsx +47 -15
  578. package/src/timeline/startup-preference.ts +33 -0
  579. package/src/timeline/startup-timings.tsx +145 -0
  580. package/src/timeline/tool-display-name.ts +8 -6
  581. package/src/timeline/tool-renderers.tsx +497 -128
  582. package/src/timeline/turn-summary.tsx +208 -44
  583. package/src/timeline/types.ts +186 -7
  584. package/src/types/machines.ts +10 -0
  585. package/src/usage/allowance-copy.ts +64 -0
  586. package/src/usage/summary.ts +93 -0
  587. package/src/usage.ts +50 -0
  588. package/styles/compiled.css +2098 -757
  589. package/styles/connect.css +284 -0
  590. package/styles/connect.d.ts +1 -0
  591. package/styles/effective-tokens.css +1 -0
  592. package/styles/index.css +201 -9
  593. package/styles/responsive.css +27 -1
  594. package/styles/session-capability.css +44 -0
  595. package/styles/tokens.css +135 -65
  596. package/dist/chunk-5UQPNLIO.js.map +0 -1
  597. package/dist/chunk-6KLX2RH5.js.map +0 -1
  598. package/dist/chunk-7WCLAEFV.js.map +0 -1
  599. package/dist/chunk-B6WPZSTT.js.map +0 -1
  600. package/dist/chunk-FK6VG4LL.js +0 -90
  601. package/dist/chunk-FK6VG4LL.js.map +0 -1
  602. package/dist/chunk-HA46CYQK.js.map +0 -1
  603. package/dist/chunk-HUIKIDM5.js.map +0 -1
  604. package/dist/chunk-IGC6A2ZI.js.map +0 -1
  605. package/dist/chunk-KCGXPP5V.js.map +0 -1
  606. package/dist/chunk-KZ73RL76.js.map +0 -1
  607. package/dist/chunk-LAKLF4PA.js +0 -141
  608. package/dist/chunk-LAKLF4PA.js.map +0 -1
  609. package/dist/chunk-LLOLUHVG.js.map +0 -1
  610. package/dist/chunk-MKPIAGVL.js +0 -465
  611. package/dist/chunk-MKPIAGVL.js.map +0 -1
  612. package/dist/chunk-PEI6RANI.js.map +0 -1
  613. package/dist/chunk-R3AZOAB5.js.map +0 -1
  614. package/dist/chunk-WSK7G5LE.js +0 -170
  615. package/dist/chunk-WSK7G5LE.js.map +0 -1
  616. package/dist/chunk-XBZWOM2K.js +0 -218
  617. package/dist/chunk-XBZWOM2K.js.map +0 -1
  618. package/dist/chunk-Y7OEDUJ5.js +0 -8810
  619. package/dist/chunk-Y7OEDUJ5.js.map +0 -1
  620. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  621. package/dist/hooks/use-packs.d.ts +0 -32
  622. package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
  623. package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
  624. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  625. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  626. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  627. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  628. package/src/hooks/use-packs.ts +0 -157
  629. /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-GTR5XQ7X.js.map} +0 -0
@@ -0,0 +1,1072 @@
1
+ import type {
2
+ BrowserAccountsClientLike,
3
+ ManagedAuthDeepLinkResolution,
4
+ ManagedAuthLoginTransaction,
5
+ ManagedAuthSessionSetProjection,
6
+ } from "@opengeni/sdk/accounts";
7
+ import {
8
+ createContext,
9
+ useCallback,
10
+ useContext,
11
+ useEffect,
12
+ useMemo,
13
+ useRef,
14
+ useState,
15
+ type ReactNode,
16
+ } from "react";
17
+
18
+ export type BrowserAccountTransitionPhase =
19
+ | "preflight"
20
+ | "blocked"
21
+ | "committing"
22
+ | "loading"
23
+ | "ready"
24
+ | "recoverable_error";
25
+
26
+ export type BrowserAccountTransitionKind =
27
+ | "add"
28
+ | "select"
29
+ | "logout_one"
30
+ | "logout_all"
31
+ | "reauth"
32
+ | "cross_tab";
33
+
34
+ export type BrowserAccountTransitionBlocker = {
35
+ id: string;
36
+ label: string;
37
+ detail?: string | undefined;
38
+ };
39
+
40
+ export type BrowserAccountTransition = {
41
+ kind: BrowserAccountTransitionKind;
42
+ from: ManagedAuthSessionSetProjection | null;
43
+ to: ManagedAuthSessionSetProjection | null;
44
+ signal: AbortSignal;
45
+ };
46
+
47
+ export type BrowserAccountsProviderProps = {
48
+ client: BrowserAccountsClientLike;
49
+ /**
50
+ * Hide the authenticated tree, abort old actor work, clear tenant-bound
51
+ * state, recreate credentials/clients, and refetch principal access here.
52
+ * Cross-tab/server invalidation first calls this with `to: null` as a
53
+ * neutral fence before authority is reread, then calls it with the accepted
54
+ * projection after the new actor is known.
55
+ */
56
+ onActorTransition: (transition: BrowserAccountTransition) => Promise<void>;
57
+ children?: ReactNode;
58
+ broadcastChannelName?: string | null | undefined;
59
+ /** Adopt the already-authenticated legacy provider session during dual-mode rollout. */
60
+ bootstrapLegacySession?: boolean | undefined;
61
+ };
62
+
63
+ type BlockerInspector = () => BrowserAccountTransitionBlocker | null;
64
+
65
+ type PendingNonSecretTransition = {
66
+ kind: Exclude<BrowserAccountTransitionKind, "add" | "reauth" | "cross_tab">;
67
+ operationId: string;
68
+ expectedGeneration: string | null;
69
+ changesActor: (projection: ManagedAuthSessionSetProjection) => boolean;
70
+ execute: (expectedGeneration: string) => Promise<ManagedAuthSessionSetProjection>;
71
+ };
72
+
73
+ export type BrowserAccountsContextValue = {
74
+ projection: ManagedAuthSessionSetProjection | null;
75
+ phase: BrowserAccountTransitionPhase;
76
+ blockers: BrowserAccountTransitionBlocker[];
77
+ error: Error | null;
78
+ transaction: ManagedAuthLoginTransaction | null;
79
+ hasPendingTransition: boolean;
80
+ refresh: () => Promise<ManagedAuthSessionSetProjection | null>;
81
+ invalidateActor: () => Promise<ManagedAuthSessionSetProjection | null>;
82
+ registerTransitionBlocker: (id: string, inspect: BlockerInspector) => () => void;
83
+ continueTransition: () => Promise<boolean>;
84
+ cancelPendingTransition: () => void;
85
+ beginAdd: (returnIntent?: string | undefined) => Promise<ManagedAuthLoginTransaction>;
86
+ beginReauth: (
87
+ slotId: string,
88
+ returnIntent?: string | undefined,
89
+ ) => Promise<ManagedAuthLoginTransaction>;
90
+ completeEmailPassword: (input: { email: string; password: string }) => Promise<boolean>;
91
+ settleExternalLoginTransaction: (transactionId: string) => Promise<boolean>;
92
+ cancelLoginTransaction: () => Promise<void>;
93
+ selectSlot: (slotId: string) => Promise<boolean>;
94
+ logoutSlot: (slotId: string, replacementSlotId: string | null) => Promise<boolean>;
95
+ logoutAll: () => Promise<boolean>;
96
+ resolveDeepLink: (path: string) => Promise<ManagedAuthDeepLinkResolution>;
97
+ };
98
+
99
+ const BrowserAccountsContext = createContext<BrowserAccountsContextValue | null>(null);
100
+ const DEFAULT_CHANNEL = "opengeni:browser-account-epoch:v1";
101
+ const CROSS_TAB_ACTOR_HOLD_MS = 30_000;
102
+
103
+ async function yieldToCrossTabActorHold(): Promise<void> {
104
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
105
+ }
106
+
107
+ function operationId(): string {
108
+ return crypto.randomUUID();
109
+ }
110
+
111
+ function sameActor(
112
+ left: ManagedAuthSessionSetProjection | null,
113
+ right: ManagedAuthSessionSetProjection | null,
114
+ ): boolean {
115
+ return (
116
+ left?.generation === right?.generation &&
117
+ left?.actorEpoch === right?.actorEpoch &&
118
+ left?.selectedSlotId === right?.selectedSlotId &&
119
+ left?.state === right?.state
120
+ );
121
+ }
122
+
123
+ function sameSelectedActor(
124
+ left: ManagedAuthSessionSetProjection | null,
125
+ right: ManagedAuthSessionSetProjection | null,
126
+ ): boolean {
127
+ return (
128
+ left !== null &&
129
+ right !== null &&
130
+ left.actorEpoch === right.actorEpoch &&
131
+ left.selectedSlotId === right.selectedSlotId &&
132
+ left.state === right.state
133
+ );
134
+ }
135
+
136
+ function compareCounter(left: string, right: string): number {
137
+ const leftValue = BigInt(left);
138
+ const rightValue = BigInt(right);
139
+ return leftValue < rightValue ? -1 : leftValue > rightValue ? 1 : 0;
140
+ }
141
+
142
+ function isOlderProjection(
143
+ candidate: ManagedAuthSessionSetProjection,
144
+ current: ManagedAuthSessionSetProjection,
145
+ ): boolean {
146
+ const epoch = compareCounter(candidate.actorEpoch, current.actorEpoch);
147
+ return epoch < 0 || (epoch === 0 && compareCounter(candidate.generation, current.generation) < 0);
148
+ }
149
+
150
+ function accountError(error: unknown): Error {
151
+ return error instanceof Error ? error : new Error("Browser account operation failed");
152
+ }
153
+
154
+ function supersededOperationError(): Error {
155
+ const error = new Error("Browser account operation was superseded by an actor change");
156
+ error.name = "AbortError";
157
+ return error;
158
+ }
159
+
160
+ function errorCode(error: unknown): string | null {
161
+ if (!error || typeof error !== "object") return null;
162
+ const code = (error as { code?: unknown }).code;
163
+ return typeof code === "string" ? code : null;
164
+ }
165
+
166
+ function needsReconciliation(error: unknown): boolean {
167
+ return new Set(["actor_change_required", "generation_conflict", "operation_outcome_unknown"]).has(
168
+ errorCode(error) ?? "",
169
+ );
170
+ }
171
+
172
+ export function BrowserAccountsProvider({
173
+ client,
174
+ onActorTransition,
175
+ children,
176
+ broadcastChannelName = DEFAULT_CHANNEL,
177
+ bootstrapLegacySession = false,
178
+ }: BrowserAccountsProviderProps) {
179
+ const [projection, setProjection] = useState<ManagedAuthSessionSetProjection | null>(null);
180
+ const [phase, setPhase] = useState<BrowserAccountTransitionPhase>("loading");
181
+ const [blockers, setBlockers] = useState<BrowserAccountTransitionBlocker[]>([]);
182
+ const [error, setError] = useState<Error | null>(null);
183
+ const [transaction, setTransaction] = useState<ManagedAuthLoginTransaction | null>(null);
184
+ const projectionRef = useRef(projection);
185
+ const transactionRef = useRef(transaction);
186
+ const blockerInspectorsRef = useRef(new Map<string, BlockerInspector>());
187
+ const pendingRef = useRef<PendingNonSecretTransition | null>(null);
188
+ const transactionTargetSlotIdRef = useRef<string | null>(null);
189
+ const beginOperationRef = useRef<{ signature: string; operationId: string } | null>(null);
190
+ const bootstrapOperationRef = useRef<{ generation: string; operationId: string } | null>(null);
191
+ const completionOperationRef = useRef<{
192
+ operationId: string;
193
+ expectedGeneration: string;
194
+ } | null>(null);
195
+ const cancelOperationRef = useRef<{
196
+ operationId: string;
197
+ expectedGeneration: string;
198
+ } | null>(null);
199
+ const pendingCommitSequenceRef = useRef<number | null>(null);
200
+ const pendingServerMutationSequenceRef = useRef<number | null>(null);
201
+ const invalidatedDuringPendingCommitRef = useRef(false);
202
+ const sequenceRef = useRef(0);
203
+ const transitionAbortRef = useRef<AbortController | null>(null);
204
+ const channelRef = useRef<BroadcastChannel | null>(null);
205
+ const crossTabActorHoldsRef = useRef(new Map<string, ReturnType<typeof setTimeout>>());
206
+ projectionRef.current = projection;
207
+ transactionRef.current = transaction;
208
+
209
+ const inspectBlockers = useCallback((): BrowserAccountTransitionBlocker[] => {
210
+ const current = [...blockerInspectorsRef.current.entries()]
211
+ .map(([id, inspect]) => {
212
+ const blocker = inspect();
213
+ return blocker ? { ...blocker, id } : null;
214
+ })
215
+ .filter((value): value is BrowserAccountTransitionBlocker => value !== null)
216
+ .sort((left, right) => left.id.localeCompare(right.id));
217
+ setBlockers(current);
218
+ return current;
219
+ }, []);
220
+
221
+ const publishActorHint = useCallback((next: ManagedAuthSessionSetProjection | null) => {
222
+ if (!next) return;
223
+ channelRef.current?.postMessage({
224
+ type: "actor-epoch-changed",
225
+ generation: next.generation,
226
+ actorEpoch: next.actorEpoch,
227
+ });
228
+ }, []);
229
+
230
+ const publishActorHold = useCallback(
231
+ (transitionId: string, current: ManagedAuthSessionSetProjection) => {
232
+ channelRef.current?.postMessage({
233
+ type: "actor-transition-pending",
234
+ transitionId,
235
+ generation: current.generation,
236
+ actorEpoch: current.actorEpoch,
237
+ });
238
+ },
239
+ [],
240
+ );
241
+
242
+ const publishActorRelease = useCallback((transitionId: string) => {
243
+ channelRef.current?.postMessage({
244
+ type: "actor-transition-released",
245
+ transitionId,
246
+ });
247
+ }, []);
248
+
249
+ const clearLoginTransactionState = useCallback(() => {
250
+ transactionRef.current = null;
251
+ beginOperationRef.current = null;
252
+ completionOperationRef.current = null;
253
+ cancelOperationRef.current = null;
254
+ transactionTargetSlotIdRef.current = null;
255
+ setTransaction(null);
256
+ }, []);
257
+
258
+ const settleActorTransition = useCallback(
259
+ async (
260
+ kind: BrowserAccountTransitionKind,
261
+ from: ManagedAuthSessionSetProjection | null,
262
+ accepted: ManagedAuthSessionSetProjection | null,
263
+ sequence: number,
264
+ publish: boolean,
265
+ authorityResetConfirmed = false,
266
+ initiatingSurfaceFenced = false,
267
+ ): Promise<ManagedAuthSessionSetProjection | null> => {
268
+ let source = from;
269
+ let target = accepted;
270
+ if (!authorityResetConfirmed && from && target && isOlderProjection(target, from)) {
271
+ target = await client.getSessionSet();
272
+ if (sequenceRef.current !== sequence) return null;
273
+ if (isOlderProjection(target, from)) {
274
+ throw new Error("Browser account response regressed the accepted actor epoch");
275
+ }
276
+ }
277
+ if (!initiatingSurfaceFenced && sameSelectedActor(source, target)) {
278
+ setProjection(target);
279
+ setPhase("ready");
280
+ setError(null);
281
+ return target;
282
+ }
283
+ while (true) {
284
+ transitionAbortRef.current?.abort();
285
+ const controller = new AbortController();
286
+ transitionAbortRef.current = controller;
287
+ // The accepted mutation is already server authority. Notify peers now,
288
+ // before this tab waits for its own auth/access reload, so they can hide
289
+ // and abort old-actor work throughout that entire window.
290
+ if (publish) publishActorHint(target);
291
+ setPhase("loading");
292
+ await onActorTransition({
293
+ kind,
294
+ from: initiatingSurfaceFenced ? null : source,
295
+ to: target,
296
+ signal: controller.signal,
297
+ });
298
+ initiatingSurfaceFenced = false;
299
+ if (controller.signal.aborted || sequenceRef.current !== sequence) return null;
300
+ if (!target) {
301
+ setProjection(null);
302
+ setPhase("ready");
303
+ setError(null);
304
+ return null;
305
+ }
306
+ const confirmed = await client.reconcileSessionSetAuthority();
307
+ if (controller.signal.aborted || sequenceRef.current !== sequence) return null;
308
+ if (sameActor(target, confirmed) || sameSelectedActor(target, confirmed)) {
309
+ setProjection(confirmed);
310
+ setPhase("ready");
311
+ setError(null);
312
+ return confirmed;
313
+ }
314
+ // Tenant state was loaded for an authority that rotated again while
315
+ // the host callback was pending. The explicit two-probe result is the
316
+ // new authority even when its counters are lower, so keep the actor
317
+ // hidden and settle that authority before exposing ready state.
318
+ source = target;
319
+ target = confirmed;
320
+ }
321
+ },
322
+ [client, onActorTransition, publishActorHint],
323
+ );
324
+
325
+ const reconcile = useCallback(
326
+ async (kind: BrowserAccountTransitionKind, publish = false) => {
327
+ const sequence = ++sequenceRef.current;
328
+ const before = projectionRef.current;
329
+ setPhase("loading");
330
+ let first = await client.reconcileSessionSetAuthority();
331
+ if (sequenceRef.current !== sequence) return null;
332
+ if (
333
+ bootstrapLegacySession &&
334
+ first.mode === "dual" &&
335
+ first.selectedSlotId === null &&
336
+ first.slots.length === 0
337
+ ) {
338
+ const bootstrapOperation =
339
+ bootstrapOperationRef.current?.generation === first.generation
340
+ ? bootstrapOperationRef.current.operationId
341
+ : operationId();
342
+ bootstrapOperationRef.current = {
343
+ generation: first.generation,
344
+ operationId: bootstrapOperation,
345
+ };
346
+ try {
347
+ first = await client.bootstrapSessionSet({
348
+ operationId: bootstrapOperation,
349
+ expectedGeneration: first.generation,
350
+ });
351
+ bootstrapOperationRef.current = null;
352
+ } catch (caught) {
353
+ if (!needsReconciliation(caught)) throw caught;
354
+ const reconciled = await client.getSessionSet();
355
+ if (sequenceRef.current !== sequence) return null;
356
+ if (reconciled.selectedSlotId === null || reconciled.slots.length === 0) throw caught;
357
+ first = reconciled;
358
+ bootstrapOperationRef.current = null;
359
+ }
360
+ }
361
+ if (sameActor(before, first) || sameSelectedActor(before, first)) {
362
+ setProjection(first);
363
+ setPhase("ready");
364
+ setError(null);
365
+ return first;
366
+ }
367
+ if (kind === "cross_tab") clearLoginTransactionState();
368
+ return await settleActorTransition(kind, before, first, sequence, publish, true);
369
+ },
370
+ [bootstrapLegacySession, clearLoginTransactionState, client, settleActorTransition],
371
+ );
372
+
373
+ const fail = useCallback(
374
+ async (caught: unknown, kind: BrowserAccountTransitionKind): Promise<never> => {
375
+ const nextError = accountError(caught);
376
+ if (needsReconciliation(caught)) {
377
+ try {
378
+ await reconcile(kind);
379
+ } catch {
380
+ // Preserve the original typed failure; a manual refresh remains available.
381
+ }
382
+ }
383
+ setError(nextError);
384
+ setPhase("recoverable_error");
385
+ throw nextError;
386
+ },
387
+ [reconcile],
388
+ );
389
+
390
+ const executePending = useCallback(
391
+ async (pending: PendingNonSecretTransition): Promise<boolean> => {
392
+ const blocked = inspectBlockers();
393
+ if (blocked.length > 0) {
394
+ pendingRef.current = pending;
395
+ setPhase("blocked");
396
+ return false;
397
+ }
398
+ const current = projectionRef.current;
399
+ if (!current) throw new Error("Browser session set is not loaded");
400
+ const expectedGeneration = pending.expectedGeneration ?? current.generation;
401
+ pending.expectedGeneration = expectedGeneration;
402
+ const sequence = ++sequenceRef.current;
403
+ pendingCommitSequenceRef.current = sequence;
404
+ pendingServerMutationSequenceRef.current = null;
405
+ invalidatedDuringPendingCommitRef.current = false;
406
+ pendingRef.current = pending;
407
+ setPhase("committing");
408
+ setError(null);
409
+ const changesActor = pending.changesActor(current);
410
+ let initiatingActorFenced = false;
411
+ try {
412
+ if (changesActor) {
413
+ // Every tab, including the initiator, must hide and abort the old actor
414
+ // before this request can be accepted. Otherwise a response-lost
415
+ // logout can leave the initiating route alive long enough for its
416
+ // event stream to reconnect with the newly revoked cookie.
417
+ publishActorHold(pending.operationId, current);
418
+ transitionAbortRef.current?.abort();
419
+ const controller = new AbortController();
420
+ transitionAbortRef.current = controller;
421
+ projectionRef.current = null;
422
+ setProjection(null);
423
+ setPhase("loading");
424
+ // The host can synchronously clear its actor surface before its
425
+ // transition promise later rejects. From this point on, every
426
+ // failure must reconcile and restore authority even though the
427
+ // account mutation has not started yet.
428
+ initiatingActorFenced = true;
429
+ await onActorTransition({
430
+ kind: pending.kind,
431
+ from: current,
432
+ to: null,
433
+ signal: controller.signal,
434
+ });
435
+ if (controller.signal.aborted || sequenceRef.current !== sequence) return false;
436
+ // Yield one task after the secret-free hold so queued BroadcastChannel
437
+ // delivery can fence peers before the network mutation starts.
438
+ await yieldToCrossTabActorHold();
439
+ if (controller.signal.aborted || sequenceRef.current !== sequence) return false;
440
+ }
441
+ pendingServerMutationSequenceRef.current = sequence;
442
+ let accepted: ManagedAuthSessionSetProjection;
443
+ try {
444
+ accepted = await pending.execute(expectedGeneration);
445
+ } catch (caught) {
446
+ if (errorCode(caught) !== "operation_outcome_unknown") throw caught;
447
+ // The command may already be durable. Replay exactly once before a
448
+ // generic authority read so a response-lost terminal mutation can
449
+ // recover its receipt with the frozen operation and admission data.
450
+ accepted = await pending.execute(expectedGeneration);
451
+ }
452
+ if (sequenceRef.current !== sequence) return false;
453
+ // A successful logout-all response is itself an authority-rotation
454
+ // receipt; every other lower-clock adoption must come from the SDK's
455
+ // explicit two-probe reconciliation path below.
456
+ let authorityResetConfirmed = pending.kind === "logout_all";
457
+ if (invalidatedDuringPendingCommitRef.current) {
458
+ accepted = await client.reconcileSessionSetAuthority();
459
+ authorityResetConfirmed = true;
460
+ if (sequenceRef.current !== sequence) return false;
461
+ }
462
+ pendingRef.current = null;
463
+ // The server response and any invalidation reconciliation are now
464
+ // authoritative. Release commit ownership before host settlement so a
465
+ // later invalidation starts its own reconciliation instead of relying
466
+ // on the already-consumed check above.
467
+ if (pendingServerMutationSequenceRef.current === sequence) {
468
+ pendingServerMutationSequenceRef.current = null;
469
+ }
470
+ if (pendingCommitSequenceRef.current === sequence) {
471
+ pendingCommitSequenceRef.current = null;
472
+ invalidatedDuringPendingCommitRef.current = false;
473
+ }
474
+ if (
475
+ !initiatingActorFenced &&
476
+ !authorityResetConfirmed &&
477
+ sameSelectedActor(current, accepted)
478
+ ) {
479
+ setProjection(accepted);
480
+ setPhase("ready");
481
+ setError(null);
482
+ } else {
483
+ await settleActorTransition(
484
+ pending.kind,
485
+ current,
486
+ accepted,
487
+ sequence,
488
+ true,
489
+ authorityResetConfirmed,
490
+ initiatingActorFenced,
491
+ );
492
+ }
493
+ return true;
494
+ } catch (caught) {
495
+ if (initiatingActorFenced) {
496
+ let authorityRestored = false;
497
+ try {
498
+ const restored = await client.reconcileSessionSetAuthority();
499
+ if (sequenceRef.current !== sequence) return false;
500
+ await settleActorTransition(
501
+ pending.kind,
502
+ current,
503
+ restored,
504
+ sequence,
505
+ false,
506
+ true,
507
+ true,
508
+ );
509
+ if (sequenceRef.current !== sequence) return false;
510
+ authorityRestored = true;
511
+ } catch {
512
+ // If authority itself cannot be reconciled, retain the existing
513
+ // fail-closed provider error path and its manual retry surface.
514
+ }
515
+ if (authorityRestored) {
516
+ // Restore transport provenance before retaining the existing
517
+ // fail-closed retry surface. The retry screen keeps tenant data
518
+ // hidden, while refresh can safely reveal this reconciled actor.
519
+ const restoredError = accountError(caught);
520
+ setError(restoredError);
521
+ setPhase("recoverable_error");
522
+ throw restoredError;
523
+ }
524
+ }
525
+ return await fail(caught, pending.kind);
526
+ } finally {
527
+ if (changesActor) publishActorRelease(pending.operationId);
528
+ if (pendingServerMutationSequenceRef.current === sequence) {
529
+ pendingServerMutationSequenceRef.current = null;
530
+ }
531
+ if (pendingCommitSequenceRef.current === sequence) {
532
+ pendingCommitSequenceRef.current = null;
533
+ invalidatedDuringPendingCommitRef.current = false;
534
+ }
535
+ }
536
+ },
537
+ [
538
+ client,
539
+ fail,
540
+ inspectBlockers,
541
+ onActorTransition,
542
+ publishActorHold,
543
+ publishActorRelease,
544
+ settleActorTransition,
545
+ ],
546
+ );
547
+
548
+ const refresh = useCallback(async () => {
549
+ try {
550
+ return await reconcile("cross_tab");
551
+ } catch (caught) {
552
+ const nextError = accountError(caught);
553
+ setError(nextError);
554
+ setPhase("recoverable_error");
555
+ throw nextError;
556
+ }
557
+ }, [reconcile]);
558
+
559
+ const beginNeutralActorInvalidation = useCallback(
560
+ async (before: ManagedAuthSessionSetProjection | null): Promise<AbortController> => {
561
+ transitionAbortRef.current?.abort();
562
+ const controller = new AbortController();
563
+ transitionAbortRef.current = controller;
564
+ projectionRef.current = null;
565
+ setProjection(null);
566
+ clearLoginTransactionState();
567
+ setPhase("loading");
568
+ setError(null);
569
+ // Do not wait for the authority reread before asking the host to remove
570
+ // and abort the prior actor. A response that was already in flight can
571
+ // otherwise commit old tenant state during the cross-tab hint/read race.
572
+ await onActorTransition({
573
+ kind: "cross_tab",
574
+ from: before,
575
+ to: null,
576
+ signal: controller.signal,
577
+ });
578
+ return controller;
579
+ },
580
+ [clearLoginTransactionState, onActorTransition],
581
+ );
582
+
583
+ const invalidateActor = useCallback(async () => {
584
+ const pendingCommitSequence = pendingCommitSequenceRef.current;
585
+ if (
586
+ pendingCommitSequence !== null &&
587
+ pendingServerMutationSequenceRef.current === pendingCommitSequence
588
+ ) {
589
+ invalidatedDuringPendingCommitRef.current = true;
590
+ await beginNeutralActorInvalidation(projectionRef.current);
591
+ return null;
592
+ }
593
+ // An authority hint that arrives while the initiating host fence is still
594
+ // pending supersedes the not-yet-dispatched mutation. Reconcile it here;
595
+ // otherwise aborting that fence makes executePending return early while no
596
+ // operation remains to restore the neutral actor surface.
597
+ if (pendingCommitSequence !== null) {
598
+ pendingCommitSequenceRef.current = null;
599
+ pendingServerMutationSequenceRef.current = null;
600
+ invalidatedDuringPendingCommitRef.current = false;
601
+ pendingRef.current = null;
602
+ }
603
+ const sequence = ++sequenceRef.current;
604
+ const before = projectionRef.current;
605
+ try {
606
+ const neutral = await beginNeutralActorInvalidation(before);
607
+ if (neutral.signal.aborted || sequenceRef.current !== sequence) return null;
608
+ const accepted = await client.reconcileSessionSetAuthority();
609
+ if (sequenceRef.current !== sequence) return null;
610
+ return await settleActorTransition("cross_tab", before, accepted, sequence, false, true);
611
+ } catch (caught) {
612
+ if (sequenceRef.current !== sequence) return null;
613
+ const nextError = accountError(caught);
614
+ setError(nextError);
615
+ setPhase("recoverable_error");
616
+ throw nextError;
617
+ }
618
+ }, [beginNeutralActorInvalidation, client, settleActorTransition]);
619
+
620
+ const registerTransitionBlocker = useCallback((id: string, inspect: BlockerInspector) => {
621
+ if (!id.trim()) throw new Error("Browser account transition blocker id is required");
622
+ blockerInspectorsRef.current.set(id, inspect);
623
+ return () => {
624
+ if (blockerInspectorsRef.current.get(id) === inspect) {
625
+ blockerInspectorsRef.current.delete(id);
626
+ }
627
+ };
628
+ }, []);
629
+
630
+ const continueTransition = useCallback(async (): Promise<boolean> => {
631
+ const pending = pendingRef.current;
632
+ return pending ? await executePending(pending) : false;
633
+ }, [executePending]);
634
+
635
+ const cancelPendingTransition = useCallback(() => {
636
+ pendingRef.current = null;
637
+ setBlockers([]);
638
+ setPhase(projectionRef.current ? "ready" : "loading");
639
+ }, []);
640
+
641
+ const beginLogin = useCallback(
642
+ async (kind: "add" | "reauth", slotId?: string, returnIntent?: string) => {
643
+ const current = projectionRef.current;
644
+ if (!current) throw new Error("Browser session set is not loaded");
645
+ if (kind === "reauth" && slotId === current.selectedSlotId && inspectBlockers().length > 0) {
646
+ setPhase("blocked");
647
+ throw new Error("Settle account transition blockers before re-authenticating");
648
+ }
649
+ const sequence = ++sequenceRef.current;
650
+ setPhase("committing");
651
+ setError(null);
652
+ const signature = JSON.stringify([
653
+ kind,
654
+ slotId ?? null,
655
+ returnIntent ?? null,
656
+ current.generation,
657
+ ]);
658
+ const beginOperation =
659
+ beginOperationRef.current?.signature === signature
660
+ ? beginOperationRef.current.operationId
661
+ : operationId();
662
+ beginOperationRef.current = { signature, operationId: beginOperation };
663
+ let next: ManagedAuthLoginTransaction;
664
+ try {
665
+ next = await client.beginLoginTransaction({
666
+ operationId: beginOperation,
667
+ expectedGeneration: current.generation,
668
+ kind,
669
+ ...(slotId ? { slotId } : {}),
670
+ ...(returnIntent ? { returnIntent } : {}),
671
+ });
672
+ } catch (caught) {
673
+ if (sequenceRef.current !== sequence) {
674
+ if (beginOperationRef.current?.operationId === beginOperation) {
675
+ beginOperationRef.current = null;
676
+ }
677
+ throw supersededOperationError();
678
+ }
679
+ return await fail(caught, kind);
680
+ }
681
+ if (sequenceRef.current !== sequence) {
682
+ if (beginOperationRef.current?.operationId === beginOperation) {
683
+ beginOperationRef.current = null;
684
+ }
685
+ throw supersededOperationError();
686
+ }
687
+ beginOperationRef.current = null;
688
+ transactionTargetSlotIdRef.current = slotId ?? null;
689
+ completionOperationRef.current = null;
690
+ cancelOperationRef.current = null;
691
+ setTransaction(next);
692
+ setPhase("ready");
693
+ return next;
694
+ },
695
+ [client, fail, inspectBlockers],
696
+ );
697
+
698
+ const beginAdd = useCallback(
699
+ async (returnIntent?: string) => await beginLogin("add", undefined, returnIntent),
700
+ [beginLogin],
701
+ );
702
+ const beginReauth = useCallback(
703
+ async (slotId: string, returnIntent?: string) =>
704
+ await beginLogin("reauth", slotId, returnIntent),
705
+ [beginLogin],
706
+ );
707
+
708
+ const completeEmailPassword = useCallback(
709
+ async (input: { email: string; password: string }): Promise<boolean> => {
710
+ const current = projectionRef.current;
711
+ const activeTransaction = transactionRef.current;
712
+ if (!current || !activeTransaction) throw new Error("No browser login transaction is active");
713
+ const selectedReauth =
714
+ activeTransaction.kind === "reauth" &&
715
+ transactionTargetSlotIdRef.current !== null &&
716
+ transactionTargetSlotIdRef.current === current.selectedSlotId;
717
+ if (selectedReauth && inspectBlockers().length > 0) {
718
+ setPhase("blocked");
719
+ return false;
720
+ }
721
+ const sequence = ++sequenceRef.current;
722
+ setPhase("committing");
723
+ setError(null);
724
+ const completionOperation = completionOperationRef.current ?? {
725
+ operationId: operationId(),
726
+ expectedGeneration: current.generation,
727
+ };
728
+ completionOperationRef.current = completionOperation;
729
+ try {
730
+ const completed = await client.completeEmailPasswordTransaction({
731
+ operationId: completionOperation.operationId,
732
+ expectedGeneration: completionOperation.expectedGeneration,
733
+ transactionId: activeTransaction.id,
734
+ email: input.email,
735
+ password: input.password,
736
+ });
737
+ if (sequenceRef.current !== sequence) return false;
738
+ completionOperationRef.current = null;
739
+ cancelOperationRef.current = null;
740
+ transactionTargetSlotIdRef.current = null;
741
+ setTransaction(null);
742
+ const actorChanged = completed.projection.actorEpoch !== current.actorEpoch;
743
+ if (actorChanged) {
744
+ await settleActorTransition(
745
+ activeTransaction.kind,
746
+ current,
747
+ completed.projection,
748
+ sequence,
749
+ true,
750
+ );
751
+ } else {
752
+ setProjection(completed.projection);
753
+ setPhase("ready");
754
+ }
755
+ return true;
756
+ } catch (caught) {
757
+ return await fail(caught, activeTransaction.kind);
758
+ }
759
+ },
760
+ [client, fail, inspectBlockers, settleActorTransition],
761
+ );
762
+
763
+ const settleExternalLoginTransaction = useCallback(
764
+ async (transactionId: string): Promise<boolean> => {
765
+ const activeTransaction = transactionRef.current;
766
+ if (!activeTransaction || activeTransaction.id !== transactionId) return false;
767
+ try {
768
+ await reconcile(activeTransaction.kind, true);
769
+ if (transactionRef.current?.id !== transactionId) return false;
770
+ completionOperationRef.current = null;
771
+ cancelOperationRef.current = null;
772
+ transactionTargetSlotIdRef.current = null;
773
+ setTransaction(null);
774
+ return true;
775
+ } catch (caught) {
776
+ const nextError = accountError(caught);
777
+ setError(nextError);
778
+ setPhase("recoverable_error");
779
+ throw nextError;
780
+ }
781
+ },
782
+ [reconcile],
783
+ );
784
+
785
+ const cancelLoginTransaction = useCallback(async () => {
786
+ const current = projectionRef.current;
787
+ const activeTransaction = transactionRef.current;
788
+ if (!current || !activeTransaction) return;
789
+ const sequence = ++sequenceRef.current;
790
+ setPhase("committing");
791
+ const cancelOperation = cancelOperationRef.current ?? {
792
+ operationId: operationId(),
793
+ expectedGeneration: current.generation,
794
+ };
795
+ cancelOperationRef.current = cancelOperation;
796
+ let next: ManagedAuthSessionSetProjection;
797
+ try {
798
+ next = await client.cancelLoginTransaction({
799
+ operationId: cancelOperation.operationId,
800
+ expectedGeneration: cancelOperation.expectedGeneration,
801
+ transactionId: activeTransaction.id,
802
+ });
803
+ } catch (caught) {
804
+ if (sequenceRef.current !== sequence) {
805
+ if (cancelOperationRef.current?.operationId === cancelOperation.operationId) {
806
+ cancelOperationRef.current = null;
807
+ }
808
+ throw supersededOperationError();
809
+ }
810
+ await fail(caught, activeTransaction.kind);
811
+ return;
812
+ }
813
+ if (sequenceRef.current !== sequence) {
814
+ if (cancelOperationRef.current?.operationId === cancelOperation.operationId) {
815
+ cancelOperationRef.current = null;
816
+ }
817
+ throw supersededOperationError();
818
+ }
819
+ clearLoginTransactionState();
820
+ setProjection(next);
821
+ setPhase("ready");
822
+ setError(null);
823
+ }, [clearLoginTransactionState, client, fail]);
824
+
825
+ const selectSlot = useCallback(
826
+ async (slotId: string) => {
827
+ const id = operationId();
828
+ return await executePending({
829
+ kind: "select",
830
+ operationId: id,
831
+ expectedGeneration: null,
832
+ changesActor: (current) => current.selectedSlotId !== slotId,
833
+ execute: async (expectedGeneration) =>
834
+ await client.selectLoginSlot({
835
+ operationId: id,
836
+ expectedGeneration,
837
+ slotId,
838
+ }),
839
+ });
840
+ },
841
+ [client, executePending],
842
+ );
843
+
844
+ const logoutSlot = useCallback(
845
+ async (slotId: string, replacementSlotId: string | null) => {
846
+ const id = operationId();
847
+ return await executePending({
848
+ kind: "logout_one",
849
+ operationId: id,
850
+ expectedGeneration: null,
851
+ changesActor: (current) => current.selectedSlotId === slotId,
852
+ execute: async (expectedGeneration) =>
853
+ await client.logoutLoginSlot({
854
+ operationId: id,
855
+ expectedGeneration,
856
+ slotId,
857
+ replacementSlotId,
858
+ }),
859
+ });
860
+ },
861
+ [client, executePending],
862
+ );
863
+
864
+ const logoutAll = useCallback(async () => {
865
+ const id = operationId();
866
+ return await executePending({
867
+ kind: "logout_all",
868
+ operationId: id,
869
+ expectedGeneration: null,
870
+ // Logout-all always rotates the browser-set authority, even when the set
871
+ // is neutral but still contains slots. Peers must therefore enter the
872
+ // same precommit hold and reconciliation boundary unconditionally.
873
+ changesActor: () => true,
874
+ execute: async (expectedGeneration) => {
875
+ await client.logoutSessionSet({ operationId: id, expectedGeneration });
876
+ return await client.getSessionSet();
877
+ },
878
+ });
879
+ }, [client, executePending]);
880
+
881
+ const resolveDeepLink = useCallback(
882
+ async (path: string) => await client.resolveDeepLink({ path }),
883
+ [client],
884
+ );
885
+
886
+ useEffect(() => {
887
+ const sequence = sequenceRef;
888
+ const transitionAbort = transitionAbortRef;
889
+ void refresh().catch((caught) => {
890
+ setError(accountError(caught));
891
+ setPhase("recoverable_error");
892
+ });
893
+ return () => {
894
+ ++sequence.current;
895
+ transitionAbort.current?.abort();
896
+ };
897
+ }, [client, refresh]);
898
+
899
+ useEffect(() => {
900
+ if (!broadcastChannelName || typeof BroadcastChannel === "undefined") return;
901
+ const channel = new BroadcastChannel(broadcastChannelName);
902
+ const actorHolds = crossTabActorHoldsRef.current;
903
+ channelRef.current = channel;
904
+ channel.onmessage = (event: MessageEvent<unknown>) => {
905
+ const value = event.data;
906
+ if (!value || typeof value !== "object") return;
907
+ const hint = value as {
908
+ type?: unknown;
909
+ transitionId?: unknown;
910
+ actorEpoch?: unknown;
911
+ generation?: unknown;
912
+ };
913
+ if (hint.type === "actor-transition-pending") {
914
+ if (
915
+ typeof hint.transitionId !== "string" ||
916
+ !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
917
+ hint.transitionId,
918
+ ) ||
919
+ typeof hint.actorEpoch !== "string" ||
920
+ typeof hint.generation !== "string" ||
921
+ crossTabActorHoldsRef.current.has(hint.transitionId)
922
+ ) {
923
+ return;
924
+ }
925
+ const current = projectionRef.current;
926
+ if (
927
+ current &&
928
+ (current.actorEpoch !== hint.actorEpoch || current.generation !== hint.generation)
929
+ ) {
930
+ return;
931
+ }
932
+ if (!current && crossTabActorHoldsRef.current.size === 0) return;
933
+ const firstHold = crossTabActorHoldsRef.current.size === 0;
934
+ const timeout = setTimeout(() => {
935
+ if (!crossTabActorHoldsRef.current.delete(hint.transitionId as string)) return;
936
+ if (crossTabActorHoldsRef.current.size === 0) {
937
+ void invalidateActor().catch(() => undefined);
938
+ }
939
+ }, CROSS_TAB_ACTOR_HOLD_MS);
940
+ crossTabActorHoldsRef.current.set(hint.transitionId, timeout);
941
+ if (firstHold) {
942
+ if (pendingCommitSequenceRef.current !== null) {
943
+ invalidatedDuringPendingCommitRef.current = true;
944
+ } else {
945
+ ++sequenceRef.current;
946
+ }
947
+ void beginNeutralActorInvalidation(current).catch(() => undefined);
948
+ }
949
+ return;
950
+ }
951
+ if (hint.type === "actor-transition-released") {
952
+ if (typeof hint.transitionId !== "string") return;
953
+ const timeout = crossTabActorHoldsRef.current.get(hint.transitionId);
954
+ if (timeout === undefined) return;
955
+ clearTimeout(timeout);
956
+ crossTabActorHoldsRef.current.delete(hint.transitionId);
957
+ if (crossTabActorHoldsRef.current.size === 0) {
958
+ void invalidateActor().catch(() => undefined);
959
+ }
960
+ return;
961
+ }
962
+ if (
963
+ hint.type !== "actor-epoch-changed" ||
964
+ typeof hint.actorEpoch !== "string" ||
965
+ typeof hint.generation !== "string" ||
966
+ (hint.actorEpoch === projectionRef.current?.actorEpoch &&
967
+ hint.generation === projectionRef.current?.generation)
968
+ ) {
969
+ return;
970
+ }
971
+ for (const timeout of crossTabActorHoldsRef.current.values()) clearTimeout(timeout);
972
+ crossTabActorHoldsRef.current.clear();
973
+ void invalidateActor().catch(() => undefined);
974
+ };
975
+ return () => {
976
+ for (const timeout of actorHolds.values()) clearTimeout(timeout);
977
+ actorHolds.clear();
978
+ channel.close();
979
+ if (channelRef.current === channel) channelRef.current = null;
980
+ };
981
+ }, [beginNeutralActorInvalidation, broadcastChannelName, invalidateActor]);
982
+
983
+ const value = useMemo<BrowserAccountsContextValue>(
984
+ () => ({
985
+ projection,
986
+ phase,
987
+ blockers,
988
+ error,
989
+ transaction,
990
+ hasPendingTransition: pendingRef.current !== null,
991
+ refresh,
992
+ invalidateActor,
993
+ registerTransitionBlocker,
994
+ continueTransition,
995
+ cancelPendingTransition,
996
+ beginAdd,
997
+ beginReauth,
998
+ completeEmailPassword,
999
+ settleExternalLoginTransaction,
1000
+ cancelLoginTransaction,
1001
+ selectSlot,
1002
+ logoutSlot,
1003
+ logoutAll,
1004
+ resolveDeepLink,
1005
+ }),
1006
+ [
1007
+ projection,
1008
+ phase,
1009
+ blockers,
1010
+ error,
1011
+ transaction,
1012
+ refresh,
1013
+ invalidateActor,
1014
+ registerTransitionBlocker,
1015
+ continueTransition,
1016
+ cancelPendingTransition,
1017
+ beginAdd,
1018
+ beginReauth,
1019
+ completeEmailPassword,
1020
+ settleExternalLoginTransaction,
1021
+ cancelLoginTransaction,
1022
+ selectSlot,
1023
+ logoutSlot,
1024
+ logoutAll,
1025
+ resolveDeepLink,
1026
+ ],
1027
+ );
1028
+
1029
+ return (
1030
+ <BrowserAccountsContext.Provider value={value}>{children}</BrowserAccountsContext.Provider>
1031
+ );
1032
+ }
1033
+
1034
+ export function useBrowserAccounts(): BrowserAccountsContextValue {
1035
+ const context = useContext(BrowserAccountsContext);
1036
+ if (!context) {
1037
+ throw new Error(
1038
+ "@opengeni/react/accounts: wrap the tree in <BrowserAccountsProvider> before using account hooks",
1039
+ );
1040
+ }
1041
+ return context;
1042
+ }
1043
+
1044
+ /** Read the optional controller without requiring non-legacy hosts to mount it. */
1045
+ export function useOptionalBrowserAccounts(): BrowserAccountsContextValue | null {
1046
+ return useContext(BrowserAccountsContext);
1047
+ }
1048
+
1049
+ export function useBrowserAccountTransitionBlocker(id: string, inspect: BlockerInspector): void {
1050
+ const { registerTransitionBlocker } = useBrowserAccounts();
1051
+ const inspectRef = useRef(inspect);
1052
+ inspectRef.current = inspect;
1053
+ useEffect(
1054
+ () => registerTransitionBlocker(id, () => inspectRef.current()),
1055
+ [id, registerTransitionBlocker],
1056
+ );
1057
+ }
1058
+
1059
+ /** No-op on legacy hosts that do not mount the optional accounts provider. */
1060
+ export function useOptionalBrowserAccountTransitionBlocker(
1061
+ id: string,
1062
+ inspect: BlockerInspector,
1063
+ ): void {
1064
+ const context = useContext(BrowserAccountsContext);
1065
+ const registerTransitionBlocker = context?.registerTransitionBlocker;
1066
+ const inspectRef = useRef(inspect);
1067
+ inspectRef.current = inspect;
1068
+ useEffect(() => {
1069
+ if (!registerTransitionBlocker) return;
1070
+ return registerTransitionBlocker(id, () => inspectRef.current());
1071
+ }, [id, registerTransitionBlocker]);
1072
+ }