@athenaintel/react 0.43.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +258 -8
- package/dist/agent-runtime/src/answer-label.cjs +137 -0
- package/dist/agent-runtime/src/answer-label.cjs.map +1 -0
- package/dist/agent-runtime/src/answer-label.d.ts +104 -0
- package/dist/agent-runtime/src/answer-label.js +137 -0
- package/dist/agent-runtime/src/answer-label.js.map +1 -0
- package/dist/agent-runtime/src/answer-rows.cjs +180 -0
- package/dist/agent-runtime/src/answer-rows.cjs.map +1 -0
- package/dist/agent-runtime/src/answer-rows.d.ts +86 -0
- package/dist/agent-runtime/src/answer-rows.js +180 -0
- package/dist/agent-runtime/src/answer-rows.js.map +1 -0
- package/dist/agent-runtime/src/call-recap.cjs +319 -0
- package/dist/agent-runtime/src/call-recap.cjs.map +1 -0
- package/dist/agent-runtime/src/call-recap.d.ts +142 -0
- package/dist/agent-runtime/src/call-recap.js +319 -0
- package/dist/agent-runtime/src/call-recap.js.map +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.cjs +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox-store.d.ts +7 -0
- package/dist/agent-runtime/src/chat-outbox-store.js +1 -0
- package/dist/agent-runtime/src/chat-outbox-store.js.map +1 -1
- package/dist/agent-runtime/src/chat-outbox.cjs +46 -5
- package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
- package/dist/agent-runtime/src/chat-outbox.d.ts +29 -0
- package/dist/agent-runtime/src/chat-outbox.js +46 -5
- package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/client-tool-bridge.cjs +15 -15
- package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-index.cjs +8 -8
- package/dist/agent-runtime/src/conversation-index.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-index.d.ts +7 -0
- package/dist/agent-runtime/src/conversation-index.js.map +1 -1
- package/dist/agent-runtime/src/conversation-list.cjs +2 -1
- package/dist/agent-runtime/src/conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/conversation-list.d.ts +19 -3
- package/dist/agent-runtime/src/conversation-list.js +2 -1
- package/dist/agent-runtime/src/conversation-list.js.map +1 -1
- package/dist/agent-runtime/src/decision-checks.cjs +207 -0
- package/dist/agent-runtime/src/decision-checks.cjs.map +1 -0
- package/dist/agent-runtime/src/decision-checks.d.ts +142 -0
- package/dist/agent-runtime/src/decision-checks.js +207 -0
- package/dist/agent-runtime/src/decision-checks.js.map +1 -0
- package/dist/agent-runtime/src/desktop-handoff.d.ts +12 -0
- package/dist/agent-runtime/src/errors.cjs +18 -0
- package/dist/agent-runtime/src/errors.cjs.map +1 -1
- package/dist/agent-runtime/src/errors.d.ts +7 -0
- package/dist/agent-runtime/src/errors.js +18 -0
- package/dist/agent-runtime/src/errors.js.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
- package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +6 -6
- package/dist/agent-runtime/src/generated/runconfig-contract.js +12 -0
- package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
- package/dist/agent-runtime/src/handoff-arrival.cjs +60 -0
- package/dist/agent-runtime/src/handoff-arrival.cjs.map +1 -0
- package/dist/agent-runtime/src/handoff-arrival.d.ts +46 -0
- package/dist/agent-runtime/src/handoff-arrival.js +60 -0
- package/dist/agent-runtime/src/handoff-arrival.js.map +1 -0
- package/dist/agent-runtime/src/index.d.ts +16 -9
- package/dist/agent-runtime/src/interrupts.cjs +71 -19
- package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
- package/dist/agent-runtime/src/interrupts.d.ts +40 -3
- package/dist/agent-runtime/src/interrupts.js +56 -4
- package/dist/agent-runtime/src/interrupts.js.map +1 -1
- package/dist/agent-runtime/src/lane-history.cjs +8 -8
- package/dist/agent-runtime/src/lane-history.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.cjs +43 -8
- package/dist/agent-runtime/src/messages.cjs.map +1 -1
- package/dist/agent-runtime/src/messages.d.ts +25 -3
- package/dist/agent-runtime/src/messages.js +43 -8
- package/dist/agent-runtime/src/messages.js.map +1 -1
- package/dist/agent-runtime/src/model-context.cjs +3 -2
- package/dist/agent-runtime/src/model-context.cjs.map +1 -1
- package/dist/agent-runtime/src/model-context.d.ts +6 -1
- package/dist/agent-runtime/src/model-context.js +3 -2
- package/dist/agent-runtime/src/model-context.js.map +1 -1
- package/dist/agent-runtime/src/offline-status.cjs +36 -0
- package/dist/agent-runtime/src/offline-status.cjs.map +1 -0
- package/dist/agent-runtime/src/offline-status.d.ts +118 -3
- package/dist/agent-runtime/src/offline-status.js +36 -0
- package/dist/agent-runtime/src/offline-status.js.map +1 -0
- package/dist/agent-runtime/src/queue.cjs +0 -9
- package/dist/agent-runtime/src/queue.cjs.map +1 -1
- package/dist/agent-runtime/src/queue.js +0 -9
- package/dist/agent-runtime/src/queue.js.map +1 -1
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +9 -9
- package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
- package/dist/agent-runtime/src/runtime-catalog.cjs +42 -0
- package/dist/agent-runtime/src/runtime-catalog.cjs.map +1 -0
- package/dist/agent-runtime/src/runtime-catalog.d.ts +35 -0
- package/dist/agent-runtime/src/runtime-catalog.js +42 -0
- package/dist/agent-runtime/src/runtime-catalog.js.map +1 -0
- package/dist/agent-runtime/src/runtime-messages.cjs.map +1 -1
- package/dist/agent-runtime/src/runtime-messages.d.ts +1 -1
- package/dist/agent-runtime/src/runtime-messages.js.map +1 -1
- package/dist/agent-runtime/src/runtime.d.ts +41 -0
- package/dist/agent-runtime/src/send-recovery.cjs +37 -3
- package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
- package/dist/agent-runtime/src/send-recovery.d.ts +19 -0
- package/dist/agent-runtime/src/send-recovery.js +37 -3
- package/dist/agent-runtime/src/send-recovery.js.map +1 -1
- package/dist/agent-runtime/src/statewire-suspended.cjs +3 -3
- package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.cjs +32 -2
- package/dist/agent-runtime/src/subagents.cjs.map +1 -1
- package/dist/agent-runtime/src/subagents.d.ts +9 -0
- package/dist/agent-runtime/src/subagents.js +30 -0
- package/dist/agent-runtime/src/subagents.js.map +1 -1
- package/dist/agent-runtime/src/thread-driver.cjs +67 -0
- package/dist/agent-runtime/src/thread-driver.cjs.map +1 -0
- package/dist/agent-runtime/src/thread-driver.d.ts +49 -0
- package/dist/agent-runtime/src/thread-driver.js +67 -0
- package/dist/agent-runtime/src/thread-driver.js.map +1 -0
- package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +172 -0
- package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +868 -0
- package/dist/agent-runtime/src/thread-handoff-qr.d.ts +11 -0
- package/dist/agent-runtime/src/thread-handoff.d.ts +3 -364
- package/dist/agent-runtime/src/thread-status.cjs +3 -3
- package/dist/agent-runtime/src/thread-status.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.cjs +210 -25
- package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-metadata.d.ts +12 -0
- package/dist/agent-runtime/src/tool-metadata.js +210 -25
- package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
- package/dist/agent-runtime/src/tool-names.cjs +2 -0
- package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
- package/dist/agent-runtime/src/tool-names.d.ts +2 -0
- package/dist/agent-runtime/src/tool-names.js +2 -0
- package/dist/agent-runtime/src/tool-names.js.map +1 -1
- package/dist/agent-runtime/src/types.d.ts +10 -2
- package/dist/agent-runtime/src/use-conversation-list.cjs +14 -13
- package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
- package/dist/agent-runtime/src/use-conversation-list.d.ts +6 -0
- package/dist/agent-runtime/src/use-conversation-list.js +3 -2
- package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +45 -20
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +10 -3
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +27 -2
- package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-config.cjs +14 -14
- package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +6 -6
- package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +40 -22
- package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +17 -0
- package/dist/agent-runtime/src/use-deep-agent-runtime.js +24 -6
- package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs +45 -45
- package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs +588 -130
- package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +162 -10
- package/dist/agent-runtime/src/use-deep-agent-voice.js +529 -71
- package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +26 -26
- package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
- package/dist/agent-runtime/src/use-historical-edit-attachments.cjs +4 -4
- package/dist/agent-runtime/src/use-historical-edit-attachments.cjs.map +1 -1
- package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +34 -26
- package/dist/agent-runtime/src/voice-earcon.cjs +139 -0
- package/dist/agent-runtime/src/voice-earcon.cjs.map +1 -0
- package/dist/agent-runtime/src/voice-earcon.d.ts +38 -0
- package/dist/agent-runtime/src/voice-earcon.js +139 -0
- package/dist/agent-runtime/src/voice-earcon.js.map +1 -0
- package/dist/agent-runtime/src/voice-media.cjs +117 -0
- package/dist/agent-runtime/src/voice-media.cjs.map +1 -0
- package/dist/agent-runtime/src/voice-media.d.ts +63 -0
- package/dist/agent-runtime/src/voice-media.js +117 -0
- package/dist/agent-runtime/src/voice-media.js.map +1 -0
- package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
- package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
- package/dist/agent-runtime/src/voice-presentation.js +2 -0
- package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
- package/dist/agent-runtime/src/voice-wire-types.d.ts +32 -0
- package/dist/assets/AssetPanel.cjs +11 -11
- package/dist/assets/AssetPanel.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.cjs +11 -9
- package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
- package/dist/assets/AthenaAssetEmbed.d.ts +18 -5
- package/dist/assets/AthenaAssetEmbed.js +4 -2
- package/dist/assets/AthenaAssetEmbed.js.map +1 -1
- package/dist/assets/AthenaLayout.cjs +16 -16
- package/dist/assets/AthenaLayout.cjs.map +1 -1
- package/dist/assets/use-asset-content.cjs +4 -4
- package/dist/assets/use-asset-content.cjs.map +1 -1
- package/dist/assets/use-asset-embed.cjs +14 -7
- package/dist/assets/use-asset-embed.cjs.map +1 -1
- package/dist/assets/use-asset-embed.d.ts +23 -6
- package/dist/assets/use-asset-embed.js +10 -3
- package/dist/assets/use-asset-embed.js.map +1 -1
- package/dist/auth/AthenaAuthContext.cjs +3 -3
- package/dist/auth/AthenaAuthContext.cjs.map +1 -1
- package/dist/auth/AthenaAuthProvider.cjs +8 -8
- package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
- package/dist/auth/AthenaCredentialSourceContext.cjs +5 -5
- package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
- package/dist/auth/AthenaSSOProvider.cjs +14 -14
- package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
- package/dist/auth/credential-source.cjs +26 -13
- package/dist/auth/credential-source.cjs.map +1 -1
- package/dist/auth/credential-source.d.ts +8 -0
- package/dist/auth/credential-source.js +26 -13
- package/dist/auth/credential-source.js.map +1 -1
- package/dist/catalog/agent-model-options.cjs +25 -17
- package/dist/catalog/agent-model-options.cjs.map +1 -1
- package/dist/catalog/agent-model-options.d.ts +38 -5
- package/dist/catalog/agent-model-options.js +25 -17
- package/dist/catalog/agent-model-options.js.map +1 -1
- package/dist/catalog/channel-refusal.cjs +36 -0
- package/dist/catalog/channel-refusal.cjs.map +1 -0
- package/dist/catalog/channel-refusal.d.ts +29 -0
- package/dist/catalog/channel-refusal.js +36 -0
- package/dist/catalog/channel-refusal.js.map +1 -0
- package/dist/catalog/chat-pickers.cjs +60 -24
- package/dist/catalog/chat-pickers.cjs.map +1 -1
- package/dist/catalog/chat-pickers.d.ts +12 -2
- package/dist/catalog/chat-pickers.js +56 -20
- package/dist/catalog/chat-pickers.js.map +1 -1
- package/dist/catalog/runtime-catalog.cjs +89 -23
- package/dist/catalog/runtime-catalog.cjs.map +1 -1
- package/dist/catalog/runtime-catalog.d.ts +8 -2
- package/dist/catalog/runtime-catalog.js +83 -17
- package/dist/catalog/runtime-catalog.js.map +1 -1
- package/dist/catalog/use-athena-chat-mode.cjs +12 -12
- package/dist/catalog/use-athena-chat-mode.cjs.map +1 -1
- package/dist/chat/AthenaChat.cjs +155 -67
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.d.ts +42 -2
- package/dist/chat/AthenaChat.js +106 -18
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/chat/AthenaChatErrorBoundary.cjs +3 -3
- package/dist/chat/AthenaChatErrorBoundary.cjs.map +1 -1
- package/dist/chat/DrivingOnChip.cjs +23 -0
- package/dist/chat/DrivingOnChip.cjs.map +1 -0
- package/dist/chat/DrivingOnChip.d.ts +17 -0
- package/dist/chat/DrivingOnChip.js +23 -0
- package/dist/chat/DrivingOnChip.js.map +1 -0
- package/dist/chat/StatewireApprovalCard.cjs +166 -37
- package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
- package/dist/chat/StatewireApprovalCard.d.ts +91 -2
- package/dist/chat/StatewireApprovalCard.js +156 -27
- package/dist/chat/StatewireApprovalCard.js.map +1 -1
- package/dist/chat/StatewireClientToolBridge.cjs +2 -2
- package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.cjs +81 -69
- package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
- package/dist/chat/StatewireQueuedMessages.d.ts +25 -13
- package/dist/chat/StatewireQueuedMessages.js +73 -61
- package/dist/chat/StatewireQueuedMessages.js.map +1 -1
- package/dist/chat/WaitingOnYouBanner.cjs +9 -5
- package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
- package/dist/chat/WaitingOnYouBanner.js +7 -3
- package/dist/chat/WaitingOnYouBanner.js.map +1 -1
- package/dist/chat/athena-chat-welcome.cjs +2 -2
- package/dist/chat/athena-chat-welcome.cjs.map +1 -1
- package/dist/chat/athena-citation-links.cjs +5 -5
- package/dist/chat/athena-citation-links.cjs.map +1 -1
- package/dist/chat/athena-composer-controls.cjs +26 -16
- package/dist/chat/athena-composer-controls.cjs.map +1 -1
- package/dist/chat/athena-composer-controls.d.ts +6 -0
- package/dist/chat/athena-composer-controls.js +26 -16
- package/dist/chat/athena-composer-controls.js.map +1 -1
- package/dist/chat/athena-turn-end-status.cjs +42 -0
- package/dist/chat/athena-turn-end-status.cjs.map +1 -0
- package/dist/chat/athena-turn-end-status.d.ts +24 -0
- package/dist/chat/athena-turn-end-status.js +42 -0
- package/dist/chat/athena-turn-end-status.js.map +1 -0
- package/dist/chat/browser-decision-check.cjs +131 -0
- package/dist/chat/browser-decision-check.cjs.map +1 -0
- package/dist/chat/browser-decision-check.d.ts +61 -0
- package/dist/chat/browser-decision-check.js +131 -0
- package/dist/chat/browser-decision-check.js.map +1 -0
- package/dist/chat/chat-outbox-rows.cjs +3 -3
- package/dist/chat/chat-outbox-rows.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.cjs +96 -29
- package/dist/chat/chat-voice-controls.cjs.map +1 -1
- package/dist/chat/chat-voice-controls.d.ts +42 -3
- package/dist/chat/chat-voice-controls.js +92 -25
- package/dist/chat/chat-voice-controls.js.map +1 -1
- package/dist/chat/composer-keyboard-hint.cjs +5 -5
- package/dist/chat/composer-keyboard-hint.cjs.map +1 -1
- package/dist/chat/device-operation.cjs +29 -0
- package/dist/chat/device-operation.cjs.map +1 -0
- package/dist/chat/device-operation.d.ts +34 -0
- package/dist/chat/device-operation.js +29 -0
- package/dist/chat/device-operation.js.map +1 -0
- package/dist/chat/super-grouping/CollapsibleGroup.cjs +14 -14
- package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
- package/dist/chat/super-grouping/GroupedMessageParts.cjs +4 -4
- package/dist/chat/super-grouping/GroupedMessageParts.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.cjs +52 -36
- package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingCard.d.ts +19 -4
- package/dist/chat/super-grouping/SuperGroupingCard.js +29 -13
- package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +32 -32
- package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
- package/dist/chat/super-grouping/SuperGroupingTranscript.js +3 -3
- package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.cjs +73 -40
- package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
- package/dist/chat/super-grouping/ToolTimeline.d.ts +10 -2
- package/dist/chat/super-grouping/ToolTimeline.js +69 -36
- package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.cjs +47 -12
- package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
- package/dist/chat/super-grouping/activity-timeline.d.ts +21 -0
- package/dist/chat/super-grouping/activity-timeline.js +47 -12
- package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
- package/dist/chat/super-grouping/grouping-function.cjs +4 -0
- package/dist/chat/super-grouping/grouping-function.cjs.map +1 -1
- package/dist/chat/super-grouping/grouping-function.d.ts +7 -0
- package/dist/chat/super-grouping/grouping-function.js +5 -1
- package/dist/chat/super-grouping/grouping-function.js.map +1 -1
- package/dist/chat/super-grouping/index.cjs +6 -0
- package/dist/chat/super-grouping/index.cjs.map +1 -1
- package/dist/chat/super-grouping/index.d.ts +5 -2
- package/dist/chat/super-grouping/index.js +7 -1
- package/dist/chat/super-grouping/index.js.map +1 -1
- package/dist/chat/super-grouping/tool-part-placement.cjs +17 -0
- package/dist/chat/super-grouping/tool-part-placement.cjs.map +1 -0
- package/dist/chat/super-grouping/tool-part-placement.d.ts +22 -0
- package/dist/chat/super-grouping/tool-part-placement.js +17 -0
- package/dist/chat/super-grouping/tool-part-placement.js.map +1 -0
- package/dist/chat/thread-scroll-to-bottom.cjs +2 -2
- package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -1
- package/dist/chat/thread-scroll-to-bottom.d.ts +10 -7
- package/dist/chat/thread-scroll-to-bottom.js +2 -2
- package/dist/chat/thread-scroll-to-bottom.js.map +1 -1
- package/dist/chat/tooltip-icon-button.cjs +2 -2
- package/dist/chat/tooltip-icon-button.cjs.map +1 -1
- package/dist/chat/use-athena-voice-live.cjs +11 -0
- package/dist/chat/use-athena-voice-live.cjs.map +1 -0
- package/dist/chat/use-athena-voice-live.d.ts +11 -0
- package/dist/chat/use-athena-voice-live.js +11 -0
- package/dist/chat/use-athena-voice-live.js.map +1 -0
- package/dist/chat/use-statewire-approval-request.cjs +56 -24
- package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
- package/dist/chat/use-statewire-approval-request.d.ts +33 -4
- package/dist/chat/use-statewire-approval-request.js +41 -9
- package/dist/chat/use-statewire-approval-request.js.map +1 -1
- package/dist/chat-ui/auth/sign-in-card.cjs +2 -2
- package/dist/chat-ui/auth/sign-in-card.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.cjs +138 -107
- package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
- package/dist/chat-ui/composer/tiptap-composer.d.ts +20 -4
- package/dist/chat-ui/composer/tiptap-composer.js +85 -54
- package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.cjs +49 -23
- package/dist/chat-ui/header/conversation-history-panel.cjs.map +1 -1
- package/dist/chat-ui/header/conversation-history-panel.d.ts +12 -1
- package/dist/chat-ui/header/conversation-history-panel.js +38 -12
- package/dist/chat-ui/header/conversation-history-panel.js.map +1 -1
- package/dist/chat-ui/index.cjs +21 -0
- package/dist/chat-ui/index.cjs.map +1 -1
- package/dist/chat-ui/index.d.ts +8 -1
- package/dist/chat-ui/index.js +21 -0
- package/dist/chat-ui/index.js.map +1 -1
- package/dist/chat-ui/mentions/mention-chip.cjs +4 -4
- package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs +10 -9
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js +3 -2
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs +29 -6
- package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.d.ts +7 -1
- package/dist/chat-ui/mentions/suggestions/components/menu-list.js +25 -2
- package/dist/chat-ui/mentions/suggestions/components/menu-list.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs +2 -2
- package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +3 -3
- package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs +56 -2
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.d.ts +12 -0
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.js +56 -2
- package/dist/chat-ui/mentions/suggestions/data/orchestrator.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +24 -3
- package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +7 -0
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js +24 -3
- package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +35 -13
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +15 -1
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +28 -6
- package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs +9 -6
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs.map +1 -1
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.d.ts +3 -0
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js +5 -2
- package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs +45 -10
- package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +24 -1
- package/dist/chat-ui/mentions/use-account-workspace-id.js +46 -11
- package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
- package/dist/chat-ui/mentions/use-member-avatar.cjs +4 -4
- package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -1
- package/dist/chat-ui/mentions/use-mention-asset.cjs +3 -3
- package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -1
- package/dist/chat-ui/messages/answer-label.cjs +42 -0
- package/dist/chat-ui/messages/answer-label.cjs.map +1 -0
- package/dist/chat-ui/messages/answer-label.d.ts +33 -0
- package/dist/chat-ui/messages/answer-label.js +42 -0
- package/dist/chat-ui/messages/answer-label.js.map +1 -0
- package/dist/chat-ui/messages/arrival-animation.cjs +13 -0
- package/dist/chat-ui/messages/arrival-animation.cjs.map +1 -0
- package/dist/chat-ui/messages/arrival-animation.d.ts +14 -0
- package/dist/chat-ui/messages/arrival-animation.js +13 -0
- package/dist/chat-ui/messages/arrival-animation.js.map +1 -0
- package/dist/chat-ui/messages/continue-pill.cjs +5 -5
- package/dist/chat-ui/messages/continue-pill.cjs.map +1 -1
- package/dist/chat-ui/messages/from-the-call-card.cjs +124 -0
- package/dist/chat-ui/messages/from-the-call-card.cjs.map +1 -0
- package/dist/chat-ui/messages/from-the-call-card.d.ts +17 -0
- package/dist/chat-ui/messages/from-the-call-card.js +124 -0
- package/dist/chat-ui/messages/from-the-call-card.js.map +1 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.cjs +44 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.cjs.map +1 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.d.ts +17 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.js +44 -0
- package/dist/chat-ui/messages/handoff-arrival-divider.js.map +1 -0
- package/dist/chat-ui/messages/message-actions-config.cjs +3 -3
- package/dist/chat-ui/messages/message-actions-config.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.cjs +8 -4
- package/dist/chat-ui/messages/message-components.cjs.map +1 -1
- package/dist/chat-ui/messages/message-components.js +5 -1
- package/dist/chat-ui/messages/message-components.js.map +1 -1
- package/dist/chat-ui/messages/message-images.cjs +66 -0
- package/dist/chat-ui/messages/message-images.cjs.map +1 -0
- package/dist/chat-ui/messages/message-images.d.ts +16 -0
- package/dist/chat-ui/messages/message-images.js +66 -0
- package/dist/chat-ui/messages/message-images.js.map +1 -0
- package/dist/chat-ui/messages/user-edit-composer.cjs +2 -2
- package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
- package/dist/chat-ui/messages/wake-marker.cjs +3 -3
- package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.cjs +3 -2
- package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-link.d.ts +4 -0
- package/dist/chat-ui/rich-text/chat-link.js +4 -3
- package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.cjs +9 -8
- package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
- package/dist/chat-ui/rich-text/chat-message-body.d.ts +12 -0
- package/dist/chat-ui/rich-text/chat-message-body.js +2 -1
- package/dist/chat-ui/rich-text/chat-message-body.js.map +1 -1
- package/dist/chat-ui/rich-text/chat-node-views.cjs +6 -6
- package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
- package/dist/chat-ui/rich-text/dom-output-spec.cjs +2 -2
- package/dist/chat-ui/rich-text/dom-output-spec.cjs.map +1 -1
- package/dist/chat-ui/statewire.cjs +3 -0
- package/dist/chat-ui/statewire.cjs.map +1 -1
- package/dist/chat-ui/statewire.d.ts +2 -1
- package/dist/chat-ui/statewire.js +3 -0
- package/dist/chat-ui/statewire.js.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.cjs +45 -14
- package/dist/chat-ui/thread/chat-thread-shell.cjs.map +1 -1
- package/dist/chat-ui/thread/chat-thread-shell.d.ts +16 -2
- package/dist/chat-ui/thread/chat-thread-shell.js +37 -6
- package/dist/chat-ui/thread/chat-thread-shell.js.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.cjs +30 -20
- package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
- package/dist/chat-ui/thread/composer-send-or-stop.d.ts +8 -0
- package/dist/chat-ui/thread/composer-send-or-stop.js +29 -19
- package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.cjs +20 -21
- package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
- package/dist/chat-ui/thread/statewire-history-edge.js +3 -4
- package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
- package/dist/chat-ui/thread/thread-loading-overlay.cjs +5 -5
- package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -1
- package/dist/collab/client.cjs +52 -3
- package/dist/collab/client.cjs.map +1 -1
- package/dist/collab/client.d.ts +27 -0
- package/dist/collab/client.js +52 -3
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/document-status.cjs +150 -0
- package/dist/collab/document-status.cjs.map +1 -0
- package/dist/collab/document-status.d.ts +68 -0
- package/dist/collab/document-status.js +150 -0
- package/dist/collab/document-status.js.map +1 -0
- package/dist/collab/index.cjs +7 -0
- package/dist/collab/index.cjs.map +1 -1
- package/dist/collab/index.d.ts +6 -1
- package/dist/collab/index.js +7 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/presence-react.cjs +11 -11
- package/dist/collab/presence-react.cjs.map +1 -1
- package/dist/collab/react.cjs +6 -6
- package/dist/collab/react.cjs.map +1 -1
- package/dist/composer/AttachmentContext.cjs +24 -11
- package/dist/composer/AttachmentContext.cjs.map +1 -1
- package/dist/composer/AttachmentContext.js +18 -5
- package/dist/composer/AttachmentContext.js.map +1 -1
- package/dist/composer/ComposerAttachmentPreview.cjs +78 -23
- package/dist/composer/ComposerAttachmentPreview.cjs.map +1 -1
- package/dist/composer/ComposerAttachmentPreview.d.ts +5 -3
- package/dist/composer/ComposerAttachmentPreview.js +79 -24
- package/dist/composer/ComposerAttachmentPreview.js.map +1 -1
- package/dist/composer/ComposerDropZone.cjs +7 -7
- package/dist/composer/ComposerDropZone.cjs.map +1 -1
- package/dist/composer/FileUploadButton.cjs +37 -22
- package/dist/composer/FileUploadButton.cjs.map +1 -1
- package/dist/composer/FileUploadButton.d.ts +6 -0
- package/dist/composer/FileUploadButton.js +34 -19
- package/dist/composer/FileUploadButton.js.map +1 -1
- package/dist/composer/QuoteContext.cjs +8 -8
- package/dist/composer/QuoteContext.cjs.map +1 -1
- package/dist/composer/composer-handoff.cjs +4 -4
- package/dist/composer/composer-handoff.cjs.map +1 -1
- package/dist/composer/index.d.ts +1 -1
- package/dist/composer/useAppendToComposer.cjs +4 -4
- package/dist/composer/useAppendToComposer.cjs.map +1 -1
- package/dist/composer/useAttachFiles.cjs +23 -6
- package/dist/composer/useAttachFiles.cjs.map +1 -1
- package/dist/composer/useAttachFiles.d.ts +15 -7
- package/dist/composer/useAttachFiles.js +22 -5
- package/dist/composer/useAttachFiles.js.map +1 -1
- package/dist/composer/useComposerAttachment.cjs +4 -4
- package/dist/composer/useComposerAttachment.cjs.map +1 -1
- package/dist/composer/useFileUpload.cjs +21 -16
- package/dist/composer/useFileUpload.cjs.map +1 -1
- package/dist/composer/useFileUpload.d.ts +12 -0
- package/dist/composer/useFileUpload.js +12 -7
- package/dist/composer/useFileUpload.js.map +1 -1
- package/dist/composer/useReadComposerDraft.cjs +27 -8
- package/dist/composer/useReadComposerDraft.cjs.map +1 -1
- package/dist/composer/useReadComposerDraft.d.ts +23 -1
- package/dist/composer/useReadComposerDraft.js +27 -8
- package/dist/composer/useReadComposerDraft.js.map +1 -1
- package/dist/composer/useSendMessage.cjs +4 -4
- package/dist/composer/useSendMessage.cjs.map +1 -1
- package/dist/diagnostics/useAthenaDiagnostics.cjs +4 -4
- package/dist/diagnostics/useAthenaDiagnostics.cjs.map +1 -1
- package/dist/dictation/audio-level-history.cjs +3 -3
- package/dist/dictation/audio-level-history.cjs.map +1 -1
- package/dist/dictation/dictation-controls.cjs +24 -20
- package/dist/dictation/dictation-controls.cjs.map +1 -1
- package/dist/dictation/dictation-controls.d.ts +6 -1
- package/dist/dictation/dictation-controls.js +24 -20
- package/dist/dictation/dictation-controls.js.map +1 -1
- package/dist/dictation/use-athena-dictation-engine.cjs +3 -3
- package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
- package/dist/dictation/use-dictation.cjs +22 -22
- package/dist/dictation/use-dictation.cjs.map +1 -1
- package/dist/index.cjs +29 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +18 -4
- package/dist/index.js +30 -3
- package/dist/index.js.map +1 -1
- package/dist/keryx-http/src/receive-only-socket.cjs +40 -0
- package/dist/keryx-http/src/receive-only-socket.cjs.map +1 -0
- package/dist/keryx-http/src/receive-only-socket.d.ts +27 -0
- package/dist/keryx-http/src/receive-only-socket.js +40 -0
- package/dist/keryx-http/src/receive-only-socket.js.map +1 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.cjs +190 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.cjs.map +1 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.d.ts +132 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.js +190 -0
- package/dist/keryx-http/src/unconfirmed-update-attributions.js.map +1 -0
- package/dist/keryx-http/src/update-attributions.cjs +141 -0
- package/dist/keryx-http/src/update-attributions.cjs.map +1 -0
- package/dist/keryx-http/src/update-attributions.d.ts +107 -0
- package/dist/keryx-http/src/update-attributions.js +141 -0
- package/dist/keryx-http/src/update-attributions.js.map +1 -0
- package/dist/lib/owner-document.cjs +6 -6
- package/dist/lib/owner-document.cjs.map +1 -1
- package/dist/lib/use-athena-rest-query.cjs +4 -4
- package/dist/lib/use-athena-rest-query.cjs.map +1 -1
- package/dist/lib/use-document-active.cjs +4 -4
- package/dist/lib/use-document-active.cjs.map +1 -1
- package/dist/lib/use-prefers-reduced-motion.cjs +2 -2
- package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -1
- package/dist/offline/offline-history.cjs +7 -7
- package/dist/offline/offline-history.cjs.map +1 -1
- package/dist/provider/AthenaContext.cjs +3 -3
- package/dist/provider/AthenaContext.cjs.map +1 -1
- package/dist/provider/AthenaProvider.cjs +120 -79
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.d.ts +11 -1
- package/dist/provider/AthenaProvider.js +44 -3
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/provider/PostHogProvider.cjs +2 -2
- package/dist/provider/PostHogProvider.cjs.map +1 -1
- package/dist/provider/agent-selection-context.cjs +2 -2
- package/dist/provider/agent-selection-context.cjs.map +1 -1
- package/dist/provider/chat-mode-context.cjs +2 -2
- package/dist/provider/chat-mode-context.cjs.map +1 -1
- package/dist/provider/session-persistence-context.cjs +10 -0
- package/dist/provider/session-persistence-context.cjs.map +1 -0
- package/dist/provider/session-persistence-context.d.ts +15 -0
- package/dist/provider/session-persistence-context.js +10 -0
- package/dist/provider/session-persistence-context.js.map +1 -0
- package/dist/provider/statewire-history-context.cjs +4 -4
- package/dist/provider/statewire-history-context.cjs.map +1 -1
- package/dist/provider/statewire-lifecycle-context.cjs +3 -3
- package/dist/provider/statewire-lifecycle-context.cjs.map +1 -1
- package/dist/provider/statewire-window-context.cjs +3 -3
- package/dist/provider/statewire-window-context.cjs.map +1 -1
- package/dist/provider/theme-style-context.cjs +3 -3
- package/dist/provider/theme-style-context.cjs.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs +10 -10
- package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
- package/dist/runtime/auth-refusal-restart.cjs +7 -7
- package/dist/runtime/auth-refusal-restart.cjs.map +1 -1
- package/dist/runtime/auth.cjs +13 -13
- package/dist/runtime/auth.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.cjs +1 -0
- package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
- package/dist/runtime/statewire-lifecycle.d.ts +3 -1
- package/dist/runtime/statewire-lifecycle.js +2 -1
- package/dist/runtime/statewire-lifecycle.js.map +1 -1
- package/dist/runtime/statewire-server-lane-context.cjs +2 -2
- package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
- package/dist/runtime/statewire-session-lane.cjs +4 -4
- package/dist/runtime/statewire-session-lane.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.cjs +10 -8
- package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
- package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
- package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/threads/Inbox.cjs +8 -8
- package/dist/threads/Inbox.cjs.map +1 -1
- package/dist/threads/SessionList.cjs +9 -9
- package/dist/threads/SessionList.cjs.map +1 -1
- package/dist/threads/SessionsPage.cjs +11 -11
- package/dist/threads/SessionsPage.cjs.map +1 -1
- package/dist/threads/api.cjs.map +1 -1
- package/dist/threads/api.d.ts +15 -0
- package/dist/threads/api.js.map +1 -1
- package/dist/threads/conversation-list-fetcher.cjs +13 -5
- package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
- package/dist/threads/conversation-list-fetcher.d.ts +4 -1
- package/dist/threads/conversation-list-fetcher.js +13 -5
- package/dist/threads/conversation-list-fetcher.js.map +1 -1
- package/dist/threads/index-triggered-refresh.cjs +10 -10
- package/dist/threads/index-triggered-refresh.cjs.map +1 -1
- package/dist/threads/mark-viewed-thread-read.cjs +12 -12
- package/dist/threads/mark-viewed-thread-read.cjs.map +1 -1
- package/dist/threads/offline-session-list.cjs +3 -3
- package/dist/threads/offline-session-list.cjs.map +1 -1
- package/dist/threads/session-list-tab-share.cjs +5 -5
- package/dist/threads/session-list-tab-share.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.cjs +79 -57
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +20 -8
- package/dist/threads/statewire-thread-list.js +28 -6
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/dist/threads/thread-id-context.cjs +5 -5
- package/dist/threads/thread-id-context.cjs.map +1 -1
- package/dist/threads/use-athena-session-attention.cjs +2 -2
- package/dist/threads/use-athena-session-attention.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.cjs +37 -15
- package/dist/threads/use-athena-sessions.cjs.map +1 -1
- package/dist/threads/use-athena-sessions.d.ts +10 -5
- package/dist/threads/use-athena-sessions.js +28 -6
- package/dist/threads/use-athena-sessions.js.map +1 -1
- package/dist/threads/use-athena-thread-model.cjs +3 -3
- package/dist/threads/use-athena-thread-model.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.cjs +3 -3
- package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
- package/dist/threads/use-rest-conversation-history.d.ts +1 -0
- package/dist/threads/use-statewire-conversation-history.cjs +8 -8
- package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
- package/dist/threads/use-thread-archive.cjs +9 -9
- package/dist/threads/use-thread-archive.cjs.map +1 -1
- package/dist/threads/use-thread-favorite.cjs +2 -2
- package/dist/threads/use-thread-favorite.cjs.map +1 -1
- package/dist/threads/use-thread-field-override.cjs +20 -20
- package/dist/threads/use-thread-field-override.cjs.map +1 -1
- package/dist/threads/use-thread-read-state.cjs +4 -4
- package/dist/threads/use-thread-read-state.cjs.map +1 -1
- package/dist/threads/use-thread-rename.cjs +2 -2
- package/dist/threads/use-thread-rename.cjs.map +1 -1
- package/dist/threads/useAthenaThreadManager.cjs +2 -2
- package/dist/threads/useAthenaThreadManager.cjs.map +1 -1
- package/dist/tools/NestedPtcMessages.cjs +6 -6
- package/dist/tools/NestedPtcMessages.cjs.map +1 -1
- package/dist/tools/append-document-tool-ui.cjs +7 -7
- package/dist/tools/append-document-tool-ui.cjs.map +1 -1
- package/dist/tools/file-tool-uis.cjs +2 -2
- package/dist/tools/file-tool-uis.cjs.map +1 -1
- package/dist/tools/misc-tool-uis.cjs +2 -2
- package/dist/tools/misc-tool-uis.cjs.map +1 -1
- package/dist/tools/primitives.cjs +6 -6
- package/dist/tools/primitives.cjs.map +1 -1
- package/dist/tools/read-asset-tool-ui.cjs +6 -6
- package/dist/tools/read-asset-tool-ui.cjs.map +1 -1
- package/dist/tools/subagent-task-tool-ui.cjs +21 -21
- package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
- package/dist/tools/test-recording-tool-uis.cjs +16 -16
- package/dist/tools/test-recording-tool-uis.cjs.map +1 -1
- package/dist/tools/todo-plan-store.cjs +4 -4
- package/dist/tools/todo-plan-store.cjs.map +1 -1
- package/dist/tools/tool-appearance.cjs +3 -3
- package/dist/tools/tool-appearance.cjs.map +1 -1
- package/dist/tools/tool-fallback.cjs +14 -14
- package/dist/tools/tool-fallback.cjs.map +1 -1
- package/dist/tools/tool-uis.cjs +74 -74
- package/dist/tools/tool-uis.cjs.map +1 -1
- package/dist/tools/use-elapsed-seconds.cjs +3 -3
- package/dist/tools/use-elapsed-seconds.cjs.map +1 -1
- package/dist/tools/write-todos-tool-ui.cjs +9 -9
- package/dist/tools/write-todos-tool-ui.cjs.map +1 -1
- package/dist/ui/image-viewer.cjs +382 -0
- package/dist/ui/image-viewer.cjs.map +1 -0
- package/dist/ui/image-viewer.d.ts +50 -0
- package/dist/ui/image-viewer.js +382 -0
- package/dist/ui/image-viewer.js.map +1 -0
- package/dist/voice/chat.cjs +6 -0
- package/dist/voice/chat.cjs.map +1 -1
- package/dist/voice/chat.d.ts +1 -1
- package/dist/voice/chat.js +8 -2
- package/dist/voice/livekit-join.cjs +52 -101
- package/dist/voice/livekit-join.cjs.map +1 -1
- package/dist/voice/livekit-join.d.ts +1 -6
- package/dist/voice/livekit-join.js +52 -101
- package/dist/voice/livekit-join.js.map +1 -1
- package/dist/voice/livekit.cjs.map +1 -1
- package/dist/voice/livekit.d.ts +11 -1
- package/dist/voice/livekit.js.map +1 -1
- package/dist/voice/use-athena-voice-session.cjs +34 -34
- package/dist/voice/use-athena-voice-session.cjs.map +1 -1
- package/dist/workbench/ComputerLiveDesktop.cjs +13 -13
- package/dist/workbench/ComputerLiveDesktop.cjs.map +1 -1
- package/dist/workbench/SessionWorkbench.cjs +22 -22
- package/dist/workbench/SessionWorkbench.cjs.map +1 -1
- package/dist/workbench/session-workbench-context.cjs +3 -3
- package/dist/workbench/session-workbench-context.cjs.map +1 -1
- package/dist/workbench/session-workbench-panes.cjs +8 -8
- package/dist/workbench/session-workbench-panes.cjs.map +1 -1
- package/dist/workbench/workbench-layout-context.cjs +3 -3
- package/dist/workbench/workbench-layout-context.cjs.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.cjs","sources":["../../src/collab/client.ts"],"sourcesContent":["/**\n * Vanilla (framework-agnostic) live client for Generic Doc assets.\n *\n * `connectGenericDoc` owns the full connection lifecycle: mint a room-bound\n * token via the public API, open the Keryx WebSocket with the v14 provider\n * (`@y/websocket` + `@y/y`), re-mint before expiry, apply the close-code\n * policy (4401 → one fresh mint, other 44xx → permanent stop, everything\n * else → provider backoff), and expose presence from awareness. React apps\n * use `useGenericDoc` from `@athenaintel/react/collab` instead of calling\n * this directly.\n *\n * A host that keeps a local copy of the document (`localCopy`) gets it applied\n * before the first connection, keeps its unacknowledged edits waiting across\n * sessions, and can hold a connection that would send edits made without one\n * until it has checked them against the server (`beforeConnect`). Offline, a\n * mint that fails for want of the network is retried (`retryMintError`)\n * instead of ending the handle, and past `offlineGateAfterMs` without a socket\n * the handle reconnects itself, re-minting each time, so every reconnect after\n * a real outage re-checks access and passes the host's gate.\n */\n\nimport { WebsocketProvider } from '@y/websocket';\nimport * as Y from '@y/y';\nimport { classifyClose } from './close-policy';\nimport {\n type CollabAuth,\n type CollabTokenResponse,\n CollabTokenError,\n mintCollabToken,\n} from './mint';\nimport { MAX_CONSECUTIVE_REMINTS, MIN_REFRESH_DELAY_MS, refreshDelayMs } from './token-refresh';\n\nexport type GenericDocStatus =\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'closed'\n | 'error';\n\nexport interface PresenceEntry {\n clientId: number;\n state: Record<string, unknown>;\n}\n\nexport interface GenericDocHandle {\n /** The live shared document. Owned by the handle; destroyed with it. */\n readonly doc: Y.Doc;\n readonly status: GenericDocStatus;\n /**\n * Whether the initial server sync has completed for the current connection.\n * `status === 'connected'` fires before the server state arrives, so a doc\n * read immediately after connect can still be empty — gate first reads on\n * this (or `waitForSync`).\n */\n readonly synced: boolean;\n /**\n * Whether every change made to this document has reached the server: `false` from a local edit\n * until the server sends it back (`@y/websocket`'s `syncStatus.localUpdatesSynced`; yhub echoes\n * every update to its sender). Kept across reconnects and re-mints: a replaced provider hands its\n * unconfirmed edits to the next, and an edit made between providers waits for one. A host that\n * closes the document while this is `false` loses those edits, unless a local copy keeps them.\n */\n readonly localChangesSynced: boolean;\n /** Granted access from the last successful mint. */\n readonly accessType: 'r' | 'rw' | null;\n /** Terminal error, when status is 'error' or 'closed'. */\n readonly error: Error | null;\n /**\n * Whether the document holds what the host's local copy stored (always `true` without one).\n * Mount readers after it: until then the document is still empty.\n */\n readonly prepared: boolean;\n /** Whether this host allows a live connection. Disabled documents remain editable locally. */\n readonly connectionEnabled: boolean;\n /**\n * A connection the host's `beforeConnect` held: the handle waits, sending nothing, until the\n * host calls `resume()` (or destroys the handle).\n */\n readonly held: boolean;\n /** Monotonic change counter — bumps on every status/presence notification. */\n readonly version: number;\n /**\n * Resolve once the initial server sync completes; reject on timeout, on a\n * terminal connection state, or if the handle is destroyed first.\n */\n waitForSync: (timeoutMs?: number) => Promise<void>;\n /**\n * Resolve once connected, initially synced, and every local change has been acknowledged,\n * including any edits the local-copy hook restores after sync. The host must prevent further\n * editing while saving a checkpoint. Reject on timeout, a disabled connection, or a terminal state.\n */\n waitForAcknowledged: (timeoutMs?: number) => Promise<void>;\n getPresence: () => PresenceEntry[];\n /** Broadcast this client's presence state (requires a live connection). */\n setPresence: (state: Record<string, unknown> | null) => void;\n /**\n * Force an early token refresh. Session-preserving: the live connection\n * stays up until the fresh token is minted; a failed mint retries on a\n * short timer instead of dropping the session. Without a connection it\n * reconnects now.\n */\n refreshNow: () => Promise<void>;\n /**\n * Disable all connections without losing the document or its pending edits. Enabling mints a\n * fresh grant and runs the host's beforeConnect gate; it never bypasses a permission or review.\n */\n setConnectionEnabled: (enabled: boolean) => void;\n /** Connect past a hold, without asking `beforeConnect` again. */\n resume: () => void;\n /** Local edits the server has not echoed yet (handed between providers too), or `null`. */\n unconfirmedEdits: () => Y.ContentIds | null;\n onChange: (listener: () => void) => () => void;\n destroy: () => void;\n}\n\n/**\n * Issues a room-bound Keryx token for one asset. The default calls the public\n * `/collab-token` route with the handle's `auth`; a host with its own trusted\n * mint (a desktop app's main process holding the user's key) passes one\n * instead, and the handle uses it for the first mint and every re-mint.\n */\nexport type CollabMint = (params: {\n assetId: string;\n access: 'view' | 'edit';\n}) => Promise<CollabTokenResponse>;\n\n/** What a host's local copy reads of the handle's transport. */\nexport interface GenericDocTransportView {\n /** True for a transaction the transport applied (the server's state, a peer's edit). */\n isRemoteOrigin: (origin: unknown) => boolean;\n /** Local edits the server has not echoed yet, or `null`. */\n getUnconfirmed: () => Y.ContentIds | null;\n /** Connected, past the initial sync, and nothing unconfirmed. */\n isFullySynced: () => boolean;\n}\n\n/** What `beforeConnect` is asked about. */\nexport interface GenericDocConnectGate {\n /** The grant the connection would use (its access is the server's current verdict). */\n grant: CollabTokenResponse;\n /** The handle has not connected yet. */\n firstConnection: boolean;\n /** How long the handle had been without a connection, when it had one before. */\n offlineForMs: number | null;\n /** Local edits made without a connection (or inherited from an earlier session) wait to be sent. */\n hasUnsyncedEdits: boolean;\n}\n\n/** A host's local copy of the document (`@athenaintel/local-copy` behind a host's glue). */\nexport interface GenericDocLocalCopy {\n /**\n * Called once, before the first mint: apply the stored copy to `doc` and return the local edits\n * it holds that the server never acknowledged. The handle sends them and waits for their echo\n * like its own. A failure here must resolve `{ unsyncedEdits: null }`: the handle then runs\n * without a copy.\n */\n prepare: (params: {\n doc: Y.Doc;\n transport: GenericDocTransportView;\n }) => Promise<{ unsyncedEdits: Y.ContentIds | null }>;\n /** The handle's unconfirmed edits or sync state changed. */\n transportChanged: () => void;\n /**\n * An explicit host pause/resume policy changed. Invalidate decisions that must be checked afresh\n * before a later manual save. A pause runs after its provider is destroyed and its status is\n * disconnected, so edits restored by the hook stay local. A resume runs before minting.\n * Network retries and an immediate conflict `resume()` do not call it.\n */\n connectionPolicyChanged?: (enabled: boolean) => void;\n /**\n * Asked after each mint and before the connection it would open: the first connection, a\n * reconnect after an outage longer than `offlineGateAfterMs`, and a re-mint after a revocation\n * (never a scheduled token refresh of a live connection, never past `resume()`). The host\n * checks what it must before anything is sent (the document still opens here; access; edits\n * made without a connection against the server's). `'hold'` keeps the handle from connecting\n * until `resume()`; a throw counts as \"not yet\" and is asked again on the next attempt.\n */\n beforeConnect?: (gate: GenericDocConnectGate) => Promise<'connect' | 'hold'>;\n}\n\n/** After this long without a socket, the handle reconnects itself (re-mint, gate) instead of the provider. */\nexport const DEFAULT_OFFLINE_GATE_AFTER_MS = 15_000;\n\n/** Retry delays for a mint that failed for want of the network. */\nconst MINT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 15_000, 30_000, 60_000];\n\n/**\n * The default `retryMintError`: a network failure, a timeout, a rate limit or a server error is\n * worth retrying; a refusal (401/403/404) is the server's verdict and ends the handle.\n */\nexport function isRetryableMintError(error: unknown): boolean {\n if (error instanceof CollabTokenError) {\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n return error instanceof TypeError || (error instanceof DOMException && error.name === 'TimeoutError');\n}\n\nfunction resolveMint({ auth, mint }: { auth?: CollabAuth; mint?: CollabMint }): CollabMint {\n if (mint) return mint;\n if (!auth) throw new Error('connectGenericDoc needs `auth` or `mint`');\n return ({ assetId, access }) => mintCollabToken({ auth, assetId, access });\n}\n\nexport function connectGenericDoc(args: {\n assetId: string;\n /** Credentials for the default mint; not used when `mint` is given. */\n auth?: CollabAuth;\n access?: 'view' | 'edit';\n mint?: CollabMint;\n /** A local copy of the document the host keeps (see {@link GenericDocLocalCopy}). */\n localCopy?: GenericDocLocalCopy;\n /** Whether a failed mint is worth retrying; defaults to {@link isRetryableMintError}. */\n retryMintError?: (error: unknown) => boolean;\n /** See {@link DEFAULT_OFFLINE_GATE_AFTER_MS}. */\n offlineGateAfterMs?: number;\n /** Start without connecting or minting (for a host's manual-save mode). Defaults to true. */\n connectionEnabled?: boolean;\n}): GenericDocHandle {\n const access = args.access ?? 'view';\n const mint = resolveMint({ auth: args.auth, mint: args.mint });\n const localCopy = args.localCopy;\n const retryMintError = args.retryMintError ?? isRetryableMintError;\n const offlineGateAfterMs = args.offlineGateAfterMs ?? DEFAULT_OFFLINE_GATE_AFTER_MS;\n const doc = new Y.Doc();\n const listeners = new Set<() => void>();\n\n let provider: WebsocketProvider | null = null;\n let refreshTimer: ReturnType<typeof setTimeout> | null = null;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n let offlineTimer: ReturnType<typeof setTimeout> | null = null;\n /** The provider whose socket was still opening, with nothing to send, at the threshold. */\n let openingPastThreshold: WebsocketProvider | null = null;\n let mintRetries = 0;\n let destroyed = false;\n let connectionEnabled = args.connectionEnabled ?? true;\n let status: GenericDocStatus = connectionEnabled ? 'connecting' : 'disconnected';\n let synced = false;\n let accessType: 'r' | 'rw' | null = null;\n let error: Error | null = null;\n let lastPresence: Record<string, unknown> | null = null;\n let version = 0;\n let consecutiveRemints = 0;\n let prepared = localCopy === undefined;\n let held = false;\n let heldGrant: CollabTokenResponse | null = null;\n let everConnected = false;\n let disconnectedSince: number | null = null;\n /** Bumped by every connect attempt: an attempt that finds it changed after an await stops. */\n let connectSeq = 0;\n /** Local edits no provider holds: handed on by a replaced provider, or made with none. */\n let carriedUpdates: WebsocketProvider['unconfirmedUpdates'] = [];\n let localChangesSynced = true;\n\n const notify = () => {\n version += 1;\n for (const listener of listeners) listener();\n };\n\n const unconfirmedEdits = (): Y.ContentIds | null => {\n const all = [...carriedUpdates, ...(provider?.unconfirmedUpdates ?? [])].map(\n (entry) => entry.ids as Y.ContentIds\n );\n if (all.length === 0) return null;\n return all.length === 1 ? (all[0] as Y.ContentIds) : Y.mergeContentIds(all);\n };\n\n const transport: GenericDocTransportView = {\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n getUnconfirmed: unconfirmedEdits,\n isFullySynced: () => status === 'connected' && synced && localChangesSynced,\n };\n\n const transportChanged = () => {\n localCopy?.transportChanged();\n };\n\n const refreshLocalChangesSynced = () => {\n const next = carriedUpdates.length === 0 && (provider?.unconfirmedUpdates.length ?? 0) === 0;\n const changed = next !== localChangesSynced;\n localChangesSynced = next;\n // After the flag: the copy reads `isFullySynced()` in its callback.\n // Before notifying: the callback can restore values and create more unconfirmed edits.\n transportChanged();\n if (changed) notify();\n };\n\n // An edit made while no provider exists (a re-mint in flight, offline) is sent by the next one,\n // which takes it as unconfirmed. The local copy's own load is not an edit.\n doc.on('update', (update: Uint8Array, origin: unknown) => {\n if (!prepared || provider !== null || destroyed || origin instanceof WebsocketProvider) return;\n carriedUpdates = [\n ...carriedUpdates,\n { created: Date.now(), ids: Y.createContentIdsFromUpdate(update) },\n ];\n refreshLocalChangesSynced();\n });\n\n const setStatus = (next: GenericDocStatus, err: Error | null = null) => {\n if (destroyed && next !== 'closed') return;\n const wasConnected = status === 'connected';\n status = next;\n error = err;\n if (next === 'connected') {\n everConnected = true;\n disconnectedSince = null;\n clearOfflineTimer();\n } else if (wasConnected || (everConnected && disconnectedSince === null)) {\n disconnectedSince = Date.now();\n }\n transportChanged();\n notify();\n };\n\n const clearRefreshTimer = () => {\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer);\n refreshTimer = null;\n }\n };\n\n const clearRetryTimer = () => {\n if (retryTimer !== null) {\n clearTimeout(retryTimer);\n retryTimer = null;\n }\n };\n\n function clearOfflineTimer() {\n if (offlineTimer !== null) {\n clearTimeout(offlineTimer);\n offlineTimer = null;\n }\n }\n\n const teardownProvider = () => {\n clearRefreshTimer();\n // A future provider must complete its own initial sync; the doc keeps its\n // content either way. Subscribers must observe the flip immediately —\n // waiting for the next provider event would let them act on synced=true\n // across the replacement gap.\n if (synced) {\n synced = false;\n notify();\n }\n if (provider) {\n // Its unconfirmed edits outlive it: the next provider sends them and waits for their echo.\n const previous = provider;\n provider = null;\n carriedUpdates = [...carriedUpdates, ...previous.unconfirmedUpdates];\n previous.destroy();\n }\n };\n\n const scheduleRefresh = (grant: CollabTokenResponse) => {\n clearRefreshTimer();\n const delay = refreshDelayMs({ expiresAtMs: grant.expires_at_ms, now: Date.now() });\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, delay);\n };\n\n /** A failed attempt that is worth retrying: try again later, or as soon as the network returns. */\n const scheduleRetry = () => {\n clearRetryTimer();\n const delay = MINT_RETRY_DELAYS_MS[Math.min(mintRetries, MINT_RETRY_DELAYS_MS.length - 1)];\n mintRetries += 1;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void connect();\n }, delay);\n };\n\n const onBrowserOnline = () => {\n // Only a handle waiting to retry: a refused or permanently closed one stays stopped.\n if (\n destroyed || !connectionEnabled || status === 'closed' || status === 'error' ||\n provider !== null || held\n ) return;\n mintRetries = 0;\n clearRetryTimer();\n void connect();\n };\n if (typeof window !== 'undefined') window.addEventListener('online', onBrowserOnline);\n\n /**\n * Past the gate's threshold without a socket, the handle reconnects itself (re-mint, gate). A\n * socket still being opened with nothing waiting to be sent is left to finish (a slow network\n * is not restarted every threshold), and the handle looks again a threshold later; if it opens\n * holding edits made since, they go through the gate first (`status`).\n */\n const armOfflineTakeover = () => {\n if (!connectionEnabled || offlineTimer !== null || !localCopy?.beforeConnect) return;\n offlineTimer = setTimeout(() => {\n offlineTimer = null;\n if (destroyed || !connectionEnabled || status === 'connected' || provider === null) return;\n if (provider.wsconnecting && !hasUnsyncedLocalEdits()) {\n openingPastThreshold = provider;\n armOfflineTakeover();\n return;\n }\n teardownProvider();\n void connect();\n }, offlineGateAfterMs);\n };\n\n const hasUnsyncedLocalEdits = () =>\n carriedUpdates.length > 0 || (provider?.unconfirmedUpdates.length ?? 0) > 0;\n\n\n const connect = async (opts?: {\n scheduledRefresh?: boolean;\n skipGate?: boolean;\n grant?: CollabTokenResponse;\n }): Promise<void> => {\n if (destroyed || !connectionEnabled) return;\n const seq = ++connectSeq;\n await preparing;\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n // Only a live connection is refreshed in place (and skips the host's gate); a refresh while the\n // socket is down is a reconnect like any other.\n const scheduledRefresh = opts?.scheduledRefresh === true && status === 'connected';\n // A scheduled refresh mints FIRST and keeps the live session up: the old\n // token has ~5 minutes of headroom, so a transient mint failure retries\n // on a short timer instead of dropping a healthy connection.\n if (!scheduledRefresh) {\n teardownProvider();\n } else {\n clearRefreshTimer();\n }\n clearRetryTimer();\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n let grant: CollabTokenResponse;\n if (opts?.grant && opts.grant.expires_at_ms - Date.now() > MIN_REFRESH_DELAY_MS) {\n grant = opts.grant;\n } else {\n try {\n grant = await mint({ assetId: args.assetId, access });\n } catch (err) {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (scheduledRefresh) {\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, MIN_REFRESH_DELAY_MS);\n return;\n }\n if (retryMintError(err)) {\n // Offline (or the mint's server is): keep the document and try again.\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n // A denied mint is authoritative (revoked / not shared / not eligible).\n setStatus('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n mintRetries = 0;\n accessType = grant.access_type;\n const beforeConnect = localCopy?.beforeConnect;\n if (beforeConnect && !scheduledRefresh && !opts?.skipGate) {\n const firstConnection = !everConnected;\n const offlineForMs = disconnectedSince === null ? null : Date.now() - disconnectedSince;\n let decision: 'connect' | 'hold';\n try {\n decision = await beforeConnect({\n grant,\n firstConnection,\n offlineForMs,\n hasUnsyncedEdits: hasUnsyncedLocalEdits(),\n });\n } catch {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (decision === 'hold') {\n held = true;\n heldGrant = grant;\n if (status !== 'disconnected') setStatus('disconnected');\n else notify();\n return;\n }\n }\n if (scheduledRefresh) {\n teardownProvider();\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n\n const nextProvider = new WebsocketProvider(grant.ws_url, `${grant.org}/${grant.doc_id}`, doc, {\n params: {\n yauth: grant.token,\n branch: grant.branch,\n gc: 'true',\n },\n // BroadcastChannel would sync same-origin clients locally, bypassing the\n // server's permission enforcement (a read-only tab could write into an\n // editor tab's doc). Permissioned docs must round-trip the server.\n disableBc: true,\n });\n provider = nextProvider;\n nextProvider.unconfirmedUpdates = [...carriedUpdates, ...nextProvider.unconfirmedUpdates];\n carriedUpdates = [];\n refreshLocalChangesSynced();\n\n nextProvider.on('sync-status', () => {\n if (provider !== nextProvider) return;\n refreshLocalChangesSynced();\n });\n\n nextProvider.on('status', (event: { status: 'connecting' | 'connected' | 'disconnected' }) => {\n if (provider !== nextProvider) return;\n if (\n event.status === 'connected' &&\n openingPastThreshold === nextProvider &&\n hasUnsyncedLocalEdits()\n ) {\n // Opened after the threshold holding edits made meanwhile: before its handshake sends\n // them (`@y/websocket` reports `connected` first), they go through the gate.\n teardownProvider();\n void connect();\n return;\n }\n if (event.status === 'connected') {\n consecutiveRemints = 0;\n }\n setStatus(event.status);\n if (event.status === 'connected' && lastPresence !== null) {\n nextProvider.awareness.setLocalState(lastPresence);\n }\n // `@y/websocket` reports `disconnected` only for a socket that had opened: one that never\n // opens (the server unreachable while the mint goes through) only ever reports `connecting`,\n // and is just as offline.\n if (event.status !== 'connected') armOfflineTakeover();\n });\n // Its first `connecting` came from its constructor, before this listener existed.\n if (!nextProvider.wsconnected) armOfflineTakeover();\n\n nextProvider.on('sync', (state: boolean) => {\n if (provider !== nextProvider) return;\n if (synced !== state) {\n synced = state;\n transportChanged();\n notify();\n }\n });\n\n nextProvider.on('connection-close', (event: CloseEvent | null) => {\n if (provider !== nextProvider) return;\n const action = classifyClose(event?.code);\n if (action === 'remint') {\n // Revoked mid-session: a fresh mint re-runs the server-side permission\n // check. If access is truly gone the mint 403s and we land in 'error'.\n // Bounded: repeated 4401s without an intervening successful connect\n // mean the server keeps rejecting freshly minted tokens — stop rather\n // than loop mint→connect→kick.\n consecutiveRemints += 1;\n teardownProvider();\n if (consecutiveRemints > MAX_CONSECUTIVE_REMINTS) {\n setStatus(\n 'closed',\n new Error('Access repeatedly revoked mid-session (4401); giving up.')\n );\n return;\n }\n void connect();\n } else if (action === 'stop') {\n teardownProvider();\n setStatus(\n 'closed',\n new Error(`Connection closed permanently (code ${event?.code ?? 'unknown'})`)\n );\n }\n // 'retry': the provider's exponential backoff handles it, until the offline takeover.\n });\n\n nextProvider.awareness.on('change', () => {\n if (provider !== nextProvider) return;\n notify();\n });\n\n scheduleRefresh(grant);\n };\n\n const preparing: Promise<void> = localCopy\n ? localCopy\n .prepare({ doc, transport })\n .catch(() => ({ unsyncedEdits: null }))\n .then(({ unsyncedEdits }) => {\n if (destroyed) return;\n if (unsyncedEdits && !(unsyncedEdits.inserts.isEmpty() && unsyncedEdits.deletes.isEmpty())) {\n carriedUpdates = [...carriedUpdates, { created: Date.now(), ids: unsyncedEdits }];\n }\n prepared = true;\n refreshLocalChangesSynced();\n notify();\n })\n : Promise.resolve();\n\n void connect();\n\n const waitForSync = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n const terminal = (): Error | null => {\n if (destroyed) return new Error('Handle destroyed before initial sync');\n if (status === 'closed' || status === 'error') {\n return error ?? new Error(`Connection ${status} before initial sync`);\n }\n return null;\n };\n if (synced) {\n resolve();\n return;\n }\n const immediate = terminal();\n if (immediate) {\n reject(immediate);\n return;\n }\n const cleanup = () => {\n clearTimeout(timer);\n listeners.delete(listener);\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`Timed out after ${timeoutMs}ms waiting for initial sync`));\n }, timeoutMs);\n const listener = () => {\n if (synced) {\n cleanup();\n resolve();\n return;\n }\n const err = terminal();\n if (err) {\n cleanup();\n reject(err);\n }\n };\n listeners.add(listener);\n });\n\n const waitForAcknowledged = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n let finished = false;\n let checkQueued = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const finish = (failure?: Error) => {\n if (finished) return;\n finished = true;\n if (timer !== null) clearTimeout(timer);\n listeners.delete(check);\n if (failure) reject(failure);\n else resolve();\n };\n const check = () => {\n if (finished || checkQueued) return;\n checkQueued = true;\n // All synchronous transport hooks and change listeners finish before a save settles.\n queueMicrotask(() => {\n checkQueued = false;\n if (finished) return;\n if (destroyed) {\n finish(new Error('Handle destroyed before local changes were acknowledged'));\n } else if (!connectionEnabled) {\n finish(new Error('Connection disabled before local changes were acknowledged'));\n } else if (status === 'closed' || status === 'error') {\n finish(error ?? new Error(`Connection ${status} before local changes were acknowledged`));\n } else if (prepared && status === 'connected' && synced && localChangesSynced) {\n finish();\n }\n });\n };\n timer = setTimeout(() => {\n finish(new Error(`Timed out after ${timeoutMs}ms waiting for local changes to be acknowledged`));\n }, timeoutMs);\n listeners.add(check);\n check();\n });\n\n return {\n doc,\n get status() {\n return status;\n },\n get synced() {\n return synced;\n },\n get localChangesSynced() {\n return localChangesSynced;\n },\n get accessType() {\n return accessType;\n },\n get error() {\n return error;\n },\n get prepared() {\n return prepared;\n },\n get connectionEnabled() {\n return connectionEnabled;\n },\n get held() {\n return held;\n },\n get version() {\n return version;\n },\n waitForSync,\n waitForAcknowledged,\n getPresence: () => {\n if (!provider) return [];\n const entries: PresenceEntry[] = [];\n provider.awareness.getStates().forEach((state, clientId) => {\n entries.push({ clientId, state: state as Record<string, unknown> });\n });\n return entries;\n },\n setPresence: (state) => {\n lastPresence = state;\n provider?.awareness.setLocalState(state);\n },\n refreshNow: () => {\n if (!connectionEnabled || held) return Promise.resolve();\n return provider ? connect({ scheduledRefresh: true }) : connect();\n },\n setConnectionEnabled: (enabled) => {\n if (destroyed || enabled === connectionEnabled) return;\n connectionEnabled = enabled;\n if (!enabled) {\n // Invalidate every mint/gate already in flight before tearing down the live provider.\n connectSeq += 1;\n clearRetryTimer();\n clearOfflineTimer();\n teardownProvider();\n setStatus('disconnected');\n localCopy?.connectionPolicyChanged?.(false);\n return;\n }\n localCopy?.connectionPolicyChanged?.(true);\n held = false;\n heldGrant = null;\n setStatus('connecting');\n void connect();\n },\n resume: () => {\n if (!held || destroyed || !connectionEnabled) return;\n held = false;\n const grant = heldGrant;\n heldGrant = null;\n notify();\n void connect({ skipGate: true, grant: grant ?? undefined });\n },\n unconfirmedEdits,\n onChange: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n destroy: () => {\n if (destroyed) return;\n destroyed = true;\n teardownProvider();\n clearRetryTimer();\n clearOfflineTimer();\n if (typeof window !== 'undefined') window.removeEventListener('online', onBrowserOnline);\n status = 'closed';\n // Final notification so pending waitForSync callers reject instead of\n // hanging on listeners that are about to be dropped.\n for (const listener of [...listeners]) listener();\n listeners.clear();\n doc.destroy();\n },\n };\n}\n\nexport { CollabTokenError };\nexport type { CollabAuth, CollabTokenResponse };\n"],"names":["CollabTokenError","mint","mintCollabToken","Y","WebsocketProvider","refreshDelayMs","MIN_REFRESH_DELAY_MS","classifyClose","MAX_CONSECUTIVE_REMINTS"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.cjs","sources":["../../src/collab/client.ts"],"sourcesContent":["/**\n * Vanilla (framework-agnostic) live client for Generic Doc assets.\n *\n * `connectGenericDoc` owns the full connection lifecycle: mint a room-bound\n * token via the public API, open the Keryx WebSocket with the v14 provider\n * (`@y/websocket` + `@y/y`), re-mint before expiry, apply the close-code\n * policy (4401 → one fresh mint, other 44xx → permanent stop, everything\n * else → provider backoff), and expose presence from awareness. React apps\n * use `useGenericDoc` from `@athenaintel/react/collab` instead of calling\n * this directly.\n *\n * A host that keeps a local copy of the document (`localCopy`) gets it applied\n * before the first connection, keeps its unacknowledged edits waiting across\n * sessions, and can hold a connection that would send edits made without one\n * until it has checked them against the server (`beforeConnect`). Offline, a\n * mint that fails for want of the network is retried (`retryMintError`)\n * instead of ending the handle, and past `offlineGateAfterMs` without a socket\n * the handle reconnects itself, re-minting each time, so every reconnect after\n * a real outage re-checks access and passes the host's gate.\n *\n * A write the host makes on its own (an editor's housekeeping, a restored value)\n * goes out as housekeeping when it is made inside `runWithDocUpdateAttributions`\n * for `handle.doc` with `BACKGROUND_UPDATE_ATTRIBUTIONS`: the socket appends the\n * scope's attributions to the update, which Keryx counts as system work instead\n * of the person's edit (`socketFor`). One made while no socket is open is kept\n * until Keryx acknowledges it and sent the same way, ahead of the next\n * connection's sync (`UnconfirmedUpdateAttributions`). On a read-only grant\n * nothing that carries document content leaves the socket.\n *\n * A host that can read Keryx's document status with the room's grant\n * (`readDocumentStatus`) learns whether Keryx takes the room's writes for now\n * (`handle.writesRefused`): a quarantined room takes none, and its socket drops\n * every edit unconfirmed without a word (`document-status.ts`).\n */\n\nimport { receiveOnlyWebSocket } from '@athenaintel/keryx-http/receive-only-socket';\nimport { UnconfirmedUpdateAttributions } from '@athenaintel/keryx-http/unconfirmed-update-attributions';\nimport {\n attributingWebSocket,\n docUpdateAttributions,\n} from '@athenaintel/keryx-http/update-attributions';\nimport { WebsocketProvider } from '@y/websocket';\nimport * as Y from '@y/y';\nimport { classifyClose } from './close-policy';\nimport { type ReadDocumentStatus, watchDocumentStatus } from './document-status';\nimport {\n type CollabAuth,\n type CollabTokenResponse,\n CollabTokenError,\n mintCollabToken,\n} from './mint';\nimport { MAX_CONSECUTIVE_REMINTS, MIN_REFRESH_DELAY_MS, refreshDelayMs } from './token-refresh';\n\nexport type GenericDocStatus =\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'closed'\n | 'error';\n\nexport interface PresenceEntry {\n clientId: number;\n state: Record<string, unknown>;\n}\n\nexport interface GenericDocHandle {\n /** The live shared document. Owned by the handle; destroyed with it. */\n readonly doc: Y.Doc;\n readonly status: GenericDocStatus;\n /**\n * Whether the initial server sync has completed for the current connection.\n * `status === 'connected'` fires before the server state arrives, so a doc\n * read immediately after connect can still be empty — gate first reads on\n * this (or `waitForSync`).\n */\n readonly synced: boolean;\n /**\n * Whether every change made to this document has reached the server: `false` from a local edit\n * until the server sends it back (`@y/websocket`'s `syncStatus.localUpdatesSynced`; yhub echoes\n * every update to its sender). Kept across reconnects and re-mints: a replaced provider hands its\n * unconfirmed edits to the next, and an edit made between providers waits for one. A host that\n * closes the document while this is `false` loses those edits, unless a local copy keeps them.\n */\n readonly localChangesSynced: boolean;\n /** Granted access from the last successful mint. */\n readonly accessType: 'r' | 'rw' | null;\n /** Terminal error, when status is 'error' or 'closed'. */\n readonly error: Error | null;\n /**\n * Whether the document holds what the host's local copy stored (always `true` without one).\n * Mount readers after it: until then the document is still empty.\n */\n readonly prepared: boolean;\n /** Whether this host allows a live connection. Disabled documents remain editable locally. */\n readonly connectionEnabled: boolean;\n /**\n * A connection the host's `beforeConnect` held: the handle waits, sending nothing, until the\n * host calls `resume()` (or destroys the handle).\n */\n readonly held: boolean;\n /** Monotonic change counter — bumps on every status/presence notification. */\n readonly version: number;\n /**\n * Resolve once the initial server sync completes; reject on timeout, on a\n * terminal connection state, or if the handle is destroyed first.\n */\n waitForSync: (timeoutMs?: number) => Promise<void>;\n /**\n * Resolve once connected, initially synced, and every local change has been acknowledged,\n * including any edits the local-copy hook restores after sync. The host must prevent further\n * editing while saving a checkpoint. Reject on timeout, a disabled connection, or a terminal state.\n */\n waitForAcknowledged: (timeoutMs?: number) => Promise<void>;\n getPresence: () => PresenceEntry[];\n /** Broadcast this client's presence state (requires a live connection). */\n setPresence: (state: Record<string, unknown> | null) => void;\n /**\n * Force an early token refresh. Session-preserving: the live connection\n * stays up until the fresh token is minted; a failed mint retries on a\n * short timer instead of dropping the session. Without a connection it\n * reconnects now.\n */\n refreshNow: () => Promise<void>;\n /**\n * Disable all connections without losing the document or its pending edits. Enabling mints a\n * fresh grant and runs the host's beforeConnect gate; it never bypasses a permission or review.\n */\n setConnectionEnabled: (enabled: boolean) => void;\n /** Connect past a hold, without asking `beforeConnect` again. */\n resume: () => void;\n /** Local edits the server has not echoed yet (handed between providers too), or `null`. */\n unconfirmedEdits: () => Y.ContentIds | null;\n /**\n * Keryx's document status, as last read with the room's grant, says the room takes no writes for\n * now: it is quarantined while it is repaired, and its socket drops every edit unconfirmed until\n * it is released. Always `false` without `readDocumentStatus`, on a read-only grant, and whenever\n * the last read could not answer.\n */\n readonly writesRefused: boolean;\n onChange: (listener: () => void) => () => void;\n destroy: () => void;\n}\n\n/**\n * Issues a room-bound Keryx token for one asset. The default calls the public\n * `/collab-token` route with the handle's `auth`; a host with its own trusted\n * mint (a desktop app's main process holding the user's key) passes one\n * instead, and the handle uses it for the first mint and every re-mint.\n */\nexport type CollabMint = (params: {\n assetId: string;\n access: 'view' | 'edit';\n}) => Promise<CollabTokenResponse>;\n\n/** What a host's local copy reads of the handle's transport. */\nexport interface GenericDocTransportView {\n /** True for a transaction the transport applied (the server's state, a peer's edit). */\n isRemoteOrigin: (origin: unknown) => boolean;\n /** Local edits the server has not echoed yet, or `null`. */\n getUnconfirmed: () => Y.ContentIds | null;\n /** Connected, past the initial sync, and nothing unconfirmed. */\n isFullySynced: () => boolean;\n}\n\n/** What `beforeConnect` is asked about. */\nexport interface GenericDocConnectGate {\n /** The grant the connection would use (its access is the server's current verdict). */\n grant: CollabTokenResponse;\n /** The handle has not connected yet. */\n firstConnection: boolean;\n /** How long the handle had been without a connection, when it had one before. */\n offlineForMs: number | null;\n /** Local edits made without a connection (or inherited from an earlier session) wait to be sent. */\n hasUnsyncedEdits: boolean;\n}\n\n/** A host's local copy of the document (`@athenaintel/local-copy` behind a host's glue). */\nexport interface GenericDocLocalCopy {\n /**\n * Called once, before the first mint: apply the stored copy to `doc` and return the local edits\n * it holds that the server never acknowledged. The handle sends them and waits for their echo\n * like its own. A failure here must resolve `{ unsyncedEdits: null }`: the handle then runs\n * without a copy.\n */\n prepare: (params: {\n doc: Y.Doc;\n transport: GenericDocTransportView;\n }) => Promise<{ unsyncedEdits: Y.ContentIds | null }>;\n /** The handle's unconfirmed edits or sync state changed. */\n transportChanged: () => void;\n /**\n * An explicit host pause/resume policy changed. Invalidate decisions that must be checked afresh\n * before a later manual save. A pause runs after its provider is destroyed and its status is\n * disconnected, so edits restored by the hook stay local. A resume runs before minting.\n * Network retries and an immediate conflict `resume()` do not call it.\n */\n connectionPolicyChanged?: (enabled: boolean) => void;\n /**\n * Asked after each mint and before the connection it would open: the first connection, a\n * reconnect after an outage longer than `offlineGateAfterMs`, and a re-mint after a revocation\n * (never a scheduled token refresh of a live connection, never past `resume()`). The host\n * checks what it must before anything is sent (the document still opens here; access; edits\n * made without a connection against the server's). `'hold'` keeps the handle from connecting\n * until `resume()`; a throw counts as \"not yet\" and is asked again on the next attempt.\n */\n beforeConnect?: (gate: GenericDocConnectGate) => Promise<'connect' | 'hold'>;\n}\n\n/** After this long without a socket, the handle reconnects itself (re-mint, gate) instead of the provider. */\nexport const DEFAULT_OFFLINE_GATE_AFTER_MS = 15_000;\n\n/** Retry delays for a mint that failed for want of the network. */\nconst MINT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 15_000, 30_000, 60_000];\n\n/**\n * The default `retryMintError`: a network failure, a timeout, a rate limit or a server error is\n * worth retrying; a refusal (401/403/404) is the server's verdict and ends the handle.\n */\nexport function isRetryableMintError(error: unknown): boolean {\n if (error instanceof CollabTokenError) {\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n return error instanceof TypeError || (error instanceof DOMException && error.name === 'TimeoutError');\n}\n\nfunction resolveMint({ auth, mint }: { auth?: CollabAuth; mint?: CollabMint }): CollabMint {\n if (mint) return mint;\n if (!auth) throw new Error('connectGenericDoc needs `auth` or `mint`');\n return ({ assetId, access }) => mintCollabToken({ auth, assetId, access });\n}\n\n/**\n * The socket a provider for `grant` opens (`@athenaintel/keryx-http`'s wrappers, the ones\n * Olympus's rooms use). On a read-write grant, each sync update a write made inside a\n * `runWithDocUpdateAttributions` scope for `doc` sends carries the scope's attributions, which\n * Keryx reads after the update (`origin: background` counts as system work; a Keryx that predates\n * the trailer ignores it), and its sync step 2 goes out behind such writes made while no socket\n * was open, each as its own marked update (`unconfirmed`). On a read-only grant no frame that\n * carries document content leaves: a sync step 2 or an update is dropped (Keryx ignores them on\n * such a grant anyway), awareness passes. Read when each provider is built, as `@y/websocket` reads\n * `WebSocket`; `undefined` where there is none, and the provider fails at connect as it always did.\n */\nfunction socketFor({\n grant,\n doc,\n unconfirmed,\n}: {\n grant: CollabTokenResponse;\n doc: Y.Doc;\n unconfirmed: UnconfirmedUpdateAttributions;\n}): typeof WebSocket | undefined {\n const Base: typeof WebSocket | undefined = globalThis.WebSocket;\n if (typeof Base !== 'function') return undefined;\n if (grant.access_type === 'r') return receiveOnlyWebSocket({ Base });\n return attributingWebSocket({\n Base,\n attributionsFor: () => docUpdateAttributions(doc),\n unconfirmed,\n });\n}\n\nexport function connectGenericDoc(args: {\n assetId: string;\n /** Credentials for the default mint; not used when `mint` is given. */\n auth?: CollabAuth;\n access?: 'view' | 'edit';\n mint?: CollabMint;\n /** A local copy of the document the host keeps (see {@link GenericDocLocalCopy}). */\n localCopy?: GenericDocLocalCopy;\n /** Whether a failed mint is worth retrying; defaults to {@link isRetryableMintError}. */\n retryMintError?: (error: unknown) => boolean;\n /** See {@link DEFAULT_OFFLINE_GATE_AFTER_MS}. */\n offlineGateAfterMs?: number;\n /** Start without connecting or minting (for a host's manual-save mode). Defaults to true. */\n connectionEnabled?: boolean;\n /**\n * Reads Keryx's document status with the room's grant (see `ReadDocumentStatus`), for\n * `handle.writesRefused`. A host that cannot read it leaves it out.\n */\n readDocumentStatus?: ReadDocumentStatus;\n}): GenericDocHandle {\n const access = args.access ?? 'view';\n const mint = resolveMint({ auth: args.auth, mint: args.mint });\n const localCopy = args.localCopy;\n const retryMintError = args.retryMintError ?? isRetryableMintError;\n const offlineGateAfterMs = args.offlineGateAfterMs ?? DEFAULT_OFFLINE_GATE_AFTER_MS;\n const doc = new Y.Doc();\n // Writes made in a `runWithDocUpdateAttributions` scope, until Keryx acknowledges them: the\n // sockets every provider opens send those made while no socket was open ahead of their sync.\n const unconfirmedAttributions = new UnconfirmedUpdateAttributions({\n doc,\n attributionsFor: () => docUpdateAttributions(doc),\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n });\n const listeners = new Set<() => void>();\n\n let provider: WebsocketProvider | null = null;\n let refreshTimer: ReturnType<typeof setTimeout> | null = null;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n let offlineTimer: ReturnType<typeof setTimeout> | null = null;\n /** The provider whose socket was still opening, with nothing to send, at the threshold. */\n let openingPastThreshold: WebsocketProvider | null = null;\n let mintRetries = 0;\n let destroyed = false;\n let connectionEnabled = args.connectionEnabled ?? true;\n let status: GenericDocStatus = connectionEnabled ? 'connecting' : 'disconnected';\n let synced = false;\n let accessType: 'r' | 'rw' | null = null;\n let error: Error | null = null;\n let lastPresence: Record<string, unknown> | null = null;\n let version = 0;\n let consecutiveRemints = 0;\n let prepared = localCopy === undefined;\n let held = false;\n let heldGrant: CollabTokenResponse | null = null;\n let everConnected = false;\n let disconnectedSince: number | null = null;\n /** Bumped by every connect attempt: an attempt that finds it changed after an await stops. */\n let connectSeq = 0;\n /** Local edits no provider holds: handed on by a replaced provider, or made with none. */\n let carriedUpdates: WebsocketProvider['unconfirmedUpdates'] = [];\n let localChangesSynced = true;\n /** The grant the current provider connects with. */\n let liveGrant: CollabTokenResponse | null = null;\n /** Keryx's auth re-check closed the socket (4401): the next connection reads the document status. */\n let readStatusOnConnect = false;\n\n const notify = () => {\n version += 1;\n for (const listener of listeners) listener();\n };\n\n const documentStatus = args.readDocumentStatus\n ? watchDocumentStatus({\n read: args.readDocumentStatus,\n currentGrant: () => liveGrant,\n onChange: () => {\n if (!destroyed) notify();\n },\n })\n : null;\n\n const unconfirmedEdits = (): Y.ContentIds | null => {\n const all = [...carriedUpdates, ...(provider?.unconfirmedUpdates ?? [])].map(\n (entry) => entry.ids as Y.ContentIds\n );\n if (all.length === 0) return null;\n return all.length === 1 ? (all[0] as Y.ContentIds) : Y.mergeContentIds(all);\n };\n\n const transport: GenericDocTransportView = {\n isRemoteOrigin: (origin) => origin instanceof WebsocketProvider,\n getUnconfirmed: unconfirmedEdits,\n isFullySynced: () => status === 'connected' && synced && localChangesSynced,\n };\n\n const transportChanged = () => {\n localCopy?.transportChanged();\n };\n\n const refreshLocalChangesSynced = () => {\n const next = carriedUpdates.length === 0 && (provider?.unconfirmedUpdates.length ?? 0) === 0;\n const changed = next !== localChangesSynced;\n localChangesSynced = next;\n documentStatus?.unconfirmedChanged(!next);\n // After the flag: the copy reads `isFullySynced()` in its callback.\n // Before notifying: the callback can restore values and create more unconfirmed edits.\n transportChanged();\n if (changed) notify();\n };\n\n // An edit made while no provider exists (a re-mint in flight, offline) is sent by the next one,\n // which takes it as unconfirmed. The local copy's own load is not an edit.\n doc.on('update', (update: Uint8Array, origin: unknown) => {\n if (!prepared || provider !== null || destroyed || origin instanceof WebsocketProvider) return;\n carriedUpdates = [\n ...carriedUpdates,\n { created: Date.now(), ids: Y.createContentIdsFromUpdate(update) },\n ];\n refreshLocalChangesSynced();\n });\n\n const setStatus = (next: GenericDocStatus, err: Error | null = null) => {\n if (destroyed && next !== 'closed') return;\n const wasConnected = status === 'connected';\n status = next;\n error = err;\n if (next === 'connected') {\n everConnected = true;\n disconnectedSince = null;\n clearOfflineTimer();\n } else {\n if (wasConnected || (everConnected && disconnectedSince === null)) {\n disconnectedSince = Date.now();\n }\n documentStatus?.disconnected();\n }\n transportChanged();\n notify();\n };\n\n const clearRefreshTimer = () => {\n if (refreshTimer !== null) {\n clearTimeout(refreshTimer);\n refreshTimer = null;\n }\n };\n\n const clearRetryTimer = () => {\n if (retryTimer !== null) {\n clearTimeout(retryTimer);\n retryTimer = null;\n }\n };\n\n function clearOfflineTimer() {\n if (offlineTimer !== null) {\n clearTimeout(offlineTimer);\n offlineTimer = null;\n }\n }\n\n const teardownProvider = () => {\n clearRefreshTimer();\n // A future provider must complete its own initial sync; the doc keeps its\n // content either way. Subscribers must observe the flip immediately —\n // waiting for the next provider event would let them act on synced=true\n // across the replacement gap.\n if (synced) {\n synced = false;\n notify();\n }\n if (provider) {\n // Its unconfirmed edits outlive it: the next provider sends them and waits for their echo.\n const previous = provider;\n provider = null;\n carriedUpdates = [...carriedUpdates, ...previous.unconfirmedUpdates];\n previous.destroy();\n }\n };\n\n const scheduleRefresh = (grant: CollabTokenResponse) => {\n clearRefreshTimer();\n const delay = refreshDelayMs({ expiresAtMs: grant.expires_at_ms, now: Date.now() });\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, delay);\n };\n\n /** A failed attempt that is worth retrying: try again later, or as soon as the network returns. */\n const scheduleRetry = () => {\n clearRetryTimer();\n const delay = MINT_RETRY_DELAYS_MS[Math.min(mintRetries, MINT_RETRY_DELAYS_MS.length - 1)];\n mintRetries += 1;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n void connect();\n }, delay);\n };\n\n const onBrowserOnline = () => {\n // Only a handle waiting to retry: a refused or permanently closed one stays stopped.\n if (\n destroyed || !connectionEnabled || status === 'closed' || status === 'error' ||\n provider !== null || held\n ) return;\n mintRetries = 0;\n clearRetryTimer();\n void connect();\n };\n if (typeof window !== 'undefined') window.addEventListener('online', onBrowserOnline);\n\n /**\n * Past the gate's threshold without a socket, the handle reconnects itself (re-mint, gate). A\n * socket still being opened with nothing waiting to be sent is left to finish (a slow network\n * is not restarted every threshold), and the handle looks again a threshold later; if it opens\n * holding edits made since, they go through the gate first (`status`).\n */\n const armOfflineTakeover = () => {\n if (!connectionEnabled || offlineTimer !== null || !localCopy?.beforeConnect) return;\n offlineTimer = setTimeout(() => {\n offlineTimer = null;\n if (destroyed || !connectionEnabled || status === 'connected' || provider === null) return;\n if (provider.wsconnecting && !hasUnsyncedLocalEdits()) {\n openingPastThreshold = provider;\n armOfflineTakeover();\n return;\n }\n teardownProvider();\n void connect();\n }, offlineGateAfterMs);\n };\n\n const hasUnsyncedLocalEdits = () =>\n carriedUpdates.length > 0 || (provider?.unconfirmedUpdates.length ?? 0) > 0;\n\n\n const connect = async (opts?: {\n scheduledRefresh?: boolean;\n skipGate?: boolean;\n grant?: CollabTokenResponse;\n }): Promise<void> => {\n if (destroyed || !connectionEnabled) return;\n const seq = ++connectSeq;\n await preparing;\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n // Only a live connection is refreshed in place (and skips the host's gate); a refresh while the\n // socket is down is a reconnect like any other.\n const scheduledRefresh = opts?.scheduledRefresh === true && status === 'connected';\n // A scheduled refresh mints FIRST and keeps the live session up: the old\n // token has ~5 minutes of headroom, so a transient mint failure retries\n // on a short timer instead of dropping a healthy connection.\n if (!scheduledRefresh) {\n teardownProvider();\n } else {\n clearRefreshTimer();\n }\n clearRetryTimer();\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n let grant: CollabTokenResponse;\n if (opts?.grant && opts.grant.expires_at_ms - Date.now() > MIN_REFRESH_DELAY_MS) {\n grant = opts.grant;\n } else {\n try {\n grant = await mint({ assetId: args.assetId, access });\n } catch (err) {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (scheduledRefresh) {\n refreshTimer = setTimeout(() => {\n void connect({ scheduledRefresh: true });\n }, MIN_REFRESH_DELAY_MS);\n return;\n }\n if (retryMintError(err)) {\n // Offline (or the mint's server is): keep the document and try again.\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n // A denied mint is authoritative (revoked / not shared / not eligible).\n setStatus('error', err instanceof Error ? err : new Error(String(err)));\n return;\n }\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n mintRetries = 0;\n accessType = grant.access_type;\n const beforeConnect = localCopy?.beforeConnect;\n if (beforeConnect && !scheduledRefresh && !opts?.skipGate) {\n const firstConnection = !everConnected;\n const offlineForMs = disconnectedSince === null ? null : Date.now() - disconnectedSince;\n let decision: 'connect' | 'hold';\n try {\n decision = await beforeConnect({\n grant,\n firstConnection,\n offlineForMs,\n hasUnsyncedEdits: hasUnsyncedLocalEdits(),\n });\n } catch {\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (status !== 'disconnected') setStatus('disconnected');\n scheduleRetry();\n return;\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n if (decision === 'hold') {\n held = true;\n heldGrant = grant;\n if (status !== 'disconnected') setStatus('disconnected');\n else notify();\n return;\n }\n }\n if (scheduledRefresh) {\n teardownProvider();\n }\n if (destroyed || !connectionEnabled || seq !== connectSeq) return;\n\n const socket = socketFor({ grant, doc, unconfirmed: unconfirmedAttributions });\n const nextProvider = new WebsocketProvider(grant.ws_url, `${grant.org}/${grant.doc_id}`, doc, {\n params: {\n yauth: grant.token,\n branch: grant.branch,\n gc: 'true',\n },\n // BroadcastChannel would sync same-origin clients locally, bypassing the\n // server's permission enforcement (a read-only tab could write into an\n // editor tab's doc). Permissioned docs must round-trip the server.\n disableBc: true,\n ...(socket && { WebSocketPolyfill: socket }),\n });\n provider = nextProvider;\n liveGrant = grant;\n nextProvider.unconfirmedUpdates = [...carriedUpdates, ...nextProvider.unconfirmedUpdates];\n carriedUpdates = [];\n refreshLocalChangesSynced();\n\n nextProvider.on('sync-status', () => {\n if (provider !== nextProvider) return;\n refreshLocalChangesSynced();\n });\n\n nextProvider.on('status', (event: { status: 'connecting' | 'connected' | 'disconnected' }) => {\n if (provider !== nextProvider) return;\n if (\n event.status === 'connected' &&\n openingPastThreshold === nextProvider &&\n hasUnsyncedLocalEdits()\n ) {\n // Opened after the threshold holding edits made meanwhile: before its handshake sends\n // them (`@y/websocket` reports `connected` first), they go through the gate.\n teardownProvider();\n void connect();\n return;\n }\n // The connections that read Keryx's document status at once: the first, the one after an auth\n // re-check close, and one after an outage the handle treats as real. Never an ordinary\n // reconnect (a Keryx deploy reconnects every room at once).\n const readStatusNow =\n event.status === 'connected' &&\n (!everConnected ||\n readStatusOnConnect ||\n (disconnectedSince !== null && Date.now() - disconnectedSince >= offlineGateAfterMs));\n if (event.status === 'connected') {\n consecutiveRemints = 0;\n readStatusOnConnect = false;\n }\n setStatus(event.status);\n if (event.status === 'connected') documentStatus?.connected({ readNow: readStatusNow });\n if (event.status === 'connected' && lastPresence !== null) {\n nextProvider.awareness.setLocalState(lastPresence);\n }\n // `@y/websocket` reports `disconnected` only for a socket that had opened: one that never\n // opens (the server unreachable while the mint goes through) only ever reports `connecting`,\n // and is just as offline.\n if (event.status !== 'connected') armOfflineTakeover();\n });\n // Its first `connecting` came from its constructor, before this listener existed.\n if (!nextProvider.wsconnected) armOfflineTakeover();\n\n nextProvider.on('sync', (state: boolean) => {\n if (provider !== nextProvider) return;\n if (synced !== state) {\n synced = state;\n transportChanged();\n notify();\n }\n });\n\n nextProvider.on('connection-close', (event: CloseEvent | null) => {\n if (provider !== nextProvider) return;\n const action = classifyClose(event?.code);\n if (action === 'remint') {\n // Revoked mid-session: a fresh mint re-runs the server-side permission\n // check. If access is truly gone the mint 403s and we land in 'error'.\n // Bounded: repeated 4401s without an intervening successful connect\n // mean the server keeps rejecting freshly minted tokens — stop rather\n // than loop mint→connect→kick.\n consecutiveRemints += 1;\n // A quarantine and a release both close the room's sockets this way, once Keryx has written\n // or cleared the marker: the reconnected socket learns which. Until then nothing is read\n // (the handle stays `connected` through the re-mint, on a grant Keryx just bounced).\n readStatusOnConnect = true;\n documentStatus?.disconnected();\n teardownProvider();\n if (consecutiveRemints > MAX_CONSECUTIVE_REMINTS) {\n setStatus(\n 'closed',\n new Error('Access repeatedly revoked mid-session (4401); giving up.')\n );\n return;\n }\n void connect();\n } else if (action === 'stop') {\n teardownProvider();\n setStatus(\n 'closed',\n new Error(`Connection closed permanently (code ${event?.code ?? 'unknown'})`)\n );\n }\n // 'retry': the provider's exponential backoff handles it, until the offline takeover.\n });\n\n nextProvider.awareness.on('change', () => {\n if (provider !== nextProvider) return;\n notify();\n });\n\n scheduleRefresh(grant);\n };\n\n const preparing: Promise<void> = localCopy\n ? localCopy\n .prepare({ doc, transport })\n .catch(() => ({ unsyncedEdits: null }))\n .then(({ unsyncedEdits }) => {\n if (destroyed) return;\n if (unsyncedEdits && !(unsyncedEdits.inserts.isEmpty() && unsyncedEdits.deletes.isEmpty())) {\n carriedUpdates = [...carriedUpdates, { created: Date.now(), ids: unsyncedEdits }];\n }\n prepared = true;\n refreshLocalChangesSynced();\n notify();\n })\n : Promise.resolve();\n\n void connect();\n\n const waitForSync = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n const terminal = (): Error | null => {\n if (destroyed) return new Error('Handle destroyed before initial sync');\n if (status === 'closed' || status === 'error') {\n return error ?? new Error(`Connection ${status} before initial sync`);\n }\n return null;\n };\n if (synced) {\n resolve();\n return;\n }\n const immediate = terminal();\n if (immediate) {\n reject(immediate);\n return;\n }\n const cleanup = () => {\n clearTimeout(timer);\n listeners.delete(listener);\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`Timed out after ${timeoutMs}ms waiting for initial sync`));\n }, timeoutMs);\n const listener = () => {\n if (synced) {\n cleanup();\n resolve();\n return;\n }\n const err = terminal();\n if (err) {\n cleanup();\n reject(err);\n }\n };\n listeners.add(listener);\n });\n\n const waitForAcknowledged = (timeoutMs = 15_000): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n let finished = false;\n let checkQueued = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const finish = (failure?: Error) => {\n if (finished) return;\n finished = true;\n if (timer !== null) clearTimeout(timer);\n listeners.delete(check);\n if (failure) reject(failure);\n else resolve();\n };\n const check = () => {\n if (finished || checkQueued) return;\n checkQueued = true;\n // All synchronous transport hooks and change listeners finish before a save settles.\n queueMicrotask(() => {\n checkQueued = false;\n if (finished) return;\n if (destroyed) {\n finish(new Error('Handle destroyed before local changes were acknowledged'));\n } else if (!connectionEnabled) {\n finish(new Error('Connection disabled before local changes were acknowledged'));\n } else if (status === 'closed' || status === 'error') {\n finish(error ?? new Error(`Connection ${status} before local changes were acknowledged`));\n } else if (prepared && status === 'connected' && synced && localChangesSynced) {\n finish();\n }\n });\n };\n timer = setTimeout(() => {\n finish(new Error(`Timed out after ${timeoutMs}ms waiting for local changes to be acknowledged`));\n }, timeoutMs);\n listeners.add(check);\n check();\n });\n\n return {\n doc,\n get status() {\n return status;\n },\n get synced() {\n return synced;\n },\n get localChangesSynced() {\n return localChangesSynced;\n },\n get accessType() {\n return accessType;\n },\n get error() {\n return error;\n },\n get prepared() {\n return prepared;\n },\n get connectionEnabled() {\n return connectionEnabled;\n },\n get held() {\n return held;\n },\n get version() {\n return version;\n },\n get writesRefused() {\n return documentStatus?.writesRefused ?? false;\n },\n waitForSync,\n waitForAcknowledged,\n getPresence: () => {\n if (!provider) return [];\n const entries: PresenceEntry[] = [];\n provider.awareness.getStates().forEach((state, clientId) => {\n entries.push({ clientId, state: state as Record<string, unknown> });\n });\n return entries;\n },\n setPresence: (state) => {\n lastPresence = state;\n provider?.awareness.setLocalState(state);\n },\n refreshNow: () => {\n if (!connectionEnabled || held) return Promise.resolve();\n return provider ? connect({ scheduledRefresh: true }) : connect();\n },\n setConnectionEnabled: (enabled) => {\n if (destroyed || enabled === connectionEnabled) return;\n connectionEnabled = enabled;\n if (!enabled) {\n // Invalidate every mint/gate already in flight before tearing down the live provider.\n connectSeq += 1;\n clearRetryTimer();\n clearOfflineTimer();\n teardownProvider();\n setStatus('disconnected');\n localCopy?.connectionPolicyChanged?.(false);\n return;\n }\n localCopy?.connectionPolicyChanged?.(true);\n held = false;\n heldGrant = null;\n setStatus('connecting');\n void connect();\n },\n resume: () => {\n if (!held || destroyed || !connectionEnabled) return;\n held = false;\n const grant = heldGrant;\n heldGrant = null;\n notify();\n void connect({ skipGate: true, grant: grant ?? undefined });\n },\n unconfirmedEdits,\n onChange: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n destroy: () => {\n if (destroyed) return;\n destroyed = true;\n documentStatus?.destroy();\n teardownProvider();\n clearRetryTimer();\n clearOfflineTimer();\n if (typeof window !== 'undefined') window.removeEventListener('online', onBrowserOnline);\n status = 'closed';\n // Final notification so pending waitForSync callers reject instead of\n // hanging on listeners that are about to be dropped.\n for (const listener of [...listeners]) listener();\n listeners.clear();\n unconfirmedAttributions.destroy();\n doc.destroy();\n },\n };\n}\n\nexport { CollabTokenError };\nexport type { CollabAuth, CollabTokenResponse };\n"],"names":["CollabTokenError","mint","mintCollabToken","receiveOnlyWebSocket","attributingWebSocket","docUpdateAttributions","Y","UnconfirmedUpdateAttributions","WebsocketProvider","documentStatus","watchDocumentStatus","refreshDelayMs","MIN_REFRESH_DELAY_MS","classifyClose","MAX_CONSECUTIVE_REMINTS"],"mappings":"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"}
|
package/dist/collab/client.d.ts
CHANGED
|
@@ -17,8 +17,23 @@
|
|
|
17
17
|
* instead of ending the handle, and past `offlineGateAfterMs` without a socket
|
|
18
18
|
* the handle reconnects itself, re-minting each time, so every reconnect after
|
|
19
19
|
* a real outage re-checks access and passes the host's gate.
|
|
20
|
+
*
|
|
21
|
+
* A write the host makes on its own (an editor's housekeeping, a restored value)
|
|
22
|
+
* goes out as housekeeping when it is made inside `runWithDocUpdateAttributions`
|
|
23
|
+
* for `handle.doc` with `BACKGROUND_UPDATE_ATTRIBUTIONS`: the socket appends the
|
|
24
|
+
* scope's attributions to the update, which Keryx counts as system work instead
|
|
25
|
+
* of the person's edit (`socketFor`). One made while no socket is open is kept
|
|
26
|
+
* until Keryx acknowledges it and sent the same way, ahead of the next
|
|
27
|
+
* connection's sync (`UnconfirmedUpdateAttributions`). On a read-only grant
|
|
28
|
+
* nothing that carries document content leaves the socket.
|
|
29
|
+
*
|
|
30
|
+
* A host that can read Keryx's document status with the room's grant
|
|
31
|
+
* (`readDocumentStatus`) learns whether Keryx takes the room's writes for now
|
|
32
|
+
* (`handle.writesRefused`): a quarantined room takes none, and its socket drops
|
|
33
|
+
* every edit unconfirmed without a word (`document-status.ts`).
|
|
20
34
|
*/
|
|
21
35
|
import * as Y from '@y/y';
|
|
36
|
+
import { type ReadDocumentStatus } from './document-status';
|
|
22
37
|
import { type CollabAuth, type CollabTokenResponse, CollabTokenError } from './mint';
|
|
23
38
|
export type GenericDocStatus = 'connecting' | 'connected' | 'disconnected' | 'closed' | 'error';
|
|
24
39
|
export interface PresenceEntry {
|
|
@@ -92,6 +107,13 @@ export interface GenericDocHandle {
|
|
|
92
107
|
resume: () => void;
|
|
93
108
|
/** Local edits the server has not echoed yet (handed between providers too), or `null`. */
|
|
94
109
|
unconfirmedEdits: () => Y.ContentIds | null;
|
|
110
|
+
/**
|
|
111
|
+
* Keryx's document status, as last read with the room's grant, says the room takes no writes for
|
|
112
|
+
* now: it is quarantined while it is repaired, and its socket drops every edit unconfirmed until
|
|
113
|
+
* it is released. Always `false` without `readDocumentStatus`, on a read-only grant, and whenever
|
|
114
|
+
* the last read could not answer.
|
|
115
|
+
*/
|
|
116
|
+
readonly writesRefused: boolean;
|
|
95
117
|
onChange: (listener: () => void) => () => void;
|
|
96
118
|
destroy: () => void;
|
|
97
119
|
}
|
|
@@ -179,6 +201,11 @@ export declare function connectGenericDoc(args: {
|
|
|
179
201
|
offlineGateAfterMs?: number;
|
|
180
202
|
/** Start without connecting or minting (for a host's manual-save mode). Defaults to true. */
|
|
181
203
|
connectionEnabled?: boolean;
|
|
204
|
+
/**
|
|
205
|
+
* Reads Keryx's document status with the room's grant (see `ReadDocumentStatus`), for
|
|
206
|
+
* `handle.writesRefused`. A host that cannot read it leaves it out.
|
|
207
|
+
*/
|
|
208
|
+
readDocumentStatus?: ReadDocumentStatus;
|
|
182
209
|
}): GenericDocHandle;
|
|
183
210
|
export { CollabTokenError };
|
|
184
211
|
export type { CollabAuth, CollabTokenResponse };
|
package/dist/collab/client.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { receiveOnlyWebSocket } from "../keryx-http/src/receive-only-socket.js";
|
|
2
|
+
import { UnconfirmedUpdateAttributions } from "../keryx-http/src/unconfirmed-update-attributions.js";
|
|
3
|
+
import { docUpdateAttributions, attributingWebSocket } from "../keryx-http/src/update-attributions.js";
|
|
1
4
|
import { WebsocketProvider } from "@y/websocket";
|
|
2
5
|
import * as Y from "@y/y";
|
|
3
6
|
import { classifyClose } from "./close-policy.js";
|
|
7
|
+
import { watchDocumentStatus } from "./document-status.js";
|
|
4
8
|
import { CollabTokenError, mintCollabToken } from "./mint.js";
|
|
5
9
|
import { MAX_CONSECUTIVE_REMINTS, refreshDelayMs, MIN_REFRESH_DELAY_MS } from "./token-refresh.js";
|
|
6
10
|
const DEFAULT_OFFLINE_GATE_AFTER_MS = 15e3;
|
|
@@ -16,6 +20,20 @@ function resolveMint({ auth, mint }) {
|
|
|
16
20
|
if (!auth) throw new Error("connectGenericDoc needs `auth` or `mint`");
|
|
17
21
|
return ({ assetId, access }) => mintCollabToken({ auth, assetId, access });
|
|
18
22
|
}
|
|
23
|
+
function socketFor({
|
|
24
|
+
grant,
|
|
25
|
+
doc,
|
|
26
|
+
unconfirmed
|
|
27
|
+
}) {
|
|
28
|
+
const Base = globalThis.WebSocket;
|
|
29
|
+
if (typeof Base !== "function") return void 0;
|
|
30
|
+
if (grant.access_type === "r") return receiveOnlyWebSocket({ Base });
|
|
31
|
+
return attributingWebSocket({
|
|
32
|
+
Base,
|
|
33
|
+
attributionsFor: () => docUpdateAttributions(doc),
|
|
34
|
+
unconfirmed
|
|
35
|
+
});
|
|
36
|
+
}
|
|
19
37
|
function connectGenericDoc(args) {
|
|
20
38
|
const access = args.access ?? "view";
|
|
21
39
|
const mint = resolveMint({ auth: args.auth, mint: args.mint });
|
|
@@ -23,6 +41,11 @@ function connectGenericDoc(args) {
|
|
|
23
41
|
const retryMintError = args.retryMintError ?? isRetryableMintError;
|
|
24
42
|
const offlineGateAfterMs = args.offlineGateAfterMs ?? DEFAULT_OFFLINE_GATE_AFTER_MS;
|
|
25
43
|
const doc = new Y.Doc();
|
|
44
|
+
const unconfirmedAttributions = new UnconfirmedUpdateAttributions({
|
|
45
|
+
doc,
|
|
46
|
+
attributionsFor: () => docUpdateAttributions(doc),
|
|
47
|
+
isRemoteOrigin: (origin) => origin instanceof WebsocketProvider
|
|
48
|
+
});
|
|
26
49
|
const listeners = /* @__PURE__ */ new Set();
|
|
27
50
|
let provider = null;
|
|
28
51
|
let refreshTimer = null;
|
|
@@ -47,10 +70,19 @@ function connectGenericDoc(args) {
|
|
|
47
70
|
let connectSeq = 0;
|
|
48
71
|
let carriedUpdates = [];
|
|
49
72
|
let localChangesSynced = true;
|
|
73
|
+
let liveGrant = null;
|
|
74
|
+
let readStatusOnConnect = false;
|
|
50
75
|
const notify = () => {
|
|
51
76
|
version += 1;
|
|
52
77
|
for (const listener of listeners) listener();
|
|
53
78
|
};
|
|
79
|
+
const documentStatus = args.readDocumentStatus ? watchDocumentStatus({
|
|
80
|
+
read: args.readDocumentStatus,
|
|
81
|
+
currentGrant: () => liveGrant,
|
|
82
|
+
onChange: () => {
|
|
83
|
+
if (!destroyed) notify();
|
|
84
|
+
}
|
|
85
|
+
}) : null;
|
|
54
86
|
const unconfirmedEdits = () => {
|
|
55
87
|
const all = [...carriedUpdates, ...(provider == null ? void 0 : provider.unconfirmedUpdates) ?? []].map(
|
|
56
88
|
(entry) => entry.ids
|
|
@@ -70,6 +102,7 @@ function connectGenericDoc(args) {
|
|
|
70
102
|
const next = carriedUpdates.length === 0 && ((provider == null ? void 0 : provider.unconfirmedUpdates.length) ?? 0) === 0;
|
|
71
103
|
const changed = next !== localChangesSynced;
|
|
72
104
|
localChangesSynced = next;
|
|
105
|
+
documentStatus == null ? void 0 : documentStatus.unconfirmedChanged(!next);
|
|
73
106
|
transportChanged();
|
|
74
107
|
if (changed) notify();
|
|
75
108
|
};
|
|
@@ -90,8 +123,11 @@ function connectGenericDoc(args) {
|
|
|
90
123
|
everConnected = true;
|
|
91
124
|
disconnectedSince = null;
|
|
92
125
|
clearOfflineTimer();
|
|
93
|
-
} else
|
|
94
|
-
disconnectedSince
|
|
126
|
+
} else {
|
|
127
|
+
if (wasConnected || everConnected && disconnectedSince === null) {
|
|
128
|
+
disconnectedSince = Date.now();
|
|
129
|
+
}
|
|
130
|
+
documentStatus == null ? void 0 : documentStatus.disconnected();
|
|
95
131
|
}
|
|
96
132
|
transportChanged();
|
|
97
133
|
notify();
|
|
@@ -235,6 +271,7 @@ function connectGenericDoc(args) {
|
|
|
235
271
|
teardownProvider();
|
|
236
272
|
}
|
|
237
273
|
if (destroyed || !connectionEnabled || seq !== connectSeq) return;
|
|
274
|
+
const socket = socketFor({ grant, doc, unconfirmed: unconfirmedAttributions });
|
|
238
275
|
const nextProvider = new WebsocketProvider(grant.ws_url, `${grant.org}/${grant.doc_id}`, doc, {
|
|
239
276
|
params: {
|
|
240
277
|
yauth: grant.token,
|
|
@@ -244,9 +281,11 @@ function connectGenericDoc(args) {
|
|
|
244
281
|
// BroadcastChannel would sync same-origin clients locally, bypassing the
|
|
245
282
|
// server's permission enforcement (a read-only tab could write into an
|
|
246
283
|
// editor tab's doc). Permissioned docs must round-trip the server.
|
|
247
|
-
disableBc: true
|
|
284
|
+
disableBc: true,
|
|
285
|
+
...socket && { WebSocketPolyfill: socket }
|
|
248
286
|
});
|
|
249
287
|
provider = nextProvider;
|
|
288
|
+
liveGrant = grant;
|
|
250
289
|
nextProvider.unconfirmedUpdates = [...carriedUpdates, ...nextProvider.unconfirmedUpdates];
|
|
251
290
|
carriedUpdates = [];
|
|
252
291
|
refreshLocalChangesSynced();
|
|
@@ -261,10 +300,13 @@ function connectGenericDoc(args) {
|
|
|
261
300
|
void connect();
|
|
262
301
|
return;
|
|
263
302
|
}
|
|
303
|
+
const readStatusNow = event.status === "connected" && (!everConnected || readStatusOnConnect || disconnectedSince !== null && Date.now() - disconnectedSince >= offlineGateAfterMs);
|
|
264
304
|
if (event.status === "connected") {
|
|
265
305
|
consecutiveRemints = 0;
|
|
306
|
+
readStatusOnConnect = false;
|
|
266
307
|
}
|
|
267
308
|
setStatus(event.status);
|
|
309
|
+
if (event.status === "connected") documentStatus == null ? void 0 : documentStatus.connected({ readNow: readStatusNow });
|
|
268
310
|
if (event.status === "connected" && lastPresence !== null) {
|
|
269
311
|
nextProvider.awareness.setLocalState(lastPresence);
|
|
270
312
|
}
|
|
@@ -284,6 +326,8 @@ function connectGenericDoc(args) {
|
|
|
284
326
|
const action = classifyClose(event == null ? void 0 : event.code);
|
|
285
327
|
if (action === "remint") {
|
|
286
328
|
consecutiveRemints += 1;
|
|
329
|
+
readStatusOnConnect = true;
|
|
330
|
+
documentStatus == null ? void 0 : documentStatus.disconnected();
|
|
287
331
|
teardownProvider();
|
|
288
332
|
if (consecutiveRemints > MAX_CONSECUTIVE_REMINTS) {
|
|
289
333
|
setStatus(
|
|
@@ -420,6 +464,9 @@ function connectGenericDoc(args) {
|
|
|
420
464
|
get version() {
|
|
421
465
|
return version;
|
|
422
466
|
},
|
|
467
|
+
get writesRefused() {
|
|
468
|
+
return (documentStatus == null ? void 0 : documentStatus.writesRefused) ?? false;
|
|
469
|
+
},
|
|
423
470
|
waitForSync,
|
|
424
471
|
waitForAcknowledged,
|
|
425
472
|
getPresence: () => {
|
|
@@ -475,6 +522,7 @@ function connectGenericDoc(args) {
|
|
|
475
522
|
destroy: () => {
|
|
476
523
|
if (destroyed) return;
|
|
477
524
|
destroyed = true;
|
|
525
|
+
documentStatus == null ? void 0 : documentStatus.destroy();
|
|
478
526
|
teardownProvider();
|
|
479
527
|
clearRetryTimer();
|
|
480
528
|
clearOfflineTimer();
|
|
@@ -482,6 +530,7 @@ function connectGenericDoc(args) {
|
|
|
482
530
|
status = "closed";
|
|
483
531
|
for (const listener of [...listeners]) listener();
|
|
484
532
|
listeners.clear();
|
|
533
|
+
unconfirmedAttributions.destroy();
|
|
485
534
|
doc.destroy();
|
|
486
535
|
}
|
|
487
536
|
};
|