@arbidocs/react 0.5.111 → 0.5.113

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 (972) hide show
  1. package/dist/account/client.js +96 -0
  2. package/dist/account/client.js.map +7 -0
  3. package/dist/account/delete.js +70 -0
  4. package/dist/account/delete.js.map +7 -0
  5. package/dist/account/didit.js +34 -0
  6. package/dist/account/didit.js.map +7 -0
  7. package/dist/account/dismissed-tips.js +33 -0
  8. package/dist/account/dismissed-tips.js.map +7 -0
  9. package/dist/account/email.js +84 -0
  10. package/dist/account/email.js.map +7 -0
  11. package/dist/account/entitlements.js +47 -0
  12. package/dist/account/entitlements.js.map +7 -0
  13. package/dist/account/identity.js +270 -0
  14. package/dist/account/identity.js.map +7 -0
  15. package/dist/account/index.js +93 -0
  16. package/dist/account/index.js.map +7 -0
  17. package/dist/account/notifications.js +59 -0
  18. package/dist/account/notifications.js.map +7 -0
  19. package/dist/account/password.js +103 -0
  20. package/dist/account/password.js.map +7 -0
  21. package/dist/account/profile.js +116 -0
  22. package/dist/account/profile.js.map +7 -0
  23. package/dist/account/recovery.js +13 -0
  24. package/dist/account/recovery.js.map +7 -0
  25. package/dist/account/relevance.js +82 -0
  26. package/dist/account/relevance.js.map +7 -0
  27. package/dist/account/sessions.js +37 -0
  28. package/dist/account/sessions.js.map +7 -0
  29. package/dist/account/settings.js +39 -0
  30. package/dist/account/settings.js.map +7 -0
  31. package/dist/account/table-views.js +16 -0
  32. package/dist/account/table-views.js.map +7 -0
  33. package/dist/ai/AiAnswer.js +83 -0
  34. package/dist/ai/AiAnswer.js.map +7 -0
  35. package/dist/ai/AiMarkdown.js +40 -0
  36. package/dist/ai/AiMarkdown.js.map +7 -0
  37. package/dist/ai/ArtifactCanvas.js +193 -0
  38. package/dist/ai/ArtifactCanvas.js.map +7 -0
  39. package/dist/ai/CitationRenderer.js +413 -0
  40. package/dist/ai/CitationRenderer.js.map +7 -0
  41. package/dist/{chunk-WL2Y2T47.js → ai/MarkdownRenderer.js} +35 -101
  42. package/dist/ai/MarkdownRenderer.js.map +7 -0
  43. package/dist/ai/MessageArtifactCard.js +75 -0
  44. package/dist/ai/MessageArtifactCard.js.map +7 -0
  45. package/dist/ai/PassageCard.js +79 -0
  46. package/dist/ai/PassageCard.js.map +7 -0
  47. package/dist/ai/engine.js +110 -0
  48. package/dist/ai/engine.js.map +7 -0
  49. package/dist/ai/index.js +63 -0
  50. package/dist/ai/index.js.map +7 -0
  51. package/dist/ai/markdown-base-components.js +37 -0
  52. package/dist/ai/markdown-base-components.js.map +7 -0
  53. package/dist/ai/markdown-streaming-context.js +6 -0
  54. package/dist/ai/markdown-streaming-context.js.map +7 -0
  55. package/dist/{chunk-VSCU7K4V.js → ai/normalize-citations.js} +12 -19
  56. package/dist/ai/normalize-citations.js.map +7 -0
  57. package/dist/ai/redline.js +41 -0
  58. package/dist/ai/redline.js.map +7 -0
  59. package/dist/ai/split-markdown-blocks.js +40 -0
  60. package/dist/ai/split-markdown-blocks.js.map +7 -0
  61. package/dist/{chunk-UW2SGTI5.js → ai/stored-markdown.js} +41 -93
  62. package/dist/ai/stored-markdown.js.map +7 -0
  63. package/dist/annotations/AnnotationPageOverlay.js +807 -0
  64. package/dist/annotations/AnnotationPageOverlay.js.map +7 -0
  65. package/dist/annotations/AnnotationToolbar.js +398 -0
  66. package/dist/annotations/AnnotationToolbar.js.map +7 -0
  67. package/dist/annotations/FreezeDialog.js +170 -0
  68. package/dist/annotations/FreezeDialog.js.map +7 -0
  69. package/dist/annotations/ProductionDialog.js +354 -0
  70. package/dist/annotations/ProductionDialog.js.map +7 -0
  71. package/dist/annotations/controller.js +49 -0
  72. package/dist/annotations/controller.js.map +7 -0
  73. package/dist/annotations/freeze/browser.js +21 -0
  74. package/dist/annotations/freeze/browser.js.map +7 -0
  75. package/dist/annotations/freeze/bundle.js +201 -0
  76. package/dist/annotations/freeze/bundle.js.map +7 -0
  77. package/dist/annotations/freeze/coords.js +37 -0
  78. package/dist/annotations/freeze/coords.js.map +7 -0
  79. package/dist/annotations/freeze/freeze.js +261 -0
  80. package/dist/annotations/freeze/freeze.js.map +7 -0
  81. package/dist/annotations/freeze/hash.js +28 -0
  82. package/dist/annotations/freeze/hash.js.map +7 -0
  83. package/dist/annotations/freeze/index-page.js +78 -0
  84. package/dist/annotations/freeze/index-page.js.map +7 -0
  85. package/dist/annotations/freeze/index.js +28 -22
  86. package/dist/annotations/freeze/index.js.map +7 -1
  87. package/dist/annotations/freeze/raster.js +208 -0
  88. package/dist/annotations/freeze/raster.js.map +7 -0
  89. package/dist/annotations/freeze/stamp.js +117 -0
  90. package/dist/annotations/freeze/stamp.js.map +7 -0
  91. package/dist/annotations/freeze/types.js +14 -0
  92. package/dist/annotations/freeze/types.js.map +7 -0
  93. package/dist/annotations/freeze/vector.js +283 -0
  94. package/dist/annotations/freeze/vector.js.map +7 -0
  95. package/dist/annotations/geometry.js +81 -0
  96. package/dist/annotations/geometry.js.map +7 -0
  97. package/dist/annotations/index.js +125 -6
  98. package/dist/annotations/index.js.map +7 -1
  99. package/dist/annotations/merge.js +53 -0
  100. package/dist/annotations/merge.js.map +7 -0
  101. package/dist/{chunk-T3USOSVN.js → annotations/model.js} +23 -16
  102. package/dist/annotations/model.js.map +7 -0
  103. package/dist/annotations/overlay-geometry.js +41 -0
  104. package/dist/annotations/overlay-geometry.js.map +7 -0
  105. package/dist/annotations/redaction-log.js +33 -0
  106. package/dist/annotations/redaction-log.js.map +7 -0
  107. package/dist/annotations/selection-marks.js +122 -0
  108. package/dist/annotations/selection-marks.js.map +7 -0
  109. package/dist/annotations/state.js +140 -0
  110. package/dist/annotations/state.js.map +7 -0
  111. package/dist/annotations/store.js +49 -0
  112. package/dist/annotations/store.js.map +7 -0
  113. package/dist/annotations/useAnnotationLayer.js +306 -0
  114. package/dist/annotations/useAnnotationLayer.js.map +7 -0
  115. package/dist/annotations/useAnnotationShortcuts.js +31 -0
  116. package/dist/annotations/useAnnotationShortcuts.js.map +7 -0
  117. package/dist/annotations/useTextSelectionMarks.js +100 -0
  118. package/dist/annotations/useTextSelectionMarks.js.map +7 -0
  119. package/dist/artifacts/artifact-kind.js +19 -0
  120. package/dist/artifacts/artifact-kind.js.map +7 -0
  121. package/dist/artifacts/index.js +89 -571
  122. package/dist/artifacts/index.js.map +7 -1
  123. package/dist/{chunk-WUTL62MC.js → artifacts/normalize-markdown.js} +12 -14
  124. package/dist/artifacts/normalize-markdown.js.map +7 -0
  125. package/dist/artifacts/redline-core.js +12 -3
  126. package/dist/artifacts/redline-core.js.map +7 -1
  127. package/dist/{chunk-74N436VK.js → artifacts/redline-diff.js} +10 -9
  128. package/dist/artifacts/redline-diff.js.map +7 -0
  129. package/dist/artifacts/redline-engine.js +14 -0
  130. package/dist/artifacts/redline-engine.js.map +7 -0
  131. package/dist/artifacts/renderArtifactMarkdown.js +9 -0
  132. package/dist/artifacts/renderArtifactMarkdown.js.map +7 -0
  133. package/dist/artifacts/useArtifactEditSession.js +183 -0
  134. package/dist/artifacts/useArtifactEditSession.js.map +7 -0
  135. package/dist/artifacts/useArtifactSession.js +173 -0
  136. package/dist/artifacts/useArtifactSession.js.map +7 -0
  137. package/dist/artifacts/useArtifactSource.js +16 -0
  138. package/dist/artifacts/useArtifactSource.js.map +7 -0
  139. package/dist/artifacts/useArtifactText.js +78 -0
  140. package/dist/artifacts/useArtifactText.js.map +7 -0
  141. package/dist/artifacts/useRedline.js +65 -0
  142. package/dist/artifacts/useRedline.js.map +7 -0
  143. package/dist/artifacts/useStreamedArtifact.js +74 -0
  144. package/dist/artifacts/useStreamedArtifact.js.map +7 -0
  145. package/dist/artifacts/versions.js +68 -0
  146. package/dist/artifacts/versions.js.map +7 -0
  147. package/dist/billing.js +200 -0
  148. package/dist/billing.js.map +7 -0
  149. package/dist/boot-timeout.js +19 -0
  150. package/dist/boot-timeout.js.map +7 -0
  151. package/dist/calendar/accounts.js +213 -0
  152. package/dist/calendar/accounts.js.map +7 -0
  153. package/dist/calendar/hooks.js +409 -0
  154. package/dist/calendar/hooks.js.map +7 -0
  155. package/dist/calendar/index.js +31 -0
  156. package/dist/calendar/index.js.map +7 -0
  157. package/dist/calendar/keys.js +5 -0
  158. package/dist/calendar/keys.js.map +7 -0
  159. package/dist/calendar/offline/outbox.js +231 -0
  160. package/dist/calendar/offline/outbox.js.map +7 -0
  161. package/dist/calendar/offline/runtime.js +109 -0
  162. package/dist/calendar/offline/runtime.js.map +7 -0
  163. package/dist/calendar/offline/support.js +41 -0
  164. package/dist/calendar/offline/support.js.map +7 -0
  165. package/dist/calendar/support.js +34 -0
  166. package/dist/calendar/support.js.map +7 -0
  167. package/dist/calls/actions.js +226 -0
  168. package/dist/calls/actions.js.map +7 -0
  169. package/dist/calls/events.js +138 -0
  170. package/dist/calls/events.js.map +7 -0
  171. package/dist/calls/gate.js +19 -0
  172. package/dist/calls/gate.js.map +7 -0
  173. package/dist/calls/hooks.js +115 -0
  174. package/dist/calls/hooks.js.map +7 -0
  175. package/dist/calls/in-call-chat.js +132 -0
  176. package/dist/calls/in-call-chat.js.map +7 -0
  177. package/dist/calls/index.js +24 -0
  178. package/dist/calls/index.js.map +7 -0
  179. package/dist/calls/keys.js +17 -0
  180. package/dist/calls/keys.js.map +7 -0
  181. package/dist/calls/livekit/index.js +6 -958
  182. package/dist/calls/livekit/index.js.map +7 -1
  183. package/dist/calls/livekit/room.js +98 -0
  184. package/dist/calls/livekit/room.js.map +7 -0
  185. package/dist/calls/livekit/useCallRecorder.js +219 -0
  186. package/dist/calls/livekit/useCallRecorder.js.map +7 -0
  187. package/dist/calls/livekit/useCallTranscriber.js +309 -0
  188. package/dist/calls/livekit/useCallTranscriber.js.map +7 -0
  189. package/dist/calls/livekit/useHostMuteNotice.js +29 -0
  190. package/dist/calls/livekit/useHostMuteNotice.js.map +7 -0
  191. package/dist/calls/livekit/useInCallChat.js +161 -0
  192. package/dist/calls/livekit/useInCallChat.js.map +7 -0
  193. package/dist/calls/livekit/useWebinar.js +239 -0
  194. package/dist/calls/livekit/useWebinar.js.map +7 -0
  195. package/dist/calls/meeting-chat.js +149 -0
  196. package/dist/calls/meeting-chat.js.map +7 -0
  197. package/dist/calls/moderation.js +50 -0
  198. package/dist/calls/moderation.js.map +7 -0
  199. package/dist/calls/open-meeting-chat.js +29 -0
  200. package/dist/calls/open-meeting-chat.js.map +7 -0
  201. package/dist/calls/read-only.js +24 -0
  202. package/dist/calls/read-only.js.map +7 -0
  203. package/dist/calls/recording-media.js +218 -0
  204. package/dist/calls/recording-media.js.map +7 -0
  205. package/dist/calls/recording-playback.js +260 -0
  206. package/dist/calls/recording-playback.js.map +7 -0
  207. package/dist/calls/recording.js +268 -0
  208. package/dist/calls/recording.js.map +7 -0
  209. package/dist/calls/save-to-thread.js +80 -0
  210. package/dist/calls/save-to-thread.js.map +7 -0
  211. package/dist/calls/session.js +134 -0
  212. package/dist/calls/session.js.map +7 -0
  213. package/dist/calls/transcript-format.js +147 -0
  214. package/dist/calls/transcript-format.js.map +7 -0
  215. package/dist/calls/transcription.js +101 -0
  216. package/dist/calls/transcription.js.map +7 -0
  217. package/dist/calls/webinar.js +71 -0
  218. package/dist/calls/webinar.js.map +7 -0
  219. package/dist/charge-watch.js +71 -0
  220. package/dist/charge-watch.js.map +7 -0
  221. package/dist/chat/ChatBubble.js +146 -0
  222. package/dist/chat/ChatBubble.js.map +7 -0
  223. package/dist/chat/ConversationScope.js +30 -0
  224. package/dist/chat/ConversationScope.js.map +7 -0
  225. package/dist/chat/active-config.js +20 -0
  226. package/dist/chat/active-config.js.map +7 -0
  227. package/dist/chat/agent-chat-owner.js +25 -0
  228. package/dist/chat/agent-chat-owner.js.map +7 -0
  229. package/dist/chat/chat-artifacts.js +64 -0
  230. package/dist/chat/chat-artifacts.js.map +7 -0
  231. package/dist/chat/citations.js +32 -0
  232. package/dist/chat/citations.js.map +7 -0
  233. package/dist/chat/config-model.js +10 -0
  234. package/dist/chat/config-model.js.map +7 -0
  235. package/dist/chat/conversation-cache.js +676 -0
  236. package/dist/chat/conversation-cache.js.map +7 -0
  237. package/dist/chat/conversation-events.js +57 -0
  238. package/dist/chat/conversation-events.js.map +7 -0
  239. package/dist/chat/conversation-mentions.js +58 -0
  240. package/dist/chat/conversation-mentions.js.map +7 -0
  241. package/dist/chat/conversation-workspace.js +58 -0
  242. package/dist/chat/conversation-workspace.js.map +7 -0
  243. package/dist/chat/mentions.js +116 -0
  244. package/dist/chat/mentions.js.map +7 -0
  245. package/dist/chat/open-document.js +106 -0
  246. package/dist/chat/open-document.js.map +7 -0
  247. package/dist/chat/orphaned.js +44 -0
  248. package/dist/chat/orphaned.js.map +7 -0
  249. package/dist/chat/pendingFirstTurn.js +30 -0
  250. package/dist/chat/pendingFirstTurn.js.map +7 -0
  251. package/dist/chat/reply-target.js +12 -0
  252. package/dist/chat/reply-target.js.map +7 -0
  253. package/dist/chat/run-finished.js +28 -0
  254. package/dist/chat/run-finished.js.map +7 -0
  255. package/dist/chat/run-state.js +91 -0
  256. package/dist/chat/run-state.js.map +7 -0
  257. package/dist/chat/stream-handlers.js +419 -0
  258. package/dist/chat/stream-handlers.js.map +7 -0
  259. package/dist/chat/thread-binding.js +76 -0
  260. package/dist/chat/thread-binding.js.map +7 -0
  261. package/dist/chat/thread-document.js +53 -0
  262. package/dist/chat/thread-document.js.map +7 -0
  263. package/dist/chat/turn-control.js +79 -0
  264. package/dist/chat/turn-control.js.map +7 -0
  265. package/dist/chat/useAgentRunControl.js +36 -0
  266. package/dist/chat/useAgentRunControl.js.map +7 -0
  267. package/dist/chat/useAnswerAgentQuestion.js +19 -0
  268. package/dist/chat/useAnswerAgentQuestion.js.map +7 -0
  269. package/dist/chat/useAskAgain.js +32 -0
  270. package/dist/chat/useAskAgain.js.map +7 -0
  271. package/dist/chat/useAutoSendDraft.js +17 -0
  272. package/dist/chat/useAutoSendDraft.js.map +7 -0
  273. package/dist/chat/useBranchNavigation.js +97 -0
  274. package/dist/chat/useBranchNavigation.js.map +7 -0
  275. package/dist/chat/useConnectRunStream.js +169 -0
  276. package/dist/chat/useConnectRunStream.js.map +7 -0
  277. package/dist/chat/useConversation.js +431 -0
  278. package/dist/chat/useConversation.js.map +7 -0
  279. package/dist/chat/useConversationActions.js +662 -0
  280. package/dist/chat/useConversationActions.js.map +7 -0
  281. package/dist/chat/useConversationData.js +143 -0
  282. package/dist/chat/useConversationData.js.map +7 -0
  283. package/dist/chat/useConversationDocuments.js +41 -0
  284. package/dist/chat/useConversationDocuments.js.map +7 -0
  285. package/dist/chat/useConversationSettings.js +78 -0
  286. package/dist/chat/useConversationSettings.js.map +7 -0
  287. package/dist/chat/useConversationTurn.js +31 -0
  288. package/dist/chat/useConversationTurn.js.map +7 -0
  289. package/dist/chat/useConversationWorkspace.js +12 -0
  290. package/dist/chat/useConversationWorkspace.js.map +7 -0
  291. package/dist/chat/useDeleteMessage.js +15 -0
  292. package/dist/chat/useDeleteMessage.js.map +7 -0
  293. package/dist/chat/useDocumentAutoAdd.js +73 -0
  294. package/dist/chat/useDocumentAutoAdd.js.map +7 -0
  295. package/dist/chat/useMessageTimer.js +39 -0
  296. package/dist/chat/useMessageTimer.js.map +7 -0
  297. package/dist/chat/useThinkingContent.js +67 -0
  298. package/dist/chat/useThinkingContent.js.map +7 -0
  299. package/dist/chat/useThreadDocument.js +61 -0
  300. package/dist/chat/useThreadDocument.js.map +7 -0
  301. package/dist/chat/workflow-run-titles.js +50 -0
  302. package/dist/chat/workflow-run-titles.js.map +7 -0
  303. package/dist/config/config-hooks.js +209 -0
  304. package/dist/config/config-hooks.js.map +7 -0
  305. package/dist/connectivity.js +72 -0
  306. package/dist/connectivity.js.map +7 -0
  307. package/dist/connectors/hooks.js +263 -0
  308. package/dist/connectors/hooks.js.map +7 -0
  309. package/dist/connectors/index.js +28 -0
  310. package/dist/connectors/index.js.map +7 -0
  311. package/dist/contacts.js +100 -0
  312. package/dist/contacts.js.map +7 -0
  313. package/dist/conversation-list.js +65 -0
  314. package/dist/conversation-list.js.map +7 -0
  315. package/dist/databases.js +195 -0
  316. package/dist/databases.js.map +7 -0
  317. package/dist/datasets/aggregate.js +281 -0
  318. package/dist/datasets/aggregate.js.map +7 -0
  319. package/dist/datasets/index.js +122 -0
  320. package/dist/datasets/index.js.map +7 -0
  321. package/dist/datasets/members.js +27 -0
  322. package/dist/datasets/members.js.map +7 -0
  323. package/dist/datasets/panel.js +44 -0
  324. package/dist/datasets/panel.js.map +7 -0
  325. package/dist/datasets/registry.js +47 -0
  326. package/dist/datasets/registry.js.map +7 -0
  327. package/dist/datasets/rows-source.js +44 -0
  328. package/dist/datasets/rows-source.js.map +7 -0
  329. package/dist/datasets/sources/activity.js +83 -0
  330. package/dist/datasets/sources/activity.js.map +7 -0
  331. package/dist/datasets/sources/conversations.js +74 -0
  332. package/dist/datasets/sources/conversations.js.map +7 -0
  333. package/dist/datasets/sources/database.js +209 -0
  334. package/dist/datasets/sources/database.js.map +7 -0
  335. package/dist/datasets/sources/documents.js +93 -0
  336. package/dist/datasets/sources/documents.js.map +7 -0
  337. package/dist/datasets/sources/facts.js +56 -0
  338. package/dist/datasets/sources/facts.js.map +7 -0
  339. package/dist/datasets/sources/projects.js +117 -0
  340. package/dist/datasets/sources/projects.js.map +7 -0
  341. package/dist/datasets/sources/tags.js +67 -0
  342. package/dist/datasets/sources/tags.js.map +7 -0
  343. package/dist/datasets/sources/usage.js +268 -0
  344. package/dist/datasets/sources/usage.js.map +7 -0
  345. package/dist/datasets/sources/workflows.js +91 -0
  346. package/dist/datasets/sources/workflows.js.map +7 -0
  347. package/dist/datasets/sources/workspaces.js +67 -0
  348. package/dist/datasets/sources/workspaces.js.map +7 -0
  349. package/dist/datasets/store.js +194 -0
  350. package/dist/datasets/store.js.map +7 -0
  351. package/dist/datasets/types.js +14 -0
  352. package/dist/datasets/types.js.map +7 -0
  353. package/dist/directmessages/ConversationList.js +148 -0
  354. package/dist/directmessages/ConversationList.js.map +7 -0
  355. package/dist/directmessages/DateSeparator.js +8 -0
  356. package/dist/directmessages/DateSeparator.js.map +7 -0
  357. package/dist/directmessages/DmAvatar.js +29 -0
  358. package/dist/directmessages/DmAvatar.js.map +7 -0
  359. package/dist/directmessages/DmComposer.js +201 -0
  360. package/dist/directmessages/DmComposer.js.map +7 -0
  361. package/dist/directmessages/arrivals.js +29 -0
  362. package/dist/directmessages/arrivals.js.map +7 -0
  363. package/dist/directmessages/chat-cache.js +192 -0
  364. package/dist/directmessages/chat-cache.js.map +7 -0
  365. package/dist/directmessages/grouping.js +26 -0
  366. package/dist/directmessages/grouping.js.map +7 -0
  367. package/dist/directmessages/index.js +81 -0
  368. package/dist/directmessages/index.js.map +7 -0
  369. package/dist/directmessages/useChats.js +266 -0
  370. package/dist/directmessages/useChats.js.map +7 -0
  371. package/dist/directmessages/utils.js +23 -0
  372. package/dist/directmessages/utils.js.map +7 -0
  373. package/dist/document-tools/can-annotate.js +7 -0
  374. package/dist/document-tools/can-annotate.js.map +7 -0
  375. package/dist/document-tools/core.js +218 -12
  376. package/dist/document-tools/core.js.map +7 -1
  377. package/dist/document-tools/document-pdf.js +76 -0
  378. package/dist/document-tools/document-pdf.js.map +7 -0
  379. package/dist/document-tools/environment.js +136 -0
  380. package/dist/document-tools/environment.js.map +7 -0
  381. package/dist/document-tools/file-shares.js +112 -0
  382. package/dist/document-tools/file-shares.js.map +7 -0
  383. package/dist/document-tools/frozen-copy.js +27 -0
  384. package/dist/document-tools/frozen-copy.js.map +7 -0
  385. package/dist/document-tools/index.js +26 -148
  386. package/dist/document-tools/index.js.map +7 -1
  387. package/dist/document-tools/markup-download.js +51 -0
  388. package/dist/document-tools/markup-download.js.map +7 -0
  389. package/dist/document-tools/markup-store.js +138 -0
  390. package/dist/document-tools/markup-store.js.map +7 -0
  391. package/dist/document-tools/markup-transfer.js +88 -0
  392. package/dist/document-tools/markup-transfer.js.map +7 -0
  393. package/dist/document-tools/production.js +147 -0
  394. package/dist/document-tools/production.js.map +7 -0
  395. package/dist/document-tools/saved-signature.js +90 -0
  396. package/dist/document-tools/saved-signature.js.map +7 -0
  397. package/dist/document-tools/signature-requests.js +310 -0
  398. package/dist/document-tools/signature-requests.js.map +7 -0
  399. package/dist/document-tools/signing.js +127 -0
  400. package/dist/document-tools/signing.js.map +7 -0
  401. package/dist/document-tools/useDocumentBytes.js +38 -0
  402. package/dist/document-tools/useDocumentBytes.js.map +7 -0
  403. package/dist/document-tools/useDocumentMarkup.js +154 -0
  404. package/dist/document-tools/useDocumentMarkup.js.map +7 -0
  405. package/dist/document-tools/useIsOnline.js +13 -0
  406. package/dist/document-tools/useIsOnline.js.map +7 -0
  407. package/dist/document-tools/verification.js +60 -0
  408. package/dist/document-tools/verification.js.map +7 -0
  409. package/dist/documents/DocumentReview.js +220 -0
  410. package/dist/documents/DocumentReview.js.map +7 -0
  411. package/dist/documents/DraftTitleControls.js +41 -0
  412. package/dist/documents/DraftTitleControls.js.map +7 -0
  413. package/dist/documents/InlineMicButton.js +90 -0
  414. package/dist/documents/InlineMicButton.js.map +7 -0
  415. package/dist/documents/MicRecordingOverlay.js +29 -0
  416. package/dist/documents/MicRecordingOverlay.js.map +7 -0
  417. package/dist/documents/MicWaveformIndicator.js +68 -0
  418. package/dist/documents/MicWaveformIndicator.js.map +7 -0
  419. package/dist/documents/PhotoCapture.js +120 -0
  420. package/dist/documents/PhotoCapture.js.map +7 -0
  421. package/dist/documents/VideoCapture.js +129 -0
  422. package/dist/documents/VideoCapture.js.map +7 -0
  423. package/dist/documents/VoiceNoteRecorder.js +166 -0
  424. package/dist/documents/VoiceNoteRecorder.js.map +7 -0
  425. package/dist/documents/audio-segmenter.js +63 -0
  426. package/dist/documents/audio-segmenter.js.map +7 -0
  427. package/dist/documents/capture-frame.js +21 -0
  428. package/dist/documents/capture-frame.js.map +7 -0
  429. package/dist/documents/chunked-recorder.js +190 -0
  430. package/dist/documents/chunked-recorder.js.map +7 -0
  431. package/dist/documents/document-download.js +53 -0
  432. package/dist/documents/document-download.js.map +7 -0
  433. package/dist/documents/document-fields.js +109 -0
  434. package/dist/documents/document-fields.js.map +7 -0
  435. package/dist/documents/documents-cache.js +110 -0
  436. package/dist/documents/documents-cache.js.map +7 -0
  437. package/dist/documents/documents-data.js +128 -0
  438. package/dist/documents/documents-data.js.map +7 -0
  439. package/dist/documents/documents-loader.js +113 -0
  440. package/dist/documents/documents-loader.js.map +7 -0
  441. package/dist/documents/documents-writes.js +448 -0
  442. package/dist/documents/documents-writes.js.map +7 -0
  443. package/dist/documents/format-elapsed.js +10 -0
  444. package/dist/documents/format-elapsed.js.map +7 -0
  445. package/dist/documents/has-video-track.js +26 -0
  446. package/dist/documents/has-video-track.js.map +7 -0
  447. package/dist/documents/index.js +266 -0
  448. package/dist/documents/index.js.map +7 -0
  449. package/dist/documents/media-error.js +18 -0
  450. package/dist/documents/media-error.js.map +7 -0
  451. package/dist/documents/offline-documents.js +160 -0
  452. package/dist/documents/offline-documents.js.map +7 -0
  453. package/dist/documents/pending-sync.js +210 -0
  454. package/dist/documents/pending-sync.js.map +7 -0
  455. package/dist/documents/processing-live.js +122 -0
  456. package/dist/documents/processing-live.js.map +7 -0
  457. package/dist/documents/processing-order.js +59 -0
  458. package/dist/documents/processing-order.js.map +7 -0
  459. package/dist/documents/processing-settle.js +21 -0
  460. package/dist/documents/processing-settle.js.map +7 -0
  461. package/dist/documents/related-documents.js +133 -0
  462. package/dist/documents/related-documents.js.map +7 -0
  463. package/dist/documents/support.js +29 -0
  464. package/dist/documents/support.js.map +7 -0
  465. package/dist/documents/upload-files.js +169 -0
  466. package/dist/documents/upload-files.js.map +7 -0
  467. package/dist/documents/useAudioRecorder.js +315 -0
  468. package/dist/documents/useAudioRecorder.js.map +7 -0
  469. package/dist/documents/useCameraStream.js +35 -0
  470. package/dist/documents/useCameraStream.js.map +7 -0
  471. package/dist/documents/useDocumentThumbnails.js +71 -0
  472. package/dist/documents/useDocumentThumbnails.js.map +7 -0
  473. package/dist/documents/useDownloadDocuments.js +90 -0
  474. package/dist/documents/useDownloadDocuments.js.map +7 -0
  475. package/dist/documents/usePassageQuotes.js +37 -0
  476. package/dist/documents/usePassageQuotes.js.map +7 -0
  477. package/dist/documents/useUploadFiles.js +165 -0
  478. package/dist/documents/useUploadFiles.js.map +7 -0
  479. package/dist/documents/useUploadFromUrls.js +63 -0
  480. package/dist/documents/useUploadFromUrls.js.map +7 -0
  481. package/dist/documents/useVideoRecorder.js +62 -0
  482. package/dist/documents/useVideoRecorder.js.map +7 -0
  483. package/dist/entities/AgentMarkers.js +61 -0
  484. package/dist/entities/AgentMarkers.js.map +7 -0
  485. package/dist/entities/DocumentEntity.js +125 -0
  486. package/dist/entities/DocumentEntity.js.map +7 -0
  487. package/dist/entities/EntityPill.js +250 -0
  488. package/dist/entities/EntityPill.js.map +7 -0
  489. package/dist/entities/ProjectEntity.js +61 -0
  490. package/dist/entities/ProjectEntity.js.map +7 -0
  491. package/dist/entities/ShieldIcon.js +49 -0
  492. package/dist/entities/ShieldIcon.js.map +7 -0
  493. package/dist/entities/TagEntity.js +79 -0
  494. package/dist/entities/TagEntity.js.map +7 -0
  495. package/dist/entities/ThreadVisibilityIcon.js +15 -0
  496. package/dist/entities/ThreadVisibilityIcon.js.map +7 -0
  497. package/dist/entities/UserEntity.js +211 -0
  498. package/dist/entities/UserEntity.js.map +7 -0
  499. package/dist/entities/VerifiedBadge.js +19 -0
  500. package/dist/entities/VerifiedBadge.js.map +7 -0
  501. package/dist/entities/agent-avatar-colors.js +26 -0
  502. package/dist/entities/agent-avatar-colors.js.map +7 -0
  503. package/dist/entities/colors.js +64 -0
  504. package/dist/entities/colors.js.map +7 -0
  505. package/dist/entities/file-type.js +151 -0
  506. package/dist/entities/file-type.js.map +7 -0
  507. package/dist/entities/index.js +100 -0
  508. package/dist/entities/index.js.map +7 -0
  509. package/dist/entities/media-type.js +61 -0
  510. package/dist/entities/media-type.js.map +7 -0
  511. package/dist/entities/registry.js +385 -0
  512. package/dist/entities/registry.js.map +7 -0
  513. package/dist/entities/status.js +43 -0
  514. package/dist/entities/status.js.map +7 -0
  515. package/dist/entities/tag-kinds.js +23 -0
  516. package/dist/entities/tag-kinds.js.map +7 -0
  517. package/dist/entities/tag-types.js +44 -0
  518. package/dist/entities/tag-types.js.map +7 -0
  519. package/dist/entities/vocabulary.js +12 -0
  520. package/dist/entities/vocabulary.js.map +7 -0
  521. package/dist/entity-extraction.js +25 -0
  522. package/dist/entity-extraction.js.map +7 -0
  523. package/dist/facts-search.js +57 -0
  524. package/dist/facts-search.js.map +7 -0
  525. package/dist/facts.js +69 -0
  526. package/dist/facts.js.map +7 -0
  527. package/dist/hooks.js +320 -0
  528. package/dist/hooks.js.map +7 -0
  529. package/dist/host/ArbiHost.js +24 -0
  530. package/dist/host/ArbiHost.js.map +7 -0
  531. package/dist/host/assistant-copy.js +54 -0
  532. package/dist/host/assistant-copy.js.map +7 -0
  533. package/dist/host/config.js +9 -0
  534. package/dist/host/config.js.map +7 -0
  535. package/dist/host/context.js +10 -0
  536. package/dist/host/context.js.map +7 -0
  537. package/dist/host/features.js +144 -0
  538. package/dist/host/features.js.map +7 -0
  539. package/dist/host/index.js +12 -0
  540. package/dist/host/index.js.map +7 -0
  541. package/dist/{chunk-DPYBZDJB.js → host/merge.js} +7 -7
  542. package/dist/host/merge.js.map +7 -0
  543. package/dist/house-template.js +40 -0
  544. package/dist/house-template.js.map +7 -0
  545. package/dist/icons/AppleIcon.js +25 -0
  546. package/dist/icons/AppleIcon.js.map +7 -0
  547. package/dist/icons/ArbiBotHeadIcon.js +46 -0
  548. package/dist/icons/ArbiBotHeadIcon.js.map +7 -0
  549. package/dist/icons/ArbiIcon.js +24 -0
  550. package/dist/icons/ArbiIcon.js.map +7 -0
  551. package/dist/icons/AudIcon.js +56 -0
  552. package/dist/icons/AudIcon.js.map +7 -0
  553. package/dist/icons/ClaudeIcon.js +28 -0
  554. package/dist/icons/ClaudeIcon.js.map +7 -0
  555. package/dist/icons/DocIcon.js +56 -0
  556. package/dist/icons/DocIcon.js.map +7 -0
  557. package/dist/icons/EmlIcon.js +57 -0
  558. package/dist/icons/EmlIcon.js.map +7 -0
  559. package/dist/icons/FireworksIcon.js +47 -0
  560. package/dist/icons/FireworksIcon.js.map +7 -0
  561. package/dist/icons/GeminiIcon.js +37 -0
  562. package/dist/icons/GeminiIcon.js.map +7 -0
  563. package/dist/icons/GitHubIcon.js +32 -0
  564. package/dist/icons/GitHubIcon.js.map +7 -0
  565. package/dist/icons/GoogleIcon.js +53 -0
  566. package/dist/icons/GoogleIcon.js.map +7 -0
  567. package/dist/icons/HtmlIcon.js +56 -0
  568. package/dist/icons/HtmlIcon.js.map +7 -0
  569. package/dist/icons/ImgIcon.js +56 -0
  570. package/dist/icons/ImgIcon.js.map +7 -0
  571. package/dist/icons/LinkedInIcon.js +25 -0
  572. package/dist/icons/LinkedInIcon.js.map +7 -0
  573. package/dist/icons/OpenAIIcon.js +28 -0
  574. package/dist/icons/OpenAIIcon.js.map +7 -0
  575. package/dist/icons/PdfIcon.js +56 -0
  576. package/dist/icons/PdfIcon.js.map +7 -0
  577. package/dist/icons/ProviderIcon.js +42 -0
  578. package/dist/icons/ProviderIcon.js.map +7 -0
  579. package/dist/icons/TxtIcon.js +56 -0
  580. package/dist/icons/TxtIcon.js.map +7 -0
  581. package/dist/icons/VidIcon.js +56 -0
  582. package/dist/icons/VidIcon.js.map +7 -0
  583. package/dist/icons/XlsIcon.js +56 -0
  584. package/dist/icons/XlsIcon.js.map +7 -0
  585. package/dist/icons/arbi-mark.js +5 -0
  586. package/dist/icons/arbi-mark.js.map +7 -0
  587. package/dist/icons/colors.js +31 -0
  588. package/dist/icons/colors.js.map +7 -0
  589. package/dist/icons/file-type.js +105 -0
  590. package/dist/icons/file-type.js.map +7 -0
  591. package/dist/icons/index.js +55 -0
  592. package/dist/icons/index.js.map +7 -0
  593. package/dist/imagecrop/ImageCropModal.js +56 -0
  594. package/dist/imagecrop/ImageCropModal.js.map +7 -0
  595. package/dist/imagecrop/ImageCropper.js +100 -0
  596. package/dist/imagecrop/ImageCropper.js.map +7 -0
  597. package/dist/imagecrop/cropImage.js +43 -0
  598. package/dist/imagecrop/cropImage.js.map +7 -0
  599. package/dist/imagecrop/index.js +13 -0
  600. package/dist/imagecrop/index.js.map +7 -0
  601. package/dist/index.js +702 -17116
  602. package/dist/index.js.map +7 -1
  603. package/dist/{chunk-SSXFVWCT.js → lazy-chunk.js} +8 -8
  604. package/dist/lazy-chunk.js.map +7 -0
  605. package/dist/lib/collision-padding.js +13 -0
  606. package/dist/lib/collision-padding.js.map +7 -0
  607. package/dist/lib/format-friendly-date.js +55 -0
  608. package/dist/lib/format-friendly-date.js.map +7 -0
  609. package/dist/lib/format-relative-time.js +52 -0
  610. package/dist/lib/format-relative-time.js.map +7 -0
  611. package/dist/lib/markdown-to-text.js +35 -0
  612. package/dist/lib/markdown-to-text.js.map +7 -0
  613. package/dist/lib/toast-interaction.js +9 -0
  614. package/dist/lib/toast-interaction.js.map +7 -0
  615. package/dist/lib/utils.js +9 -0
  616. package/dist/lib/utils.js.map +7 -0
  617. package/dist/mail/client.js +103 -0
  618. package/dist/mail/client.js.map +7 -0
  619. package/dist/mail/document-attachment.js +38 -0
  620. package/dist/mail/document-attachment.js.map +7 -0
  621. package/dist/mail/filing.js +132 -0
  622. package/dist/mail/filing.js.map +7 -0
  623. package/dist/mail/hooks.js +393 -0
  624. package/dist/mail/hooks.js.map +7 -0
  625. package/dist/mail/index.js +120 -0
  626. package/dist/mail/index.js.map +7 -0
  627. package/dist/mail/offline/changes.js +258 -0
  628. package/dist/mail/offline/changes.js.map +7 -0
  629. package/dist/mail/offline/confirm-sign-out.js +37 -0
  630. package/dist/mail/offline/confirm-sign-out.js.map +7 -0
  631. package/dist/mail/offline/crypto.js +26 -0
  632. package/dist/mail/offline/crypto.js.map +7 -0
  633. package/dist/mail/offline/drafts.js +69 -0
  634. package/dist/mail/offline/drafts.js.map +7 -0
  635. package/dist/mail/offline/hooks.js +104 -0
  636. package/dist/mail/offline/hooks.js.map +7 -0
  637. package/dist/mail/offline/index.js +48 -0
  638. package/dist/mail/offline/index.js.map +7 -0
  639. package/dist/mail/offline/live.js +233 -0
  640. package/dist/mail/offline/live.js.map +7 -0
  641. package/dist/mail/offline/mailbox.js +191 -0
  642. package/dist/mail/offline/mailbox.js.map +7 -0
  643. package/dist/mail/offline/outbox.js +167 -0
  644. package/dist/mail/offline/outbox.js.map +7 -0
  645. package/dist/mail/offline/reads.js +159 -0
  646. package/dist/mail/offline/reads.js.map +7 -0
  647. package/dist/mail/offline/runtime.js +100 -0
  648. package/dist/mail/offline/runtime.js.map +7 -0
  649. package/dist/mail/offline/settings.js +84 -0
  650. package/dist/mail/offline/settings.js.map +7 -0
  651. package/dist/mail/offline/store.js +29 -0
  652. package/dist/mail/offline/store.js.map +7 -0
  653. package/dist/mail/offline/sync.js +251 -0
  654. package/dist/mail/offline/sync.js.map +7 -0
  655. package/dist/mail/offline/wipe.js +19 -0
  656. package/dist/mail/offline/wipe.js.map +7 -0
  657. package/dist/mail/thread-keys.js +53 -0
  658. package/dist/mail/thread-keys.js.map +7 -0
  659. package/dist/mail/threads.js +71 -0
  660. package/dist/mail/threads.js.map +7 -0
  661. package/dist/mail/useMailClient.js +42 -0
  662. package/dist/mail/useMailClient.js.map +7 -0
  663. package/dist/model-connections.js +58 -0
  664. package/dist/model-connections.js.map +7 -0
  665. package/dist/notifications/ActivityFeed.js +70 -0
  666. package/dist/notifications/ActivityFeed.js.map +7 -0
  667. package/dist/notifications/NotificationBell.js +200 -0
  668. package/dist/notifications/NotificationBell.js.map +7 -0
  669. package/dist/notifications/Toaster.js +24 -0
  670. package/dist/notifications/Toaster.js.map +7 -0
  671. package/dist/notifications/activity-types.js +65 -0
  672. package/dist/notifications/activity-types.js.map +7 -0
  673. package/dist/notifications/bell.js +24 -0
  674. package/dist/notifications/bell.js.map +7 -0
  675. package/dist/notifications/calendar-notifications.js +79 -0
  676. package/dist/notifications/calendar-notifications.js.map +7 -0
  677. package/dist/notifications/index.js +108 -0
  678. package/dist/notifications/index.js.map +7 -0
  679. package/dist/notifications/live.js +28 -0
  680. package/dist/notifications/live.js.map +7 -0
  681. package/dist/notifications/notification-types.js +127 -0
  682. package/dist/notifications/notification-types.js.map +7 -0
  683. package/dist/{chunk-BF5KW5ZI.js → notifications/notify-store.js} +24 -74
  684. package/dist/notifications/notify-store.js.map +7 -0
  685. package/dist/notifications/server-notifications.js +452 -0
  686. package/dist/notifications/server-notifications.js.map +7 -0
  687. package/dist/notifications/useNotifications.js +34 -0
  688. package/dist/notifications/useNotifications.js.map +7 -0
  689. package/dist/offline-store/network.js +11 -0
  690. package/dist/offline-store/network.js.map +7 -0
  691. package/dist/offline-store/store.js +136 -0
  692. package/dist/offline-store/store.js.map +7 -0
  693. package/dist/offline-store/wipe.js +8 -0
  694. package/dist/offline-store/wipe.js.map +7 -0
  695. package/dist/offline.js +58 -0
  696. package/dist/offline.js.map +7 -0
  697. package/dist/people.js +122 -0
  698. package/dist/people.js.map +7 -0
  699. package/dist/projects.js +30 -0
  700. package/dist/projects.js.map +7 -0
  701. package/dist/query-client.js +63 -0
  702. package/dist/query-client.js.map +7 -0
  703. package/dist/{chunk-ZM6N7YZH.js → query-keys.js} +18 -31
  704. package/dist/query-keys.js.map +7 -0
  705. package/dist/query-persist.js +66 -0
  706. package/dist/query-persist.js.map +7 -0
  707. package/dist/queued-writes.js +59 -0
  708. package/dist/queued-writes.js.map +7 -0
  709. package/dist/remote-control.js +67 -0
  710. package/dist/remote-control.js.map +7 -0
  711. package/dist/search/index.js +23 -0
  712. package/dist/search/index.js.map +7 -0
  713. package/dist/search/session.js +58 -0
  714. package/dist/search/session.js.map +7 -0
  715. package/dist/search/useSemanticSearch.js +82 -0
  716. package/dist/search/useSemanticSearch.js.map +7 -0
  717. package/dist/session/chat.js +512 -0
  718. package/dist/session/chat.js.map +7 -0
  719. package/dist/session/documents.js +196 -0
  720. package/dist/session/documents.js.map +7 -0
  721. package/dist/session/drafts.js +103 -0
  722. package/dist/session/drafts.js.map +7 -0
  723. package/dist/session/index.js +123 -0
  724. package/dist/session/index.js.map +7 -0
  725. package/dist/session/layout.js +339 -0
  726. package/dist/session/layout.js.map +7 -0
  727. package/dist/session/persist.js +106 -0
  728. package/dist/session/persist.js.map +7 -0
  729. package/dist/session/session-hooks.js +53 -0
  730. package/dist/session/session-hooks.js.map +7 -0
  731. package/dist/session/signed-in.js +36 -0
  732. package/dist/session/signed-in.js.map +7 -0
  733. package/dist/session/store.js +166 -0
  734. package/dist/session/store.js.map +7 -0
  735. package/dist/session/thread-tabs.js +121 -0
  736. package/dist/session/thread-tabs.js.map +7 -0
  737. package/dist/session/ui-state-storage.js +76 -0
  738. package/dist/session/ui-state-storage.js.map +7 -0
  739. package/dist/session/workspace.js +77 -0
  740. package/dist/session/workspace.js.map +7 -0
  741. package/dist/shell/index.js +43 -10
  742. package/dist/shell/index.js.map +7 -1
  743. package/dist/skill-pack.js +111 -0
  744. package/dist/skill-pack.js.map +7 -0
  745. package/dist/storage.js +186 -0
  746. package/dist/storage.js.map +7 -0
  747. package/dist/support/index.js +35 -0
  748. package/dist/support/index.js.map +7 -0
  749. package/dist/tags.js +204 -0
  750. package/dist/tags.js.map +7 -0
  751. package/dist/ui/DebouncedInput.js +109 -0
  752. package/dist/ui/DebouncedInput.js.map +7 -0
  753. package/dist/ui/DictateContext.js +8 -0
  754. package/dist/ui/DictateContext.js.map +7 -0
  755. package/dist/ui/IconToggle.js +79 -0
  756. package/dist/ui/IconToggle.js.map +7 -0
  757. package/dist/ui/VerifiedToggle.js +38 -0
  758. package/dist/ui/VerifiedToggle.js.map +7 -0
  759. package/dist/ui/VisibilityToggle.js +103 -0
  760. package/dist/ui/VisibilityToggle.js.map +7 -0
  761. package/dist/ui/avatar.js +40 -0
  762. package/dist/ui/avatar.js.map +7 -0
  763. package/dist/ui/badge.js +28 -0
  764. package/dist/ui/badge.js.map +7 -0
  765. package/dist/ui/button.js +48 -0
  766. package/dist/ui/button.js.map +7 -0
  767. package/dist/ui/card.js +90 -0
  768. package/dist/ui/card.js.map +7 -0
  769. package/dist/ui/checkbox.js +22 -0
  770. package/dist/ui/checkbox.js.map +7 -0
  771. package/dist/ui/collapsible.js +10 -0
  772. package/dist/ui/collapsible.js.map +7 -0
  773. package/dist/ui/command.js +103 -0
  774. package/dist/ui/command.js.map +7 -0
  775. package/dist/{chunk-YNNAJJ5Z.js → ui/dialog.js} +30 -68
  776. package/dist/ui/dialog.js.map +7 -0
  777. package/dist/{chunk-47CCGUWR.js → ui/dropdown-menu.js} +40 -45
  778. package/dist/ui/dropdown-menu.js.map +7 -0
  779. package/dist/ui/hover-card.js +36 -0
  780. package/dist/ui/hover-card.js.map +7 -0
  781. package/dist/ui/index.js +290 -10
  782. package/dist/ui/index.js.map +7 -1
  783. package/dist/ui/input.js +65 -0
  784. package/dist/ui/input.js.map +7 -0
  785. package/dist/ui/label.js +16 -0
  786. package/dist/ui/label.js.map +7 -0
  787. package/dist/ui/mark-menu.js +300 -0
  788. package/dist/ui/mark-menu.js.map +7 -0
  789. package/dist/ui/popover.js +40 -0
  790. package/dist/ui/popover.js.map +7 -0
  791. package/dist/ui/portal-container.js +17 -0
  792. package/dist/ui/portal-container.js.map +7 -0
  793. package/dist/ui/progress.js +24 -0
  794. package/dist/ui/progress.js.map +7 -0
  795. package/dist/ui/radio-group.js +29 -0
  796. package/dist/ui/radio-group.js.map +7 -0
  797. package/dist/ui/scroll-area.js +39 -0
  798. package/dist/ui/scroll-area.js.map +7 -0
  799. package/dist/ui/select.js +130 -0
  800. package/dist/ui/select.js.map +7 -0
  801. package/dist/ui/separator.js +23 -0
  802. package/dist/ui/separator.js.map +7 -0
  803. package/dist/ui/slider.js +23 -0
  804. package/dist/ui/slider.js.map +7 -0
  805. package/dist/ui/switch.js +28 -0
  806. package/dist/ui/switch.js.map +7 -0
  807. package/dist/ui/table.js +75 -0
  808. package/dist/ui/table.js.map +7 -0
  809. package/dist/ui/tabs.js +48 -0
  810. package/dist/ui/tabs.js.map +7 -0
  811. package/dist/ui/textarea.js +63 -0
  812. package/dist/ui/textarea.js.map +7 -0
  813. package/dist/ui/toggle-group.js +43 -0
  814. package/dist/ui/toggle-group.js.map +7 -0
  815. package/dist/ui/toggle.js +40 -0
  816. package/dist/ui/toggle.js.map +7 -0
  817. package/dist/ui/tooltip.js +215 -0
  818. package/dist/ui/tooltip.js.map +7 -0
  819. package/dist/usage-metered.js +8 -0
  820. package/dist/usage-metered.js.map +7 -0
  821. package/dist/useArbi.js +16 -0
  822. package/dist/useArbi.js.map +7 -0
  823. package/dist/useInstallSkillPack.js +81 -0
  824. package/dist/useInstallSkillPack.js.map +7 -0
  825. package/dist/usermenu/UserMenu.js +188 -0
  826. package/dist/usermenu/UserMenu.js.map +7 -0
  827. package/dist/usermenu/index.js +5 -0
  828. package/dist/usermenu/index.js.map +7 -0
  829. package/dist/users/index.js +15 -0
  830. package/dist/users/index.js.map +7 -0
  831. package/dist/users/user-display.js +60 -0
  832. package/dist/users/user-display.js.map +7 -0
  833. package/dist/viewers/AudioViewer.js +23 -0
  834. package/dist/viewers/AudioViewer.js.map +7 -0
  835. package/dist/viewers/DocxViewer.js +81 -0
  836. package/dist/viewers/DocxViewer.js.map +7 -0
  837. package/dist/viewers/ImageViewer.js +31 -0
  838. package/dist/viewers/ImageViewer.js.map +7 -0
  839. package/dist/viewers/PdfViewer.js +19 -3
  840. package/dist/viewers/PdfViewer.js.map +7 -1
  841. package/dist/{PdfViewerImpl-TEBYF2QI.js → viewers/PdfViewerImpl.js} +25 -19
  842. package/dist/viewers/PdfViewerImpl.js.map +7 -0
  843. package/dist/viewers/VideoViewer.js +31 -0
  844. package/dist/viewers/VideoViewer.js.map +7 -0
  845. package/dist/viewers/XlsxViewer.js +102 -0
  846. package/dist/viewers/XlsxViewer.js.map +7 -0
  847. package/dist/viewers/index.js +61 -271
  848. package/dist/viewers/index.js.map +7 -1
  849. package/dist/viewers/page-scroll.js +59 -0
  850. package/dist/viewers/page-scroll.js.map +7 -0
  851. package/dist/viewers/pdf-viewer-constants.js +9 -0
  852. package/dist/viewers/pdf-viewer-constants.js.map +7 -0
  853. package/dist/{chunk-PTOP7OHG.js → viewers/pdfjs-polyfills.js} +5 -6
  854. package/dist/viewers/pdfjs-polyfills.js.map +7 -0
  855. package/dist/viewers/selection-runs.js +38 -0
  856. package/dist/viewers/selection-runs.js.map +7 -0
  857. package/dist/viewers/usePageIntersectionObserver.js +68 -0
  858. package/dist/viewers/usePageIntersectionObserver.js.map +7 -0
  859. package/dist/viewers/useProcessedChunks.js +58 -0
  860. package/dist/viewers/useProcessedChunks.js.map +7 -0
  861. package/dist/viewers/viewer-zoom.js +163 -0
  862. package/dist/viewers/viewer-zoom.js.map +7 -0
  863. package/dist/websocket/ArbiWebSocketProvider.js +207 -0
  864. package/dist/websocket/ArbiWebSocketProvider.js.map +7 -0
  865. package/dist/websocket/context.js +14 -0
  866. package/dist/websocket/context.js.map +7 -0
  867. package/dist/websocket/hooks.js +30 -0
  868. package/dist/websocket/hooks.js.map +7 -0
  869. package/dist/websocket/index.js +22 -0
  870. package/dist/websocket/index.js.map +7 -0
  871. package/dist/websocket/live-updates.js +38 -0
  872. package/dist/websocket/live-updates.js.map +7 -0
  873. package/dist/websocket/reconnect.js +13 -0
  874. package/dist/websocket/reconnect.js.map +7 -0
  875. package/dist/websocket/store.js +58 -0
  876. package/dist/websocket/store.js.map +7 -0
  877. package/dist/workforce.js +607 -0
  878. package/dist/workforce.js.map +7 -0
  879. package/dist/workspaces/access-request.js +35 -0
  880. package/dist/workspaces/access-request.js.map +7 -0
  881. package/dist/workspaces/archive.js +59 -0
  882. package/dist/workspaces/archive.js.map +7 -0
  883. package/dist/workspaces/current.js +20 -0
  884. package/dist/workspaces/current.js.map +7 -0
  885. package/dist/workspaces/delete-workspaces.js +15 -0
  886. package/dist/workspaces/delete-workspaces.js.map +7 -0
  887. package/dist/workspaces/export-archive.js +40 -0
  888. package/dist/workspaces/export-archive.js.map +7 -0
  889. package/dist/workspaces/index.js +99 -0
  890. package/dist/workspaces/index.js.map +7 -0
  891. package/dist/workspaces/settings.js +45 -0
  892. package/dist/workspaces/settings.js.map +7 -0
  893. package/dist/workspaces/shell-workspaces.js +49 -0
  894. package/dist/workspaces/shell-workspaces.js.map +7 -0
  895. package/dist/workspaces/switch.js +234 -0
  896. package/dist/workspaces/switch.js.map +7 -0
  897. package/dist/workspaces/transfer.js +170 -0
  898. package/dist/workspaces/transfer.js.map +7 -0
  899. package/dist/workspaces/useShellWorkspaces.js +86 -0
  900. package/dist/workspaces/useShellWorkspaces.js.map +7 -0
  901. package/dist/workspaces/workspace-users.js +65 -0
  902. package/dist/workspaces/workspace-users.js.map +7 -0
  903. package/package.json +4 -4
  904. package/dist/PdfViewerImpl-TEBYF2QI.js.map +0 -1
  905. package/dist/PdfViewerImpl.d-B28hLEuj.d.cts +0 -62
  906. package/dist/ProductionDialog.d-CpzslFn0.d.cts +0 -51
  907. package/dist/annotations/freeze/index.d.cts +0 -205
  908. package/dist/annotations/index.d.cts +0 -360
  909. package/dist/artifacts/index.d.cts +0 -476
  910. package/dist/artifacts/redline-core.d.cts +0 -39
  911. package/dist/bundle-YNOX7VIL.js +0 -5
  912. package/dist/bundle-YNOX7VIL.js.map +0 -1
  913. package/dist/bundle.d-BnCSbHy2.d.cts +0 -85
  914. package/dist/calls/livekit/index.d.cts +0 -280
  915. package/dist/chunk-47CCGUWR.js.map +0 -1
  916. package/dist/chunk-4FL3X3LA.js +0 -2057
  917. package/dist/chunk-4FL3X3LA.js.map +0 -1
  918. package/dist/chunk-6QNBSXCE.js +0 -271
  919. package/dist/chunk-6QNBSXCE.js.map +0 -1
  920. package/dist/chunk-74N436VK.js.map +0 -1
  921. package/dist/chunk-APZZQZ6P.js +0 -147
  922. package/dist/chunk-APZZQZ6P.js.map +0 -1
  923. package/dist/chunk-BF5KW5ZI.js.map +0 -1
  924. package/dist/chunk-DPYBZDJB.js.map +0 -1
  925. package/dist/chunk-DZKRL5H3.js +0 -2766
  926. package/dist/chunk-DZKRL5H3.js.map +0 -1
  927. package/dist/chunk-HDCRPPBW.js +0 -75
  928. package/dist/chunk-HDCRPPBW.js.map +0 -1
  929. package/dist/chunk-L2IPPTVC.js +0 -20
  930. package/dist/chunk-L2IPPTVC.js.map +0 -1
  931. package/dist/chunk-LSU4UPS5.js +0 -1011
  932. package/dist/chunk-LSU4UPS5.js.map +0 -1
  933. package/dist/chunk-NIKPG4PW.js +0 -1128
  934. package/dist/chunk-NIKPG4PW.js.map +0 -1
  935. package/dist/chunk-NNAJLY6B.js +0 -4974
  936. package/dist/chunk-NNAJLY6B.js.map +0 -1
  937. package/dist/chunk-OYPKKHXY.js +0 -559
  938. package/dist/chunk-OYPKKHXY.js.map +0 -1
  939. package/dist/chunk-PTOP7OHG.js.map +0 -1
  940. package/dist/chunk-QMY2JKBI.js +0 -246
  941. package/dist/chunk-QMY2JKBI.js.map +0 -1
  942. package/dist/chunk-SN5YV6FF.js +0 -11
  943. package/dist/chunk-SN5YV6FF.js.map +0 -1
  944. package/dist/chunk-SSXFVWCT.js.map +0 -1
  945. package/dist/chunk-T3USOSVN.js.map +0 -1
  946. package/dist/chunk-T4CLW3DN.js +0 -2560
  947. package/dist/chunk-T4CLW3DN.js.map +0 -1
  948. package/dist/chunk-UW2SGTI5.js.map +0 -1
  949. package/dist/chunk-VSCU7K4V.js.map +0 -1
  950. package/dist/chunk-WL2Y2T47.js.map +0 -1
  951. package/dist/chunk-WUTL62MC.js.map +0 -1
  952. package/dist/chunk-XWPLOFDN.js +0 -644
  953. package/dist/chunk-XWPLOFDN.js.map +0 -1
  954. package/dist/chunk-Y3MTRA7D.js +0 -97
  955. package/dist/chunk-Y3MTRA7D.js.map +0 -1
  956. package/dist/chunk-YNNAJJ5Z.js.map +0 -1
  957. package/dist/chunk-ZM6N7YZH.js.map +0 -1
  958. package/dist/document-tools/core.d.cts +0 -883
  959. package/dist/document-tools/index.d.cts +0 -90
  960. package/dist/index.d-LArLnpI8.d.cts +0 -2036
  961. package/dist/index.d-oR5FKZpJ.d.cts +0 -579
  962. package/dist/index.d.cts +0 -15923
  963. package/dist/lazy-chunk.d-B6YDLMKI.d.cts +0 -31
  964. package/dist/model.d-CNtRWKVK.d.cts +0 -110
  965. package/dist/query-keys.d-B1Am9tIF.d.cts +0 -337
  966. package/dist/shell/index.d.cts +0 -6
  967. package/dist/store.d-GADDvC7w.d.cts +0 -35
  968. package/dist/stored-markdown.d-Bp18vrbr.d.cts +0 -125
  969. package/dist/ui/index.d.cts +0 -26
  970. package/dist/useAudioRecorder.d-B9rlMI_E.d.cts +0 -778
  971. package/dist/viewers/PdfViewer.d.cts +0 -9
  972. package/dist/viewers/index.d.cts +0 -262
@@ -1,2766 +0,0 @@
1
- import { clearSealedDrafts, useWorkspaces } from './chunk-4FL3X3LA.js';
2
- import { useArbi, arbiQueryKeys, useArbiHost, callQueryKeys } from './chunk-ZM6N7YZH.js';
3
- import { notify, clearChatArtifacts } from './chunk-BF5KW5ZI.js';
4
- import { getUserDisplayName, DEFAULT_SEGMENTER_CONFIG, INITIAL_SEGMENTER_STATE, flushSegmenter, stepSegmenter, levelFromRms } from './chunk-APZZQZ6P.js';
5
- import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
6
- import { useMemo, useSyncExternalStore, useEffect, useState, useCallback } from 'react';
7
- import { chats, calls, ArbiApiError, CallApiError, documents, continuityPrompt } from '@arbidocs/sdk/browser';
8
- import { createOfflineSealer, generateChatKey, sealCallKey, sealChatKey, decryptCallTitle, encryptWithChatKey, decryptWithChatKey, initSodium, bytesToBase64, encryptFile, decryptFile, base64ToBytes, buildCallLink, encryptCallTitle } from '@arbidocs/client';
9
-
10
- function useUserSettings(options) {
11
- const arbi = useArbi();
12
- return useQuery({
13
- queryKey: arbiQueryKeys.userSettings(),
14
- queryFn: () => arbi.settings.get(),
15
- // Edited about once a month, and every write here patches the cache: no refetch on each mount.
16
- staleTime: 30 * 60 * 1e3,
17
- refetchOnMount: options?.refetchOnMount,
18
- enabled: (options?.enabled ?? true) && arbi.isLoggedIn
19
- });
20
- }
21
- function useUpdateUserSettings() {
22
- const arbi = useArbi();
23
- const qc = useQueryClient();
24
- return useMutation({
25
- mutationFn: (patch) => arbi.settings.update(patch),
26
- onMutate: async (patch) => {
27
- await qc.cancelQueries({ queryKey: arbiQueryKeys.userSettings() });
28
- const previous = qc.getQueryData(arbiQueryKeys.userSettings());
29
- qc.setQueryData(
30
- arbiQueryKeys.userSettings(),
31
- (old) => old ? { ...old, ...patch } : old
32
- );
33
- return { previous };
34
- },
35
- onError: (_err, _patch, context) => {
36
- qc.setQueryData(arbiQueryKeys.userSettings(), context?.previous);
37
- },
38
- onSettled: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.userSettings() })
39
- });
40
- }
41
- var ALWAYS_ON = { on: true, set: () => {
42
- } };
43
- function useUnlisted() {
44
- return ALWAYS_ON;
45
- }
46
- function useUserSettingSwitch(source) {
47
- const { userSetting, default: fallback } = source;
48
- const { data } = useUserSettings();
49
- const { mutate } = useUpdateUserSettings();
50
- const saved = data?.[userSetting];
51
- const set = useCallback((on) => mutate({ [userSetting]: on }), [mutate, userSetting]);
52
- return { on: saved ?? fallback, set };
53
- }
54
- function useLocalSwitch(source, feature) {
55
- const { local, default: fallback } = source;
56
- const saved = useSyncExternalStore(local.subscribe, () => local.get(feature));
57
- const set = useCallback((on) => local.set(feature, on), [local, feature]);
58
- return { on: saved ?? fallback, set };
59
- }
60
- function useFeatureSwitch(feature) {
61
- const source = useArbiHost().features?.[feature];
62
- const useSource = !source ? useUnlisted : "userSetting" in source ? useUserSettingSwitch : useLocalSwitch;
63
- return useSource(source, feature);
64
- }
65
- function useFeature(feature) {
66
- return useFeatureSwitch(feature).on;
67
- }
68
- function useNoSettings() {
69
- return { data: void 0 };
70
- }
71
- function useFeatureCheck() {
72
- const features = useArbiHost().features;
73
- const useSettings = Object.values(features ?? {}).some(
74
- (source) => !!source && "userSetting" in source
75
- ) ? useUserSettings : useNoSettings;
76
- const { data } = useSettings();
77
- const locals = useMemo(() => {
78
- const entries = Object.entries(features ?? {}).filter(
79
- (entry) => !!entry[1] && "local" in entry[1]
80
- );
81
- return {
82
- subscribe: (listener) => {
83
- const stops = [...new Set(entries.map(([, source]) => source.local))].map(
84
- (store2) => store2.subscribe(listener)
85
- );
86
- return () => stops.forEach((stop) => stop());
87
- },
88
- // A primitive snapshot, so an unrelated store write does not re-render.
89
- snapshot: () => entries.map(([name, source]) => `${source.local.get(name)}`).join(",")
90
- };
91
- }, [features]);
92
- useSyncExternalStore(locals.subscribe, locals.snapshot, locals.snapshot);
93
- return (feature) => {
94
- const source = features?.[feature];
95
- if (!source) return true;
96
- if ("local" in source) return source.local.get(feature) ?? source.default;
97
- const saved = data?.[source.userSetting];
98
- return saved ?? source.default;
99
- };
100
- }
101
- function readLocalFeature(features, feature) {
102
- const source = features[feature];
103
- if (!source) return true;
104
- if ("local" in source) return source.local.get(feature) ?? source.default;
105
- return source.default;
106
- }
107
- function defaultStorage() {
108
- try {
109
- return typeof localStorage === "undefined" ? null : localStorage;
110
- } catch {
111
- return null;
112
- }
113
- }
114
- function parseValues(raw) {
115
- if (raw === null) return null;
116
- try {
117
- const parsed = JSON.parse(raw);
118
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
119
- return Object.fromEntries(
120
- Object.entries(parsed).filter(([, value]) => typeof value === "boolean")
121
- );
122
- } catch {
123
- return {};
124
- }
125
- }
126
- function createLocalFeatureStore({
127
- key,
128
- storage = defaultStorage(),
129
- migrate
130
- }) {
131
- const listeners4 = /* @__PURE__ */ new Set();
132
- const read = () => {
133
- try {
134
- return storage?.getItem(key) ?? null;
135
- } catch {
136
- return null;
137
- }
138
- };
139
- const write = () => {
140
- try {
141
- storage?.setItem(key, JSON.stringify(values));
142
- } catch {
143
- }
144
- };
145
- const notify2 = () => listeners4.forEach((listener) => listener());
146
- const saved = parseValues(read());
147
- let values = saved ?? {};
148
- let hydrated = saved !== null || !migrate;
149
- const ready = hydrated ? Promise.resolve() : migrate().catch((error) => {
150
- console.warn(`[features] The saved ${key} could not be brought in`, error);
151
- return null;
152
- }).then((earlier) => {
153
- values = { ...earlier ?? {}, ...values };
154
- write();
155
- hydrated = true;
156
- notify2();
157
- });
158
- return {
159
- get: (feature) => values[feature],
160
- set(feature, on) {
161
- if (values[feature] === on) return;
162
- values = { ...values, [feature]: on };
163
- write();
164
- notify2();
165
- },
166
- subscribe(listener) {
167
- listeners4.add(listener);
168
- return () => listeners4.delete(listener);
169
- },
170
- isHydrated: () => hydrated,
171
- hydrated: () => ready
172
- };
173
- }
174
-
175
- // src/conversation-list.ts
176
- function isConversationListKey(queryKey) {
177
- return queryKey.length === 3 && queryKey[0] === "arbi" && queryKey[1] === "conversations";
178
- }
179
- var LISTS = {
180
- predicate: (query) => isConversationListKey(query.queryKey)
181
- };
182
- function patchConversationList(queryClient, workspaceId, reducer) {
183
- if (!workspaceId) return;
184
- const key = arbiQueryKeys.conversations(workspaceId);
185
- const current = queryClient.getQueryData(key) ?? [];
186
- const next = reducer(current);
187
- if (next !== current) queryClient.setQueryData(key, next);
188
- }
189
- function addConversationToList(queryClient, workspaceId, conversation) {
190
- patchConversationList(queryClient, workspaceId, (old) => [
191
- conversation,
192
- ...old.filter((c) => c.external_id !== conversation.external_id)
193
- ]);
194
- }
195
- function patchConversation(queryClient, conversationId, update2) {
196
- queryClient.setQueriesData(LISTS, (old) => {
197
- if (!old?.some((c) => c.external_id === conversationId)) return old;
198
- return old.map(
199
- (c) => c.external_id === conversationId ? typeof update2 === "function" ? update2(c) : { ...c, ...update2 } : c
200
- );
201
- });
202
- }
203
- function removeConversationFromLists(queryClient, conversationId) {
204
- queryClient.setQueriesData(
205
- LISTS,
206
- (old) => old?.some((c) => c.external_id === conversationId) ? old.filter((c) => c.external_id !== conversationId) : old
207
- );
208
- }
209
- function invalidateConversationLists(queryClient) {
210
- return queryClient.invalidateQueries(LISTS);
211
- }
212
- function findConversation(queryClient, conversationId) {
213
- if (!conversationId) return void 0;
214
- for (const [, list] of queryClient.getQueriesData(LISTS)) {
215
- const row = list?.find((c) => c.external_id === conversationId);
216
- if (row) return row;
217
- }
218
- return void 0;
219
- }
220
- function isConversationShared(queryClient, conversationId) {
221
- return findConversation(queryClient, conversationId)?.is_shared ?? false;
222
- }
223
- function invalidateConversationDetails(queryClient, conversationId) {
224
- return queryClient.invalidateQueries({
225
- predicate: ({ queryKey }) => queryKey[0] === "arbi" && queryKey[1] === "conversations" && queryKey[2] === conversationId && queryKey[3] !== "threads"
226
- });
227
- }
228
- function myChatId(arbi) {
229
- try {
230
- return arbi.user.identity()?.externalId ?? null;
231
- } catch {
232
- return null;
233
- }
234
- }
235
- var openChatExtId = null;
236
- function setOpenChat(chatExtId) {
237
- openChatExtId = chatExtId;
238
- }
239
- function getOpenChat() {
240
- return openChatExtId;
241
- }
242
- function byActivity(a, b) {
243
- const at = Date.parse(a.last_message_at ?? a.created_at);
244
- const bt = Date.parse(b.last_message_at ?? b.created_at);
245
- return bt - at;
246
- }
247
- function cachedChats(queryClient) {
248
- return queryClient.getQueryData(arbiQueryKeys.chatList()) ?? [];
249
- }
250
- function cachedChat(queryClient, chatExtId) {
251
- return cachedChats(queryClient).find((c) => c.external_id === chatExtId);
252
- }
253
- function upsertChat(queryClient, chat) {
254
- queryClient.setQueryData(arbiQueryKeys.chatList(), (old) => {
255
- if (!old) return old;
256
- const rest = old.filter((c) => c.external_id !== chat.external_id);
257
- return [chat, ...rest].sort(byActivity);
258
- });
259
- }
260
- function removeChat(queryClient, chatExtId) {
261
- queryClient.setQueryData(
262
- arbiQueryKeys.chatList(),
263
- (old) => old?.filter((c) => c.external_id !== chatExtId)
264
- );
265
- queryClient.removeQueries({ queryKey: arbiQueryKeys.chatThread(chatExtId) });
266
- }
267
- function appendToThread(queryClient, chatExtId, message, replaceOptimisticId) {
268
- queryClient.setQueryData(arbiQueryKeys.chatThread(chatExtId), (old) => {
269
- if (!old) return old;
270
- const without = old.messages.filter(
271
- (m) => m.external_id !== message.external_id && m.external_id !== replaceOptimisticId
272
- );
273
- return { ...old, messages: [...without, message] };
274
- });
275
- }
276
- function dropFromThread(queryClient, chatExtId, messageExtId) {
277
- queryClient.setQueryData(
278
- arbiQueryKeys.chatThread(chatExtId),
279
- (old) => old ? { ...old, messages: old.messages.filter((m) => m.external_id !== messageExtId) } : old
280
- );
281
- }
282
- function replaceInThread(queryClient, chatExtId, message) {
283
- queryClient.setQueryData(arbiQueryKeys.chatThread(chatExtId), (old) => {
284
- if (!old || !old.messages.some((m) => m.external_id === message.external_id)) return old;
285
- return {
286
- ...old,
287
- messages: old.messages.map((m) => m.external_id === message.external_id ? message : m)
288
- };
289
- });
290
- }
291
- function patchLastMessage(queryClient, chatExtId, message) {
292
- queryClient.setQueryData(
293
- arbiQueryKeys.chatList(),
294
- (old) => old?.map(
295
- (c) => c.external_id === chatExtId && c.last_message?.external_id === message.external_id ? { ...c, last_message: message } : c
296
- )
297
- );
298
- }
299
- async function deleteChatMessage(arbi, queryClient, chatExtId, messageExtId) {
300
- const thread = queryClient.getQueryData(arbiQueryKeys.chatThread(chatExtId));
301
- const before = thread?.messages.find((m) => m.external_id === messageExtId);
302
- const listed = cachedChat(queryClient, chatExtId);
303
- const wasLast = listed?.last_message?.external_id === messageExtId ? listed.last_message : null;
304
- if (before) replaceInThread(queryClient, chatExtId, chats.chatMessageTombstone(before));
305
- if (wasLast) patchLastMessage(queryClient, chatExtId, chats.chatMessageTombstone(wasLast));
306
- try {
307
- await arbi.chats.deleteMessage(chatExtId, messageExtId);
308
- } catch (err) {
309
- if (before) replaceInThread(queryClient, chatExtId, before);
310
- if (wasLast) patchLastMessage(queryClient, chatExtId, wasLast);
311
- throw err;
312
- }
313
- }
314
- async function applyChangedMessage(arbi, queryClient, chatExtId, message) {
315
- if (message.deleted) {
316
- replaceInThread(queryClient, chatExtId, chats.chatMessageTombstone(message));
317
- patchLastMessage(queryClient, chatExtId, chats.chatMessageTombstone(message));
318
- return;
319
- }
320
- const chat = cachedChat(queryClient, chatExtId);
321
- if (!chat || !queryClient.getQueryData(arbiQueryKeys.chatThread(chatExtId))) return;
322
- try {
323
- replaceInThread(queryClient, chatExtId, await arbi.chats.decrypt(chat, message));
324
- } catch (err) {
325
- console.error("[chats] could not decrypt a changed message", err);
326
- }
327
- }
328
- async function applyChatMessage(arbi, queryClient, chatExtId, message) {
329
- if (message.deleted) return applyChangedMessage(arbi, queryClient, chatExtId, message);
330
- const me = myChatId(arbi);
331
- const chat = cachedChat(queryClient, chatExtId);
332
- if (!chat) {
333
- void queryClient.invalidateQueries({ queryKey: arbiQueryKeys.chatList() });
334
- return;
335
- }
336
- const mine = message.sender_ext_id === me;
337
- const isOpen = openChatExtId === chatExtId;
338
- upsertChat(queryClient, {
339
- ...chat,
340
- last_message: message,
341
- last_message_at: message.created_at,
342
- unread_count: mine ? 0 : isOpen ? chat.unread_count : chat.unread_count + 1,
343
- members: mine ? chat.members.map(
344
- (m) => m.user.external_id === me ? { ...m, last_read_at: message.created_at } : m
345
- ) : chat.members
346
- });
347
- if (queryClient.getQueryData(arbiQueryKeys.chatThread(chatExtId))) {
348
- try {
349
- appendToThread(queryClient, chatExtId, await arbi.chats.decrypt(chat, message));
350
- } catch (err) {
351
- console.error("[chats] could not decrypt a live message", err);
352
- }
353
- }
354
- }
355
- function applyChatRead(arbi, queryClient, chatExtId, userExtId, lastReadAt) {
356
- const me = myChatId(arbi);
357
- queryClient.setQueryData(
358
- arbiQueryKeys.chatList(),
359
- (old) => old?.map(
360
- (c) => c.external_id !== chatExtId ? c : {
361
- ...c,
362
- unread_count: userExtId === me ? 0 : c.unread_count,
363
- members: c.members.map(
364
- (m) => m.user.external_id === userExtId ? { ...m, last_read_at: lastReadAt } : m
365
- )
366
- }
367
- )
368
- );
369
- }
370
- async function applyChatUpdated(arbi, queryClient, chatExtId, message) {
371
- if (message) await applyChangedMessage(arbi, queryClient, chatExtId, message);
372
- let chat;
373
- try {
374
- chat = await arbi.chats.get(chatExtId);
375
- } catch {
376
- removeChat(queryClient, chatExtId);
377
- return;
378
- }
379
- if (chat.rotation_required) {
380
- chat = await arbi.chats.ready(chat).catch(() => chat);
381
- }
382
- upsertChat(queryClient, chat);
383
- if (!message)
384
- void queryClient.invalidateQueries({ queryKey: arbiQueryKeys.chatThread(chatExtId) });
385
- }
386
- function applyAgentDmStatus(queryClient, status) {
387
- if (!["queued", "working", "done", "failed"].includes(status.status)) return;
388
- queryClient.setQueryData(arbiQueryKeys.agentDmStatus(status.agent_ext_id), status);
389
- }
390
- async function applyChatEvent(arbi, queryClient, event) {
391
- const e = event;
392
- if (e.type === "chat.message")
393
- return applyChatMessage(arbi, queryClient, e.chat_ext_id, e.message);
394
- if (e.type === "chat.read")
395
- return applyChatRead(arbi, queryClient, e.chat_ext_id, e.user_ext_id, e.last_read_at);
396
- if (e.type === "chat.updated")
397
- return applyChatUpdated(arbi, queryClient, e.chat_ext_id, e.message);
398
- if (e.type === "agent_dm_status") applyAgentDmStatus(queryClient, e);
399
- }
400
-
401
- // src/calls/keys.ts
402
- function serverCallsExperimental(queryClient) {
403
- return queryClient.getQueryData(callQueryKeys.config())?.experimental !== false;
404
- }
405
- function invalidateCall(queryClient, message) {
406
- void queryClient.invalidateQueries({ queryKey: callQueryKeys.call(message.call_ext_id) });
407
- const thread = message.log_conversation_ext_id;
408
- if (thread) {
409
- void queryClient.invalidateQueries({ queryKey: arbiQueryKeys.conversationActivity(thread) });
410
- }
411
- }
412
-
413
- // src/calls/moderation.ts
414
- var CALL_MODERATION_TOPIC = "arbi.moderation";
415
- function trackOf(value) {
416
- return value === "audio" || value === "video" ? value : null;
417
- }
418
- function mutedNoticeFromPacket(payload) {
419
- try {
420
- const parsed = JSON.parse(new TextDecoder().decode(payload));
421
- if (!parsed || typeof parsed !== "object") return null;
422
- const p = parsed;
423
- const track = trackOf(p.track);
424
- if (p.action !== "muted" || !track) return null;
425
- return { track, byName: typeof p.by_name === "string" ? p.by_name : null };
426
- } catch {
427
- return null;
428
- }
429
- }
430
- function mutedNoticeText(notice) {
431
- return notice.track === "audio" ? "The host muted you" : "The host turned off your camera";
432
- }
433
- var MUTED_DEDUPE_MS = 5e3;
434
- function createMutedNotifier(show, now = Date.now) {
435
- const last = /* @__PURE__ */ new Map();
436
- return (notice) => {
437
- const at = now();
438
- const prev = last.get(notice.track);
439
- if (prev !== void 0 && at - prev < MUTED_DEDUPE_MS) return;
440
- last.set(notice.track, at);
441
- show(mutedNoticeText(notice));
442
- };
443
- }
444
- function mutedNoticeFromEvent(raw) {
445
- if (!raw || typeof raw !== "object") return null;
446
- const r = raw;
447
- const track = trackOf(r.track);
448
- if (typeof r.call_ext_id !== "string" || !track) return null;
449
- return {
450
- callExtId: r.call_ext_id,
451
- track,
452
- byName: typeof r.by_name === "string" ? r.by_name : null
453
- };
454
- }
455
- var DEFAULT_JOIN_CHOICES = { audioEnabled: true, videoEnabled: false };
456
- var EMPTY_CALL_SESSION = {
457
- active: null,
458
- incoming: [],
459
- knocks: [],
460
- liveCalls: {}
461
- };
462
- var state = EMPTY_CALL_SESSION;
463
- var listeners = /* @__PURE__ */ new Set();
464
- function update(next) {
465
- const changed = next(state);
466
- if (changed === state) return;
467
- state = changed;
468
- for (const listener of listeners) listener();
469
- }
470
- var callSession = {
471
- getState: () => state,
472
- subscribe(listener) {
473
- listeners.add(listener);
474
- return () => {
475
- listeners.delete(listener);
476
- };
477
- },
478
- setActiveCall(next) {
479
- update((s) => ({
480
- ...s,
481
- active: { ...next, minimized: next.minimized ?? false, startedAt: Date.now() },
482
- // Joining a call answers any ring for it; knocks belong to the previous call.
483
- incoming: s.incoming.filter((ring) => ring.call_ext_id !== next.callExtId),
484
- knocks: s.knocks.filter((k) => k.callExtId === next.callExtId)
485
- }));
486
- },
487
- /** Patch the active call (no-op when it is a different call or none). */
488
- updateActiveCall(callExtId, patch) {
489
- update(
490
- (s) => s.active?.callExtId === callExtId ? { ...s, active: { ...s.active, ...patch } } : s
491
- );
492
- },
493
- endActiveCall() {
494
- update((s) => {
495
- s.active?.knock?.abort();
496
- return { ...s, active: null, knocks: [] };
497
- });
498
- },
499
- setCallMinimized(minimized) {
500
- update((s) => s.active ? { ...s, active: { ...s.active, minimized } } : s);
501
- },
502
- /** Queue a ring. A repeat ring for the same call replaces the earlier entry. */
503
- enqueueIncomingCall(ring) {
504
- update((s) => {
505
- if (s.active?.callExtId === ring.call_ext_id) return s;
506
- return {
507
- ...s,
508
- incoming: [
509
- ...s.incoming.filter((r) => r.call_ext_id !== ring.call_ext_id),
510
- { ...ring, receivedAt: Date.now() }
511
- ]
512
- };
513
- });
514
- },
515
- removeIncomingCall(callExtId) {
516
- update((s) => ({ ...s, incoming: s.incoming.filter((r) => r.call_ext_id !== callExtId) }));
517
- },
518
- addKnock(knock) {
519
- update((s) => {
520
- if (s.active?.callExtId !== knock.callExtId) return s;
521
- return {
522
- ...s,
523
- knocks: [
524
- ...s.knocks.filter((k) => k.knockId !== knock.knockId),
525
- { ...knock, receivedAt: Date.now() }
526
- ]
527
- };
528
- });
529
- },
530
- removeKnock(knockId) {
531
- update((s) => ({ ...s, knocks: s.knocks.filter((k) => k.knockId !== knockId) }));
532
- },
533
- markCallLive(callExtId, where) {
534
- update((s) => ({ ...s, liveCalls: { ...s.liveCalls, [callExtId]: where } }));
535
- },
536
- /** Call ended: forget it and drop any unanswered ring / knock for it. */
537
- markCallEnded(callExtId) {
538
- update((s) => {
539
- const liveCalls = { ...s.liveCalls };
540
- delete liveCalls[callExtId];
541
- return {
542
- ...s,
543
- liveCalls,
544
- incoming: s.incoming.filter((r) => r.call_ext_id !== callExtId),
545
- knocks: s.knocks.filter((k) => k.callExtId !== callExtId)
546
- };
547
- });
548
- }
549
- };
550
- function resetCallSession() {
551
- update(() => EMPTY_CALL_SESSION);
552
- }
553
- function useCallSession(selector) {
554
- return useSyncExternalStore(
555
- callSession.subscribe,
556
- () => selector(state),
557
- () => selector(state)
558
- );
559
- }
560
- function threadLiveCallId(s, conversationExtId) {
561
- const found = Object.entries(s.liveCalls).find(
562
- ([, c]) => c.logConversationExtId === conversationExtId
563
- );
564
- return found ? found[0] : null;
565
- }
566
- function threadHasLiveCall(s, conversationExtId) {
567
- return threadLiveCallId(s, conversationExtId) !== null;
568
- }
569
- function chatLiveCallId(s, chatExtId) {
570
- const found = Object.entries(s.liveCalls).find(([, c]) => c.chatExtId === chatExtId);
571
- return found ? found[0] : null;
572
- }
573
- function chatHasLiveCall(s, chatExtId) {
574
- return chatLiveCallId(s, chatExtId) !== null;
575
- }
576
- var listeners2 = /* @__PURE__ */ new Map();
577
- function onCallEvent(type, listener) {
578
- let set = listeners2.get(type);
579
- if (!set) listeners2.set(type, set = /* @__PURE__ */ new Set());
580
- set.add(listener);
581
- return () => {
582
- set.delete(listener);
583
- };
584
- }
585
- function relay(type, message) {
586
- if (!message) return;
587
- for (const listener of listeners2.get(type) ?? []) {
588
- listener(message);
589
- }
590
- }
591
- var str = (value) => typeof value === "string" && value ? value : null;
592
- function applyCallEvent(queryClient, event, options = {}) {
593
- const m = event;
594
- const callExtId = str(m.call_ext_id);
595
- switch (m.type) {
596
- case "call.ringing": {
597
- const ring = m;
598
- const optedOut = options.acceptRings === false && serverCallsExperimental(queryClient);
599
- if (optedOut || !callExtId || !ring.sealed_key) return true;
600
- if (options.me && ring.caller_ext_id === options.me) return true;
601
- callSession.enqueueIncomingCall({
602
- call_ext_id: ring.call_ext_id,
603
- room_name: ring.room_name,
604
- caller_ext_id: ring.caller_ext_id,
605
- caller_name: ring.caller_name,
606
- chat_ext_id: ring.chat_ext_id ?? null,
607
- log_conversation_ext_id: ring.log_conversation_ext_id ?? null,
608
- meeting_conversation_ext_id: ring.meeting_conversation_ext_id ?? null,
609
- workspace_ext_id: ring.workspace_ext_id ?? null,
610
- context: ring.context ?? null,
611
- sealed_key: ring.sealed_key,
612
- link_version: ring.link_version,
613
- title: ring.title ?? null
614
- });
615
- return true;
616
- }
617
- case "call.declined":
618
- if (callExtId && callSession.getState().active?.callExtId === callExtId) {
619
- notify.info("Call declined", { record: false, ambient: false });
620
- }
621
- return true;
622
- case "call.started":
623
- if (!callExtId) return true;
624
- callSession.markCallLive(callExtId, {
625
- chatExtId: str(m.chat_ext_id),
626
- logConversationExtId: str(m.log_conversation_ext_id),
627
- meetingConversationExtId: str(m.meeting_conversation_ext_id)
628
- });
629
- invalidateCall(queryClient, {
630
- call_ext_id: callExtId,
631
- log_conversation_ext_id: str(m.log_conversation_ext_id)
632
- });
633
- return true;
634
- case "call.ended":
635
- if (!callExtId) return true;
636
- callSession.markCallEnded(callExtId);
637
- invalidateCall(queryClient, {
638
- call_ext_id: callExtId,
639
- log_conversation_ext_id: str(m.log_conversation_ext_id)
640
- });
641
- return true;
642
- case "call.knock": {
643
- const knock = m;
644
- if (!callExtId) return true;
645
- callSession.addKnock({
646
- callExtId,
647
- knockId: knock.knock_id,
648
- displayName: knock.display_name,
649
- userExtId: knock.user_ext_id
650
- });
651
- return true;
652
- }
653
- case "call.knock_resolved": {
654
- const knockId = str(m.knock_id);
655
- if (knockId) callSession.removeKnock(knockId);
656
- return true;
657
- }
658
- case "call.recording": {
659
- if (callExtId)
660
- void queryClient.invalidateQueries({ queryKey: callQueryKeys.recordingsOf(callExtId) });
661
- const state2 = calls.recordingStateFrom(m);
662
- relay("call.recording", callExtId && state2 ? { ...state2, call_ext_id: callExtId } : null);
663
- return true;
664
- }
665
- case "call.recording_updated": {
666
- if (callExtId)
667
- void queryClient.invalidateQueries({ queryKey: callQueryKeys.recordingsOf(callExtId) });
668
- return true;
669
- }
670
- case "call.recording_deleted": {
671
- if (callExtId)
672
- void queryClient.invalidateQueries({ queryKey: callQueryKeys.recordingsOf(callExtId) });
673
- const recordingExtId = str(m.recording_ext_id);
674
- relay(
675
- "call.recording_deleted",
676
- callExtId && recordingExtId ? { call_ext_id: callExtId, recording_ext_id: recordingExtId } : null
677
- );
678
- return true;
679
- }
680
- case "call.transcription": {
681
- const state2 = calls.transcriptionStateFrom(m);
682
- relay("call.transcription", callExtId && state2 ? { ...state2, call_ext_id: callExtId } : null);
683
- return true;
684
- }
685
- case "call.webinar":
686
- relay(
687
- "call.webinar",
688
- callExtId && typeof m.live === "boolean" ? {
689
- type: "call.webinar",
690
- call_ext_id: callExtId,
691
- live: m.live,
692
- chat: m.chat === "everyone" ? "everyone" : "panelists"
693
- } : null
694
- );
695
- return true;
696
- case "call.muted":
697
- relay("call.muted", mutedNoticeFromEvent(m));
698
- return true;
699
- default:
700
- return false;
701
- }
702
- }
703
- var OfflineMailLockedError = class extends Error {
704
- constructor() {
705
- super("Sign in to open the mail saved on this device");
706
- this.name = "OfflineMailLockedError";
707
- }
708
- };
709
- var sealer = createOfflineSealer("arbi-offline-mail-v1", {
710
- locked: () => new OfflineMailLockedError()
711
- });
712
- var forgetOfflineMailKeys = sealer.forget;
713
- var sealBytes = sealer.sealBytes;
714
- var openBytes = sealer.openBytes;
715
- var sealJson = sealer.sealJson;
716
- var openJson = sealer.openJson;
717
- var blind = sealer.blind;
718
-
719
- // src/offline-store/store.ts
720
- var DB_VERSION = 1;
721
- var RECORDS = "records";
722
- var META = "meta";
723
- function promisify(request) {
724
- return new Promise((resolve, reject) => {
725
- request.onsuccess = () => resolve(request.result);
726
- request.onerror = () => reject(request.error);
727
- });
728
- }
729
- function createRecordStore(dbName) {
730
- let dbPromise = null;
731
- function openDB() {
732
- if (dbPromise) return dbPromise;
733
- let request;
734
- try {
735
- request = indexedDB.open(dbName, DB_VERSION);
736
- } catch (error) {
737
- return Promise.reject(error);
738
- }
739
- dbPromise = new Promise((resolve, reject) => {
740
- request.onerror = () => {
741
- dbPromise = null;
742
- reject(request.error);
743
- };
744
- request.onsuccess = () => {
745
- const db = request.result;
746
- db.onversionchange = () => {
747
- db.close();
748
- dbPromise = null;
749
- };
750
- resolve(db);
751
- };
752
- request.onupgradeneeded = () => {
753
- const db = request.result;
754
- if (!db.objectStoreNames.contains(RECORDS)) {
755
- const records = db.createObjectStore(RECORDS, { keyPath: "key" });
756
- records.createIndex("bucket", "bucket");
757
- records.createIndex("kind", "kind");
758
- }
759
- if (!db.objectStoreNames.contains(META)) db.createObjectStore(META, { keyPath: "key" });
760
- };
761
- });
762
- return dbPromise;
763
- }
764
- async function run(store2, mode, fn) {
765
- const db = await openDB();
766
- return promisify(fn(db.transaction(store2, mode).objectStore(store2)));
767
- }
768
- async function scan(pick) {
769
- const db = await openDB();
770
- const store2 = db.transaction(RECORDS, "readonly").objectStore(RECORDS);
771
- return new Promise((resolve, reject) => {
772
- const out = [];
773
- const cursor = store2.openCursor();
774
- cursor.onerror = () => reject(cursor.error);
775
- cursor.onsuccess = () => {
776
- const c = cursor.result;
777
- if (!c) return resolve(out);
778
- out.push(pick(c.value));
779
- c.continue();
780
- };
781
- });
782
- }
783
- const self = {
784
- dbName,
785
- async putRecord(record) {
786
- await run(RECORDS, "readwrite", (s) => s.put(record));
787
- },
788
- async getRecord(key) {
789
- return await run(RECORDS, "readonly", (s) => s.get(key));
790
- },
791
- async hasRecord(key) {
792
- return await run(RECORDS, "readonly", (s) => s.count(key)) > 0;
793
- },
794
- async deleteRecords(keys) {
795
- if (keys.length === 0) return;
796
- const db = await openDB();
797
- const tx = db.transaction(RECORDS, "readwrite");
798
- const store2 = tx.objectStore(RECORDS);
799
- for (const key of keys) store2.delete(key);
800
- await new Promise((resolve, reject) => {
801
- tx.oncomplete = () => resolve();
802
- tx.onerror = () => reject(tx.error);
803
- tx.onabort = () => reject(tx.error);
804
- });
805
- },
806
- async recordsInBucket(bucket) {
807
- return await run(
808
- RECORDS,
809
- "readonly",
810
- (s) => s.index("bucket").getAll(bucket)
811
- );
812
- },
813
- async recordsOfKind(kind) {
814
- return await run(
815
- RECORDS,
816
- "readonly",
817
- (s) => s.index("kind").getAll(kind)
818
- );
819
- },
820
- allRecordSizes() {
821
- return scan(({ key, kind, size }) => ({ key, kind, size }));
822
- },
823
- allRecordAccess() {
824
- return scan(({ key, kind, lastAccess }) => ({ key, kind, lastAccess }));
825
- },
826
- async touchRecord(key) {
827
- const record = await self.getRecord(key);
828
- if (record) await self.putRecord({ ...record, lastAccess: Date.now() });
829
- },
830
- async getMeta(key) {
831
- const row = await run(META, "readonly", (s) => s.get(key));
832
- return row?.value;
833
- },
834
- async setMeta(key, value) {
835
- await run(META, "readwrite", (s) => s.put({ key, value }));
836
- },
837
- async deleteDatabase() {
838
- const db = await dbPromise?.catch(() => null);
839
- db?.close();
840
- dbPromise = null;
841
- await new Promise((resolve, reject) => {
842
- const request = indexedDB.deleteDatabase(dbName);
843
- request.onsuccess = () => resolve();
844
- request.onerror = () => reject(request.error);
845
- request.onblocked = () => {
846
- };
847
- });
848
- }
849
- };
850
- return self;
851
- }
852
-
853
- // src/mail/offline/store.ts
854
- var OFFLINE_MAIL_DB = "arbi-offline-mail";
855
- var store = createRecordStore(OFFLINE_MAIL_DB);
856
- var putRecord = store.putRecord;
857
- var getRecord = store.getRecord;
858
- var hasRecord = store.hasRecord;
859
- var deleteRecords = store.deleteRecords;
860
- var recordsInBucket = store.recordsInBucket;
861
- var recordsOfKind = store.recordsOfKind;
862
- var allRecordSizes = store.allRecordSizes;
863
- var touchRecord = store.touchRecord;
864
- var getMeta = store.getMeta;
865
- var setMeta = store.setMeta;
866
- var deleteOfflineMailDatabase = store.deleteDatabase;
867
-
868
- // src/mail/offline/settings.ts
869
- var DEFAULT_OFFLINE_MAIL_SETTINGS = {
870
- enabled: true,
871
- scope: "7d",
872
- attachmentCapMb: 25,
873
- quotaMb: 1024
874
- };
875
- var SCOPE_DAYS = {
876
- "1d": 1,
877
- "7d": 7,
878
- "30d": 30,
879
- "90d": 90
880
- };
881
- var DAY_MS = 24 * 60 * 60 * 1e3;
882
- function offlineWindowStart(settings, now = Date.now()) {
883
- return now - SCOPE_DAYS[settings.scope] * DAY_MS;
884
- }
885
- function inOfflineWindow(settings, receivedAt, now = Date.now()) {
886
- const at = receivedAt ? Date.parse(receivedAt) || 0 : 0;
887
- return settings.enabled && (!at || at >= offlineWindowStart(settings, now));
888
- }
889
- function normalize(saved) {
890
- const merged = { ...DEFAULT_OFFLINE_MAIL_SETTINGS, ...saved };
891
- const scope = merged.scope;
892
- if (scope in SCOPE_DAYS) return merged;
893
- const longer = scope === "365d" || scope === "all";
894
- return { ...merged, scope: longer ? "90d" : DEFAULT_OFFLINE_MAIL_SETTINGS.scope };
895
- }
896
- var STORAGE_PREFIX = "arbi-offline-mail-settings:";
897
- var SIGNED_OUT = { ...DEFAULT_OFFLINE_MAIL_SETTINGS, enabled: false };
898
- function getOfflineMailSettings(userExtId) {
899
- if (!userExtId) return SIGNED_OUT;
900
- const key = STORAGE_PREFIX + userExtId;
901
- try {
902
- const raw = localStorage.getItem(key);
903
- return raw ? normalize(JSON.parse(raw)) : DEFAULT_OFFLINE_MAIL_SETTINGS;
904
- } catch {
905
- return DEFAULT_OFFLINE_MAIL_SETTINGS;
906
- }
907
- }
908
- function setOfflineMailSettings(userExtId, patch) {
909
- const next = { ...getOfflineMailSettings(userExtId), ...patch };
910
- if (userExtId) {
911
- try {
912
- localStorage.setItem(STORAGE_PREFIX + userExtId, JSON.stringify(next));
913
- } catch {
914
- }
915
- }
916
- notifyOfflineMailChange("settings");
917
- return next;
918
- }
919
- var listeners3 = /* @__PURE__ */ new Set();
920
- var CHANNEL = "arbi-offline-mail";
921
- var channel = null;
922
- function getChannel() {
923
- if (channel || typeof BroadcastChannel === "undefined") return channel;
924
- channel = new BroadcastChannel(CHANNEL);
925
- channel.onmessage = (event) => {
926
- for (const listener of listeners3) listener(event.data);
927
- };
928
- return channel;
929
- }
930
- function notifyOfflineMailChange(change) {
931
- for (const listener of listeners3) listener(change);
932
- try {
933
- getChannel()?.postMessage(change);
934
- } catch {
935
- }
936
- }
937
- function onOfflineMailChange(listener) {
938
- getChannel();
939
- listeners3.add(listener);
940
- return () => listeners3.delete(listener);
941
- }
942
-
943
- // src/mail/offline/wipe.ts
944
- var OWNER_KEY = "owner";
945
- async function wipeOfflineMail() {
946
- forgetOfflineMailKeys();
947
- await deleteOfflineMailDatabase();
948
- notifyOfflineMailChange("wiped");
949
- }
950
- async function claimOfflineMail(userExtId) {
951
- const owner = await getMeta(OWNER_KEY);
952
- if (owner && owner !== userExtId) await wipeOfflineMail();
953
- await setMeta(OWNER_KEY, userExtId);
954
- }
955
- function toProfileView(profile) {
956
- return {
957
- ...profile,
958
- fullName: [profile.givenName, profile.familyName].map((part) => part?.trim()).filter(Boolean).join(" ")
959
- };
960
- }
961
- function useProfile(options) {
962
- const { client, enabled } = useAccountClient();
963
- const qc = useQueryClient();
964
- useEffect(
965
- () => client.onProfileChange(() => qc.setQueryData(arbiQueryKeys.profile(), client.profile())),
966
- [client, qc]
967
- );
968
- return useQuery({
969
- queryKey: arbiQueryKeys.profile(),
970
- queryFn: () => client.profile(),
971
- enabled: (options?.enabled ?? true) && enabled,
972
- staleTime: Infinity
973
- });
974
- }
975
- function useUpdateProfile() {
976
- const { client } = useAccountClient();
977
- const qc = useQueryClient();
978
- return useMutation({
979
- mutationFn: async (vars) => {
980
- await client.updateProfile(vars);
981
- return client.profile();
982
- },
983
- onSuccess: (profile) => {
984
- qc.setQueryData(arbiQueryKeys.profile(), profile);
985
- void qc.invalidateQueries({ queryKey: arbiQueryKeys.identity() });
986
- return qc.invalidateQueries({ queryKey: arbiQueryKeys.workspaces() });
987
- }
988
- });
989
- }
990
- function useNameEditor({ givenName, familyName, save }) {
991
- const [isEditing, setIsEditing] = useState(false);
992
- const [given, setGiven] = useState("");
993
- const [family, setFamily] = useState("");
994
- const [isSaving, setIsSaving] = useState(false);
995
- const [error, setError] = useState(null);
996
- const onStartEdit = useCallback(() => {
997
- setGiven(givenName ?? "");
998
- setFamily(familyName ?? "");
999
- setError(null);
1000
- setIsEditing(true);
1001
- }, [givenName, familyName]);
1002
- const onSave = useCallback(() => {
1003
- const trimmedGiven = given.trim();
1004
- if (!trimmedGiven) return;
1005
- setIsSaving(true);
1006
- setError(null);
1007
- void Promise.resolve().then(() => save({ givenName: trimmedGiven, familyName: family.trim() })).then(() => setIsEditing(false)).catch((e) => setError(e)).finally(() => setIsSaving(false));
1008
- }, [given, family, save]);
1009
- return {
1010
- isEditing,
1011
- givenName: given,
1012
- familyName: family,
1013
- onGivenNameChange: setGiven,
1014
- onFamilyNameChange: setFamily,
1015
- onStartEdit,
1016
- onSave,
1017
- onCancel: () => setIsEditing(false),
1018
- isSaving,
1019
- error
1020
- };
1021
- }
1022
- var MAX_AVATAR_FILE_BYTES = 5 * 1024 * 1024;
1023
- function useAvatarCrop({
1024
- upload,
1025
- onProblem,
1026
- maxBytes = MAX_AVATAR_FILE_BYTES
1027
- }) {
1028
- const [pendingImage, setPendingImage] = useState(null);
1029
- const [isUploading, setIsUploading] = useState(false);
1030
- const onFileChosen = useCallback(
1031
- (file) => {
1032
- if (!file.type.startsWith("image/")) return onProblem?.("not-image");
1033
- if (file.size > maxBytes) return onProblem?.("too-large");
1034
- const reader = new FileReader();
1035
- reader.onload = () => setPendingImage(reader.result);
1036
- reader.onerror = () => onProblem?.("unreadable");
1037
- reader.readAsDataURL(file);
1038
- },
1039
- [maxBytes, onProblem]
1040
- );
1041
- const onCropComplete = useCallback(
1042
- (result) => {
1043
- setPendingImage(null);
1044
- setIsUploading(true);
1045
- void Promise.resolve().then(() => upload(result.dataUrl)).catch(() => {
1046
- }).finally(() => setIsUploading(false));
1047
- },
1048
- [upload]
1049
- );
1050
- return {
1051
- onFileChosen,
1052
- pendingImage,
1053
- onCropComplete,
1054
- onCropCancel: () => setPendingImage(null),
1055
- isUploading
1056
- };
1057
- }
1058
-
1059
- // src/account/client.tsx
1060
- function arbiProfile(arbi) {
1061
- const profile = arbi.user.profile();
1062
- return profile ? toProfileView(profile) : null;
1063
- }
1064
- function arbiAccountClient(arbi, overrides = {}) {
1065
- return {
1066
- profile: () => arbiProfile(arbi),
1067
- onProfileChange: (listener) => arbi.user.onProfileChange(() => listener()),
1068
- updateProfile: async (vars) => {
1069
- await arbi.profile.update({
1070
- ...vars.givenName !== void 0 && { given_name: vars.givenName.trim() },
1071
- ...vars.familyName !== void 0 && { family_name: vars.familyName.trim() },
1072
- ...vars.picture !== void 0 && { picture: vars.picture }
1073
- });
1074
- },
1075
- requestEmailChange: (newEmail) => arbi.account.requestEmailChange(newEmail),
1076
- confirmEmailChange: async (newEmail, code) => {
1077
- await arbi.account.confirmEmailChange(newEmail, code);
1078
- },
1079
- changePassword: (vars) => arbi.account.changePassword(vars),
1080
- listSessions: () => arbi.sessions.list(),
1081
- currentSessionId: () => arbi.sessions.currentId(),
1082
- terminateSession: (sessionId) => arbi.sessions.terminate(sessionId),
1083
- signOut: async ({ everywhere } = {}) => {
1084
- try {
1085
- if (everywhere) await arbi.sessions.logoutAll();
1086
- else await arbi.logout();
1087
- } finally {
1088
- clearSealedDrafts();
1089
- clearChatArtifacts();
1090
- await wipeOfflineMail().catch(() => {
1091
- });
1092
- }
1093
- },
1094
- requestDeletion: () => arbi.account.requestDeletion(),
1095
- identity: {
1096
- status: () => arbi.identity.status(),
1097
- purchase: () => arbi.identity.purchase(),
1098
- startSession: () => arbi.identity.startSession(),
1099
- refresh: () => arbi.identity.refresh(),
1100
- acceptName: () => arbi.identity.acceptName(),
1101
- remove: () => arbi.identity.remove()
1102
- },
1103
- ...overrides
1104
- };
1105
- }
1106
- var NO_ACCOUNT_ERROR = "The account needs an <ArbiHost> with `account` or an `arbi`";
1107
- var refuse = () => Promise.reject(new Error(NO_ACCOUNT_ERROR));
1108
- var NO_ACCOUNT = {
1109
- client: {
1110
- profile: () => null,
1111
- onProfileChange: () => () => {
1112
- },
1113
- updateProfile: refuse,
1114
- requestEmailChange: refuse,
1115
- confirmEmailChange: refuse,
1116
- changePassword: refuse,
1117
- listSessions: refuse,
1118
- currentSessionId: () => null,
1119
- terminateSession: refuse,
1120
- signOut: refuse,
1121
- requestDeletion: refuse,
1122
- identity: {
1123
- status: refuse,
1124
- purchase: refuse,
1125
- startSession: refuse,
1126
- refresh: refuse,
1127
- acceptName: refuse,
1128
- remove: refuse
1129
- }
1130
- },
1131
- enabled: false
1132
- };
1133
- var ALWAYS = () => true;
1134
- function useAccountClient() {
1135
- const { account, arbi } = useArbiHost();
1136
- const fallback = useMemo(() => arbi ? arbiAccountClient(arbi) : null, [arbi]);
1137
- const useEnabled = account?.useEnabled ?? ALWAYS;
1138
- const enabled = useEnabled();
1139
- const client = account?.client;
1140
- const provided = useMemo(() => client ? { client, enabled } : null, [client, enabled]);
1141
- if (provided) return provided;
1142
- if (!arbi || !fallback) return NO_ACCOUNT;
1143
- return { client: fallback, enabled: arbi.isLoggedIn };
1144
- }
1145
- function useEntitlements() {
1146
- const { arbi } = useArbiHost();
1147
- return useQuery({
1148
- queryKey: arbiQueryKeys.entitlements(),
1149
- queryFn: () => arbi.account.entitlements(),
1150
- enabled: !!arbi?.isLoggedIn,
1151
- // A plan change shows on the next read; the API enforces it at once either way.
1152
- staleTime: 5 * 60 * 1e3
1153
- });
1154
- }
1155
- function useInvalidateEntitlements() {
1156
- const qc = useQueryClient();
1157
- return () => qc.invalidateQueries({ queryKey: arbiQueryKeys.entitlements() });
1158
- }
1159
- function useIsEntitled(feature) {
1160
- const { data } = useEntitlements();
1161
- return data?.[feature] === true;
1162
- }
1163
- function entitlementRefusal(reason) {
1164
- switch (reason) {
1165
- case "external_user":
1166
- return {
1167
- title: "Not available for external users",
1168
- description: "Mail, Calendar and hosting calls are for members of the firm. You can still join calls others host."
1169
- };
1170
- case "not_entitled":
1171
- return {
1172
- title: "Not available on this account",
1173
- description: "Mail, Calendar and hosting calls are not available on this account."
1174
- };
1175
- default:
1176
- return {
1177
- title: "Available on Pro",
1178
- description: "Mail, Calendar and hosting calls come with a Pro plan. You can still join calls others host."
1179
- };
1180
- }
1181
- }
1182
- function meetingChatRefFrom(row) {
1183
- if (row.chat_ext_id) return { kind: "chat", chatExtId: row.chat_ext_id };
1184
- const workspaceExtId = row.workspace_ext_id ?? row.locked_workspace_ext_id;
1185
- if (row.meeting_conversation_ext_id && workspaceExtId) {
1186
- return {
1187
- kind: "thread",
1188
- conversationExtId: row.meeting_conversation_ext_id,
1189
- workspaceExtId
1190
- };
1191
- }
1192
- return null;
1193
- }
1194
- function callMemberKeys(call) {
1195
- const keys = /* @__PURE__ */ new Map();
1196
- if (call.creator_ext_id && call.creator_encryption_public_key) {
1197
- keys.set(call.creator_ext_id, call.creator_encryption_public_key);
1198
- }
1199
- for (const i of call.invitees ?? []) {
1200
- if (i.encryption_public_key) keys.set(i.user_ext_id, i.encryption_public_key);
1201
- }
1202
- return keys;
1203
- }
1204
- async function publicKeysFor(arbi, queryClient, userExtIds, known) {
1205
- const wanted = new Set(userExtIds);
1206
- const keys = new Map([...known].filter(([id]) => wanted.has(id)));
1207
- if (![...wanted].some((id) => !keys.has(id))) return keys;
1208
- for (const chat of cachedChats(queryClient)) {
1209
- for (const m of chat.members) {
1210
- if (wanted.has(m.user.external_id) && !keys.has(m.user.external_id) && m.user.encryption_public_key) {
1211
- keys.set(m.user.external_id, m.user.encryption_public_key);
1212
- }
1213
- }
1214
- }
1215
- if ([...wanted].some((id) => !keys.has(id))) {
1216
- try {
1217
- for (const c of await arbi.contacts.list()) {
1218
- const u = c.user;
1219
- if (u && wanted.has(u.external_id) && u.encryption_public_key && !keys.has(u.external_id)) {
1220
- keys.set(u.external_id, u.encryption_public_key);
1221
- }
1222
- }
1223
- } catch (err) {
1224
- console.warn("[calls] could not load contacts for the meeting chat", err);
1225
- }
1226
- }
1227
- return keys;
1228
- }
1229
- async function buildMeetingChatBody(arbi, queryClient, call, callKey, extraMembers = []) {
1230
- if (!arbi.isLoggedIn) throw new Error("Sign in to keep the meeting chat");
1231
- const { externalId: me, publicKey: myPublicKey } = await arbi.chats.identity();
1232
- const hosts = /* @__PURE__ */ new Set([
1233
- call.creator_ext_id,
1234
- ...(call.invitees ?? []).map((i) => i.user_ext_id)
1235
- ]);
1236
- const memberIds = [.../* @__PURE__ */ new Set([...hosts, ...extraMembers])].filter(
1237
- (id) => id && id !== me && !chats.isAgentExtId(id)
1238
- );
1239
- const pubKeys = await publicKeysFor(arbi, queryClient, memberIds, callMemberKeys(call));
1240
- const key = await generateChatKey();
1241
- try {
1242
- const members = [];
1243
- for (const id of memberIds) {
1244
- const pk = pubKeys.get(id);
1245
- if (!pk) {
1246
- console.warn("[calls] no public key for meeting-chat member", id);
1247
- continue;
1248
- }
1249
- members.push({
1250
- user_ext_id: id,
1251
- sealed_key: await sealChatKey(key, pk),
1252
- ...hosts.has(id) ? {} : { call_sealed_key: await sealCallKey(callKey, pk) }
1253
- });
1254
- }
1255
- const title = call.title ? await decryptCallTitle(call.title, callKey) : null;
1256
- return {
1257
- title: await encryptWithChatKey(title?.trim() || "Meeting", key),
1258
- creator_sealed_key: await sealChatKey(key, myPublicKey),
1259
- members
1260
- };
1261
- } finally {
1262
- key.fill(0);
1263
- }
1264
- }
1265
- var pending = /* @__PURE__ */ new Map();
1266
- function ensureMeetingChat(arbi, queryClient, callExtId, callKey) {
1267
- const inFlight = pending.get(callExtId);
1268
- if (inFlight) return inFlight;
1269
- const run = (async () => {
1270
- const call = await arbi.calls.get(callExtId);
1271
- const existing = meetingChatRefFrom(call);
1272
- if (existing) return existing;
1273
- const body = call.workspace_locked ? void 0 : await buildMeetingChatBody(arbi, queryClient, call, callKey);
1274
- const answer = await arbi.calls.chat(callExtId, body);
1275
- const ref = meetingChatRefFrom({
1276
- ...answer,
1277
- locked_workspace_ext_id: call.locked_workspace_ext_id
1278
- });
1279
- if (!ref) throw new Error("The server did not return a meeting chat");
1280
- if (ref.kind === "chat")
1281
- void queryClient.invalidateQueries({ queryKey: arbiQueryKeys.chatList() });
1282
- else void invalidateConversationLists(queryClient);
1283
- return ref;
1284
- })();
1285
- pending.set(callExtId, run);
1286
- run.catch(() => pending.delete(callExtId));
1287
- return run;
1288
- }
1289
- function clearMeetingChatCache() {
1290
- pending.clear();
1291
- }
1292
- function knownMeetingChat(target) {
1293
- if (target.chatExtId) return { kind: "chat", chatExtId: target.chatExtId };
1294
- if (target.meetingConversationExtId && target.workspaceExtId) {
1295
- return {
1296
- kind: "thread",
1297
- conversationExtId: target.meetingConversationExtId,
1298
- workspaceExtId: target.workspaceExtId
1299
- };
1300
- }
1301
- return null;
1302
- }
1303
- async function resolveMeetingChat(arbi, queryClient, target) {
1304
- const known = knownMeetingChat(target);
1305
- if (known) return known;
1306
- const key = target.callKey ?? await arbi.calls.key(await arbi.calls.get(target.callExtId));
1307
- if (!key) throw new Error("You are not invited to this call");
1308
- return ensureMeetingChat(arbi, queryClient, target.callExtId, key);
1309
- }
1310
- function sortTranscriptMessages(messages) {
1311
- const spokenAt = (m) => {
1312
- const parsed = m.decryptFailed ? null : chats.parseTranscriptContent(m.content);
1313
- const at = Date.parse(parsed?.started_at ?? m.created_at);
1314
- return Number.isNaN(at) ? 0 : at;
1315
- };
1316
- return messages.map((m, i) => ({ m, i, at: spokenAt(m) })).sort((a, b) => a.at - b.at || a.i - b.i).map(({ m }) => m);
1317
- }
1318
- function transcriptSegmentOf(tools) {
1319
- if (!tools || typeof tools !== "object") return void 0;
1320
- const record = tools;
1321
- const byKey = record.transcript_segment;
1322
- const candidates = byKey ? [byKey] : Object.values(record);
1323
- for (const c of candidates) {
1324
- if (!c || typeof c !== "object") continue;
1325
- const t = c;
1326
- if (c !== byKey && t.name !== "transcript_segment") continue;
1327
- if (typeof t.segment_id !== "string" || typeof t.speaker_ext_id !== "string") continue;
1328
- return {
1329
- segment_id: t.segment_id,
1330
- speaker_ext_id: t.speaker_ext_id,
1331
- started_at: typeof t.started_at === "string" ? t.started_at : null
1332
- };
1333
- }
1334
- return void 0;
1335
- }
1336
- var pad = (n) => String(n).padStart(2, "0");
1337
- function clockTime(iso) {
1338
- if (!iso) return "";
1339
- const d = new Date(iso);
1340
- if (Number.isNaN(d.getTime())) return "";
1341
- return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
1342
- }
1343
- function formatTranscriptMarkdown(opts) {
1344
- const lines = [...opts.lines].filter((l) => l.text.trim()).sort((a, b) => (Date.parse(a.at ?? "") || 0) - (Date.parse(b.at ?? "") || 0));
1345
- const first = lines.find((l) => l.at)?.at;
1346
- const date = opts.date ?? (first ? new Date(first) : null);
1347
- const heading = `## Transcript: ${opts.title?.trim() || "Meeting"}`;
1348
- const dateLine = date ? `_${date.toLocaleDateString(void 0, { year: "numeric", month: "long", day: "numeric" })}_` : null;
1349
- const body = lines.map((l) => {
1350
- const time = clockTime(l.at);
1351
- return `**${l.speaker}**${time ? ` [${time}]` : ""}: ${l.text.trim().replace(/\s*\n\s*/g, " ")}`;
1352
- });
1353
- return [heading, ...dateLine ? [dateLine] : [], ...body].join("\n\n");
1354
- }
1355
- function threadTranscriptLines(messages, nameOf) {
1356
- const seen = /* @__PURE__ */ new Set();
1357
- const lines = [];
1358
- for (const m of messages) {
1359
- const marker = transcriptSegmentOf(m.tools);
1360
- if (!marker || seen.has(marker.segment_id)) continue;
1361
- seen.add(marker.segment_id);
1362
- const name = nameOf(marker.speaker_ext_id);
1363
- lines.push({
1364
- speaker: name || "Former member",
1365
- at: marker.started_at ?? m.created_at ?? null,
1366
- text: stripSpeakerPrefix(m.content ?? "", name)
1367
- });
1368
- }
1369
- return lines;
1370
- }
1371
- function stripSpeakerPrefix(content, speakerName) {
1372
- if (speakerName && content.startsWith(`${speakerName}: `)) {
1373
- return content.slice(speakerName.length + 2);
1374
- }
1375
- return content;
1376
- }
1377
- function isRecordingSegmentId(segmentId) {
1378
- return typeof segmentId === "string" && segmentId.startsWith("rec-");
1379
- }
1380
- function recordingWindowsOf(recordings) {
1381
- return recordings.map((r) => ({
1382
- trackExtIds: (r.tracks ?? []).map((t) => t.external_id),
1383
- startedAt: r.started_at,
1384
- stoppedAt: r.stopped_at ?? null
1385
- }));
1386
- }
1387
- function chatTranscriptRef(message) {
1388
- if (!chats.isTranscriptMessage(message)) return null;
1389
- const parsed = message.decryptFailed ? null : chats.parseTranscriptContent(message.content);
1390
- return { segmentId: message.dedupe_key, startedAt: parsed?.started_at ?? message.created_at };
1391
- }
1392
- function threadTranscriptRef(message) {
1393
- const marker = transcriptSegmentOf(message.tools ?? message.meta?.tools);
1394
- if (!marker) return null;
1395
- return { segmentId: marker.segment_id, startedAt: marker.started_at ?? message.created_at };
1396
- }
1397
- function supersededTranscriptLines(lines, refOf, recordings = []) {
1398
- const superseded = /* @__PURE__ */ new Set();
1399
- const recLines = [];
1400
- for (const line of lines) {
1401
- const ref = refOf(line);
1402
- if (ref && isRecordingSegmentId(ref.segmentId)) {
1403
- recLines.push({ segmentId: ref.segmentId, at: Date.parse(ref.startedAt ?? "") });
1404
- }
1405
- }
1406
- if (!recLines.length) return superseded;
1407
- const windows = [];
1408
- const claimed = /* @__PURE__ */ new Set();
1409
- for (const r of recordings) {
1410
- const prefixes = r.trackExtIds.map((t) => `rec-${t}-`);
1411
- const mine = recLines.filter((l) => prefixes.some((p) => l.segmentId.startsWith(p)));
1412
- if (!mine.length) continue;
1413
- for (const l of mine) claimed.add(l.segmentId);
1414
- const start = Date.parse(r.startedAt);
1415
- const stop = r.stoppedAt ? Date.parse(r.stoppedAt) : Number.POSITIVE_INFINITY;
1416
- if (!Number.isNaN(start)) windows.push([start, Number.isNaN(stop) ? Infinity : stop]);
1417
- }
1418
- const unclaimed = recLines.filter((l) => !claimed.has(l.segmentId) && !Number.isNaN(l.at));
1419
- if (unclaimed.length) {
1420
- const times = unclaimed.map((l) => l.at);
1421
- windows.push([Math.min(...times), Math.max(...times)]);
1422
- }
1423
- if (!windows.length) return superseded;
1424
- for (const line of lines) {
1425
- const ref = refOf(line);
1426
- if (!ref || isRecordingSegmentId(ref.segmentId)) continue;
1427
- const at = Date.parse(ref.startedAt ?? "");
1428
- if (Number.isNaN(at)) continue;
1429
- if (windows.some(([start, stop]) => at >= start && at <= stop)) superseded.add(line);
1430
- }
1431
- return superseded;
1432
- }
1433
- function supersedeLiveTranscript(lines, refOf, recordings = []) {
1434
- const superseded = supersededTranscriptLines(lines, refOf, recordings);
1435
- return superseded.size ? lines.filter((l) => !superseded.has(l)) : [...lines];
1436
- }
1437
- function hasRecordingTranscript(lines, refOf) {
1438
- return lines.some((l) => isRecordingSegmentId(refOf(l)?.segmentId));
1439
- }
1440
- var CALL_CHAT_TOPIC = "arbi.chat";
1441
- var READ_ONLY_MEETING_TEXT = "Read only: you can\u2019t post in this meeting chat";
1442
- var CALL_CHAT_MAX_CHARS = 4e3;
1443
- var encoder = new TextEncoder();
1444
- var decoder = new TextDecoder();
1445
- function newPacketId() {
1446
- const bytes = new Uint8Array(8);
1447
- globalThis.crypto.getRandomValues(bytes);
1448
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
1449
- }
1450
- async function encodeCallChatPacket(packet, callKey) {
1451
- return encoder.encode(await encryptWithChatKey(JSON.stringify(packet), callKey));
1452
- }
1453
- async function decodeCallChatPacket(payload, callKey) {
1454
- try {
1455
- const parsed = JSON.parse(await decryptWithChatKey(decoder.decode(payload), callKey));
1456
- if (!parsed || typeof parsed !== "object") return null;
1457
- const p = parsed;
1458
- if (p.v !== 1 || typeof p.id !== "string" || typeof p.text !== "string") return null;
1459
- const text = p.text.slice(0, CALL_CHAT_MAX_CHARS);
1460
- if (!text.trim()) return null;
1461
- return { v: 1, id: p.id, text, at: typeof p.at === "number" ? p.at : Date.now() };
1462
- } catch {
1463
- return null;
1464
- }
1465
- }
1466
- async function chatByExtId(arbi, queryClient, chatExtId) {
1467
- return cachedChat(queryClient, chatExtId) ?? arbi.chats.get(chatExtId);
1468
- }
1469
- async function persistMeetingMessage(arbi, queryClient, callExtId, callKey, text) {
1470
- const ref = await ensureMeetingChat(arbi, queryClient, callExtId, callKey);
1471
- if (ref.kind === "chat") {
1472
- await arbi.chats.send(await chatByExtId(arbi, queryClient, ref.chatExtId), text);
1473
- } else {
1474
- try {
1475
- await arbi.conversations.postMessage({
1476
- content: text,
1477
- conversation_ext_id: ref.conversationExtId,
1478
- assistant_mode: "mentioned"
1479
- });
1480
- } catch (err) {
1481
- const status = err instanceof ArbiApiError ? err.status : void 0;
1482
- const detail = err instanceof ArbiApiError ? err.detail : void 0;
1483
- throw new Error(
1484
- `Could not save the message to the meeting thread (${status ?? "?"})${detail ? `: ${detail}` : ""}`
1485
- );
1486
- }
1487
- }
1488
- return ref;
1489
- }
1490
- var HISTORY_LIMIT = 50;
1491
- async function loadMeetingHistory(arbi, queryClient, callExtId) {
1492
- const ref = meetingChatRefFrom(await arbi.calls.get(callExtId));
1493
- if (!ref) return null;
1494
- if (ref.kind === "chat") {
1495
- const chat = await chatByExtId(arbi, queryClient, ref.chatExtId);
1496
- const page = await arbi.chats.page(chat);
1497
- const names = new Map(chat.members.map((m) => [m.user.external_id, getUserDisplayName(m.user)]));
1498
- return {
1499
- ref,
1500
- messages: page.messages.filter((m) => m.kind === "text" && !m.decryptFailed && m.content).slice(-HISTORY_LIMIT).map((m) => ({
1501
- id: m.external_id,
1502
- senderExtId: m.sender_ext_id ?? null,
1503
- senderName: m.sender_ext_id && names.get(m.sender_ext_id) || null,
1504
- text: m.content ?? "",
1505
- at: Date.parse(m.created_at)
1506
- }))
1507
- };
1508
- }
1509
- const data = await arbi.conversations.getThreads(ref.conversationExtId).catch(() => null);
1510
- if (!data) return { ref, messages: [] };
1511
- const seen = /* @__PURE__ */ new Map();
1512
- for (const thread of data.threads) {
1513
- for (const m of thread.history) {
1514
- if (seen.has(m.external_id) || m.role === "system" || !m.content) continue;
1515
- if (transcriptSegmentOf(m.tools)) continue;
1516
- seen.set(m.external_id, {
1517
- id: m.external_id,
1518
- senderExtId: m.role === "assistant" ? null : m.created_by_ext_id,
1519
- senderName: m.role === "assistant" ? "ARBI" : null,
1520
- text: m.content,
1521
- at: Date.parse(m.created_at)
1522
- });
1523
- }
1524
- }
1525
- return {
1526
- ref,
1527
- messages: [...seen.values()].sort((a, b) => a.at - b.at).slice(-HISTORY_LIMIT)
1528
- };
1529
- }
1530
- var SAME_MESSAGE_MS = 5 * 60 * 1e3;
1531
- function mergeChatLines(history, live, context) {
1532
- const historyLines = history.map((m) => ({
1533
- id: `h:${m.id}`,
1534
- senderIdentity: m.senderExtId ?? "arbi",
1535
- senderName: m.senderName ?? (m.senderExtId ? context.nameOf(m.senderExtId) : null) ?? "Someone",
1536
- text: m.text,
1537
- at: m.at,
1538
- mine: !!m.senderExtId && m.senderExtId === context.myIdentity,
1539
- status: "history"
1540
- }));
1541
- const used = /* @__PURE__ */ new Set();
1542
- const liveOnly = live.filter((line) => {
1543
- const match = history.findIndex(
1544
- (m, i) => !used.has(i) && m.senderExtId === line.senderIdentity && m.text === line.text && Math.abs(m.at - line.at) < SAME_MESSAGE_MS
1545
- );
1546
- if (match < 0) return true;
1547
- used.add(match);
1548
- return false;
1549
- });
1550
- return [...historyLines, ...liveOnly].sort((a, b) => a.at - b.at);
1551
- }
1552
- var CALL_RECORDING_TOPIC = "arbi.recording";
1553
- var RECORDING_CHUNK_MS = 3e4;
1554
- var SPEAKER_AUDIO_BITS_PER_SECOND = 24e3;
1555
- var COMPOSITE_VIDEO_BITS_PER_SECOND = 5e5;
1556
- var COMPOSITE_AUDIO_BITS_PER_SECOND = 32e3;
1557
- function partOffsetMs(partStartedAt, recordingStartedAt) {
1558
- const start = typeof recordingStartedAt === "number" ? recordingStartedAt : Date.parse(recordingStartedAt);
1559
- if (!Number.isFinite(start)) return 0;
1560
- return Math.max(0, Math.round(partStartedAt - start));
1561
- }
1562
- function newTrackKey() {
1563
- return generateChatKey();
1564
- }
1565
- async function wrapTrackKey(fileKey, conversationKey) {
1566
- await initSodium();
1567
- return bytesToBase64(encryptFile(fileKey, conversationKey));
1568
- }
1569
- async function unwrapTrackKey(wrapped, conversationKey) {
1570
- await initSodium();
1571
- return decryptFile(base64ToBytes(wrapped), conversationKey);
1572
- }
1573
- async function encryptPart(bytes, fileKey) {
1574
- await initSodium();
1575
- return encryptFile(bytes, fileKey);
1576
- }
1577
- async function decryptPart(cipher, fileKey) {
1578
- await initSodium();
1579
- return decryptFile(cipher, fileKey);
1580
- }
1581
- async function conversationKeyForCall(arbi, queryClient, call, options = {}) {
1582
- if (call.workspace_locked && call.locked_workspace_ext_id) {
1583
- const key2 = await arbi.workspaces.key(call.locked_workspace_ext_id);
1584
- return { key: key2, keyVersion: null };
1585
- }
1586
- let chatExtId = call.chat_ext_id ?? null;
1587
- if (!chatExtId) {
1588
- if (!options.callKey) throw new Error("This call has no meeting chat to keep a recording in");
1589
- const ref = await ensureMeetingChat(arbi, queryClient, call.external_id, options.callKey);
1590
- if (ref.kind !== "chat") throw new Error("Expected an end-to-end meeting chat");
1591
- chatExtId = ref.chatExtId;
1592
- }
1593
- const chat = await arbi.chats.ready(await chatByExtId(arbi, queryClient, chatExtId));
1594
- const ring = await arbi.chats.ring(chat);
1595
- const version = options.keyVersion ?? ring.currentVersion;
1596
- const key = ring.keys.get(version);
1597
- if (!key) throw new Error("No key for this recording in the meeting chat");
1598
- return { key, keyVersion: version };
1599
- }
1600
- async function meetingRefForCall(arbi, queryClient, call, callKey) {
1601
- const ref = meetingChatRefFrom(call);
1602
- if (ref) return ref;
1603
- if (!callKey) throw new Error("This call has no meeting chat yet");
1604
- return ensureMeetingChat(arbi, queryClient, call.external_id, callKey);
1605
- }
1606
- var defaultDeps = (arbi) => ({
1607
- createTrack: (...args) => arbi.calls.recording.createTrack(...args),
1608
- presign: (...args) => arbi.calls.recording.presignPart(...args),
1609
- commit: (...args) => arbi.calls.recording.commitPart(...args),
1610
- getRecording: (...args) => arbi.calls.recording.get(...args),
1611
- put: (url, body, headers) => documents.presignedPut(url, body, void 0, headers),
1612
- encrypt: encryptPart,
1613
- wrap: wrapTrackKey,
1614
- unwrap: unwrapTrackKey,
1615
- newKey: newTrackKey,
1616
- sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
1617
- });
1618
- var UPLOAD_ATTEMPTS = 5;
1619
- var UPLOAD_BACKOFF_MS = 1e3;
1620
- var SeqTakenError = class extends Error {
1621
- };
1622
- function isRetryable(err) {
1623
- if (!(err instanceof CallApiError)) return true;
1624
- if (calls.isQuotaError(err)) return false;
1625
- if (err.code === "part_not_uploaded") return true;
1626
- const s = err.status ?? 0;
1627
- return s === 0 || s === 408 || s === 429 || s >= 500 && s !== 507;
1628
- }
1629
- function isRecordingOver(err) {
1630
- if (!(err instanceof CallApiError)) return false;
1631
- return err.code === "recording_stopped" || err.code === "composite_needs_video" || err.status === 404 || err.status === 410;
1632
- }
1633
- var TrackUploader = class {
1634
- constructor(options) {
1635
- this.options = options;
1636
- this.deps = { ...defaultDeps(options.arbi), ...options.deps };
1637
- }
1638
- options;
1639
- deps;
1640
- track = null;
1641
- trackPromise = null;
1642
- nextSeq = 0;
1643
- queue = [];
1644
- running = null;
1645
- /** No more parts are accepted (quota, or the recording is gone). */
1646
- stopped = false;
1647
- /** Parts committed (for tests and the UI). */
1648
- committed = 0;
1649
- /** Queue a part; parts upload one at a time, in order. */
1650
- enqueue(part) {
1651
- if (this.stopped) return;
1652
- this.queue.push(part);
1653
- this.drain();
1654
- }
1655
- /** Resolves once every queued part was uploaded (or given up). */
1656
- async flush() {
1657
- while (this.running) await this.running;
1658
- }
1659
- drain() {
1660
- if (this.running) return;
1661
- this.running = (async () => {
1662
- try {
1663
- while (this.queue.length && !this.stopped) {
1664
- const part = this.queue.shift();
1665
- await this.uploadPart(part);
1666
- }
1667
- } finally {
1668
- this.running = null;
1669
- }
1670
- })();
1671
- }
1672
- async withRetry(label, run) {
1673
- let lastError;
1674
- for (let attempt = 0; attempt < UPLOAD_ATTEMPTS; attempt++) {
1675
- try {
1676
- return await run();
1677
- } catch (err) {
1678
- lastError = err;
1679
- if (!isRetryable(err) || attempt === UPLOAD_ATTEMPTS - 1) break;
1680
- console.warn(`[calls] recording ${label} failed, retrying`, err);
1681
- await this.deps.sleep(UPLOAD_BACKOFF_MS * 2 ** attempt);
1682
- }
1683
- }
1684
- throw lastError;
1685
- }
1686
- ensureTrack() {
1687
- if (this.track) return Promise.resolve(this.track);
1688
- if (!this.trackPromise) {
1689
- this.trackPromise = this.withRetry("track", () => this.createTrack()).then(
1690
- (track) => {
1691
- this.track = track;
1692
- return track;
1693
- },
1694
- (err) => {
1695
- this.trackPromise = null;
1696
- throw err;
1697
- }
1698
- );
1699
- }
1700
- return this.trackPromise;
1701
- }
1702
- async createTrack() {
1703
- const { callExtId, recordingExtId, kind, mimeType } = this.options;
1704
- const conv = await this.options.conversationKey();
1705
- const fileKey = await this.deps.newKey();
1706
- const wrapped = await this.deps.wrap(fileKey, conv.key);
1707
- const created = await this.deps.createTrack(callExtId, recordingExtId, {
1708
- kind,
1709
- wrapped_key: wrapped,
1710
- key_version: conv.keyVersion,
1711
- mime_type: mimeType,
1712
- ...this.options.linkVersion ? { link_version: this.options.linkVersion } : {}
1713
- });
1714
- const key = created.wrapped_key && created.wrapped_key !== wrapped ? await this.deps.unwrap(created.wrapped_key, conv.key) : fileKey;
1715
- let startedAt = this.options.recordingStartedAt ?? null;
1716
- let parts = created.parts;
1717
- if (!startedAt || !parts) {
1718
- const recording = await this.deps.getRecording(callExtId, recordingExtId);
1719
- startedAt = startedAt ?? recording.started_at;
1720
- parts = parts ?? (recording.tracks ?? []).find((t) => t.external_id === created.external_id)?.parts;
1721
- }
1722
- this.nextSeq = Math.max(this.nextSeq, nextSeqAfter(parts ?? []));
1723
- return { externalId: created.external_id, fileKey: key, startedAt };
1724
- }
1725
- async uploadPart(part) {
1726
- const { callExtId, recordingExtId } = this.options;
1727
- try {
1728
- const track = await this.ensureTrack();
1729
- const bytes = new Uint8Array(await part.blob.arrayBuffer());
1730
- const cipher = await this.deps.encrypt(bytes, track.fileKey);
1731
- const offset = partOffsetMs(part.startedAt, track.startedAt);
1732
- let seq = this.nextSeq++;
1733
- await this.withRetry("part", async () => {
1734
- let upload;
1735
- try {
1736
- upload = await this.deps.presign(callExtId, recordingExtId, track.externalId, {
1737
- seq,
1738
- offset_ms: offset,
1739
- duration_ms: Math.max(0, Math.round(part.durationMs)),
1740
- size_bytes: cipher.length
1741
- });
1742
- } catch (err) {
1743
- if (err instanceof CallApiError && err.code === "part_committed") {
1744
- seq = this.nextSeq++;
1745
- throw new SeqTakenError(err.message);
1746
- }
1747
- throw err;
1748
- }
1749
- await this.deps.put(upload.upload_url, cipher, upload.headers ?? void 0);
1750
- await this.deps.commit(callExtId, recordingExtId, track.externalId, seq);
1751
- });
1752
- this.committed += 1;
1753
- } catch (err) {
1754
- if (calls.isQuotaError(err)) {
1755
- this.stopped = true;
1756
- this.queue = [];
1757
- this.options.onStopped?.(err);
1758
- return;
1759
- }
1760
- if (isRecordingOver(err)) {
1761
- this.stopped = true;
1762
- this.queue = [];
1763
- }
1764
- console.warn("[calls] a recording part could not be kept", err);
1765
- this.options.onPartLost?.(err);
1766
- }
1767
- }
1768
- };
1769
- function nextSeqAfter(parts) {
1770
- return parts.reduce((max, p) => Math.max(max, p.seq + 1), 0);
1771
- }
1772
- var uploaders = /* @__PURE__ */ new Map();
1773
- function trackUploaderFor(options) {
1774
- const key = `${options.recordingExtId}:${options.kind}`;
1775
- let uploader = uploaders.get(key);
1776
- if (!uploader || uploader.stopped) {
1777
- uploader = new TrackUploader(options);
1778
- uploaders.set(key, uploader);
1779
- }
1780
- return uploader;
1781
- }
1782
- function clearTrackUploaders() {
1783
- uploaders.clear();
1784
- }
1785
-
1786
- // src/calls/recording-playback.ts
1787
- var partKey = (p) => `${p.trackExtId}:${p.seq}`;
1788
- function timelineOf(tracks) {
1789
- return tracks.flatMap(
1790
- (t) => (t.parts ?? []).map((p) => ({
1791
- trackExtId: t.external_id,
1792
- seq: p.seq,
1793
- offsetMs: p.offset_ms,
1794
- durationMs: p.duration_ms
1795
- }))
1796
- ).sort((a, b) => a.offsetMs - b.offsetMs || a.seq - b.seq);
1797
- }
1798
- function timelineDurationMs(parts) {
1799
- return parts.reduce((max, p) => Math.max(max, p.offsetMs + p.durationMs), 0);
1800
- }
1801
- var PLAYBACK_LOOKAHEAD_MS = 2e4;
1802
- function partsDue(parts, playheadMs, lookaheadMs, scheduled) {
1803
- return parts.filter(
1804
- (p) => !scheduled.has(partKey(p)) && p.offsetMs < playheadMs + lookaheadMs && p.offsetMs + p.durationMs > playheadMs
1805
- );
1806
- }
1807
- function schedulePart(params) {
1808
- const { partOffsetMs: partOffsetMs2, bufferDurationS, ctxStart, seekMs, ctxNow } = params;
1809
- let when = ctxStart + (partOffsetMs2 - seekMs) / 1e3;
1810
- let offset = 0;
1811
- if (when < ctxNow) {
1812
- offset = ctxNow - when;
1813
- when = ctxNow;
1814
- }
1815
- if (offset >= bufferDurationS) return null;
1816
- return { when, offset };
1817
- }
1818
- function playheadAt(ctxNow, ctxStart, seekMs) {
1819
- return seekMs + Math.max(0, ctxNow - ctxStart) * 1e3;
1820
- }
1821
- var EBML_MAGIC = [26, 69, 223, 163];
1822
- var FTYP = [102, 116, 121, 112];
1823
- function startsMediaFile(bytes) {
1824
- if (EBML_MAGIC.every((b, i) => bytes[i] === b)) return true;
1825
- return FTYP.every((b, i) => bytes[4 + i] === b);
1826
- }
1827
- function splitIntoFiles(parts) {
1828
- const files = [];
1829
- for (const part of parts) {
1830
- if (!files.length || startsMediaFile(part)) files.push([part]);
1831
- else files[files.length - 1].push(part);
1832
- }
1833
- return files;
1834
- }
1835
- function extensionFor(mimeType) {
1836
- if (mimeType.includes("mp4")) return mimeType.startsWith("video") ? "mp4" : "m4a";
1837
- if (mimeType.includes("ogg")) return "ogg";
1838
- return "webm";
1839
- }
1840
- function fileSafe(name) {
1841
- return name.replace(/[^\p{L}\p{N} ._-]+/gu, "").trim().replace(/\s+/g, "-").slice(0, 60) || "recording";
1842
- }
1843
- var EXPORT_SAMPLE_RATE = 16e3;
1844
- function writeSamples(target, samples, offsetSamples) {
1845
- const start = Math.max(0, Math.round(offsetSamples));
1846
- const n = Math.min(samples.length, target.length - start);
1847
- for (let i = 0; i < n; i++) {
1848
- const s = Math.max(-1, Math.min(1, samples[i]));
1849
- target[start + i] = s < 0 ? s * 32768 : s * 32767;
1850
- }
1851
- }
1852
- function encodeWav(samples, sampleRate) {
1853
- const dataBytes = samples.length * 2;
1854
- const out = new Uint8Array(44 + dataBytes);
1855
- const view = new DataView(out.buffer);
1856
- const ascii = (offset, text) => {
1857
- for (let i = 0; i < text.length; i++) out[offset + i] = text.charCodeAt(i);
1858
- };
1859
- ascii(0, "RIFF");
1860
- view.setUint32(4, 36 + dataBytes, true);
1861
- ascii(8, "WAVE");
1862
- ascii(12, "fmt ");
1863
- view.setUint32(16, 16, true);
1864
- view.setUint16(20, 1, true);
1865
- view.setUint16(22, 1, true);
1866
- view.setUint32(24, sampleRate, true);
1867
- view.setUint32(28, sampleRate * 2, true);
1868
- view.setUint16(32, 2, true);
1869
- view.setUint16(34, 16, true);
1870
- ascii(36, "data");
1871
- view.setUint32(40, dataBytes, true);
1872
- for (let i = 0; i < samples.length; i++) view.setInt16(44 + i * 2, samples[i], true);
1873
- return out;
1874
- }
1875
- function standalone(bytes) {
1876
- return new Uint8Array(bytes);
1877
- }
1878
- function floatToWav(samples, sampleRate) {
1879
- const pcm = new Int16Array(samples.length);
1880
- writeSamples(pcm, samples, 0);
1881
- return encodeWav(pcm, sampleRate);
1882
- }
1883
- var SEGMENT_FRAME_MS = 50;
1884
- var SEGMENT_PRE_ROLL_MS = 200;
1885
- var RECORDING_SEGMENTER = {
1886
- maxMs: 25e3,
1887
- minVoiceMs: 300,
1888
- silenceMs: 1500
1889
- };
1890
- var SHORT_PIECE_MERGE_GAP_MS = 1e3;
1891
- function createTrackCutter(sampleRate, config = {}, options = {}) {
1892
- const cfg = { ...DEFAULT_SEGMENTER_CONFIG, ...config };
1893
- const frame = Math.max(1, Math.round(sampleRate * SEGMENT_FRAME_MS / 1e3));
1894
- const preRoll = Math.round(SEGMENT_PRE_ROLL_MS / 1e3 * sampleRate);
1895
- const toSample = (ms) => Math.round(ms / 1e3 * sampleRate);
1896
- const toMs = (sample) => sample / sampleRate * 1e3;
1897
- let buf = new Float32Array(sampleRate * 4);
1898
- let bufStart = 0;
1899
- let len = 0;
1900
- let origin = null;
1901
- let cursor = 0;
1902
- let nextFrame = 0;
1903
- let state2 = INITIAL_SEGMENTER_STATE;
1904
- let pending2 = null;
1905
- let out = [];
1906
- const append = (samples) => {
1907
- if (len + samples.length > buf.length) {
1908
- const grown = new Float32Array(Math.max(buf.length * 2, len + samples.length));
1909
- grown.set(buf.subarray(0, len));
1910
- buf = grown;
1911
- }
1912
- buf.set(samples, len);
1913
- len += samples.length;
1914
- cursor += samples.length;
1915
- };
1916
- const emit = (piece) => {
1917
- const from = Math.max(piece.start, bufStart);
1918
- if (piece.end <= from) return;
1919
- out.push({
1920
- start: from,
1921
- end: piece.end,
1922
- voiceMs: piece.voiceMs,
1923
- samples: buf.slice(from - bufStart, piece.end - bufStart)
1924
- });
1925
- };
1926
- const onEvents = (events) => {
1927
- for (const e of events) {
1928
- if (e.type === "start") {
1929
- if (pending2 && e.at - pending2.at > SHORT_PIECE_MERGE_GAP_MS) pending2 = null;
1930
- continue;
1931
- }
1932
- let piece = {
1933
- start: Math.max(origin ?? 0, toSample(e.startedAt) - preRoll),
1934
- end: Math.min(cursor, toSample(e.at)),
1935
- voiceMs: e.voiceMs,
1936
- at: e.at
1937
- };
1938
- if (pending2) {
1939
- if (piece.end - pending2.start <= toSample(cfg.maxMs) + preRoll) {
1940
- piece = { ...piece, start: pending2.start, voiceMs: piece.voiceMs + pending2.voiceMs };
1941
- }
1942
- pending2 = null;
1943
- }
1944
- if (piece.voiceMs >= cfg.minVoiceMs) emit(piece);
1945
- else if (options.mergeShort && piece.end > piece.start) pending2 = piece;
1946
- }
1947
- };
1948
- const step = (from, n) => {
1949
- let sum = 0;
1950
- const base = from - bufStart;
1951
- for (let j = 0; j < n; j++) sum += buf[base + j] * buf[base + j];
1952
- const result = stepSegmenter(state2, levelFromRms(Math.sqrt(sum / n)), toMs(from), cfg);
1953
- state2 = result.state;
1954
- onEvents(result.events);
1955
- };
1956
- const run = () => {
1957
- while (nextFrame + frame <= cursor) {
1958
- step(nextFrame, frame);
1959
- nextFrame += frame;
1960
- }
1961
- let keepFrom = cursor - preRoll;
1962
- if (state2.phase === "voice") keepFrom = Math.min(keepFrom, toSample(state2.startedAt) - preRoll);
1963
- if (pending2) keepFrom = Math.min(keepFrom, pending2.start);
1964
- keepFrom = Math.min(Math.max(keepFrom, bufStart), nextFrame);
1965
- if (keepFrom > bufStart) {
1966
- buf.copyWithin(0, keepFrom - bufStart, len);
1967
- len -= keepFrom - bufStart;
1968
- bufStart = keepFrom;
1969
- }
1970
- };
1971
- const take = () => {
1972
- const done = out;
1973
- out = [];
1974
- return done;
1975
- };
1976
- return {
1977
- push(offsetMs, samples) {
1978
- const at = toSample(Math.max(0, offsetMs));
1979
- if (origin === null) {
1980
- origin = at;
1981
- bufStart = cursor = nextFrame = at;
1982
- }
1983
- if (at > cursor) {
1984
- const second = new Float32Array(sampleRate);
1985
- while (cursor < at) {
1986
- append(second.subarray(0, Math.min(sampleRate, at - cursor)));
1987
- run();
1988
- }
1989
- }
1990
- const fresh = at < cursor ? samples.subarray(Math.min(samples.length, cursor - at)) : samples;
1991
- if (fresh.length) {
1992
- append(fresh);
1993
- run();
1994
- }
1995
- return take();
1996
- },
1997
- finish() {
1998
- if (origin !== null) {
1999
- if (nextFrame < cursor) {
2000
- step(nextFrame, cursor - nextFrame);
2001
- nextFrame = cursor;
2002
- }
2003
- onEvents(flushSegmenter(state2, toMs(cursor), cfg).events);
2004
- state2 = INITIAL_SEGMENTER_STATE;
2005
- }
2006
- pending2 = null;
2007
- return take();
2008
- }
2009
- };
2010
- }
2011
- function cutAtPauses(samples, sampleRate, config = {}) {
2012
- const cutter = createTrackCutter(sampleRate, config);
2013
- return [...cutter.push(0, samples), ...cutter.finish()].map(({ start, end }) => ({ start, end }));
2014
- }
2015
- var CALL_CAPTION_TOPIC = "arbi.caption";
2016
- var CALL_TRANSCRIPTION_TOPIC = "arbi.transcription";
2017
- var CAPTION_MAX_CHARS = 2e3;
2018
- var LIVE_SEGMENTER = { minVoiceMs: 400, holdShortMs: 1e3 };
2019
- var encoder2 = new TextEncoder();
2020
- var decoder2 = new TextDecoder();
2021
- var SEGMENT_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;
2022
- function newSegmentId() {
2023
- const bytes = new Uint8Array(12);
2024
- globalThis.crypto.getRandomValues(bytes);
2025
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2026
- }
2027
- async function encodeCaptionPacket(packet, callKey) {
2028
- return encoder2.encode(await encryptWithChatKey(JSON.stringify(packet), callKey));
2029
- }
2030
- async function decodeCaptionPacket(payload, callKey) {
2031
- try {
2032
- const parsed = JSON.parse(await decryptWithChatKey(decoder2.decode(payload), callKey));
2033
- if (!parsed || typeof parsed !== "object") return null;
2034
- const p = parsed;
2035
- if (p.v !== 1 || typeof p.segment_id !== "string" || !SEGMENT_ID_PATTERN.test(p.segment_id) || typeof p.text !== "string" || typeof p.identity !== "string") {
2036
- return null;
2037
- }
2038
- const text = p.text.trim().slice(0, CAPTION_MAX_CHARS);
2039
- if (!text) return null;
2040
- return {
2041
- v: 1,
2042
- segment_id: p.segment_id,
2043
- text,
2044
- identity: p.identity,
2045
- name: typeof p.name === "string" ? p.name : p.identity,
2046
- t: typeof p.t === "number" ? p.t : Date.now(),
2047
- ...p.proxy === true ? { proxy: true } : {}
2048
- };
2049
- } catch {
2050
- return null;
2051
- }
2052
- }
2053
- function transcriptPersistRole(params) {
2054
- if (!params.canPost || !params.hasCallKey) return null;
2055
- if (params.speakerIdentity === params.myIdentity) return "own";
2056
- if (params.speakerNeedsProxy) return "proxy";
2057
- return null;
2058
- }
2059
- function threadTranscriptText(segment) {
2060
- return `${segment.speakerName}: ${segment.text}`;
2061
- }
2062
- async function persistTranscriptSegment(arbi, queryClient, callExtId, callKey, segment) {
2063
- const ref = await ensureMeetingChat(arbi, queryClient, callExtId, callKey);
2064
- await storeTranscriptSegment(arbi, queryClient, ref, segment);
2065
- return ref;
2066
- }
2067
- async function storeTranscriptSegment(arbi, queryClient, ref, segment) {
2068
- if (ref.kind === "chat") {
2069
- const chat = await arbi.chats.ready(await chatByExtId(arbi, queryClient, ref.chatExtId));
2070
- const ring = await arbi.chats.ring(chat);
2071
- const key = ring.keys.get(ring.currentVersion);
2072
- if (!key) throw new Error("No key for the meeting chat");
2073
- const content = {
2074
- text: segment.text,
2075
- speaker_identity: segment.speakerIdentity,
2076
- speaker_name: segment.speakerName,
2077
- started_at: segment.startedAt
2078
- };
2079
- await arbi.calls.transcription.postChatLine(ref.chatExtId, {
2080
- content: await encryptWithChatKey(JSON.stringify(content), key),
2081
- key_version: ring.currentVersion,
2082
- dedupe_key: segment.segmentId
2083
- });
2084
- return;
2085
- }
2086
- const transcript = {
2087
- segment_id: segment.segmentId,
2088
- speaker_ext_id: segment.speakerIdentity,
2089
- started_at: segment.startedAt
2090
- };
2091
- await arbi.conversations.postMessage({
2092
- content: threadTranscriptText(segment),
2093
- conversation_ext_id: ref.conversationExtId,
2094
- assistant_mode: "mentioned",
2095
- transcript
2096
- });
2097
- }
2098
- async function openRecording(arbi, queryClient, call, recordingExtId, loaded) {
2099
- const recording = loaded ?? await arbi.calls.recording.get(call.external_id, recordingExtId);
2100
- const convKeys = /* @__PURE__ */ new Map();
2101
- const keys = /* @__PURE__ */ new Map();
2102
- for (const track of recording.tracks ?? []) {
2103
- const version = track.key_version ?? null;
2104
- const id = String(version);
2105
- if (!convKeys.has(id)) {
2106
- convKeys.set(
2107
- id,
2108
- conversationKeyForCall(arbi, queryClient, call, { keyVersion: version }).then((c) => c.key)
2109
- );
2110
- }
2111
- try {
2112
- keys.set(track.external_id, await unwrapTrackKey(track.wrapped_key, await convKeys.get(id)));
2113
- } catch (err) {
2114
- console.warn("[calls] a recording track key does not open", err);
2115
- }
2116
- }
2117
- return { recording, keys };
2118
- }
2119
- function speakerTracks(recording) {
2120
- return (recording.tracks ?? []).filter((t) => t.kind === "speaker");
2121
- }
2122
- function compositeTrack(recording) {
2123
- return (recording.tracks ?? []).find((t) => t.kind === "composite") ?? null;
2124
- }
2125
- function sortedParts(track) {
2126
- return [...track.parts ?? []].sort((a, b) => a.seq - b.seq);
2127
- }
2128
- async function fetchPart(arbi, part, fileKey) {
2129
- if (!part.download_url) throw new Error("This recording\u2019s media was deleted");
2130
- return decryptPart(await arbi.calls.recording.downloadPart(part.download_url), fileKey);
2131
- }
2132
- async function compositeFiles(arbi, track, fileKey) {
2133
- const parts = [];
2134
- for (const part of sortedParts(track)) parts.push(await fetchPart(arbi, part, fileKey));
2135
- const type = track.mime_type.split(";")[0] || "video/webm";
2136
- return splitIntoFiles(parts).map((file) => new Blob(file.map(standalone), { type }));
2137
- }
2138
- async function decodeMono16k(bytes) {
2139
- const ctx = new OfflineAudioContext(1, 1, EXPORT_SAMPLE_RATE);
2140
- const buffer = await ctx.decodeAudioData(standalone(bytes).buffer);
2141
- return buffer.getChannelData(0);
2142
- }
2143
- async function speakerWav(arbi, track, fileKey, onPart) {
2144
- const parts = sortedParts(track);
2145
- const totalMs = timelineDurationMs(timelineOf([track]));
2146
- const samples = new Int16Array(Math.ceil(totalMs / 1e3 * EXPORT_SAMPLE_RATE) + 1);
2147
- for (const part of parts) {
2148
- const bytes = await fetchPart(arbi, part, fileKey);
2149
- try {
2150
- writeSamples(
2151
- samples,
2152
- await decodeMono16k(bytes),
2153
- part.offset_ms / 1e3 * EXPORT_SAMPLE_RATE
2154
- );
2155
- } catch (err) {
2156
- console.warn("[calls] a recording part does not decode", err);
2157
- }
2158
- onPart?.();
2159
- }
2160
- return new Blob([encodeWav(samples, EXPORT_SAMPLE_RATE)], { type: "audio/wav" });
2161
- }
2162
- async function recordingFiles(arbi, opened, title, onProgress) {
2163
- const { recording, keys } = opened;
2164
- const base = fileSafe(title || "Meeting");
2165
- const date = recording.started_at.slice(0, 10);
2166
- const total = (recording.tracks ?? []).reduce((n, t) => n + (t.parts?.length ?? 0), 0);
2167
- let done = 0;
2168
- const tick = () => onProgress?.(++done, total);
2169
- const files = [];
2170
- for (const track of speakerTracks(recording)) {
2171
- const key = keys.get(track.external_id);
2172
- if (!key || !track.parts?.length) continue;
2173
- const wav = await speakerWav(arbi, track, key, tick);
2174
- const who = fileSafe(track.speaker_name || track.speaker_ext_id || "speaker");
2175
- files.push(new File([wav], `${base}-${date}-${who}.wav`, { type: "audio/wav" }));
2176
- }
2177
- const composite = compositeTrack(recording);
2178
- const compositeKey = composite && keys.get(composite.external_id);
2179
- if (composite && compositeKey && composite.parts?.length) {
2180
- const videos = await compositeFiles(arbi, composite, compositeKey);
2181
- done += composite.parts.length;
2182
- onProgress?.(done, total);
2183
- const ext = extensionFor(composite.mime_type);
2184
- videos.forEach(
2185
- (blob, i) => files.push(
2186
- new File([blob], `${base}-${date}-video${videos.length > 1 ? `-${i + 1}` : ""}.${ext}`, {
2187
- type: blob.type
2188
- })
2189
- )
2190
- );
2191
- }
2192
- return files;
2193
- }
2194
- var PROMPT_HISTORY_CHARS = 400;
2195
- async function transcribeRecording(params) {
2196
- const {
2197
- arbi,
2198
- queryClient,
2199
- callExtId,
2200
- opened,
2201
- ref,
2202
- onProgress,
2203
- decode = decodeMono16k,
2204
- language
2205
- } = params;
2206
- const { recording, keys } = opened;
2207
- const tracks = speakerTracks(recording).filter((t) => keys.has(t.external_id));
2208
- const total = tracks.reduce((n, t) => n + (t.parts?.length ?? 0), 0);
2209
- const start = Date.parse(recording.started_at);
2210
- let done = 0;
2211
- let stored = 0;
2212
- let failed = 0;
2213
- for (const track of tracks) {
2214
- const key = keys.get(track.external_id);
2215
- const cutter = createTrackCutter(EXPORT_SAMPLE_RATE, RECORDING_SEGMENTER, { mergeShort: true });
2216
- let previous = "";
2217
- let nextSegment = 0;
2218
- const send = async (request) => {
2219
- try {
2220
- const result = await arbi.calls.recording.transcribe(callExtId, recording.external_id, {
2221
- audio: request.audio,
2222
- trackExtId: track.external_id,
2223
- seq: request.seq ?? null,
2224
- segment: request.segment ?? null,
2225
- segmentOffsetMs: request.seq == null ? request.offsetMs : 0,
2226
- language,
2227
- prompt: continuityPrompt(previous)
2228
- });
2229
- const text = result.text.trim();
2230
- if (!text) return;
2231
- previous = `${previous} ${text}`.slice(-PROMPT_HISTORY_CHARS);
2232
- const segment = {
2233
- segmentId: result.segment_id || (request.seq != null ? `rec-${track.external_id}-${request.seq}` : `rec-${track.external_id}-s${request.segment}`),
2234
- text,
2235
- speakerIdentity: result.speaker_ext_id ?? track.speaker_ext_id ?? "",
2236
- speakerName: result.speaker_name ?? track.speaker_name ?? "Speaker",
2237
- startedAt: Number.isFinite(start) ? new Date(start + (result.offset_ms ?? Math.round(request.offsetMs))).toISOString() : null
2238
- };
2239
- await storeTranscriptSegment(arbi, queryClient, ref, segment);
2240
- stored += 1;
2241
- } catch (err) {
2242
- failed += 1;
2243
- console.warn("[calls] a recording piece could not be transcribed", err);
2244
- }
2245
- };
2246
- const sendPieces = async (pieces) => {
2247
- for (const piece of pieces) {
2248
- await send({
2249
- audio: new Blob([floatToWav(piece.samples, EXPORT_SAMPLE_RATE)], { type: "audio/wav" }),
2250
- segment: nextSegment++,
2251
- offsetMs: piece.start / EXPORT_SAMPLE_RATE * 1e3
2252
- });
2253
- }
2254
- };
2255
- for (const part of sortedParts(track)) {
2256
- let bytes;
2257
- try {
2258
- bytes = await fetchPart(arbi, part, key);
2259
- } catch (err) {
2260
- failed += 1;
2261
- console.warn("[calls] a recording part could not be read", err);
2262
- onProgress?.(++done, total);
2263
- continue;
2264
- }
2265
- let pcm = null;
2266
- try {
2267
- pcm = await decode(bytes);
2268
- } catch (err) {
2269
- console.warn("[calls] a recording part does not decode; sending it whole", err);
2270
- }
2271
- if (pcm) {
2272
- await sendPieces(cutter.push(part.offset_ms, pcm));
2273
- } else {
2274
- await send({
2275
- audio: new Blob([standalone(bytes)], { type: track.mime_type }),
2276
- seq: part.seq,
2277
- offsetMs: part.offset_ms
2278
- });
2279
- }
2280
- onProgress?.(++done, total);
2281
- }
2282
- await sendPieces(cutter.finish());
2283
- }
2284
- return { stored, failed };
2285
- }
2286
- function useCallsConfig() {
2287
- const arbi = useArbi();
2288
- const { data } = useQuery({
2289
- queryKey: callQueryKeys.config(),
2290
- queryFn: () => arbi.calls.config(),
2291
- enabled: arbi.isLoggedIn,
2292
- staleTime: 5 * 6e4,
2293
- retry: false
2294
- });
2295
- return data;
2296
- }
2297
- function useServerCallsEnabled() {
2298
- return useCallsConfig()?.enabled === true;
2299
- }
2300
- function useServerCallsExperimental() {
2301
- return useCallsConfig()?.experimental !== false;
2302
- }
2303
- function useCallTranscriptionAvailable() {
2304
- return useCallsConfig()?.transcription_available === true;
2305
- }
2306
- function useCall(callExtId) {
2307
- const arbi = useArbi();
2308
- return useQuery({
2309
- queryKey: callQueryKeys.call(callExtId ?? ""),
2310
- queryFn: () => arbi.calls.get(callExtId),
2311
- enabled: !!callExtId && arbi.isLoggedIn,
2312
- staleTime: 6e4,
2313
- retry: false
2314
- });
2315
- }
2316
- function useCallRecordings(callExtId, enabled = true) {
2317
- const arbi = useArbi();
2318
- return useQuery({
2319
- queryKey: callQueryKeys.recordings(callExtId ?? ""),
2320
- queryFn: () => arbi.calls.recording.list(callExtId),
2321
- enabled: !!callExtId && enabled && arbi.isLoggedIn,
2322
- retry: false
2323
- });
2324
- }
2325
- function useCallRecording(callExtId, recordingExtId) {
2326
- const arbi = useArbi();
2327
- return useQuery({
2328
- queryKey: callQueryKeys.recording(callExtId ?? "", recordingExtId ?? ""),
2329
- queryFn: () => arbi.calls.recording.get(callExtId, recordingExtId),
2330
- enabled: !!callExtId && !!recordingExtId && arbi.isLoggedIn,
2331
- retry: false
2332
- });
2333
- }
2334
- var NO_WINDOWS = [];
2335
- function useRecordingWindows(callExtId, enabled) {
2336
- const { data } = useCallRecordings(callExtId, enabled);
2337
- return useMemo(() => data ? recordingWindowsOf(data) : NO_WINDOWS, [data]);
2338
- }
2339
- function useCallInviteLinks(callExtId) {
2340
- const arbi = useArbi();
2341
- return useQuery({
2342
- queryKey: callQueryKeys.inviteLinks(callExtId ?? ""),
2343
- queryFn: () => arbi.calls.inviteLinks.list(callExtId),
2344
- enabled: !!callExtId && arbi.isLoggedIn,
2345
- retry: false
2346
- });
2347
- }
2348
- function useRecordingActions(call) {
2349
- const arbi = useArbi();
2350
- const queryClient = useQueryClient();
2351
- return useMemo(
2352
- () => ({
2353
- refresh: () => void queryClient.invalidateQueries({
2354
- queryKey: callQueryKeys.recordingsOf(call.external_id)
2355
- }),
2356
- open: (recording) => openRecording(arbi, queryClient, call, recording.external_id, recording),
2357
- transcribe: async (opened, onProgress) => transcribeRecording({
2358
- arbi,
2359
- queryClient,
2360
- callExtId: call.external_id,
2361
- opened,
2362
- ref: await meetingRefForCall(arbi, queryClient, call),
2363
- onProgress
2364
- })
2365
- }),
2366
- [arbi, queryClient, call]
2367
- );
2368
- }
2369
- function useRevokeCallInviteLink(callExtId) {
2370
- const arbi = useArbi();
2371
- const queryClient = useQueryClient();
2372
- return useCallback(
2373
- async (inviteExtId) => {
2374
- await arbi.calls.inviteLinks.revoke(callExtId, inviteExtId);
2375
- void queryClient.invalidateQueries({ queryKey: callQueryKeys.inviteLinks(callExtId) });
2376
- },
2377
- [arbi, queryClient, callExtId]
2378
- );
2379
- }
2380
- async function postToThread(arbi, conversationExtId, newThreadTitle, content) {
2381
- const posted = await arbi.conversations.postMessage({
2382
- content,
2383
- assistant_mode: "mentioned",
2384
- ...conversationExtId ? { conversation_ext_id: conversationExtId } : { title: newThreadTitle }
2385
- });
2386
- return posted?.conversation_ext_id ?? null;
2387
- }
2388
- function postTranscriptToThread(arbi, params) {
2389
- return postToThread(
2390
- arbi,
2391
- params.conversationExtId,
2392
- `Transcript: ${params.title?.trim() || "Meeting"}`,
2393
- formatTranscriptMarkdown({ title: params.title, lines: params.lines })
2394
- );
2395
- }
2396
- function postRecordingDocsToThread(arbi, params) {
2397
- const meeting = params.title?.trim() || "Meeting";
2398
- const content = [
2399
- `**Recording: ${meeting}**`,
2400
- "",
2401
- ...params.docExtIds.map((id) => `- \`${id}\``)
2402
- ].join("\n");
2403
- return postToThread(arbi, params.conversationExtId, `Recording: ${meeting}`, content);
2404
- }
2405
- async function saveRecordingFilesToThread(arbi, params) {
2406
- const workspaceId = params.workspaceExtId;
2407
- const workspaceKey = await arbi.workspaces.key(workspaceId).catch(() => null);
2408
- params.onUploading?.();
2409
- const result = workspaceKey ? await arbi.documents.uploadDirect(
2410
- workspaceId,
2411
- workspaceKey,
2412
- await Promise.all(
2413
- params.files.map(async (file) => ({
2414
- name: file.name,
2415
- data: new Uint8Array(await file.arrayBuffer()),
2416
- contentType: file.type || documents.mimeFromName(file.name)
2417
- }))
2418
- ),
2419
- { shared: true }
2420
- ) : await arbi.documents.upload(params.files, { shared: true, workspaceExtId: workspaceId });
2421
- const docExtIds = result.doc_ext_ids ?? [];
2422
- const skipped = result.skipped ?? [];
2423
- if (!docExtIds.length) {
2424
- throw new Error(`The files were not uploaded${skipped[0] ? `: ${skipped[0].reason}` : ""}`);
2425
- }
2426
- return postRecordingDocsToThread(arbi, {
2427
- conversationExtId: params.conversationExtId,
2428
- title: params.title,
2429
- docExtIds
2430
- });
2431
- }
2432
- function useSaveToThread() {
2433
- const arbi = useArbi();
2434
- const queryClient = useQueryClient();
2435
- return useMemo(() => {
2436
- const thenRefresh = async (run) => {
2437
- const result = await run;
2438
- void invalidateConversationLists(queryClient);
2439
- return result;
2440
- };
2441
- return {
2442
- transcript: (params) => thenRefresh(postTranscriptToThread(arbi, params)),
2443
- recording: (params) => thenRefresh(saveRecordingFilesToThread(arbi, params))
2444
- };
2445
- }, [arbi, queryClient]);
2446
- }
2447
- function callLink(callExtId, key, linkVersion) {
2448
- return buildCallLink(window.location.origin, callExtId, key, linkVersion);
2449
- }
2450
- function alreadyInCall(callExtId) {
2451
- const active = callSession.getState().active;
2452
- if (!active || active.callExtId === callExtId) return false;
2453
- notify.warning("You are already in a call. Leave it first.");
2454
- return true;
2455
- }
2456
- function fail(err, what = "start the call") {
2457
- console.error(`[calls] failed to ${what}`, err);
2458
- const message = err instanceof Error ? err.message : "Unknown error";
2459
- notify.error(`Could not ${what}: ${message}`);
2460
- }
2461
- function callContext(call) {
2462
- return {
2463
- chatExtId: call.chat_ext_id ?? null,
2464
- logConversationExtId: call.log_conversation_ext_id ?? null,
2465
- meetingConversationExtId: call.meeting_conversation_ext_id ?? null,
2466
- lockedWorkspaceExtId: call.locked_workspace_ext_id ?? null
2467
- };
2468
- }
2469
- async function sendInviteLinks(arbi, callExtId, key, linkVersion, invites) {
2470
- let sent = 0;
2471
- for (const invite of invites) {
2472
- try {
2473
- await arbi.calls.inviteLinks.create(callExtId, {
2474
- contact_ext_id: invite.contactExtId,
2475
- link: callLink(callExtId, key, linkVersion)
2476
- });
2477
- sent += 1;
2478
- } catch (err) {
2479
- fail(err, `invite ${invite.name || "a contact"}`);
2480
- }
2481
- }
2482
- if (sent) notify.success(`Sent ${sent} ${sent === 1 ? "invitation" : "invitations"}`);
2483
- return sent;
2484
- }
2485
- async function startCall(arbi, opts) {
2486
- if (alreadyInCall()) return false;
2487
- try {
2488
- const {
2489
- call,
2490
- key,
2491
- title,
2492
- sealedKeys: ringOnJoin
2493
- } = await arbi.calls.start({ ...opts.context, title: opts.title, invitees: opts.ring });
2494
- callSession.setActiveCall({
2495
- callExtId: call.external_id,
2496
- key,
2497
- linkVersion: call.link_version,
2498
- title,
2499
- isCreator: call.is_creator,
2500
- ...callContext(call),
2501
- phase: "prejoin",
2502
- tokenResponse: null,
2503
- choices: null,
2504
- knock: null,
2505
- ringOnJoin: Object.keys(ringOnJoin).length ? ringOnJoin : null
2506
- });
2507
- if (opts.invites?.length) {
2508
- void sendInviteLinks(arbi, call.external_id, key, call.link_version, opts.invites);
2509
- }
2510
- return true;
2511
- } catch (err) {
2512
- fail(err);
2513
- return false;
2514
- }
2515
- }
2516
- function startThreadCall(arbi, opts) {
2517
- return startCall(arbi, {
2518
- context: { threadExtId: opts.threadExtId },
2519
- title: opts.title,
2520
- ring: opts.ring
2521
- });
2522
- }
2523
- function startChatCall(arbi, opts) {
2524
- return startCall(arbi, {
2525
- context: { chatExtId: opts.chatExtId },
2526
- title: opts.title,
2527
- ring: opts.ring
2528
- });
2529
- }
2530
- async function startDmCall(arbi, peer) {
2531
- if (alreadyInCall()) return false;
2532
- if (!peer.encryption_public_key) {
2533
- fail(new Error("This person cannot receive encrypted calls"));
2534
- return false;
2535
- }
2536
- let chatExtId;
2537
- try {
2538
- chatExtId = (await arbi.chats.openDirect(peer.external_id)).external_id;
2539
- } catch (err) {
2540
- fail(err);
2541
- return false;
2542
- }
2543
- return startChatCall(arbi, { chatExtId, title: peer.name ?? null, ring: [peer] });
2544
- }
2545
- function startContactsCall(arbi, opts) {
2546
- return startCall(arbi, { context: {}, title: opts.title, ring: opts.ring, invites: opts.invites });
2547
- }
2548
- async function openCall(arbi, opts) {
2549
- if (alreadyInCall(opts.callExtId)) return false;
2550
- try {
2551
- const { call, key, title } = await arbi.calls.open(opts.callExtId, opts.key);
2552
- callSession.setActiveCall({
2553
- callExtId: call.external_id,
2554
- key,
2555
- linkVersion: opts.linkVersion ?? call.link_version,
2556
- title,
2557
- isCreator: call.is_creator,
2558
- ...callContext(call),
2559
- phase: "prejoin",
2560
- tokenResponse: null,
2561
- choices: null,
2562
- knock: null,
2563
- ringOnJoin: null,
2564
- inviteToken: opts.inviteToken ?? null
2565
- });
2566
- return true;
2567
- } catch (err) {
2568
- fail(err, "open the call");
2569
- return false;
2570
- }
2571
- }
2572
- async function acceptRing(arbi, ring) {
2573
- const current = callSession.getState().active;
2574
- if (current && current.callExtId !== ring.call_ext_id) callSession.endActiveCall();
2575
- try {
2576
- const { key, token, title } = await arbi.calls.answer(ring);
2577
- callSession.setActiveCall({
2578
- callExtId: ring.call_ext_id,
2579
- key,
2580
- linkVersion: ring.link_version,
2581
- title: title || ring.caller_name,
2582
- isCreator: false,
2583
- chatExtId: ring.chat_ext_id ?? null,
2584
- logConversationExtId: ring.log_conversation_ext_id ?? null,
2585
- meetingConversationExtId: ring.meeting_conversation_ext_id ?? null,
2586
- lockedWorkspaceExtId: ring.context === "thread" ? ring.workspace_ext_id ?? null : null,
2587
- phase: "connected",
2588
- tokenResponse: token,
2589
- choices: DEFAULT_JOIN_CHOICES,
2590
- knock: null,
2591
- ringOnJoin: null
2592
- });
2593
- return true;
2594
- } catch (err) {
2595
- fail(err, "join the call");
2596
- callSession.removeIncomingCall(ring.call_ext_id);
2597
- return false;
2598
- }
2599
- }
2600
- function declineRing(arbi, ring) {
2601
- callSession.removeIncomingCall(ring.call_ext_id);
2602
- arbi.calls.decline(ring.call_ext_id).catch((err) => console.warn("[calls] decline failed", err));
2603
- }
2604
- var KNOCK_POLL_MS = 2e3;
2605
- async function waitForAdmission(arbi, callExtId, knock, signal) {
2606
- for (; ; ) {
2607
- if (signal.aborted) throw new DOMException("Stopped waiting", "AbortError");
2608
- await new Promise((resolve) => setTimeout(resolve, KNOCK_POLL_MS));
2609
- if (signal.aborted) throw new DOMException("Stopped waiting", "AbortError");
2610
- const state2 = await arbi.calls.pollKnock(callExtId, knock.knock_id);
2611
- if (state2.status === "admitted" && state2.token) return state2.token;
2612
- if (state2.status === "denied") throw new CallApiError("The host declined your request.", 403);
2613
- if (state2.status === "expired") throw new CallApiError("Nobody let you in. Try again.", 410);
2614
- }
2615
- }
2616
- async function joinFromPreJoin(arbi, choices) {
2617
- const active = callSession.getState().active;
2618
- if (!active) return;
2619
- const { callExtId, linkVersion, inviteToken } = active;
2620
- const update2 = (patch) => callSession.updateActiveCall(callExtId, patch);
2621
- try {
2622
- let tokenResponse;
2623
- try {
2624
- tokenResponse = await arbi.calls.token(callExtId, linkVersion, inviteToken);
2625
- } catch (err) {
2626
- if (!(err instanceof CallApiError && err.code === "knock_required")) throw err;
2627
- const knock = await arbi.calls.knock(callExtId, linkVersion);
2628
- if (knock.status === "admitted" && knock.token) tokenResponse = knock.token;
2629
- else {
2630
- const controller = new AbortController();
2631
- update2({ phase: "knocking", choices, knock: { abort: () => controller.abort() } });
2632
- tokenResponse = await waitForAdmission(arbi, callExtId, knock, controller.signal);
2633
- }
2634
- }
2635
- if (callSession.getState().active?.callExtId !== callExtId) return;
2636
- update2({ phase: "connected", tokenResponse, choices, knock: null });
2637
- const ring = active.ringOnJoin;
2638
- if (ring && Object.keys(ring).length) {
2639
- update2({ ringOnJoin: null });
2640
- await arbi.calls.ring(callExtId, ring, linkVersion).catch((err) => console.warn("[calls] ring failed", err));
2641
- }
2642
- } catch (err) {
2643
- if (err instanceof DOMException && err.name === "AbortError") return;
2644
- if (err instanceof CallApiError && err.code === "webinar_not_live") {
2645
- update2({ phase: "webinar-waiting", choices, knock: null });
2646
- return;
2647
- }
2648
- fail(err, "join the call");
2649
- if (callSession.getState().active?.callExtId === callExtId) {
2650
- callSession.endActiveCall();
2651
- }
2652
- }
2653
- }
2654
- var CALL_WEBINAR_TOPIC = "arbi.webinar";
2655
- var AUDIENCE_CHOICES = { audioEnabled: false, videoEnabled: false };
2656
- var isHand = (h) => !!h && typeof h === "object" && typeof h.identity === "string" && typeof h.raised_at === "string";
2657
- function parseWebinarPacket(payload, fromParticipant) {
2658
- if (fromParticipant) return null;
2659
- let raw;
2660
- try {
2661
- raw = JSON.parse(new TextDecoder().decode(payload));
2662
- } catch {
2663
- return null;
2664
- }
2665
- if (!raw || typeof raw !== "object") return null;
2666
- const p = raw;
2667
- switch (p.type) {
2668
- case "state":
2669
- if (typeof p.live !== "boolean") return null;
2670
- return {
2671
- type: "state",
2672
- live: p.live,
2673
- live_at: typeof p.live_at === "string" ? p.live_at : null,
2674
- chat: p.chat === "everyone" ? "everyone" : "panelists"
2675
- };
2676
- case "hands":
2677
- return {
2678
- type: "hands",
2679
- hands: Array.isArray(p.hands) ? p.hands.filter(isHand).map((h) => ({ ...h, name: String(h.name ?? "") })) : []
2680
- };
2681
- case "questions":
2682
- case "promoted":
2683
- case "demoted":
2684
- return { type: p.type };
2685
- default:
2686
- return null;
2687
- }
2688
- }
2689
- var UNREADABLE = "(This question could not be decrypted.)";
2690
- function sealQuestionText(text, key) {
2691
- return encryptCallTitle(text, key);
2692
- }
2693
- async function openQuestion(q, key) {
2694
- const [text, answerText] = await Promise.all([
2695
- decryptCallTitle(q.body, key),
2696
- q.answer ? decryptCallTitle(q.answer, key) : Promise.resolve(null)
2697
- ]);
2698
- return { ...q, text: text ?? UNREADABLE, answerText };
2699
- }
2700
- function markRejoining(callExtId, on = true) {
2701
- callSession.updateActiveCall(callExtId, { rejoining: on });
2702
- }
2703
- async function rejoinAsAudience(arbi, callExtId) {
2704
- if (callSession.getState().active?.callExtId !== callExtId) return;
2705
- markRejoining(callExtId);
2706
- try {
2707
- await joinFromPreJoin(arbi, AUDIENCE_CHOICES);
2708
- } finally {
2709
- markRejoining(callExtId, false);
2710
- }
2711
- }
2712
-
2713
- // src/calls/read-only.ts
2714
- function isWorkspaceGuestOf(workspaces, workspaceExtId, me) {
2715
- if (!workspaceExtId || !me || !workspaces) return false;
2716
- const workspace = workspaces.find((w) => w.external_id === workspaceExtId);
2717
- return workspace?.users?.find((wu) => wu.user.external_id === me)?.role === "guest";
2718
- }
2719
- function useMeetingReadOnly(lockedWorkspaceExtId) {
2720
- const arbi = useArbi();
2721
- const me = arbi.isLoggedIn ? arbi.user.identity()?.externalId ?? null : null;
2722
- const { data: workspaces } = useWorkspaces({
2723
- enabled: !!lockedWorkspaceExtId && arbi.isLoggedIn
2724
- });
2725
- return isWorkspaceGuestOf(
2726
- workspaces,
2727
- lockedWorkspaceExtId,
2728
- me
2729
- );
2730
- }
2731
-
2732
- // src/calls/gate.ts
2733
- function useCallsEnabled() {
2734
- const serverEnabled = useServerCallsEnabled();
2735
- const experimental = useServerCallsExperimental();
2736
- const switchedOn = useFeature("calls");
2737
- return serverEnabled && (switchedOn || !experimental);
2738
- }
2739
- function useCanHostCalls() {
2740
- const callsEnabled = useCallsEnabled();
2741
- const entitled = useIsEntitled("host_calls");
2742
- return callsEnabled && entitled;
2743
- }
2744
- function useOpenCallMeetingChat() {
2745
- const arbi = useArbi();
2746
- const queryClient = useQueryClient();
2747
- const open = useArbiHost().calls?.openMeetingChat;
2748
- return useCallback(
2749
- async (target) => {
2750
- try {
2751
- const ref = await resolveMeetingChat(arbi, queryClient, target);
2752
- open?.(ref);
2753
- } catch (err) {
2754
- console.warn("[calls] could not open the meeting chat", err);
2755
- notify.error(
2756
- `Could not open the meeting chat: ${err instanceof Error ? err.message : "unknown error"}`
2757
- );
2758
- }
2759
- },
2760
- [arbi, queryClient, open]
2761
- );
2762
- }
2763
-
2764
- export { AUDIENCE_CHOICES, CALL_CAPTION_TOPIC, CALL_CHAT_MAX_CHARS, CALL_CHAT_TOPIC, CALL_MODERATION_TOPIC, CALL_RECORDING_TOPIC, CALL_TRANSCRIPTION_TOPIC, CALL_WEBINAR_TOPIC, CAPTION_MAX_CHARS, COMPOSITE_AUDIO_BITS_PER_SECOND, COMPOSITE_VIDEO_BITS_PER_SECOND, DEFAULT_JOIN_CHOICES, EMPTY_CALL_SESSION, EXPORT_SAMPLE_RATE, HISTORY_LIMIT, LIVE_SEGMENTER, MAX_AVATAR_FILE_BYTES, MUTED_DEDUPE_MS, OFFLINE_MAIL_DB, PLAYBACK_LOOKAHEAD_MS, READ_ONLY_MEETING_TEXT, RECORDING_CHUNK_MS, RECORDING_SEGMENTER, SCOPE_DAYS, SEGMENT_FRAME_MS, SEGMENT_ID_PATTERN, SEGMENT_PRE_ROLL_MS, SHORT_PIECE_MERGE_GAP_MS, SPEAKER_AUDIO_BITS_PER_SECOND, TrackUploader, UPLOAD_ATTEMPTS, UPLOAD_BACKOFF_MS, acceptRing, addConversationToList, allRecordSizes, appendToThread, applyAgentDmStatus, applyCallEvent, applyChatEvent, applyChatMessage, applyChatRead, applyChatUpdated, arbiAccountClient, blind, buildMeetingChatBody, cachedChat, cachedChats, callLink, callMemberKeys, callSession, chatByExtId, chatHasLiveCall, chatLiveCallId, chatTranscriptRef, claimOfflineMail, clearMeetingChatCache, clearTrackUploaders, clockTime, compositeFiles, compositeTrack, conversationKeyForCall, createLocalFeatureStore, createMutedNotifier, createRecordStore, createTrackCutter, cutAtPauses, declineRing, decodeCallChatPacket, decodeCaptionPacket, decodeMono16k, decryptPart, deleteChatMessage, deleteRecords, dropFromThread, encodeCallChatPacket, encodeCaptionPacket, encodeWav, encryptPart, ensureMeetingChat, entitlementRefusal, extensionFor, fetchPart, fileSafe, findConversation, floatToWav, formatTranscriptMarkdown, getMeta, getOfflineMailSettings, getOpenChat, getRecord, hasRecord, hasRecordingTranscript, inOfflineWindow, invalidateCall, invalidateConversationDetails, invalidateConversationLists, isConversationListKey, isConversationShared, isRecordingOver, isRecordingSegmentId, isRetryable, isWorkspaceGuestOf, joinFromPreJoin, knownMeetingChat, loadMeetingHistory, markRejoining, meetingChatRefFrom, meetingRefForCall, mergeChatLines, mutedNoticeFromEvent, mutedNoticeFromPacket, mutedNoticeText, myChatId, newPacketId, newSegmentId, newTrackKey, nextSeqAfter, notifyOfflineMailChange, offlineWindowStart, onCallEvent, onOfflineMailChange, openBytes, openCall, openJson, openQuestion, openRecording, parseWebinarPacket, partKey, partOffsetMs, partsDue, patchConversation, patchConversationList, persistMeetingMessage, persistTranscriptSegment, playheadAt, postRecordingDocsToThread, postTranscriptToThread, putRecord, readLocalFeature, recordingFiles, recordingWindowsOf, recordsInBucket, recordsOfKind, rejoinAsAudience, removeChat, removeConversationFromLists, resetCallSession, resolveMeetingChat, saveRecordingFilesToThread, schedulePart, sealBytes, sealJson, sealQuestionText, serverCallsExperimental, setMeta, setOfflineMailSettings, setOpenChat, sortTranscriptMessages, sortedParts, speakerTracks, speakerWav, splitIntoFiles, standalone, startChatCall, startContactsCall, startDmCall, startThreadCall, startsMediaFile, storeTranscriptSegment, stripSpeakerPrefix, supersedeLiveTranscript, supersededTranscriptLines, threadHasLiveCall, threadLiveCallId, threadTranscriptLines, threadTranscriptRef, threadTranscriptText, timelineDurationMs, timelineOf, toProfileView, touchRecord, trackUploaderFor, transcribeRecording, transcriptPersistRole, transcriptSegmentOf, unwrapTrackKey, upsertChat, useAccountClient, useAvatarCrop, useCall, useCallInviteLinks, useCallRecording, useCallRecordings, useCallSession, useCallTranscriptionAvailable, useCallsConfig, useCallsEnabled, useCanHostCalls, useEntitlements, useFeature, useFeatureCheck, useFeatureSwitch, useInvalidateEntitlements, useIsEntitled, useMeetingReadOnly, useNameEditor, useOpenCallMeetingChat, useProfile, useRecordingActions, useRecordingWindows, useRevokeCallInviteLink, useSaveToThread, useServerCallsEnabled, useServerCallsExperimental, useUpdateProfile, useUpdateUserSettings, useUserSettings, wipeOfflineMail, wrapTrackKey, writeSamples };
2765
- //# sourceMappingURL=chunk-DZKRL5H3.js.map
2766
- //# sourceMappingURL=chunk-DZKRL5H3.js.map