@arbidocs/react 0.5.111 → 0.5.112
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.
- package/dist/account/client.js +96 -0
- package/dist/account/client.js.map +7 -0
- package/dist/account/delete.js +70 -0
- package/dist/account/delete.js.map +7 -0
- package/dist/account/didit.js +34 -0
- package/dist/account/didit.js.map +7 -0
- package/dist/account/dismissed-tips.js +33 -0
- package/dist/account/dismissed-tips.js.map +7 -0
- package/dist/account/email.js +84 -0
- package/dist/account/email.js.map +7 -0
- package/dist/account/entitlements.js +47 -0
- package/dist/account/entitlements.js.map +7 -0
- package/dist/account/identity.js +270 -0
- package/dist/account/identity.js.map +7 -0
- package/dist/account/index.js +93 -0
- package/dist/account/index.js.map +7 -0
- package/dist/account/notifications.js +59 -0
- package/dist/account/notifications.js.map +7 -0
- package/dist/account/password.js +103 -0
- package/dist/account/password.js.map +7 -0
- package/dist/account/profile.js +116 -0
- package/dist/account/profile.js.map +7 -0
- package/dist/account/recovery.js +13 -0
- package/dist/account/recovery.js.map +7 -0
- package/dist/account/relevance.js +82 -0
- package/dist/account/relevance.js.map +7 -0
- package/dist/account/sessions.js +37 -0
- package/dist/account/sessions.js.map +7 -0
- package/dist/account/settings.js +39 -0
- package/dist/account/settings.js.map +7 -0
- package/dist/account/table-views.js +16 -0
- package/dist/account/table-views.js.map +7 -0
- package/dist/ai/AiAnswer.js +83 -0
- package/dist/ai/AiAnswer.js.map +7 -0
- package/dist/ai/AiMarkdown.js +40 -0
- package/dist/ai/AiMarkdown.js.map +7 -0
- package/dist/ai/ArtifactCanvas.js +193 -0
- package/dist/ai/ArtifactCanvas.js.map +7 -0
- package/dist/ai/CitationRenderer.js +413 -0
- package/dist/ai/CitationRenderer.js.map +7 -0
- package/dist/{chunk-WL2Y2T47.js → ai/MarkdownRenderer.js} +35 -101
- package/dist/ai/MarkdownRenderer.js.map +7 -0
- package/dist/ai/MessageArtifactCard.js +75 -0
- package/dist/ai/MessageArtifactCard.js.map +7 -0
- package/dist/ai/PassageCard.js +79 -0
- package/dist/ai/PassageCard.js.map +7 -0
- package/dist/ai/engine.js +110 -0
- package/dist/ai/engine.js.map +7 -0
- package/dist/ai/index.js +63 -0
- package/dist/ai/index.js.map +7 -0
- package/dist/ai/markdown-base-components.js +37 -0
- package/dist/ai/markdown-base-components.js.map +7 -0
- package/dist/ai/markdown-streaming-context.js +6 -0
- package/dist/ai/markdown-streaming-context.js.map +7 -0
- package/dist/{chunk-VSCU7K4V.js → ai/normalize-citations.js} +12 -19
- package/dist/ai/normalize-citations.js.map +7 -0
- package/dist/ai/redline.js +41 -0
- package/dist/ai/redline.js.map +7 -0
- package/dist/ai/split-markdown-blocks.js +40 -0
- package/dist/ai/split-markdown-blocks.js.map +7 -0
- package/dist/{chunk-UW2SGTI5.js → ai/stored-markdown.js} +41 -93
- package/dist/ai/stored-markdown.js.map +7 -0
- package/dist/annotations/AnnotationPageOverlay.js +807 -0
- package/dist/annotations/AnnotationPageOverlay.js.map +7 -0
- package/dist/annotations/AnnotationToolbar.js +398 -0
- package/dist/annotations/AnnotationToolbar.js.map +7 -0
- package/dist/annotations/FreezeDialog.js +170 -0
- package/dist/annotations/FreezeDialog.js.map +7 -0
- package/dist/annotations/ProductionDialog.js +354 -0
- package/dist/annotations/ProductionDialog.js.map +7 -0
- package/dist/annotations/controller.js +49 -0
- package/dist/annotations/controller.js.map +7 -0
- package/dist/annotations/freeze/browser.js +21 -0
- package/dist/annotations/freeze/browser.js.map +7 -0
- package/dist/annotations/freeze/bundle.js +201 -0
- package/dist/annotations/freeze/bundle.js.map +7 -0
- package/dist/annotations/freeze/coords.js +37 -0
- package/dist/annotations/freeze/coords.js.map +7 -0
- package/dist/annotations/freeze/freeze.js +261 -0
- package/dist/annotations/freeze/freeze.js.map +7 -0
- package/dist/annotations/freeze/hash.js +28 -0
- package/dist/annotations/freeze/hash.js.map +7 -0
- package/dist/annotations/freeze/index-page.js +78 -0
- package/dist/annotations/freeze/index-page.js.map +7 -0
- package/dist/annotations/freeze/index.js +28 -22
- package/dist/annotations/freeze/index.js.map +7 -1
- package/dist/annotations/freeze/raster.js +208 -0
- package/dist/annotations/freeze/raster.js.map +7 -0
- package/dist/annotations/freeze/stamp.js +117 -0
- package/dist/annotations/freeze/stamp.js.map +7 -0
- package/dist/annotations/freeze/types.js +14 -0
- package/dist/annotations/freeze/types.js.map +7 -0
- package/dist/annotations/freeze/vector.js +283 -0
- package/dist/annotations/freeze/vector.js.map +7 -0
- package/dist/annotations/geometry.js +81 -0
- package/dist/annotations/geometry.js.map +7 -0
- package/dist/annotations/index.js +125 -6
- package/dist/annotations/index.js.map +7 -1
- package/dist/annotations/merge.js +53 -0
- package/dist/annotations/merge.js.map +7 -0
- package/dist/{chunk-T3USOSVN.js → annotations/model.js} +23 -16
- package/dist/annotations/model.js.map +7 -0
- package/dist/annotations/overlay-geometry.js +41 -0
- package/dist/annotations/overlay-geometry.js.map +7 -0
- package/dist/annotations/redaction-log.js +33 -0
- package/dist/annotations/redaction-log.js.map +7 -0
- package/dist/annotations/selection-marks.js +122 -0
- package/dist/annotations/selection-marks.js.map +7 -0
- package/dist/annotations/state.js +140 -0
- package/dist/annotations/state.js.map +7 -0
- package/dist/annotations/store.js +49 -0
- package/dist/annotations/store.js.map +7 -0
- package/dist/annotations/useAnnotationLayer.js +306 -0
- package/dist/annotations/useAnnotationLayer.js.map +7 -0
- package/dist/annotations/useAnnotationShortcuts.js +31 -0
- package/dist/annotations/useAnnotationShortcuts.js.map +7 -0
- package/dist/annotations/useTextSelectionMarks.js +100 -0
- package/dist/annotations/useTextSelectionMarks.js.map +7 -0
- package/dist/artifacts/artifact-kind.js +19 -0
- package/dist/artifacts/artifact-kind.js.map +7 -0
- package/dist/artifacts/index.js +89 -571
- package/dist/artifacts/index.js.map +7 -1
- package/dist/{chunk-WUTL62MC.js → artifacts/normalize-markdown.js} +12 -14
- package/dist/artifacts/normalize-markdown.js.map +7 -0
- package/dist/artifacts/redline-core.js +12 -3
- package/dist/artifacts/redline-core.js.map +7 -1
- package/dist/{chunk-74N436VK.js → artifacts/redline-diff.js} +10 -9
- package/dist/artifacts/redline-diff.js.map +7 -0
- package/dist/artifacts/redline-engine.js +14 -0
- package/dist/artifacts/redline-engine.js.map +7 -0
- package/dist/artifacts/renderArtifactMarkdown.js +9 -0
- package/dist/artifacts/renderArtifactMarkdown.js.map +7 -0
- package/dist/artifacts/useArtifactEditSession.js +183 -0
- package/dist/artifacts/useArtifactEditSession.js.map +7 -0
- package/dist/artifacts/useArtifactSession.js +173 -0
- package/dist/artifacts/useArtifactSession.js.map +7 -0
- package/dist/artifacts/useArtifactSource.js +16 -0
- package/dist/artifacts/useArtifactSource.js.map +7 -0
- package/dist/artifacts/useArtifactText.js +78 -0
- package/dist/artifacts/useArtifactText.js.map +7 -0
- package/dist/artifacts/useRedline.js +65 -0
- package/dist/artifacts/useRedline.js.map +7 -0
- package/dist/artifacts/useStreamedArtifact.js +74 -0
- package/dist/artifacts/useStreamedArtifact.js.map +7 -0
- package/dist/artifacts/versions.js +68 -0
- package/dist/artifacts/versions.js.map +7 -0
- package/dist/billing.js +200 -0
- package/dist/billing.js.map +7 -0
- package/dist/boot-timeout.js +19 -0
- package/dist/boot-timeout.js.map +7 -0
- package/dist/calendar/accounts.js +213 -0
- package/dist/calendar/accounts.js.map +7 -0
- package/dist/calendar/hooks.js +409 -0
- package/dist/calendar/hooks.js.map +7 -0
- package/dist/calendar/index.js +31 -0
- package/dist/calendar/index.js.map +7 -0
- package/dist/calendar/keys.js +5 -0
- package/dist/calendar/keys.js.map +7 -0
- package/dist/calendar/offline/outbox.js +231 -0
- package/dist/calendar/offline/outbox.js.map +7 -0
- package/dist/calendar/offline/runtime.js +109 -0
- package/dist/calendar/offline/runtime.js.map +7 -0
- package/dist/calendar/offline/support.js +41 -0
- package/dist/calendar/offline/support.js.map +7 -0
- package/dist/calendar/support.js +34 -0
- package/dist/calendar/support.js.map +7 -0
- package/dist/calls/actions.js +226 -0
- package/dist/calls/actions.js.map +7 -0
- package/dist/calls/events.js +138 -0
- package/dist/calls/events.js.map +7 -0
- package/dist/calls/gate.js +19 -0
- package/dist/calls/gate.js.map +7 -0
- package/dist/calls/hooks.js +115 -0
- package/dist/calls/hooks.js.map +7 -0
- package/dist/calls/in-call-chat.js +132 -0
- package/dist/calls/in-call-chat.js.map +7 -0
- package/dist/calls/index.js +24 -0
- package/dist/calls/index.js.map +7 -0
- package/dist/calls/keys.js +17 -0
- package/dist/calls/keys.js.map +7 -0
- package/dist/calls/livekit/index.js +6 -958
- package/dist/calls/livekit/index.js.map +7 -1
- package/dist/calls/livekit/room.js +98 -0
- package/dist/calls/livekit/room.js.map +7 -0
- package/dist/calls/livekit/useCallRecorder.js +219 -0
- package/dist/calls/livekit/useCallRecorder.js.map +7 -0
- package/dist/calls/livekit/useCallTranscriber.js +309 -0
- package/dist/calls/livekit/useCallTranscriber.js.map +7 -0
- package/dist/calls/livekit/useHostMuteNotice.js +29 -0
- package/dist/calls/livekit/useHostMuteNotice.js.map +7 -0
- package/dist/calls/livekit/useInCallChat.js +161 -0
- package/dist/calls/livekit/useInCallChat.js.map +7 -0
- package/dist/calls/livekit/useWebinar.js +239 -0
- package/dist/calls/livekit/useWebinar.js.map +7 -0
- package/dist/calls/meeting-chat.js +149 -0
- package/dist/calls/meeting-chat.js.map +7 -0
- package/dist/calls/moderation.js +50 -0
- package/dist/calls/moderation.js.map +7 -0
- package/dist/calls/open-meeting-chat.js +29 -0
- package/dist/calls/open-meeting-chat.js.map +7 -0
- package/dist/calls/read-only.js +24 -0
- package/dist/calls/read-only.js.map +7 -0
- package/dist/calls/recording-media.js +218 -0
- package/dist/calls/recording-media.js.map +7 -0
- package/dist/calls/recording-playback.js +260 -0
- package/dist/calls/recording-playback.js.map +7 -0
- package/dist/calls/recording.js +268 -0
- package/dist/calls/recording.js.map +7 -0
- package/dist/calls/save-to-thread.js +80 -0
- package/dist/calls/save-to-thread.js.map +7 -0
- package/dist/calls/session.js +134 -0
- package/dist/calls/session.js.map +7 -0
- package/dist/calls/transcript-format.js +147 -0
- package/dist/calls/transcript-format.js.map +7 -0
- package/dist/calls/transcription.js +101 -0
- package/dist/calls/transcription.js.map +7 -0
- package/dist/calls/webinar.js +71 -0
- package/dist/calls/webinar.js.map +7 -0
- package/dist/charge-watch.js +71 -0
- package/dist/charge-watch.js.map +7 -0
- package/dist/chat/ChatBubble.js +146 -0
- package/dist/chat/ChatBubble.js.map +7 -0
- package/dist/chat/ConversationScope.js +30 -0
- package/dist/chat/ConversationScope.js.map +7 -0
- package/dist/chat/active-config.js +20 -0
- package/dist/chat/active-config.js.map +7 -0
- package/dist/chat/agent-chat-owner.js +25 -0
- package/dist/chat/agent-chat-owner.js.map +7 -0
- package/dist/chat/chat-artifacts.js +64 -0
- package/dist/chat/chat-artifacts.js.map +7 -0
- package/dist/chat/citations.js +32 -0
- package/dist/chat/citations.js.map +7 -0
- package/dist/chat/config-model.js +10 -0
- package/dist/chat/config-model.js.map +7 -0
- package/dist/chat/conversation-cache.js +676 -0
- package/dist/chat/conversation-cache.js.map +7 -0
- package/dist/chat/conversation-events.js +57 -0
- package/dist/chat/conversation-events.js.map +7 -0
- package/dist/chat/conversation-mentions.js +58 -0
- package/dist/chat/conversation-mentions.js.map +7 -0
- package/dist/chat/conversation-workspace.js +58 -0
- package/dist/chat/conversation-workspace.js.map +7 -0
- package/dist/chat/mentions.js +116 -0
- package/dist/chat/mentions.js.map +7 -0
- package/dist/chat/open-document.js +106 -0
- package/dist/chat/open-document.js.map +7 -0
- package/dist/chat/orphaned.js +44 -0
- package/dist/chat/orphaned.js.map +7 -0
- package/dist/chat/pendingFirstTurn.js +30 -0
- package/dist/chat/pendingFirstTurn.js.map +7 -0
- package/dist/chat/reply-target.js +12 -0
- package/dist/chat/reply-target.js.map +7 -0
- package/dist/chat/run-finished.js +28 -0
- package/dist/chat/run-finished.js.map +7 -0
- package/dist/chat/run-state.js +91 -0
- package/dist/chat/run-state.js.map +7 -0
- package/dist/chat/stream-handlers.js +419 -0
- package/dist/chat/stream-handlers.js.map +7 -0
- package/dist/chat/thread-binding.js +76 -0
- package/dist/chat/thread-binding.js.map +7 -0
- package/dist/chat/thread-document.js +53 -0
- package/dist/chat/thread-document.js.map +7 -0
- package/dist/chat/turn-control.js +79 -0
- package/dist/chat/turn-control.js.map +7 -0
- package/dist/chat/useAgentRunControl.js +36 -0
- package/dist/chat/useAgentRunControl.js.map +7 -0
- package/dist/chat/useAnswerAgentQuestion.js +19 -0
- package/dist/chat/useAnswerAgentQuestion.js.map +7 -0
- package/dist/chat/useAskAgain.js +32 -0
- package/dist/chat/useAskAgain.js.map +7 -0
- package/dist/chat/useAutoSendDraft.js +17 -0
- package/dist/chat/useAutoSendDraft.js.map +7 -0
- package/dist/chat/useBranchNavigation.js +97 -0
- package/dist/chat/useBranchNavigation.js.map +7 -0
- package/dist/chat/useConnectRunStream.js +169 -0
- package/dist/chat/useConnectRunStream.js.map +7 -0
- package/dist/chat/useConversation.js +431 -0
- package/dist/chat/useConversation.js.map +7 -0
- package/dist/chat/useConversationActions.js +662 -0
- package/dist/chat/useConversationActions.js.map +7 -0
- package/dist/chat/useConversationData.js +143 -0
- package/dist/chat/useConversationData.js.map +7 -0
- package/dist/chat/useConversationDocuments.js +41 -0
- package/dist/chat/useConversationDocuments.js.map +7 -0
- package/dist/chat/useConversationSettings.js +78 -0
- package/dist/chat/useConversationSettings.js.map +7 -0
- package/dist/chat/useConversationTurn.js +31 -0
- package/dist/chat/useConversationTurn.js.map +7 -0
- package/dist/chat/useConversationWorkspace.js +12 -0
- package/dist/chat/useConversationWorkspace.js.map +7 -0
- package/dist/chat/useDeleteMessage.js +15 -0
- package/dist/chat/useDeleteMessage.js.map +7 -0
- package/dist/chat/useDocumentAutoAdd.js +73 -0
- package/dist/chat/useDocumentAutoAdd.js.map +7 -0
- package/dist/chat/useMessageTimer.js +39 -0
- package/dist/chat/useMessageTimer.js.map +7 -0
- package/dist/chat/useThinkingContent.js +67 -0
- package/dist/chat/useThinkingContent.js.map +7 -0
- package/dist/chat/useThreadDocument.js +61 -0
- package/dist/chat/useThreadDocument.js.map +7 -0
- package/dist/chat/workflow-run-titles.js +50 -0
- package/dist/chat/workflow-run-titles.js.map +7 -0
- package/dist/{chunk-Z3W4XFWB.cjs → chunk-C72FSQUE.cjs} +3 -3
- package/dist/{chunk-Z3W4XFWB.cjs.map → chunk-C72FSQUE.cjs.map} +1 -1
- package/dist/{chunk-LBAG7KL7.cjs → chunk-FQVNZCTD.cjs} +3 -3
- package/dist/{chunk-LBAG7KL7.cjs.map → chunk-FQVNZCTD.cjs.map} +1 -1
- package/dist/{chunk-DI5KSVKY.cjs → chunk-UDDJIUHJ.cjs} +3 -3
- package/dist/{chunk-DI5KSVKY.cjs.map → chunk-UDDJIUHJ.cjs.map} +1 -1
- package/dist/config/config-hooks.js +209 -0
- package/dist/config/config-hooks.js.map +7 -0
- package/dist/connectivity.js +72 -0
- package/dist/connectivity.js.map +7 -0
- package/dist/connectors/hooks.js +263 -0
- package/dist/connectors/hooks.js.map +7 -0
- package/dist/connectors/index.js +28 -0
- package/dist/connectors/index.js.map +7 -0
- package/dist/contacts.js +100 -0
- package/dist/contacts.js.map +7 -0
- package/dist/conversation-list.js +65 -0
- package/dist/conversation-list.js.map +7 -0
- package/dist/databases.js +195 -0
- package/dist/databases.js.map +7 -0
- package/dist/datasets/aggregate.js +281 -0
- package/dist/datasets/aggregate.js.map +7 -0
- package/dist/datasets/index.js +122 -0
- package/dist/datasets/index.js.map +7 -0
- package/dist/datasets/members.js +27 -0
- package/dist/datasets/members.js.map +7 -0
- package/dist/datasets/panel.js +44 -0
- package/dist/datasets/panel.js.map +7 -0
- package/dist/datasets/registry.js +47 -0
- package/dist/datasets/registry.js.map +7 -0
- package/dist/datasets/rows-source.js +44 -0
- package/dist/datasets/rows-source.js.map +7 -0
- package/dist/datasets/sources/activity.js +83 -0
- package/dist/datasets/sources/activity.js.map +7 -0
- package/dist/datasets/sources/conversations.js +74 -0
- package/dist/datasets/sources/conversations.js.map +7 -0
- package/dist/datasets/sources/database.js +209 -0
- package/dist/datasets/sources/database.js.map +7 -0
- package/dist/datasets/sources/documents.js +93 -0
- package/dist/datasets/sources/documents.js.map +7 -0
- package/dist/datasets/sources/facts.js +56 -0
- package/dist/datasets/sources/facts.js.map +7 -0
- package/dist/datasets/sources/projects.js +117 -0
- package/dist/datasets/sources/projects.js.map +7 -0
- package/dist/datasets/sources/tags.js +67 -0
- package/dist/datasets/sources/tags.js.map +7 -0
- package/dist/datasets/sources/usage.js +268 -0
- package/dist/datasets/sources/usage.js.map +7 -0
- package/dist/datasets/sources/workflows.js +91 -0
- package/dist/datasets/sources/workflows.js.map +7 -0
- package/dist/datasets/sources/workspaces.js +67 -0
- package/dist/datasets/sources/workspaces.js.map +7 -0
- package/dist/datasets/store.js +194 -0
- package/dist/datasets/store.js.map +7 -0
- package/dist/datasets/types.js +14 -0
- package/dist/datasets/types.js.map +7 -0
- package/dist/directmessages/ConversationList.js +148 -0
- package/dist/directmessages/ConversationList.js.map +7 -0
- package/dist/directmessages/DateSeparator.js +8 -0
- package/dist/directmessages/DateSeparator.js.map +7 -0
- package/dist/directmessages/DmAvatar.js +29 -0
- package/dist/directmessages/DmAvatar.js.map +7 -0
- package/dist/directmessages/DmComposer.js +201 -0
- package/dist/directmessages/DmComposer.js.map +7 -0
- package/dist/directmessages/arrivals.js +29 -0
- package/dist/directmessages/arrivals.js.map +7 -0
- package/dist/directmessages/chat-cache.js +192 -0
- package/dist/directmessages/chat-cache.js.map +7 -0
- package/dist/directmessages/grouping.js +26 -0
- package/dist/directmessages/grouping.js.map +7 -0
- package/dist/directmessages/index.js +81 -0
- package/dist/directmessages/index.js.map +7 -0
- package/dist/directmessages/useChats.js +266 -0
- package/dist/directmessages/useChats.js.map +7 -0
- package/dist/directmessages/utils.js +23 -0
- package/dist/directmessages/utils.js.map +7 -0
- package/dist/document-tools/can-annotate.js +7 -0
- package/dist/document-tools/can-annotate.js.map +7 -0
- package/dist/document-tools/core.cjs +80 -80
- package/dist/document-tools/core.js +218 -12
- package/dist/document-tools/core.js.map +7 -1
- package/dist/document-tools/document-pdf.js +76 -0
- package/dist/document-tools/document-pdf.js.map +7 -0
- package/dist/document-tools/environment.js +136 -0
- package/dist/document-tools/environment.js.map +7 -0
- package/dist/document-tools/file-shares.js +112 -0
- package/dist/document-tools/file-shares.js.map +7 -0
- package/dist/document-tools/frozen-copy.js +27 -0
- package/dist/document-tools/frozen-copy.js.map +7 -0
- package/dist/document-tools/index.cjs +80 -80
- package/dist/document-tools/index.js +26 -148
- package/dist/document-tools/index.js.map +7 -1
- package/dist/document-tools/markup-download.js +51 -0
- package/dist/document-tools/markup-download.js.map +7 -0
- package/dist/document-tools/markup-store.js +138 -0
- package/dist/document-tools/markup-store.js.map +7 -0
- package/dist/document-tools/markup-transfer.js +88 -0
- package/dist/document-tools/markup-transfer.js.map +7 -0
- package/dist/document-tools/production.js +147 -0
- package/dist/document-tools/production.js.map +7 -0
- package/dist/document-tools/saved-signature.js +90 -0
- package/dist/document-tools/saved-signature.js.map +7 -0
- package/dist/document-tools/signature-requests.js +310 -0
- package/dist/document-tools/signature-requests.js.map +7 -0
- package/dist/document-tools/signing.js +127 -0
- package/dist/document-tools/signing.js.map +7 -0
- package/dist/document-tools/useDocumentBytes.js +38 -0
- package/dist/document-tools/useDocumentBytes.js.map +7 -0
- package/dist/document-tools/useDocumentMarkup.js +154 -0
- package/dist/document-tools/useDocumentMarkup.js.map +7 -0
- package/dist/document-tools/useIsOnline.js +13 -0
- package/dist/document-tools/useIsOnline.js.map +7 -0
- package/dist/document-tools/verification.js +60 -0
- package/dist/document-tools/verification.js.map +7 -0
- package/dist/documents/DocumentReview.js +220 -0
- package/dist/documents/DocumentReview.js.map +7 -0
- package/dist/documents/DraftTitleControls.js +41 -0
- package/dist/documents/DraftTitleControls.js.map +7 -0
- package/dist/documents/InlineMicButton.js +90 -0
- package/dist/documents/InlineMicButton.js.map +7 -0
- package/dist/documents/MicRecordingOverlay.js +29 -0
- package/dist/documents/MicRecordingOverlay.js.map +7 -0
- package/dist/documents/MicWaveformIndicator.js +68 -0
- package/dist/documents/MicWaveformIndicator.js.map +7 -0
- package/dist/documents/PhotoCapture.js +120 -0
- package/dist/documents/PhotoCapture.js.map +7 -0
- package/dist/documents/VideoCapture.js +129 -0
- package/dist/documents/VideoCapture.js.map +7 -0
- package/dist/documents/VoiceNoteRecorder.js +166 -0
- package/dist/documents/VoiceNoteRecorder.js.map +7 -0
- package/dist/documents/audio-segmenter.js +63 -0
- package/dist/documents/audio-segmenter.js.map +7 -0
- package/dist/documents/capture-frame.js +21 -0
- package/dist/documents/capture-frame.js.map +7 -0
- package/dist/documents/chunked-recorder.js +190 -0
- package/dist/documents/chunked-recorder.js.map +7 -0
- package/dist/documents/document-download.js +53 -0
- package/dist/documents/document-download.js.map +7 -0
- package/dist/documents/document-fields.js +109 -0
- package/dist/documents/document-fields.js.map +7 -0
- package/dist/documents/documents-cache.js +110 -0
- package/dist/documents/documents-cache.js.map +7 -0
- package/dist/documents/documents-data.js +128 -0
- package/dist/documents/documents-data.js.map +7 -0
- package/dist/documents/documents-loader.js +113 -0
- package/dist/documents/documents-loader.js.map +7 -0
- package/dist/documents/documents-writes.js +448 -0
- package/dist/documents/documents-writes.js.map +7 -0
- package/dist/documents/format-elapsed.js +10 -0
- package/dist/documents/format-elapsed.js.map +7 -0
- package/dist/documents/has-video-track.js +26 -0
- package/dist/documents/has-video-track.js.map +7 -0
- package/dist/documents/index.js +266 -0
- package/dist/documents/index.js.map +7 -0
- package/dist/documents/media-error.js +18 -0
- package/dist/documents/media-error.js.map +7 -0
- package/dist/documents/offline-documents.js +160 -0
- package/dist/documents/offline-documents.js.map +7 -0
- package/dist/documents/pending-sync.js +210 -0
- package/dist/documents/pending-sync.js.map +7 -0
- package/dist/documents/processing-live.js +122 -0
- package/dist/documents/processing-live.js.map +7 -0
- package/dist/documents/processing-order.js +59 -0
- package/dist/documents/processing-order.js.map +7 -0
- package/dist/documents/processing-settle.js +21 -0
- package/dist/documents/processing-settle.js.map +7 -0
- package/dist/documents/related-documents.js +133 -0
- package/dist/documents/related-documents.js.map +7 -0
- package/dist/documents/support.js +29 -0
- package/dist/documents/support.js.map +7 -0
- package/dist/documents/upload-files.js +169 -0
- package/dist/documents/upload-files.js.map +7 -0
- package/dist/documents/useAudioRecorder.js +315 -0
- package/dist/documents/useAudioRecorder.js.map +7 -0
- package/dist/documents/useCameraStream.js +35 -0
- package/dist/documents/useCameraStream.js.map +7 -0
- package/dist/documents/useDocumentThumbnails.js +71 -0
- package/dist/documents/useDocumentThumbnails.js.map +7 -0
- package/dist/documents/useDownloadDocuments.js +90 -0
- package/dist/documents/useDownloadDocuments.js.map +7 -0
- package/dist/documents/usePassageQuotes.js +37 -0
- package/dist/documents/usePassageQuotes.js.map +7 -0
- package/dist/documents/useUploadFiles.js +165 -0
- package/dist/documents/useUploadFiles.js.map +7 -0
- package/dist/documents/useUploadFromUrls.js +63 -0
- package/dist/documents/useUploadFromUrls.js.map +7 -0
- package/dist/documents/useVideoRecorder.js +62 -0
- package/dist/documents/useVideoRecorder.js.map +7 -0
- package/dist/entities/AgentMarkers.js +61 -0
- package/dist/entities/AgentMarkers.js.map +7 -0
- package/dist/entities/DocumentEntity.js +125 -0
- package/dist/entities/DocumentEntity.js.map +7 -0
- package/dist/entities/EntityPill.js +250 -0
- package/dist/entities/EntityPill.js.map +7 -0
- package/dist/entities/ProjectEntity.js +61 -0
- package/dist/entities/ProjectEntity.js.map +7 -0
- package/dist/entities/ShieldIcon.js +49 -0
- package/dist/entities/ShieldIcon.js.map +7 -0
- package/dist/entities/TagEntity.js +79 -0
- package/dist/entities/TagEntity.js.map +7 -0
- package/dist/entities/ThreadVisibilityIcon.js +15 -0
- package/dist/entities/ThreadVisibilityIcon.js.map +7 -0
- package/dist/entities/UserEntity.js +211 -0
- package/dist/entities/UserEntity.js.map +7 -0
- package/dist/entities/VerifiedBadge.js +19 -0
- package/dist/entities/VerifiedBadge.js.map +7 -0
- package/dist/entities/agent-avatar-colors.js +26 -0
- package/dist/entities/agent-avatar-colors.js.map +7 -0
- package/dist/entities/colors.js +64 -0
- package/dist/entities/colors.js.map +7 -0
- package/dist/entities/file-type.js +151 -0
- package/dist/entities/file-type.js.map +7 -0
- package/dist/entities/index.js +100 -0
- package/dist/entities/index.js.map +7 -0
- package/dist/entities/media-type.js +61 -0
- package/dist/entities/media-type.js.map +7 -0
- package/dist/entities/registry.js +385 -0
- package/dist/entities/registry.js.map +7 -0
- package/dist/entities/status.js +43 -0
- package/dist/entities/status.js.map +7 -0
- package/dist/entities/tag-kinds.js +23 -0
- package/dist/entities/tag-kinds.js.map +7 -0
- package/dist/entities/tag-types.js +44 -0
- package/dist/entities/tag-types.js.map +7 -0
- package/dist/entities/vocabulary.js +12 -0
- package/dist/entities/vocabulary.js.map +7 -0
- package/dist/entity-extraction.js +25 -0
- package/dist/entity-extraction.js.map +7 -0
- package/dist/facts-search.js +57 -0
- package/dist/facts-search.js.map +7 -0
- package/dist/facts.js +69 -0
- package/dist/facts.js.map +7 -0
- package/dist/hooks.js +320 -0
- package/dist/hooks.js.map +7 -0
- package/dist/host/ArbiHost.js +24 -0
- package/dist/host/ArbiHost.js.map +7 -0
- package/dist/host/assistant-copy.js +54 -0
- package/dist/host/assistant-copy.js.map +7 -0
- package/dist/host/config.js +9 -0
- package/dist/host/config.js.map +7 -0
- package/dist/host/context.js +10 -0
- package/dist/host/context.js.map +7 -0
- package/dist/host/features.js +144 -0
- package/dist/host/features.js.map +7 -0
- package/dist/host/index.js +12 -0
- package/dist/host/index.js.map +7 -0
- package/dist/{chunk-DPYBZDJB.js → host/merge.js} +7 -7
- package/dist/host/merge.js.map +7 -0
- package/dist/house-template.js +40 -0
- package/dist/house-template.js.map +7 -0
- package/dist/icons/AppleIcon.js +25 -0
- package/dist/icons/AppleIcon.js.map +7 -0
- package/dist/icons/ArbiBotHeadIcon.js +46 -0
- package/dist/icons/ArbiBotHeadIcon.js.map +7 -0
- package/dist/icons/ArbiIcon.js +24 -0
- package/dist/icons/ArbiIcon.js.map +7 -0
- package/dist/icons/AudIcon.js +56 -0
- package/dist/icons/AudIcon.js.map +7 -0
- package/dist/icons/ClaudeIcon.js +28 -0
- package/dist/icons/ClaudeIcon.js.map +7 -0
- package/dist/icons/DocIcon.js +56 -0
- package/dist/icons/DocIcon.js.map +7 -0
- package/dist/icons/EmlIcon.js +57 -0
- package/dist/icons/EmlIcon.js.map +7 -0
- package/dist/icons/FireworksIcon.js +47 -0
- package/dist/icons/FireworksIcon.js.map +7 -0
- package/dist/icons/GeminiIcon.js +37 -0
- package/dist/icons/GeminiIcon.js.map +7 -0
- package/dist/icons/GitHubIcon.js +32 -0
- package/dist/icons/GitHubIcon.js.map +7 -0
- package/dist/icons/GoogleIcon.js +53 -0
- package/dist/icons/GoogleIcon.js.map +7 -0
- package/dist/icons/HtmlIcon.js +56 -0
- package/dist/icons/HtmlIcon.js.map +7 -0
- package/dist/icons/ImgIcon.js +56 -0
- package/dist/icons/ImgIcon.js.map +7 -0
- package/dist/icons/LinkedInIcon.js +25 -0
- package/dist/icons/LinkedInIcon.js.map +7 -0
- package/dist/icons/OpenAIIcon.js +28 -0
- package/dist/icons/OpenAIIcon.js.map +7 -0
- package/dist/icons/PdfIcon.js +56 -0
- package/dist/icons/PdfIcon.js.map +7 -0
- package/dist/icons/ProviderIcon.js +42 -0
- package/dist/icons/ProviderIcon.js.map +7 -0
- package/dist/icons/TxtIcon.js +56 -0
- package/dist/icons/TxtIcon.js.map +7 -0
- package/dist/icons/VidIcon.js +56 -0
- package/dist/icons/VidIcon.js.map +7 -0
- package/dist/icons/XlsIcon.js +56 -0
- package/dist/icons/XlsIcon.js.map +7 -0
- package/dist/icons/arbi-mark.js +5 -0
- package/dist/icons/arbi-mark.js.map +7 -0
- package/dist/icons/colors.js +31 -0
- package/dist/icons/colors.js.map +7 -0
- package/dist/icons/file-type.js +105 -0
- package/dist/icons/file-type.js.map +7 -0
- package/dist/icons/index.js +55 -0
- package/dist/icons/index.js.map +7 -0
- package/dist/imagecrop/ImageCropModal.js +56 -0
- package/dist/imagecrop/ImageCropModal.js.map +7 -0
- package/dist/imagecrop/ImageCropper.js +100 -0
- package/dist/imagecrop/ImageCropper.js.map +7 -0
- package/dist/imagecrop/cropImage.js +43 -0
- package/dist/imagecrop/cropImage.js.map +7 -0
- package/dist/imagecrop/index.js +13 -0
- package/dist/imagecrop/index.js.map +7 -0
- package/dist/index.cjs +282 -282
- package/dist/index.js +702 -17116
- package/dist/index.js.map +7 -1
- package/dist/{chunk-SSXFVWCT.js → lazy-chunk.js} +8 -8
- package/dist/lazy-chunk.js.map +7 -0
- package/dist/lib/collision-padding.js +13 -0
- package/dist/lib/collision-padding.js.map +7 -0
- package/dist/lib/format-friendly-date.js +55 -0
- package/dist/lib/format-friendly-date.js.map +7 -0
- package/dist/lib/format-relative-time.js +52 -0
- package/dist/lib/format-relative-time.js.map +7 -0
- package/dist/lib/markdown-to-text.js +35 -0
- package/dist/lib/markdown-to-text.js.map +7 -0
- package/dist/lib/toast-interaction.js +9 -0
- package/dist/lib/toast-interaction.js.map +7 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +7 -0
- package/dist/mail/client.js +103 -0
- package/dist/mail/client.js.map +7 -0
- package/dist/mail/document-attachment.js +38 -0
- package/dist/mail/document-attachment.js.map +7 -0
- package/dist/mail/filing.js +132 -0
- package/dist/mail/filing.js.map +7 -0
- package/dist/mail/hooks.js +393 -0
- package/dist/mail/hooks.js.map +7 -0
- package/dist/mail/index.js +120 -0
- package/dist/mail/index.js.map +7 -0
- package/dist/mail/offline/changes.js +258 -0
- package/dist/mail/offline/changes.js.map +7 -0
- package/dist/mail/offline/confirm-sign-out.js +37 -0
- package/dist/mail/offline/confirm-sign-out.js.map +7 -0
- package/dist/mail/offline/crypto.js +26 -0
- package/dist/mail/offline/crypto.js.map +7 -0
- package/dist/mail/offline/drafts.js +69 -0
- package/dist/mail/offline/drafts.js.map +7 -0
- package/dist/mail/offline/hooks.js +104 -0
- package/dist/mail/offline/hooks.js.map +7 -0
- package/dist/mail/offline/index.js +48 -0
- package/dist/mail/offline/index.js.map +7 -0
- package/dist/mail/offline/live.js +233 -0
- package/dist/mail/offline/live.js.map +7 -0
- package/dist/mail/offline/mailbox.js +191 -0
- package/dist/mail/offline/mailbox.js.map +7 -0
- package/dist/mail/offline/outbox.js +167 -0
- package/dist/mail/offline/outbox.js.map +7 -0
- package/dist/mail/offline/reads.js +159 -0
- package/dist/mail/offline/reads.js.map +7 -0
- package/dist/mail/offline/runtime.js +100 -0
- package/dist/mail/offline/runtime.js.map +7 -0
- package/dist/mail/offline/settings.js +84 -0
- package/dist/mail/offline/settings.js.map +7 -0
- package/dist/mail/offline/store.js +29 -0
- package/dist/mail/offline/store.js.map +7 -0
- package/dist/mail/offline/sync.js +251 -0
- package/dist/mail/offline/sync.js.map +7 -0
- package/dist/mail/offline/wipe.js +19 -0
- package/dist/mail/offline/wipe.js.map +7 -0
- package/dist/mail/thread-keys.js +53 -0
- package/dist/mail/thread-keys.js.map +7 -0
- package/dist/mail/threads.js +71 -0
- package/dist/mail/threads.js.map +7 -0
- package/dist/mail/useMailClient.js +42 -0
- package/dist/mail/useMailClient.js.map +7 -0
- package/dist/model-connections.js +58 -0
- package/dist/model-connections.js.map +7 -0
- package/dist/notifications/ActivityFeed.js +70 -0
- package/dist/notifications/ActivityFeed.js.map +7 -0
- package/dist/notifications/NotificationBell.js +200 -0
- package/dist/notifications/NotificationBell.js.map +7 -0
- package/dist/notifications/Toaster.js +24 -0
- package/dist/notifications/Toaster.js.map +7 -0
- package/dist/notifications/activity-types.js +65 -0
- package/dist/notifications/activity-types.js.map +7 -0
- package/dist/notifications/bell.js +24 -0
- package/dist/notifications/bell.js.map +7 -0
- package/dist/notifications/calendar-notifications.js +79 -0
- package/dist/notifications/calendar-notifications.js.map +7 -0
- package/dist/notifications/index.js +108 -0
- package/dist/notifications/index.js.map +7 -0
- package/dist/notifications/live.js +28 -0
- package/dist/notifications/live.js.map +7 -0
- package/dist/notifications/notification-types.js +127 -0
- package/dist/notifications/notification-types.js.map +7 -0
- package/dist/{chunk-BF5KW5ZI.js → notifications/notify-store.js} +24 -74
- package/dist/notifications/notify-store.js.map +7 -0
- package/dist/notifications/server-notifications.js +452 -0
- package/dist/notifications/server-notifications.js.map +7 -0
- package/dist/notifications/useNotifications.js +34 -0
- package/dist/notifications/useNotifications.js.map +7 -0
- package/dist/offline-store/network.js +11 -0
- package/dist/offline-store/network.js.map +7 -0
- package/dist/offline-store/store.js +136 -0
- package/dist/offline-store/store.js.map +7 -0
- package/dist/offline-store/wipe.js +8 -0
- package/dist/offline-store/wipe.js.map +7 -0
- package/dist/offline.js +58 -0
- package/dist/offline.js.map +7 -0
- package/dist/people.js +122 -0
- package/dist/people.js.map +7 -0
- package/dist/projects.js +30 -0
- package/dist/projects.js.map +7 -0
- package/dist/query-client.js +63 -0
- package/dist/query-client.js.map +7 -0
- package/dist/{chunk-ZM6N7YZH.js → query-keys.js} +18 -31
- package/dist/query-keys.js.map +7 -0
- package/dist/query-persist.js +66 -0
- package/dist/query-persist.js.map +7 -0
- package/dist/queued-writes.js +59 -0
- package/dist/queued-writes.js.map +7 -0
- package/dist/remote-control.js +67 -0
- package/dist/remote-control.js.map +7 -0
- package/dist/search/index.js +23 -0
- package/dist/search/index.js.map +7 -0
- package/dist/search/session.js +58 -0
- package/dist/search/session.js.map +7 -0
- package/dist/search/useSemanticSearch.js +82 -0
- package/dist/search/useSemanticSearch.js.map +7 -0
- package/dist/session/chat.js +512 -0
- package/dist/session/chat.js.map +7 -0
- package/dist/session/documents.js +196 -0
- package/dist/session/documents.js.map +7 -0
- package/dist/session/drafts.js +103 -0
- package/dist/session/drafts.js.map +7 -0
- package/dist/session/index.js +123 -0
- package/dist/session/index.js.map +7 -0
- package/dist/session/layout.js +339 -0
- package/dist/session/layout.js.map +7 -0
- package/dist/session/persist.js +106 -0
- package/dist/session/persist.js.map +7 -0
- package/dist/session/session-hooks.js +53 -0
- package/dist/session/session-hooks.js.map +7 -0
- package/dist/session/signed-in.js +36 -0
- package/dist/session/signed-in.js.map +7 -0
- package/dist/session/store.js +166 -0
- package/dist/session/store.js.map +7 -0
- package/dist/session/thread-tabs.js +121 -0
- package/dist/session/thread-tabs.js.map +7 -0
- package/dist/session/ui-state-storage.js +76 -0
- package/dist/session/ui-state-storage.js.map +7 -0
- package/dist/session/workspace.js +77 -0
- package/dist/session/workspace.js.map +7 -0
- package/dist/shell/index.cjs +37 -37
- package/dist/shell/index.js +43 -10
- package/dist/shell/index.js.map +7 -1
- package/dist/skill-pack.js +111 -0
- package/dist/skill-pack.js.map +7 -0
- package/dist/storage.js +186 -0
- package/dist/storage.js.map +7 -0
- package/dist/support/index.js +35 -0
- package/dist/support/index.js.map +7 -0
- package/dist/tags.js +204 -0
- package/dist/tags.js.map +7 -0
- package/dist/ui/DebouncedInput.js +109 -0
- package/dist/ui/DebouncedInput.js.map +7 -0
- package/dist/ui/DictateContext.js +8 -0
- package/dist/ui/DictateContext.js.map +7 -0
- package/dist/ui/IconToggle.js +79 -0
- package/dist/ui/IconToggle.js.map +7 -0
- package/dist/ui/VerifiedToggle.js +38 -0
- package/dist/ui/VerifiedToggle.js.map +7 -0
- package/dist/ui/VisibilityToggle.js +103 -0
- package/dist/ui/VisibilityToggle.js.map +7 -0
- package/dist/ui/avatar.js +40 -0
- package/dist/ui/avatar.js.map +7 -0
- package/dist/ui/badge.js +28 -0
- package/dist/ui/badge.js.map +7 -0
- package/dist/ui/button.js +48 -0
- package/dist/ui/button.js.map +7 -0
- package/dist/ui/card.js +90 -0
- package/dist/ui/card.js.map +7 -0
- package/dist/ui/checkbox.js +22 -0
- package/dist/ui/checkbox.js.map +7 -0
- package/dist/ui/collapsible.js +10 -0
- package/dist/ui/collapsible.js.map +7 -0
- package/dist/ui/command.js +103 -0
- package/dist/ui/command.js.map +7 -0
- package/dist/{chunk-YNNAJJ5Z.js → ui/dialog.js} +30 -68
- package/dist/ui/dialog.js.map +7 -0
- package/dist/{chunk-47CCGUWR.js → ui/dropdown-menu.js} +40 -45
- package/dist/ui/dropdown-menu.js.map +7 -0
- package/dist/ui/hover-card.js +36 -0
- package/dist/ui/hover-card.js.map +7 -0
- package/dist/ui/index.cjs +154 -154
- package/dist/ui/index.js +290 -10
- package/dist/ui/index.js.map +7 -1
- package/dist/ui/input.js +65 -0
- package/dist/ui/input.js.map +7 -0
- package/dist/ui/label.js +16 -0
- package/dist/ui/label.js.map +7 -0
- package/dist/ui/mark-menu.js +300 -0
- package/dist/ui/mark-menu.js.map +7 -0
- package/dist/ui/popover.js +40 -0
- package/dist/ui/popover.js.map +7 -0
- package/dist/ui/portal-container.js +17 -0
- package/dist/ui/portal-container.js.map +7 -0
- package/dist/ui/progress.js +24 -0
- package/dist/ui/progress.js.map +7 -0
- package/dist/ui/radio-group.js +29 -0
- package/dist/ui/radio-group.js.map +7 -0
- package/dist/ui/scroll-area.js +39 -0
- package/dist/ui/scroll-area.js.map +7 -0
- package/dist/ui/select.js +130 -0
- package/dist/ui/select.js.map +7 -0
- package/dist/ui/separator.js +23 -0
- package/dist/ui/separator.js.map +7 -0
- package/dist/ui/slider.js +23 -0
- package/dist/ui/slider.js.map +7 -0
- package/dist/ui/switch.js +28 -0
- package/dist/ui/switch.js.map +7 -0
- package/dist/ui/table.js +75 -0
- package/dist/ui/table.js.map +7 -0
- package/dist/ui/tabs.js +48 -0
- package/dist/ui/tabs.js.map +7 -0
- package/dist/ui/textarea.js +63 -0
- package/dist/ui/textarea.js.map +7 -0
- package/dist/ui/toggle-group.js +43 -0
- package/dist/ui/toggle-group.js.map +7 -0
- package/dist/ui/toggle.js +40 -0
- package/dist/ui/toggle.js.map +7 -0
- package/dist/ui/tooltip.js +215 -0
- package/dist/ui/tooltip.js.map +7 -0
- package/dist/usage-metered.js +8 -0
- package/dist/usage-metered.js.map +7 -0
- package/dist/useArbi.js +16 -0
- package/dist/useArbi.js.map +7 -0
- package/dist/useInstallSkillPack.js +81 -0
- package/dist/useInstallSkillPack.js.map +7 -0
- package/dist/usermenu/UserMenu.js +188 -0
- package/dist/usermenu/UserMenu.js.map +7 -0
- package/dist/usermenu/index.js +5 -0
- package/dist/usermenu/index.js.map +7 -0
- package/dist/users/index.js +15 -0
- package/dist/users/index.js.map +7 -0
- package/dist/users/user-display.js +60 -0
- package/dist/users/user-display.js.map +7 -0
- package/dist/viewers/AudioViewer.js +23 -0
- package/dist/viewers/AudioViewer.js.map +7 -0
- package/dist/viewers/DocxViewer.js +81 -0
- package/dist/viewers/DocxViewer.js.map +7 -0
- package/dist/viewers/ImageViewer.js +31 -0
- package/dist/viewers/ImageViewer.js.map +7 -0
- package/dist/viewers/PdfViewer.js +19 -3
- package/dist/viewers/PdfViewer.js.map +7 -1
- package/dist/{PdfViewerImpl-TEBYF2QI.js → viewers/PdfViewerImpl.js} +25 -19
- package/dist/viewers/PdfViewerImpl.js.map +7 -0
- package/dist/viewers/VideoViewer.js +31 -0
- package/dist/viewers/VideoViewer.js.map +7 -0
- package/dist/viewers/XlsxViewer.js +102 -0
- package/dist/viewers/XlsxViewer.js.map +7 -0
- package/dist/viewers/index.js +61 -271
- package/dist/viewers/index.js.map +7 -1
- package/dist/viewers/page-scroll.js +59 -0
- package/dist/viewers/page-scroll.js.map +7 -0
- package/dist/viewers/pdf-viewer-constants.js +9 -0
- package/dist/viewers/pdf-viewer-constants.js.map +7 -0
- package/dist/{chunk-PTOP7OHG.js → viewers/pdfjs-polyfills.js} +5 -6
- package/dist/viewers/pdfjs-polyfills.js.map +7 -0
- package/dist/viewers/selection-runs.js +38 -0
- package/dist/viewers/selection-runs.js.map +7 -0
- package/dist/viewers/usePageIntersectionObserver.js +68 -0
- package/dist/viewers/usePageIntersectionObserver.js.map +7 -0
- package/dist/viewers/useProcessedChunks.js +58 -0
- package/dist/viewers/useProcessedChunks.js.map +7 -0
- package/dist/viewers/viewer-zoom.js +163 -0
- package/dist/viewers/viewer-zoom.js.map +7 -0
- package/dist/websocket/ArbiWebSocketProvider.js +207 -0
- package/dist/websocket/ArbiWebSocketProvider.js.map +7 -0
- package/dist/websocket/context.js +14 -0
- package/dist/websocket/context.js.map +7 -0
- package/dist/websocket/hooks.js +30 -0
- package/dist/websocket/hooks.js.map +7 -0
- package/dist/websocket/index.js +22 -0
- package/dist/websocket/index.js.map +7 -0
- package/dist/websocket/live-updates.js +38 -0
- package/dist/websocket/live-updates.js.map +7 -0
- package/dist/websocket/reconnect.js +13 -0
- package/dist/websocket/reconnect.js.map +7 -0
- package/dist/websocket/store.js +58 -0
- package/dist/websocket/store.js.map +7 -0
- package/dist/workforce.js +607 -0
- package/dist/workforce.js.map +7 -0
- package/dist/workspaces/access-request.js +35 -0
- package/dist/workspaces/access-request.js.map +7 -0
- package/dist/workspaces/archive.js +59 -0
- package/dist/workspaces/archive.js.map +7 -0
- package/dist/workspaces/current.js +20 -0
- package/dist/workspaces/current.js.map +7 -0
- package/dist/workspaces/delete-workspaces.js +15 -0
- package/dist/workspaces/delete-workspaces.js.map +7 -0
- package/dist/workspaces/export-archive.js +40 -0
- package/dist/workspaces/export-archive.js.map +7 -0
- package/dist/workspaces/index.js +99 -0
- package/dist/workspaces/index.js.map +7 -0
- package/dist/workspaces/settings.js +45 -0
- package/dist/workspaces/settings.js.map +7 -0
- package/dist/workspaces/shell-workspaces.js +49 -0
- package/dist/workspaces/shell-workspaces.js.map +7 -0
- package/dist/workspaces/switch.js +234 -0
- package/dist/workspaces/switch.js.map +7 -0
- package/dist/workspaces/transfer.js +170 -0
- package/dist/workspaces/transfer.js.map +7 -0
- package/dist/workspaces/useShellWorkspaces.js +86 -0
- package/dist/workspaces/useShellWorkspaces.js.map +7 -0
- package/dist/workspaces/workspace-users.js +65 -0
- package/dist/workspaces/workspace-users.js.map +7 -0
- package/package.json +4 -4
- package/dist/PdfViewerImpl-TEBYF2QI.js.map +0 -1
- package/dist/PdfViewerImpl.d-B28hLEuj.d.cts +0 -62
- package/dist/ProductionDialog.d-CpzslFn0.d.cts +0 -51
- package/dist/annotations/freeze/index.d.cts +0 -205
- package/dist/annotations/index.d.cts +0 -360
- package/dist/artifacts/index.d.cts +0 -476
- package/dist/artifacts/redline-core.d.cts +0 -39
- package/dist/bundle-YNOX7VIL.js +0 -5
- package/dist/bundle-YNOX7VIL.js.map +0 -1
- package/dist/bundle.d-BnCSbHy2.d.cts +0 -85
- package/dist/calls/livekit/index.d.cts +0 -280
- package/dist/chunk-47CCGUWR.js.map +0 -1
- package/dist/chunk-4FL3X3LA.js +0 -2057
- package/dist/chunk-4FL3X3LA.js.map +0 -1
- package/dist/chunk-6QNBSXCE.js +0 -271
- package/dist/chunk-6QNBSXCE.js.map +0 -1
- package/dist/chunk-74N436VK.js.map +0 -1
- package/dist/chunk-APZZQZ6P.js +0 -147
- package/dist/chunk-APZZQZ6P.js.map +0 -1
- package/dist/chunk-BF5KW5ZI.js.map +0 -1
- package/dist/chunk-DPYBZDJB.js.map +0 -1
- package/dist/chunk-DZKRL5H3.js +0 -2766
- package/dist/chunk-DZKRL5H3.js.map +0 -1
- package/dist/chunk-HDCRPPBW.js +0 -75
- package/dist/chunk-HDCRPPBW.js.map +0 -1
- package/dist/chunk-L2IPPTVC.js +0 -20
- package/dist/chunk-L2IPPTVC.js.map +0 -1
- package/dist/chunk-LSU4UPS5.js +0 -1011
- package/dist/chunk-LSU4UPS5.js.map +0 -1
- package/dist/chunk-NIKPG4PW.js +0 -1128
- package/dist/chunk-NIKPG4PW.js.map +0 -1
- package/dist/chunk-NNAJLY6B.js +0 -4974
- package/dist/chunk-NNAJLY6B.js.map +0 -1
- package/dist/chunk-OYPKKHXY.js +0 -559
- package/dist/chunk-OYPKKHXY.js.map +0 -1
- package/dist/chunk-PTOP7OHG.js.map +0 -1
- package/dist/chunk-QMY2JKBI.js +0 -246
- package/dist/chunk-QMY2JKBI.js.map +0 -1
- package/dist/chunk-SN5YV6FF.js +0 -11
- package/dist/chunk-SN5YV6FF.js.map +0 -1
- package/dist/chunk-SSXFVWCT.js.map +0 -1
- package/dist/chunk-T3USOSVN.js.map +0 -1
- package/dist/chunk-T4CLW3DN.js +0 -2560
- package/dist/chunk-T4CLW3DN.js.map +0 -1
- package/dist/chunk-UW2SGTI5.js.map +0 -1
- package/dist/chunk-VSCU7K4V.js.map +0 -1
- package/dist/chunk-WL2Y2T47.js.map +0 -1
- package/dist/chunk-WUTL62MC.js.map +0 -1
- package/dist/chunk-XWPLOFDN.js +0 -644
- package/dist/chunk-XWPLOFDN.js.map +0 -1
- package/dist/chunk-Y3MTRA7D.js +0 -97
- package/dist/chunk-Y3MTRA7D.js.map +0 -1
- package/dist/chunk-YNNAJJ5Z.js.map +0 -1
- package/dist/chunk-ZM6N7YZH.js.map +0 -1
- package/dist/document-tools/core.d.cts +0 -883
- package/dist/document-tools/index.d.cts +0 -90
- package/dist/index.d-LArLnpI8.d.cts +0 -2036
- package/dist/index.d-oR5FKZpJ.d.cts +0 -579
- package/dist/index.d.cts +0 -15923
- package/dist/lazy-chunk.d-B6YDLMKI.d.cts +0 -31
- package/dist/model.d-CNtRWKVK.d.cts +0 -110
- package/dist/query-keys.d-B1Am9tIF.d.cts +0 -337
- package/dist/shell/index.d.cts +0 -6
- package/dist/store.d-GADDvC7w.d.cts +0 -35
- package/dist/stored-markdown.d-Bp18vrbr.d.cts +0 -125
- package/dist/ui/index.d.cts +0 -26
- package/dist/useAudioRecorder.d-B9rlMI_E.d.cts +0 -778
- package/dist/viewers/PdfViewer.d.cts +0 -9
- package/dist/viewers/index.d.cts +0 -262
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
base64ToBytes,
|
|
3
|
+
bytesToBase64,
|
|
4
|
+
decryptFile,
|
|
5
|
+
encryptFile,
|
|
6
|
+
generateChatKey,
|
|
7
|
+
initSodium
|
|
8
|
+
} from "@arbidocs/client";
|
|
9
|
+
import { CallApiError, calls, documents } from "@arbidocs/sdk/browser";
|
|
10
|
+
import { chatByExtId } from "./in-call-chat.js";
|
|
11
|
+
import { ensureMeetingChat, meetingChatRefFrom } from "./meeting-chat.js";
|
|
12
|
+
const CALL_RECORDING_TOPIC = "arbi.recording";
|
|
13
|
+
const RECORDING_CHUNK_MS = 3e4;
|
|
14
|
+
const SPEAKER_AUDIO_BITS_PER_SECOND = 24e3;
|
|
15
|
+
const COMPOSITE_VIDEO_BITS_PER_SECOND = 5e5;
|
|
16
|
+
const COMPOSITE_AUDIO_BITS_PER_SECOND = 32e3;
|
|
17
|
+
function partOffsetMs(partStartedAt, recordingStartedAt) {
|
|
18
|
+
const start = typeof recordingStartedAt === "number" ? recordingStartedAt : Date.parse(recordingStartedAt);
|
|
19
|
+
if (!Number.isFinite(start)) return 0;
|
|
20
|
+
return Math.max(0, Math.round(partStartedAt - start));
|
|
21
|
+
}
|
|
22
|
+
function newTrackKey() {
|
|
23
|
+
return generateChatKey();
|
|
24
|
+
}
|
|
25
|
+
async function wrapTrackKey(fileKey, conversationKey) {
|
|
26
|
+
await initSodium();
|
|
27
|
+
return bytesToBase64(encryptFile(fileKey, conversationKey));
|
|
28
|
+
}
|
|
29
|
+
async function unwrapTrackKey(wrapped, conversationKey) {
|
|
30
|
+
await initSodium();
|
|
31
|
+
return decryptFile(base64ToBytes(wrapped), conversationKey);
|
|
32
|
+
}
|
|
33
|
+
async function encryptPart(bytes, fileKey) {
|
|
34
|
+
await initSodium();
|
|
35
|
+
return encryptFile(bytes, fileKey);
|
|
36
|
+
}
|
|
37
|
+
async function decryptPart(cipher, fileKey) {
|
|
38
|
+
await initSodium();
|
|
39
|
+
return decryptFile(cipher, fileKey);
|
|
40
|
+
}
|
|
41
|
+
async function conversationKeyForCall(arbi, queryClient, call, options = {}) {
|
|
42
|
+
if (call.workspace_locked && call.locked_workspace_ext_id) {
|
|
43
|
+
const key2 = await arbi.workspaces.key(call.locked_workspace_ext_id);
|
|
44
|
+
return { key: key2, keyVersion: null };
|
|
45
|
+
}
|
|
46
|
+
let chatExtId = call.chat_ext_id ?? null;
|
|
47
|
+
if (!chatExtId) {
|
|
48
|
+
if (!options.callKey) throw new Error("This call has no meeting chat to keep a recording in");
|
|
49
|
+
const ref = await ensureMeetingChat(arbi, queryClient, call.external_id, options.callKey);
|
|
50
|
+
if (ref.kind !== "chat") throw new Error("Expected an end-to-end meeting chat");
|
|
51
|
+
chatExtId = ref.chatExtId;
|
|
52
|
+
}
|
|
53
|
+
const chat = await arbi.chats.ready(await chatByExtId(arbi, queryClient, chatExtId));
|
|
54
|
+
const ring = await arbi.chats.ring(chat);
|
|
55
|
+
const version = options.keyVersion ?? ring.currentVersion;
|
|
56
|
+
const key = ring.keys.get(version);
|
|
57
|
+
if (!key) throw new Error("No key for this recording in the meeting chat");
|
|
58
|
+
return { key, keyVersion: version };
|
|
59
|
+
}
|
|
60
|
+
async function meetingRefForCall(arbi, queryClient, call, callKey) {
|
|
61
|
+
const ref = meetingChatRefFrom(call);
|
|
62
|
+
if (ref) return ref;
|
|
63
|
+
if (!callKey) throw new Error("This call has no meeting chat yet");
|
|
64
|
+
return ensureMeetingChat(arbi, queryClient, call.external_id, callKey);
|
|
65
|
+
}
|
|
66
|
+
const defaultDeps = (arbi) => ({
|
|
67
|
+
createTrack: (...args) => arbi.calls.recording.createTrack(...args),
|
|
68
|
+
presign: (...args) => arbi.calls.recording.presignPart(...args),
|
|
69
|
+
commit: (...args) => arbi.calls.recording.commitPart(...args),
|
|
70
|
+
getRecording: (...args) => arbi.calls.recording.get(...args),
|
|
71
|
+
put: (url, body, headers) => documents.presignedPut(url, body, void 0, headers),
|
|
72
|
+
encrypt: encryptPart,
|
|
73
|
+
wrap: wrapTrackKey,
|
|
74
|
+
unwrap: unwrapTrackKey,
|
|
75
|
+
newKey: newTrackKey,
|
|
76
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
77
|
+
});
|
|
78
|
+
const UPLOAD_ATTEMPTS = 5;
|
|
79
|
+
const UPLOAD_BACKOFF_MS = 1e3;
|
|
80
|
+
class SeqTakenError extends Error {
|
|
81
|
+
}
|
|
82
|
+
function isRetryable(err) {
|
|
83
|
+
if (!(err instanceof CallApiError)) return true;
|
|
84
|
+
if (calls.isQuotaError(err)) return false;
|
|
85
|
+
if (err.code === "part_not_uploaded") return true;
|
|
86
|
+
const s = err.status ?? 0;
|
|
87
|
+
return s === 0 || s === 408 || s === 429 || s >= 500 && s !== 507;
|
|
88
|
+
}
|
|
89
|
+
function isRecordingOver(err) {
|
|
90
|
+
if (!(err instanceof CallApiError)) return false;
|
|
91
|
+
return err.code === "recording_stopped" || err.code === "composite_needs_video" || err.status === 404 || err.status === 410;
|
|
92
|
+
}
|
|
93
|
+
class TrackUploader {
|
|
94
|
+
constructor(options) {
|
|
95
|
+
this.options = options;
|
|
96
|
+
this.deps = { ...defaultDeps(options.arbi), ...options.deps };
|
|
97
|
+
}
|
|
98
|
+
options;
|
|
99
|
+
deps;
|
|
100
|
+
track = null;
|
|
101
|
+
trackPromise = null;
|
|
102
|
+
nextSeq = 0;
|
|
103
|
+
queue = [];
|
|
104
|
+
running = null;
|
|
105
|
+
/** No more parts are accepted (quota, or the recording is gone). */
|
|
106
|
+
stopped = false;
|
|
107
|
+
/** Parts committed (for tests and the UI). */
|
|
108
|
+
committed = 0;
|
|
109
|
+
/** Queue a part; parts upload one at a time, in order. */
|
|
110
|
+
enqueue(part) {
|
|
111
|
+
if (this.stopped) return;
|
|
112
|
+
this.queue.push(part);
|
|
113
|
+
this.drain();
|
|
114
|
+
}
|
|
115
|
+
/** Resolves once every queued part was uploaded (or given up). */
|
|
116
|
+
async flush() {
|
|
117
|
+
while (this.running) await this.running;
|
|
118
|
+
}
|
|
119
|
+
drain() {
|
|
120
|
+
if (this.running) return;
|
|
121
|
+
this.running = (async () => {
|
|
122
|
+
try {
|
|
123
|
+
while (this.queue.length && !this.stopped) {
|
|
124
|
+
const part = this.queue.shift();
|
|
125
|
+
await this.uploadPart(part);
|
|
126
|
+
}
|
|
127
|
+
} finally {
|
|
128
|
+
this.running = null;
|
|
129
|
+
}
|
|
130
|
+
})();
|
|
131
|
+
}
|
|
132
|
+
async withRetry(label, run) {
|
|
133
|
+
let lastError;
|
|
134
|
+
for (let attempt = 0; attempt < UPLOAD_ATTEMPTS; attempt++) {
|
|
135
|
+
try {
|
|
136
|
+
return await run();
|
|
137
|
+
} catch (err) {
|
|
138
|
+
lastError = err;
|
|
139
|
+
if (!isRetryable(err) || attempt === UPLOAD_ATTEMPTS - 1) break;
|
|
140
|
+
console.warn(`[calls] recording ${label} failed, retrying`, err);
|
|
141
|
+
await this.deps.sleep(UPLOAD_BACKOFF_MS * 2 ** attempt);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
throw lastError;
|
|
145
|
+
}
|
|
146
|
+
ensureTrack() {
|
|
147
|
+
if (this.track) return Promise.resolve(this.track);
|
|
148
|
+
if (!this.trackPromise) {
|
|
149
|
+
this.trackPromise = this.withRetry("track", () => this.createTrack()).then(
|
|
150
|
+
(track) => {
|
|
151
|
+
this.track = track;
|
|
152
|
+
return track;
|
|
153
|
+
},
|
|
154
|
+
(err) => {
|
|
155
|
+
this.trackPromise = null;
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return this.trackPromise;
|
|
161
|
+
}
|
|
162
|
+
async createTrack() {
|
|
163
|
+
const { callExtId, recordingExtId, kind, mimeType } = this.options;
|
|
164
|
+
const conv = await this.options.conversationKey();
|
|
165
|
+
const fileKey = await this.deps.newKey();
|
|
166
|
+
const wrapped = await this.deps.wrap(fileKey, conv.key);
|
|
167
|
+
const created = await this.deps.createTrack(callExtId, recordingExtId, {
|
|
168
|
+
kind,
|
|
169
|
+
wrapped_key: wrapped,
|
|
170
|
+
key_version: conv.keyVersion,
|
|
171
|
+
mime_type: mimeType,
|
|
172
|
+
...this.options.linkVersion ? { link_version: this.options.linkVersion } : {}
|
|
173
|
+
});
|
|
174
|
+
const key = created.wrapped_key && created.wrapped_key !== wrapped ? await this.deps.unwrap(created.wrapped_key, conv.key) : fileKey;
|
|
175
|
+
let startedAt = this.options.recordingStartedAt ?? null;
|
|
176
|
+
let parts = created.parts;
|
|
177
|
+
if (!startedAt || !parts) {
|
|
178
|
+
const recording = await this.deps.getRecording(callExtId, recordingExtId);
|
|
179
|
+
startedAt = startedAt ?? recording.started_at;
|
|
180
|
+
parts = parts ?? (recording.tracks ?? []).find((t) => t.external_id === created.external_id)?.parts;
|
|
181
|
+
}
|
|
182
|
+
this.nextSeq = Math.max(this.nextSeq, nextSeqAfter(parts ?? []));
|
|
183
|
+
return { externalId: created.external_id, fileKey: key, startedAt };
|
|
184
|
+
}
|
|
185
|
+
async uploadPart(part) {
|
|
186
|
+
const { callExtId, recordingExtId } = this.options;
|
|
187
|
+
try {
|
|
188
|
+
const track = await this.ensureTrack();
|
|
189
|
+
const bytes = new Uint8Array(await part.blob.arrayBuffer());
|
|
190
|
+
const cipher = await this.deps.encrypt(bytes, track.fileKey);
|
|
191
|
+
const offset = partOffsetMs(part.startedAt, track.startedAt);
|
|
192
|
+
let seq = this.nextSeq++;
|
|
193
|
+
await this.withRetry("part", async () => {
|
|
194
|
+
let upload;
|
|
195
|
+
try {
|
|
196
|
+
upload = await this.deps.presign(callExtId, recordingExtId, track.externalId, {
|
|
197
|
+
seq,
|
|
198
|
+
offset_ms: offset,
|
|
199
|
+
duration_ms: Math.max(0, Math.round(part.durationMs)),
|
|
200
|
+
size_bytes: cipher.length
|
|
201
|
+
});
|
|
202
|
+
} catch (err) {
|
|
203
|
+
if (err instanceof CallApiError && err.code === "part_committed") {
|
|
204
|
+
seq = this.nextSeq++;
|
|
205
|
+
throw new SeqTakenError(err.message);
|
|
206
|
+
}
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
await this.deps.put(upload.upload_url, cipher, upload.headers ?? void 0);
|
|
210
|
+
await this.deps.commit(callExtId, recordingExtId, track.externalId, seq);
|
|
211
|
+
});
|
|
212
|
+
this.committed += 1;
|
|
213
|
+
} catch (err) {
|
|
214
|
+
if (calls.isQuotaError(err)) {
|
|
215
|
+
this.stopped = true;
|
|
216
|
+
this.queue = [];
|
|
217
|
+
this.options.onStopped?.(err);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (isRecordingOver(err)) {
|
|
221
|
+
this.stopped = true;
|
|
222
|
+
this.queue = [];
|
|
223
|
+
}
|
|
224
|
+
console.warn("[calls] a recording part could not be kept", err);
|
|
225
|
+
this.options.onPartLost?.(err);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function nextSeqAfter(parts) {
|
|
230
|
+
return parts.reduce((max, p) => Math.max(max, p.seq + 1), 0);
|
|
231
|
+
}
|
|
232
|
+
const uploaders = /* @__PURE__ */ new Map();
|
|
233
|
+
function trackUploaderFor(options) {
|
|
234
|
+
const key = `${options.recordingExtId}:${options.kind}`;
|
|
235
|
+
let uploader = uploaders.get(key);
|
|
236
|
+
if (!uploader || uploader.stopped) {
|
|
237
|
+
uploader = new TrackUploader(options);
|
|
238
|
+
uploaders.set(key, uploader);
|
|
239
|
+
}
|
|
240
|
+
return uploader;
|
|
241
|
+
}
|
|
242
|
+
function clearTrackUploaders() {
|
|
243
|
+
uploaders.clear();
|
|
244
|
+
}
|
|
245
|
+
export {
|
|
246
|
+
CALL_RECORDING_TOPIC,
|
|
247
|
+
COMPOSITE_AUDIO_BITS_PER_SECOND,
|
|
248
|
+
COMPOSITE_VIDEO_BITS_PER_SECOND,
|
|
249
|
+
RECORDING_CHUNK_MS,
|
|
250
|
+
SPEAKER_AUDIO_BITS_PER_SECOND,
|
|
251
|
+
TrackUploader,
|
|
252
|
+
UPLOAD_ATTEMPTS,
|
|
253
|
+
UPLOAD_BACKOFF_MS,
|
|
254
|
+
clearTrackUploaders,
|
|
255
|
+
conversationKeyForCall,
|
|
256
|
+
decryptPart,
|
|
257
|
+
encryptPart,
|
|
258
|
+
isRecordingOver,
|
|
259
|
+
isRetryable,
|
|
260
|
+
meetingRefForCall,
|
|
261
|
+
newTrackKey,
|
|
262
|
+
nextSeqAfter,
|
|
263
|
+
partOffsetMs,
|
|
264
|
+
trackUploaderFor,
|
|
265
|
+
unwrapTrackKey,
|
|
266
|
+
wrapTrackKey
|
|
267
|
+
};
|
|
268
|
+
//# sourceMappingURL=recording.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/calls/recording.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Call recording in the browser (ARBI `docs/meeting-chats-plan.md` \u00A76).\n *\n * Calls are end-to-end encrypted, so the server never records them: every participant's browser\n * records its OWN microphone (attribution by origin), and in \"Audio + video\" mode the host's\n * browser also records one composite of its view. The server only ever stores ciphertext.\n *\n * Keys: each track (one per speaker, plus the composite) has a random file key, wrapped under the\n * conversation key \u2014 the meeting chat's epoch key for a contacts call, the workspace key for a\n * thread call \u2014 and stored with the track (`wrapped_key`, `key_version`). Each ~30 s part is\n * SecretBox-encrypted with the file key here and uploaded like a document: presign \u2192 PUT the\n * ciphertext straight to the object store \u2192 commit (HEAD-verified server-side).\n *\n * Offsets are relative to the recording's `started_at`, so the tracks align in time.\n */\n\nimport {\n base64ToBytes,\n bytesToBase64,\n decryptFile,\n encryptFile,\n generateChatKey,\n initSodium,\n} from '@arbidocs/client'\nimport type { QueryClient } from '@tanstack/react-query'\nimport { CallApiError, calls, documents, type Arbi } from '@arbidocs/sdk/browser'\nimport { chatByExtId } from './in-call-chat'\nimport { ensureMeetingChat, meetingChatRefFrom, type MeetingChatRef } from './meeting-chat'\n\n/** Server-sent, plaintext: `{on, mode, recording_ext_id, by_identity, by_name}`. */\nexport const CALL_RECORDING_TOPIC = 'arbi.recording'\n/** Part length: every part is a standalone file of about this long. */\nexport const RECORDING_CHUNK_MS = 30_000\n/** Speaker audio: Opus ~16\u201324 kbps mono (~7\u201311 MB per speaker-hour). */\nexport const SPEAKER_AUDIO_BITS_PER_SECOND = 24_000\n/** Composite video (\u2264720p): ~300\u2013600 kbps. */\nexport const COMPOSITE_VIDEO_BITS_PER_SECOND = 500_000\nexport const COMPOSITE_AUDIO_BITS_PER_SECOND = 32_000\n\n// \u2500\u2500 Time \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** A part's offset from the recording start, ms (never negative). */\nexport function partOffsetMs(partStartedAt: number, recordingStartedAt: string | number): number {\n const start =\n typeof recordingStartedAt === 'number' ? recordingStartedAt : Date.parse(recordingStartedAt)\n if (!Number.isFinite(start)) return 0\n return Math.max(0, Math.round(partStartedAt - start))\n}\n\n// \u2500\u2500 Keys \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** A fresh random 32-byte file key. */\nexport function newTrackKey(): Promise<Uint8Array> {\n return generateChatKey()\n}\n\n/** The file key under the conversation key: base64(nonce \u2016 secretbox). */\nexport async function wrapTrackKey(\n fileKey: Uint8Array,\n conversationKey: Uint8Array\n): Promise<string> {\n await initSodium()\n return bytesToBase64(encryptFile(fileKey, conversationKey))\n}\n\nexport async function unwrapTrackKey(\n wrapped: string,\n conversationKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n return decryptFile(base64ToBytes(wrapped), conversationKey)\n}\n\nexport async function encryptPart(bytes: Uint8Array, fileKey: Uint8Array): Promise<Uint8Array> {\n await initSodium()\n return encryptFile(bytes, fileKey)\n}\n\nexport async function decryptPart(cipher: Uint8Array, fileKey: Uint8Array): Promise<Uint8Array> {\n await initSodium()\n return decryptFile(cipher, fileKey)\n}\n\n/** The key a recording's tracks are wrapped under, and its version (null: the workspace key). */\nexport interface ConversationKey {\n key: Uint8Array\n keyVersion: number | null\n}\n\n/**\n * The conversation key of a call's recordings:\n * - a thread call: its locked workspace's key (the key direct uploads use, unwrapped here);\n * - a contacts call: the meeting chat's epoch key \u2014 the current one to record (`keyVersion`\n * omitted; the chat is made on first use, which needs the call key K), or the given version\n * to read a track.\n */\nexport async function conversationKeyForCall(\n arbi: Arbi,\n queryClient: QueryClient,\n call: Pick<\n calls.CallResponse,\n 'external_id' | 'chat_ext_id' | 'workspace_locked' | 'locked_workspace_ext_id'\n >,\n options: { callKey?: Uint8Array | null; keyVersion?: number | null } = {}\n): Promise<ConversationKey> {\n if (call.workspace_locked && call.locked_workspace_ext_id) {\n const key = await arbi.workspaces.key(call.locked_workspace_ext_id)\n return { key, keyVersion: null }\n }\n let chatExtId = call.chat_ext_id ?? null\n if (!chatExtId) {\n if (!options.callKey) throw new Error('This call has no meeting chat to keep a recording in')\n const ref = await ensureMeetingChat(arbi, queryClient, call.external_id, options.callKey)\n if (ref.kind !== 'chat') throw new Error('Expected an end-to-end meeting chat')\n chatExtId = ref.chatExtId\n }\n const chat = await arbi.chats.ready(await chatByExtId(arbi, queryClient, chatExtId))\n const ring = await arbi.chats.ring(chat)\n const version = options.keyVersion ?? ring.currentVersion\n const key = ring.keys.get(version)\n if (!key) throw new Error('No key for this recording in the meeting chat')\n return { key, keyVersion: version }\n}\n\n/** The meeting chat a call's recording transcript goes to (made on first use when K is known). */\nexport async function meetingRefForCall(\n arbi: Arbi,\n queryClient: QueryClient,\n call: calls.CallResponse,\n callKey?: Uint8Array | null\n): Promise<MeetingChatRef> {\n const ref = meetingChatRefFrom(call)\n if (ref) return ref\n if (!callKey) throw new Error('This call has no meeting chat yet')\n return ensureMeetingChat(arbi, queryClient, call.external_id, callKey)\n}\n\n// \u2500\u2500 Upload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** One recorded part, as the recorder hands it over. */\nexport interface PendingPart {\n blob: Blob\n /** Wall clock, ms since epoch. */\n startedAt: number\n durationMs: number\n}\n\ntype RecordingApi = Arbi['calls']['recording']\n\nexport interface UploaderDeps {\n createTrack: RecordingApi['createTrack']\n presign: RecordingApi['presignPart']\n commit: RecordingApi['commitPart']\n getRecording: RecordingApi['get']\n put(url: string, body: Uint8Array, headers?: Record<string, string>): Promise<void>\n encrypt(bytes: Uint8Array, key: Uint8Array): Promise<Uint8Array>\n wrap(fileKey: Uint8Array, conversationKey: Uint8Array): Promise<string>\n unwrap(wrapped: string, conversationKey: Uint8Array): Promise<Uint8Array>\n newKey(): Promise<Uint8Array>\n sleep(ms: number): Promise<void>\n}\n\nconst defaultDeps = (arbi: Arbi): UploaderDeps => ({\n createTrack: (...args) => arbi.calls.recording.createTrack(...args),\n presign: (...args) => arbi.calls.recording.presignPart(...args),\n commit: (...args) => arbi.calls.recording.commitPart(...args),\n getRecording: (...args) => arbi.calls.recording.get(...args),\n put: (url, body, headers) => documents.presignedPut(url, body, undefined, headers),\n encrypt: encryptPart,\n wrap: wrapTrackKey,\n unwrap: unwrapTrackKey,\n newKey: newTrackKey,\n sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n})\n\n/** Attempts per part (and for the track) before a transient failure is given up. */\nexport const UPLOAD_ATTEMPTS = 5\nexport const UPLOAD_BACKOFF_MS = 1000\n\n/** A part number already in use: retried under the next number. */\nclass SeqTakenError extends Error {}\n\n/**\n * Network errors, 408/429, 5xx (but 507, the quota) and a commit that found no object yet\n * (409 `part_not_uploaded`: presign and PUT again \u2014 re-presigning is allowed until committed).\n */\nexport function isRetryable(err: unknown): boolean {\n if (!(err instanceof CallApiError)) return true\n if (calls.isQuotaError(err)) return false\n if (err.code === 'part_not_uploaded') return true\n const s = err.status ?? 0\n return s === 0 || s === 408 || s === 429 || (s >= 500 && s !== 507)\n}\n\n/** The recording takes no more parts: over (past its grace), gone, or not ours to add to. */\nexport function isRecordingOver(err: unknown): boolean {\n if (!(err instanceof CallApiError)) return false\n return (\n err.code === 'recording_stopped' ||\n err.code === 'composite_needs_video' ||\n err.status === 404 ||\n err.status === 410\n )\n}\n\nexport interface TrackUploaderOptions {\n /** Who uploads: the parts go through `arbi.calls.recording`. */\n arbi: Arbi\n callExtId: string\n recordingExtId: string\n kind: calls.RecordingTrackKind\n mimeType: string\n /** The conversation key to wrap the file key under (resolved once, lazily). */\n conversationKey(): Promise<ConversationKey>\n /** The recording's start (`CallRecordingState.started_at`; otherwise read from the recording). */\n recordingStartedAt?: string | null\n /** The call link version I joined with (admission, as for transcription). */\n linkVersion?: number | null\n /** The recording can take no more parts (quota): the server stopped it. */\n onStopped?(err: CallApiError): void\n /** A part could not be kept. */\n onPartLost?(err: unknown): void\n deps?: Partial<UploaderDeps>\n}\n\n/**\n * Uploads one track's parts in order: encrypt \u2192 presign \u2192 PUT \u2192 commit, retried with backoff.\n *\n * The track is created on the first part. Creation is idempotent per speaker (and for the\n * composite), so after a reconnect \u2014 or a reload \u2014 the server hands back the SAME track: its\n * existing wrapped key is unwrapped and used, and numbering resumes after its last part.\n */\nexport class TrackUploader {\n private readonly deps: UploaderDeps\n private track: { externalId: string; fileKey: Uint8Array; startedAt: string } | null = null\n private trackPromise: Promise<NonNullable<TrackUploader['track']>> | null = null\n private nextSeq = 0\n private queue: PendingPart[] = []\n private running: Promise<void> | null = null\n /** No more parts are accepted (quota, or the recording is gone). */\n stopped = false\n /** Parts committed (for tests and the UI). */\n committed = 0\n\n constructor(private readonly options: TrackUploaderOptions) {\n this.deps = { ...defaultDeps(options.arbi), ...options.deps }\n }\n\n /** Queue a part; parts upload one at a time, in order. */\n enqueue(part: PendingPart): void {\n if (this.stopped) return\n this.queue.push(part)\n this.drain()\n }\n\n /** Resolves once every queued part was uploaded (or given up). */\n async flush(): Promise<void> {\n while (this.running) await this.running\n }\n\n private drain(): void {\n if (this.running) return\n this.running = (async () => {\n try {\n while (this.queue.length && !this.stopped) {\n const part = this.queue.shift()!\n await this.uploadPart(part)\n }\n } finally {\n this.running = null\n }\n })()\n }\n\n private async withRetry<T>(label: string, run: () => Promise<T>): Promise<T> {\n let lastError: unknown\n for (let attempt = 0; attempt < UPLOAD_ATTEMPTS; attempt++) {\n try {\n return await run()\n } catch (err) {\n lastError = err\n if (!isRetryable(err) || attempt === UPLOAD_ATTEMPTS - 1) break\n console.warn(`[calls] recording ${label} failed, retrying`, err)\n await this.deps.sleep(UPLOAD_BACKOFF_MS * 2 ** attempt)\n }\n }\n throw lastError\n }\n\n private ensureTrack(): Promise<NonNullable<TrackUploader['track']>> {\n if (this.track) return Promise.resolve(this.track)\n if (!this.trackPromise) {\n this.trackPromise = this.withRetry('track', () => this.createTrack()).then(\n (track) => {\n this.track = track\n return track\n },\n (err: unknown) => {\n this.trackPromise = null\n throw err\n }\n )\n }\n return this.trackPromise\n }\n\n private async createTrack(): Promise<NonNullable<TrackUploader['track']>> {\n const { callExtId, recordingExtId, kind, mimeType } = this.options\n const conv = await this.options.conversationKey()\n const fileKey = await this.deps.newKey()\n const wrapped = await this.deps.wrap(fileKey, conv.key)\n const created: calls.RecordingTrack = await this.deps.createTrack(callExtId, recordingExtId, {\n kind,\n wrapped_key: wrapped,\n key_version: conv.keyVersion,\n mime_type: mimeType,\n ...(this.options.linkVersion ? { link_version: this.options.linkVersion } : {}),\n })\n // An existing track (reconnect): its key is the one its parts are under.\n const key =\n created.wrapped_key && created.wrapped_key !== wrapped\n ? await this.deps.unwrap(created.wrapped_key, conv.key)\n : fileKey\n let startedAt = this.options.recordingStartedAt ?? null\n let parts = created.parts\n if (!startedAt || !parts) {\n const recording: calls.CallRecording = await this.deps.getRecording(callExtId, recordingExtId)\n startedAt = startedAt ?? recording.started_at\n parts =\n parts ?? (recording.tracks ?? []).find((t) => t.external_id === created.external_id)?.parts\n }\n this.nextSeq = Math.max(this.nextSeq, nextSeqAfter(parts ?? []))\n return { externalId: created.external_id, fileKey: key, startedAt }\n }\n\n private async uploadPart(part: PendingPart): Promise<void> {\n const { callExtId, recordingExtId } = this.options\n try {\n const track = await this.ensureTrack()\n const bytes = new Uint8Array(await part.blob.arrayBuffer())\n const cipher = await this.deps.encrypt(bytes, track.fileKey)\n const offset = partOffsetMs(part.startedAt, track.startedAt)\n let seq = this.nextSeq++\n await this.withRetry('part', async () => {\n let upload\n try {\n upload = await this.deps.presign(callExtId, recordingExtId, track.externalId, {\n seq,\n offset_ms: offset,\n duration_ms: Math.max(0, Math.round(part.durationMs)),\n size_bytes: cipher.length,\n })\n } catch (err) {\n // That number is committed already (an earlier session's part): take the next one.\n if (err instanceof CallApiError && err.code === 'part_committed') {\n seq = this.nextSeq++\n throw new SeqTakenError(err.message)\n }\n throw err\n }\n await this.deps.put(upload.upload_url, cipher, upload.headers ?? undefined)\n await this.deps.commit(callExtId, recordingExtId, track.externalId, seq)\n })\n this.committed += 1\n } catch (err) {\n if (calls.isQuotaError(err)) {\n this.stopped = true\n this.queue = []\n this.options.onStopped?.(err as CallApiError)\n return\n }\n if (isRecordingOver(err)) {\n // Stopped past its grace, deleted, or a composite for an audio-only recording.\n this.stopped = true\n this.queue = []\n }\n console.warn('[calls] a recording part could not be kept', err)\n this.options.onPartLost?.(err)\n }\n }\n}\n\n/** The seq after a track's last part (0 for a new track). */\nexport function nextSeqAfter(parts: { seq: number }[]): number {\n return parts.reduce((max, p) => Math.max(max, p.seq + 1), 0)\n}\n\n/**\n * One uploader per (recording, track kind) for the whole page session, so a reconnect (the call\n * room remounting) resumes the same track and numbering instead of starting over.\n */\nconst uploaders = new Map<string, TrackUploader>()\n\nexport function trackUploaderFor(options: TrackUploaderOptions): TrackUploader {\n const key = `${options.recordingExtId}:${options.kind}`\n let uploader = uploaders.get(key)\n if (!uploader || uploader.stopped) {\n uploader = new TrackUploader(options)\n uploaders.set(key, uploader)\n }\n return uploader\n}\n\n/** Forget the uploaders (tests; sign-out). */\nexport function clearTrackUploaders(): void {\n uploaders.clear()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["key"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { documents } from "@arbidocs/sdk/browser";
|
|
4
|
+
import { useArbi } from "../useArbi.js";
|
|
5
|
+
import { invalidateConversationLists } from "../conversation-list.js";
|
|
6
|
+
import { formatTranscriptMarkdown } from "./transcript-format.js";
|
|
7
|
+
async function postToThread(arbi, conversationExtId, newThreadTitle, content) {
|
|
8
|
+
const posted = await arbi.conversations.postMessage({
|
|
9
|
+
content,
|
|
10
|
+
assistant_mode: "mentioned",
|
|
11
|
+
...conversationExtId ? { conversation_ext_id: conversationExtId } : { title: newThreadTitle }
|
|
12
|
+
});
|
|
13
|
+
return posted?.conversation_ext_id ?? null;
|
|
14
|
+
}
|
|
15
|
+
function postTranscriptToThread(arbi, params) {
|
|
16
|
+
return postToThread(
|
|
17
|
+
arbi,
|
|
18
|
+
params.conversationExtId,
|
|
19
|
+
`Transcript: ${params.title?.trim() || "Meeting"}`,
|
|
20
|
+
formatTranscriptMarkdown({ title: params.title, lines: params.lines })
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
function postRecordingDocsToThread(arbi, params) {
|
|
24
|
+
const meeting = params.title?.trim() || "Meeting";
|
|
25
|
+
const content = [
|
|
26
|
+
`**Recording: ${meeting}**`,
|
|
27
|
+
"",
|
|
28
|
+
...params.docExtIds.map((id) => `- \`${id}\``)
|
|
29
|
+
].join("\n");
|
|
30
|
+
return postToThread(arbi, params.conversationExtId, `Recording: ${meeting}`, content);
|
|
31
|
+
}
|
|
32
|
+
async function saveRecordingFilesToThread(arbi, params) {
|
|
33
|
+
const workspaceId = params.workspaceExtId;
|
|
34
|
+
const workspaceKey = await arbi.workspaces.key(workspaceId).catch(() => null);
|
|
35
|
+
params.onUploading?.();
|
|
36
|
+
const result = workspaceKey ? await arbi.documents.uploadDirect(
|
|
37
|
+
workspaceId,
|
|
38
|
+
workspaceKey,
|
|
39
|
+
await Promise.all(
|
|
40
|
+
params.files.map(async (file) => ({
|
|
41
|
+
name: file.name,
|
|
42
|
+
data: new Uint8Array(await file.arrayBuffer()),
|
|
43
|
+
contentType: file.type || documents.mimeFromName(file.name)
|
|
44
|
+
}))
|
|
45
|
+
),
|
|
46
|
+
{ shared: true }
|
|
47
|
+
) : await arbi.documents.upload(params.files, { shared: true, workspaceExtId: workspaceId });
|
|
48
|
+
const docExtIds = result.doc_ext_ids ?? [];
|
|
49
|
+
const skipped = result.skipped ?? [];
|
|
50
|
+
if (!docExtIds.length) {
|
|
51
|
+
throw new Error(`The files were not uploaded${skipped[0] ? `: ${skipped[0].reason}` : ""}`);
|
|
52
|
+
}
|
|
53
|
+
return postRecordingDocsToThread(arbi, {
|
|
54
|
+
conversationExtId: params.conversationExtId,
|
|
55
|
+
title: params.title,
|
|
56
|
+
docExtIds
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function useSaveToThread() {
|
|
60
|
+
const arbi = useArbi();
|
|
61
|
+
const queryClient = useQueryClient();
|
|
62
|
+
return useMemo(() => {
|
|
63
|
+
const thenRefresh = async (run) => {
|
|
64
|
+
const result = await run;
|
|
65
|
+
void invalidateConversationLists(queryClient);
|
|
66
|
+
return result;
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
transcript: (params) => thenRefresh(postTranscriptToThread(arbi, params)),
|
|
70
|
+
recording: (params) => thenRefresh(saveRecordingFilesToThread(arbi, params))
|
|
71
|
+
};
|
|
72
|
+
}, [arbi, queryClient]);
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
postRecordingDocsToThread,
|
|
76
|
+
postTranscriptToThread,
|
|
77
|
+
saveRecordingFilesToThread,
|
|
78
|
+
useSaveToThread
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=save-to-thread.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/calls/save-to-thread.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The host's \"Save \u2026 to thread\": one comment in the picked thread, or a new thread titled after the\n * meeting when no thread is picked (`conversationExtId` null). Resolves to the thread it went to.\n */\n\nimport { useMemo } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { documents, type Arbi } from '@arbidocs/sdk/browser'\nimport { useArbi } from '../useArbi'\nimport { invalidateConversationLists } from '../conversation-list'\nimport { formatTranscriptMarkdown, type TranscriptExportLine } from './transcript-format'\n\nasync function postToThread(\n arbi: Arbi,\n conversationExtId: string | null,\n newThreadTitle: string,\n content: string\n): Promise<string | null> {\n const posted = await arbi.conversations.postMessage({\n content,\n assistant_mode: 'mentioned',\n ...(conversationExtId ? { conversation_ext_id: conversationExtId } : { title: newThreadTitle }),\n })\n return posted?.conversation_ext_id ?? null\n}\n\n/** The (locally decrypted) transcript as ONE comment. */\nexport function postTranscriptToThread(\n arbi: Arbi,\n params: {\n conversationExtId: string | null\n title: string | null | undefined\n lines: TranscriptExportLine[]\n }\n): Promise<string | null> {\n return postToThread(\n arbi,\n params.conversationExtId,\n `Transcript: ${params.title?.trim() || 'Meeting'}`,\n formatTranscriptMarkdown({ title: params.title, lines: params.lines })\n )\n}\n\n/** A recording's uploaded documents, listed as `doc-\u2026` pills in ONE comment. */\nexport function postRecordingDocsToThread(\n arbi: Arbi,\n params: {\n conversationExtId: string | null\n title: string | null | undefined\n docExtIds: string[]\n }\n): Promise<string | null> {\n const meeting = params.title?.trim() || 'Meeting'\n const content = [\n `**Recording: ${meeting}**`,\n '',\n ...params.docExtIds.map((id) => `- \\`${id}\\``),\n ].join('\\n')\n return postToThread(arbi, params.conversationExtId, `Recording: ${meeting}`, content)\n}\n\n/**\n * A recording's decrypted files, uploaded as shared documents into the call's workspace\n * (`workspaceExtId`) and listed in ONE comment. They are encrypted here under that workspace's key\n * and sent straight to storage (`uploadDirect`, whose init and commit name the workspace); without\n * a key of mine for it they go through the server, named. Never into whichever workspace happens\n * to be open.\n */\nexport async function saveRecordingFilesToThread(\n arbi: Arbi,\n params: {\n workspaceExtId: string\n files: File[]\n conversationExtId: string | null\n title: string | null | undefined\n /** The upload starts (after the files are decrypted). */\n onUploading?: () => void\n }\n): Promise<string | null> {\n const workspaceId = params.workspaceExtId\n // A workspace I hold no key for (public, a temporary grant, a guest's) goes through the server,\n // which encrypts; the upload names the workspace either way.\n const workspaceKey = await arbi.workspaces.key(workspaceId).catch(() => null)\n params.onUploading?.()\n const result = workspaceKey\n ? await arbi.documents.uploadDirect(\n workspaceId,\n workspaceKey,\n await Promise.all(\n params.files.map(async (file) => ({\n name: file.name,\n data: new Uint8Array(await file.arrayBuffer()),\n contentType: file.type || documents.mimeFromName(file.name),\n }))\n ),\n { shared: true }\n )\n : await arbi.documents.upload(params.files, { shared: true, workspaceExtId: workspaceId })\n const docExtIds = result.doc_ext_ids ?? []\n const skipped = result.skipped ?? []\n if (!docExtIds.length) {\n throw new Error(`The files were not uploaded${skipped[0] ? `: ${skipped[0].reason}` : ''}`)\n }\n return postRecordingDocsToThread(arbi, {\n conversationExtId: params.conversationExtId,\n title: params.title,\n docExtIds,\n })\n}\n\n/** The \"Save \u2026 to thread\" actions on the signed-in session; the thread lists are re-read after. */\nexport function useSaveToThread() {\n const arbi = useArbi()\n const queryClient = useQueryClient()\n return useMemo(() => {\n const thenRefresh = async <T>(run: Promise<T>): Promise<T> => {\n const result = await run\n void invalidateConversationLists(queryClient)\n return result\n }\n return {\n transcript: (params: Parameters<typeof postTranscriptToThread>[1]) =>\n thenRefresh(postTranscriptToThread(arbi, params)),\n recording: (params: Parameters<typeof saveRecordingFilesToThread>[1]) =>\n thenRefresh(saveRecordingFilesToThread(arbi, params)),\n }\n }, [arbi, queryClient])\n}\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,iBAA4B;AACrC,SAAS,eAAe;AACxB,SAAS,mCAAmC;AAC5C,SAAS,gCAA2D;AAEpE,eAAe,aACb,MACA,mBACA,gBACA,SACwB;AACxB,QAAM,SAAS,MAAM,KAAK,cAAc,YAAY;AAAA,IAClD;AAAA,IACA,gBAAgB;AAAA,IAChB,GAAI,oBAAoB,EAAE,qBAAqB,kBAAkB,IAAI,EAAE,OAAO,eAAe;AAAA,EAC/F,CAAC;AACD,SAAO,QAAQ,uBAAuB;AACxC;AAGO,SAAS,uBACd,MACA,QAKwB;AACxB,SAAO;AAAA,IACL;AAAA,IACA,OAAO;AAAA,IACP,eAAe,OAAO,OAAO,KAAK,KAAK,SAAS;AAAA,IAChD,yBAAyB,EAAE,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,CAAC;AAAA,EACvE;AACF;AAGO,SAAS,0BACd,MACA,QAKwB;AACxB,QAAM,UAAU,OAAO,OAAO,KAAK,KAAK;AACxC,QAAM,UAAU;AAAA,IACd,gBAAgB,OAAO;AAAA,IACvB;AAAA,IACA,GAAG,OAAO,UAAU,IAAI,CAAC,OAAO,OAAO,EAAE,IAAI;AAAA,EAC/C,EAAE,KAAK,IAAI;AACX,SAAO,aAAa,MAAM,OAAO,mBAAmB,cAAc,OAAO,IAAI,OAAO;AACtF;AASA,eAAsB,2BACpB,MACA,QAQwB;AACxB,QAAM,cAAc,OAAO;AAG3B,QAAM,eAAe,MAAM,KAAK,WAAW,IAAI,WAAW,EAAE,MAAM,MAAM,IAAI;AAC5E,SAAO,cAAc;AACrB,QAAM,SAAS,eACX,MAAM,KAAK,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,IACA,MAAM,QAAQ;AAAA,MACZ,OAAO,MAAM,IAAI,OAAO,UAAU;AAAA,QAChC,MAAM,KAAK;AAAA,QACX,MAAM,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AAAA,QAC7C,aAAa,KAAK,QAAQ,UAAU,aAAa,KAAK,IAAI;AAAA,MAC5D,EAAE;AAAA,IACJ;AAAA,IACA,EAAE,QAAQ,KAAK;AAAA,EACjB,IACA,MAAM,KAAK,UAAU,OAAO,OAAO,OAAO,EAAE,QAAQ,MAAM,gBAAgB,YAAY,CAAC;AAC3F,QAAM,YAAY,OAAO,eAAe,CAAC;AACzC,QAAM,UAAU,OAAO,WAAW,CAAC;AACnC,MAAI,CAAC,UAAU,QAAQ;AACrB,UAAM,IAAI,MAAM,8BAA8B,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,MAAM,KAAK,EAAE,EAAE;AAAA,EAC5F;AACA,SAAO,0BAA0B,MAAM;AAAA,IACrC,mBAAmB,OAAO;AAAA,IAC1B,OAAO,OAAO;AAAA,IACd;AAAA,EACF,CAAC;AACH;AAGO,SAAS,kBAAkB;AAChC,QAAM,OAAO,QAAQ;AACrB,QAAM,cAAc,eAAe;AACnC,SAAO,QAAQ,MAAM;AACnB,UAAM,cAAc,OAAU,QAAgC;AAC5D,YAAM,SAAS,MAAM;AACrB,WAAK,4BAA4B,WAAW;AAC5C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,YAAY,CAAC,WACX,YAAY,uBAAuB,MAAM,MAAM,CAAC;AAAA,MAClD,WAAW,CAAC,WACV,YAAY,2BAA2B,MAAM,MAAM,CAAC;AAAA,IACxD;AAAA,EACF,GAAG,CAAC,MAAM,WAAW,CAAC;AACxB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
const DEFAULT_JOIN_CHOICES = { audioEnabled: true, videoEnabled: false };
|
|
3
|
+
const EMPTY_CALL_SESSION = {
|
|
4
|
+
active: null,
|
|
5
|
+
incoming: [],
|
|
6
|
+
knocks: [],
|
|
7
|
+
liveCalls: {}
|
|
8
|
+
};
|
|
9
|
+
let state = EMPTY_CALL_SESSION;
|
|
10
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
11
|
+
function update(next) {
|
|
12
|
+
const changed = next(state);
|
|
13
|
+
if (changed === state) return;
|
|
14
|
+
state = changed;
|
|
15
|
+
for (const listener of listeners) listener();
|
|
16
|
+
}
|
|
17
|
+
const callSession = {
|
|
18
|
+
getState: () => state,
|
|
19
|
+
subscribe(listener) {
|
|
20
|
+
listeners.add(listener);
|
|
21
|
+
return () => {
|
|
22
|
+
listeners.delete(listener);
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
setActiveCall(next) {
|
|
26
|
+
update((s) => ({
|
|
27
|
+
...s,
|
|
28
|
+
active: { ...next, minimized: next.minimized ?? false, startedAt: Date.now() },
|
|
29
|
+
// Joining a call answers any ring for it; knocks belong to the previous call.
|
|
30
|
+
incoming: s.incoming.filter((ring) => ring.call_ext_id !== next.callExtId),
|
|
31
|
+
knocks: s.knocks.filter((k) => k.callExtId === next.callExtId)
|
|
32
|
+
}));
|
|
33
|
+
},
|
|
34
|
+
/** Patch the active call (no-op when it is a different call or none). */
|
|
35
|
+
updateActiveCall(callExtId, patch) {
|
|
36
|
+
update(
|
|
37
|
+
(s) => s.active?.callExtId === callExtId ? { ...s, active: { ...s.active, ...patch } } : s
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
endActiveCall() {
|
|
41
|
+
update((s) => {
|
|
42
|
+
s.active?.knock?.abort();
|
|
43
|
+
return { ...s, active: null, knocks: [] };
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
setCallMinimized(minimized) {
|
|
47
|
+
update((s) => s.active ? { ...s, active: { ...s.active, minimized } } : s);
|
|
48
|
+
},
|
|
49
|
+
/** Queue a ring. A repeat ring for the same call replaces the earlier entry. */
|
|
50
|
+
enqueueIncomingCall(ring) {
|
|
51
|
+
update((s) => {
|
|
52
|
+
if (s.active?.callExtId === ring.call_ext_id) return s;
|
|
53
|
+
return {
|
|
54
|
+
...s,
|
|
55
|
+
incoming: [
|
|
56
|
+
...s.incoming.filter((r) => r.call_ext_id !== ring.call_ext_id),
|
|
57
|
+
{ ...ring, receivedAt: Date.now() }
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
removeIncomingCall(callExtId) {
|
|
63
|
+
update((s) => ({ ...s, incoming: s.incoming.filter((r) => r.call_ext_id !== callExtId) }));
|
|
64
|
+
},
|
|
65
|
+
addKnock(knock) {
|
|
66
|
+
update((s) => {
|
|
67
|
+
if (s.active?.callExtId !== knock.callExtId) return s;
|
|
68
|
+
return {
|
|
69
|
+
...s,
|
|
70
|
+
knocks: [
|
|
71
|
+
...s.knocks.filter((k) => k.knockId !== knock.knockId),
|
|
72
|
+
{ ...knock, receivedAt: Date.now() }
|
|
73
|
+
]
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
removeKnock(knockId) {
|
|
78
|
+
update((s) => ({ ...s, knocks: s.knocks.filter((k) => k.knockId !== knockId) }));
|
|
79
|
+
},
|
|
80
|
+
markCallLive(callExtId, where) {
|
|
81
|
+
update((s) => ({ ...s, liveCalls: { ...s.liveCalls, [callExtId]: where } }));
|
|
82
|
+
},
|
|
83
|
+
/** Call ended: forget it and drop any unanswered ring / knock for it. */
|
|
84
|
+
markCallEnded(callExtId) {
|
|
85
|
+
update((s) => {
|
|
86
|
+
const liveCalls = { ...s.liveCalls };
|
|
87
|
+
delete liveCalls[callExtId];
|
|
88
|
+
return {
|
|
89
|
+
...s,
|
|
90
|
+
liveCalls,
|
|
91
|
+
incoming: s.incoming.filter((r) => r.call_ext_id !== callExtId),
|
|
92
|
+
knocks: s.knocks.filter((k) => k.callExtId !== callExtId)
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
function resetCallSession() {
|
|
98
|
+
update(() => EMPTY_CALL_SESSION);
|
|
99
|
+
}
|
|
100
|
+
function useCallSession(selector) {
|
|
101
|
+
return useSyncExternalStore(
|
|
102
|
+
callSession.subscribe,
|
|
103
|
+
() => selector(state),
|
|
104
|
+
() => selector(state)
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
function threadLiveCallId(s, conversationExtId) {
|
|
108
|
+
const found = Object.entries(s.liveCalls).find(
|
|
109
|
+
([, c]) => c.logConversationExtId === conversationExtId
|
|
110
|
+
);
|
|
111
|
+
return found ? found[0] : null;
|
|
112
|
+
}
|
|
113
|
+
function threadHasLiveCall(s, conversationExtId) {
|
|
114
|
+
return threadLiveCallId(s, conversationExtId) !== null;
|
|
115
|
+
}
|
|
116
|
+
function chatLiveCallId(s, chatExtId) {
|
|
117
|
+
const found = Object.entries(s.liveCalls).find(([, c]) => c.chatExtId === chatExtId);
|
|
118
|
+
return found ? found[0] : null;
|
|
119
|
+
}
|
|
120
|
+
function chatHasLiveCall(s, chatExtId) {
|
|
121
|
+
return chatLiveCallId(s, chatExtId) !== null;
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
DEFAULT_JOIN_CHOICES,
|
|
125
|
+
EMPTY_CALL_SESSION,
|
|
126
|
+
callSession,
|
|
127
|
+
chatHasLiveCall,
|
|
128
|
+
chatLiveCallId,
|
|
129
|
+
resetCallSession,
|
|
130
|
+
threadHasLiveCall,
|
|
131
|
+
threadLiveCallId,
|
|
132
|
+
useCallSession
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/calls/session.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The call session: the one active call of this browser tab, the queue of incoming rings, lobby\n * knocks waiting for this user's decision, and which calls the server says are live.\n *\n * Session-only and in memory: a LiveKit token and the call key never reach storage, so a reload\n * starts empty. One per tab (a tab is in at most one call), so it is a module store read with\n * {@link useCallSession} and changed with {@link callSession}'s actions, from React and from plain\n * code (call actions, the WebSocket) alike. Signing out calls {@link resetCallSession}.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { calls } from '@arbidocs/sdk/browser'\n\n/** The devices picked before joining (the pre-join). */\nexport interface JoinChoices {\n audioEnabled: boolean\n videoEnabled: boolean\n audioDeviceId?: string\n videoDeviceId?: string\n}\n\n/** Microphone on, camera off: an answered ring joins with these (calls are audio-first). */\nexport const DEFAULT_JOIN_CHOICES: JoinChoices = { audioEnabled: true, videoEnabled: false }\n\nexport interface ActiveCall {\n callExtId: string\n /** The call's E2EE key K (32 bytes). */\n key: Uint8Array\n linkVersion: number\n /** Display label for the dock header. */\n title: string | null\n isCreator: boolean\n /** The call's E2E chat (DM, group or meeting chat), when it has one. */\n chatExtId: string | null\n /** Thread call: the thread with the log card. */\n logConversationExtId: string | null\n /** Thread call: its meeting thread, once made. */\n meetingConversationExtId: string | null\n /** Thread call: the workspace it is locked to. */\n lockedWorkspaceExtId: string | null\n /**\n * `prejoin` shows the device check, `knocking` waits in the lobby, `connected` mounts the room.\n * A webinar's audience also has `webinar-waiting` (\"Starting soon\": not live yet, joins by itself\n * once it is) and `webinar-ended` (the host ended it).\n */\n phase: 'prejoin' | 'knocking' | 'connected' | 'webinar-waiting' | 'webinar-ended'\n tokenResponse: calls.CallTokenResponse | null\n choices: JoinChoices | null\n /** While knocking: stops waiting for admission. */\n knock: { abort(): void } | null\n /** Users to ring once we join: user ext id \u2192 K sealed to them. */\n ringOnJoin: Record<string, string> | null\n /** A personal invite link's token (`/call/<id>?i=\u2026`): redeemed for a token, no lobby. */\n inviteToken?: string | null\n minimized: boolean\n startedAt: number\n /**\n * A webinar's stage changed under us (moved to the audience, or stepped down): the server removes\n * us from the room and we join again with a new token, so that room's disconnect is not a leave.\n */\n rejoining?: boolean\n}\n\n/** A ring waiting for accept/decline. */\nexport interface IncomingCall extends Omit<calls.CallRingingMessage, 'type'> {\n receivedAt: number\n}\n\n/** Someone in the lobby of a call this user can admit people to. */\nexport interface PendingKnock {\n callExtId: string\n knockId: string\n displayName: string\n /** The signed-in user asking (everyone in a call has an account). */\n userExtId: string\n receivedAt: number\n}\n\n/** Where a live call belongs (from `call.started`). */\nexport interface LiveCall {\n chatExtId: string | null\n logConversationExtId: string | null\n meetingConversationExtId: string | null\n}\n\nexport interface CallSessionState {\n active: ActiveCall | null\n incoming: IncomingCall[]\n knocks: PendingKnock[]\n /** Calls the server says are live (`call.started` \u2026 `call.ended`), by call ext id. */\n liveCalls: Record<string, LiveCall>\n}\n\nexport type NewActiveCall = Omit<ActiveCall, 'minimized' | 'startedAt'> & { minimized?: boolean }\n\nexport const EMPTY_CALL_SESSION: CallSessionState = {\n active: null,\n incoming: [],\n knocks: [],\n liveCalls: {},\n}\n\nlet state: CallSessionState = EMPTY_CALL_SESSION\nconst listeners = new Set<() => void>()\n\nfunction update(next: (current: CallSessionState) => CallSessionState): void {\n const changed = next(state)\n if (changed === state) return\n state = changed\n for (const listener of listeners) listener()\n}\n\n/** The call session's state and actions (usable outside React). */\nexport const callSession = {\n getState: (): CallSessionState => state,\n\n subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n\n setActiveCall(next: NewActiveCall): void {\n update((s) => ({\n ...s,\n active: { ...next, minimized: next.minimized ?? false, startedAt: Date.now() },\n // Joining a call answers any ring for it; knocks belong to the previous call.\n incoming: s.incoming.filter((ring) => ring.call_ext_id !== next.callExtId),\n knocks: s.knocks.filter((k) => k.callExtId === next.callExtId),\n }))\n },\n\n /** Patch the active call (no-op when it is a different call or none). */\n updateActiveCall(callExtId: string, patch: Partial<ActiveCall>): void {\n update((s) =>\n s.active?.callExtId === callExtId ? { ...s, active: { ...s.active, ...patch } } : s\n )\n },\n\n endActiveCall(): void {\n update((s) => {\n s.active?.knock?.abort()\n return { ...s, active: null, knocks: [] }\n })\n },\n\n setCallMinimized(minimized: boolean): void {\n update((s) => (s.active ? { ...s, active: { ...s.active, minimized } } : s))\n },\n\n /** Queue a ring. A repeat ring for the same call replaces the earlier entry. */\n enqueueIncomingCall(ring: Omit<IncomingCall, 'receivedAt'>): void {\n update((s) => {\n // Already in this call \u2014 nothing to ring.\n if (s.active?.callExtId === ring.call_ext_id) return s\n return {\n ...s,\n incoming: [\n ...s.incoming.filter((r) => r.call_ext_id !== ring.call_ext_id),\n { ...ring, receivedAt: Date.now() },\n ],\n }\n })\n },\n\n removeIncomingCall(callExtId: string): void {\n update((s) => ({ ...s, incoming: s.incoming.filter((r) => r.call_ext_id !== callExtId) }))\n },\n\n addKnock(knock: Omit<PendingKnock, 'receivedAt'>): void {\n update((s) => {\n // Only prompt for the call we are in.\n if (s.active?.callExtId !== knock.callExtId) return s\n return {\n ...s,\n knocks: [\n ...s.knocks.filter((k) => k.knockId !== knock.knockId),\n { ...knock, receivedAt: Date.now() },\n ],\n }\n })\n },\n\n removeKnock(knockId: string): void {\n update((s) => ({ ...s, knocks: s.knocks.filter((k) => k.knockId !== knockId) }))\n },\n\n markCallLive(callExtId: string, where: LiveCall): void {\n update((s) => ({ ...s, liveCalls: { ...s.liveCalls, [callExtId]: where } }))\n },\n\n /** Call ended: forget it and drop any unanswered ring / knock for it. */\n markCallEnded(callExtId: string): void {\n update((s) => {\n const liveCalls = { ...s.liveCalls }\n delete liveCalls[callExtId]\n return {\n ...s,\n liveCalls,\n incoming: s.incoming.filter((r) => r.call_ext_id !== callExtId),\n knocks: s.knocks.filter((k) => k.callExtId !== callExtId),\n }\n })\n },\n}\n\n/** Forget everything (signing out). A call in progress is left by its room unmounting. */\nexport function resetCallSession(): void {\n update(() => EMPTY_CALL_SESSION)\n}\n\n/** Read the call session in React, re-rendering when the selected value changes. */\nexport function useCallSession<T>(selector: (state: CallSessionState) => T): T {\n return useSyncExternalStore(\n callSession.subscribe,\n () => selector(state),\n () => selector(state)\n )\n}\n\n/** The id of the thread's live call, if the server reports one (a thread call). */\nexport function threadLiveCallId(s: CallSessionState, conversationExtId: string): string | null {\n const found = Object.entries(s.liveCalls).find(\n ([, c]) => c.logConversationExtId === conversationExtId\n )\n return found ? found[0] : null\n}\n\n/** Whether the server reports a live call logged in this thread. */\nexport function threadHasLiveCall(s: CallSessionState, conversationExtId: string): boolean {\n return threadLiveCallId(s, conversationExtId) !== null\n}\n\n/** The id of the chat's live call (DM, group or meeting chat), if the server reports one. */\nexport function chatLiveCallId(s: CallSessionState, chatExtId: string): string | null {\n const found = Object.entries(s.liveCalls).find(([, c]) => c.chatExtId === chatExtId)\n return found ? found[0] : null\n}\n\n/** Whether the server reports a live call in this chat (DM, group or meeting chat). */\nexport function chatHasLiveCall(s: CallSessionState, chatExtId: string): boolean {\n return chatLiveCallId(s, chatExtId) !== null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|