@abloatai/humans 0.37.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 +52 -0
- package/dist/Ablo.d.ts +208 -0
- package/dist/Ablo.js +120 -0
- package/dist/client.d.ts +317 -0
- package/dist/client.js +13 -0
- package/dist/core.d.ts +35 -0
- package/dist/core.js +48 -0
- package/dist/humans.d.ts +28 -0
- package/dist/humans.js +34 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +6 -0
- package/dist/local/BaseSyncedStore.d.ts +807 -0
- package/dist/local/BaseSyncedStore.js +1516 -0
- package/dist/local/Database.d.ts +322 -0
- package/dist/local/Database.js +1589 -0
- package/dist/local/InstanceCache.d.ts +255 -0
- package/dist/local/InstanceCache.js +1263 -0
- package/dist/local/LazyReferenceCollection.d.ts +177 -0
- package/dist/local/LazyReferenceCollection.js +461 -0
- package/dist/local/Model.d.ts +475 -0
- package/dist/local/Model.js +950 -0
- package/dist/local/ModelRegistry.d.ts +225 -0
- package/dist/local/ModelRegistry.js +539 -0
- package/dist/local/NetworkMonitor.d.ts +28 -0
- package/dist/local/NetworkMonitor.js +79 -0
- package/dist/local/RuntimeContext.d.ts +52 -0
- package/dist/local/RuntimeContext.js +80 -0
- package/dist/local/SyncClient.d.ts +516 -0
- package/dist/local/SyncClient.js +1754 -0
- package/dist/local/adapters/alwaysOnline.d.ts +14 -0
- package/dist/local/adapters/alwaysOnline.js +17 -0
- package/dist/local/adapters/inMemoryStorage.d.ts +37 -0
- package/dist/local/adapters/inMemoryStorage.js +122 -0
- package/dist/local/client/clientPrelude.d.ts +52 -0
- package/dist/local/client/clientPrelude.js +60 -0
- package/dist/local/client/consoleLogger.d.ts +35 -0
- package/dist/local/client/consoleLogger.js +44 -0
- package/dist/local/client/createInternalComponents.d.ts +50 -0
- package/dist/local/client/createInternalComponents.js +98 -0
- package/dist/local/client/createModelProxy.d.ts +248 -0
- package/dist/local/client/createModelProxy.js +880 -0
- package/dist/local/client/modelRegistration.d.ts +10 -0
- package/dist/local/client/modelRegistration.js +316 -0
- package/dist/local/client/options.d.ts +440 -0
- package/dist/local/client/options.js +7 -0
- package/dist/local/client/reactiveEngine.d.ts +53 -0
- package/dist/local/client/reactiveEngine.js +705 -0
- package/dist/local/client/resourceTypes.d.ts +12 -0
- package/dist/local/client/resourceTypes.js +10 -0
- package/dist/local/client/schemaConfig.d.ts +44 -0
- package/dist/local/client/schemaConfig.js +185 -0
- package/dist/local/client/storeCluster.d.ts +46 -0
- package/dist/local/client/storeCluster.js +133 -0
- package/dist/local/client/storeLifecycle.d.ts +61 -0
- package/dist/local/client/storeLifecycle.js +236 -0
- package/dist/local/client/validateAbloOptions.d.ts +42 -0
- package/dist/local/client/validateAbloOptions.js +43 -0
- package/dist/local/client/wsMutationExecutor.d.ts +27 -0
- package/dist/local/client/wsMutationExecutor.js +72 -0
- package/dist/local/context.d.ts +42 -0
- package/dist/local/context.js +81 -0
- package/dist/local/coordination/ClaimLog.d.ts +26 -0
- package/dist/local/coordination/ClaimLog.js +32 -0
- package/dist/local/interfaces/index.d.ts +311 -0
- package/dist/local/interfaces/index.js +9 -0
- package/dist/local/localModelContract.d.ts +14 -0
- package/dist/local/localModelContract.js +1 -0
- package/dist/local/logPosition.d.ts +31 -0
- package/dist/local/logPosition.js +53 -0
- package/dist/local/mutationPersistence.d.ts +6 -0
- package/dist/local/mutationPersistence.js +1 -0
- package/dist/local/mutators/RecordingMutation.d.ts +36 -0
- package/dist/local/mutators/RecordingMutation.js +182 -0
- package/dist/local/mutators/Transaction.d.ts +40 -0
- package/dist/local/mutators/Transaction.js +58 -0
- package/dist/local/mutators/UndoManager.d.ts +258 -0
- package/dist/local/mutators/UndoManager.js +665 -0
- package/dist/local/mutators/defineMutators.d.ts +60 -0
- package/dist/local/mutators/defineMutators.js +18 -0
- package/dist/local/mutators/inverseOp.d.ts +126 -0
- package/dist/local/mutators/inverseOp.js +71 -0
- package/dist/local/mutators/mutateActions.d.ts +45 -0
- package/dist/local/mutators/mutateActions.js +105 -0
- package/dist/local/mutators/readerActions.d.ts +33 -0
- package/dist/local/mutators/readerActions.js +57 -0
- package/dist/local/mutators/undoApply.d.ts +51 -0
- package/dist/local/mutators/undoApply.js +117 -0
- package/dist/local/persistence.d.ts +7 -0
- package/dist/local/persistence.js +9 -0
- package/dist/local/query/QueryProcessor.d.ts +75 -0
- package/dist/local/query/QueryProcessor.js +255 -0
- package/dist/local/query/client.d.ts +64 -0
- package/dist/local/query/client.js +138 -0
- package/dist/local/query/types.d.ts +85 -0
- package/dist/local/query/types.js +16 -0
- package/dist/local/schema/serialize.d.ts +1 -0
- package/dist/local/schema/serialize.js +1 -0
- package/dist/local/store/queryApi.d.ts +13 -0
- package/dist/local/store/queryApi.js +35 -0
- package/dist/local/storeContract.d.ts +145 -0
- package/dist/local/storeContract.js +12 -0
- package/dist/local/stores/DatabaseManager.d.ts +112 -0
- package/dist/local/stores/DatabaseManager.js +400 -0
- package/dist/local/stores/ObjectStore.d.ts +115 -0
- package/dist/local/stores/ObjectStore.js +393 -0
- package/dist/local/stores/ObjectStoreContract.d.ts +38 -0
- package/dist/local/stores/ObjectStoreContract.js +1 -0
- package/dist/local/stores/StoreManager.d.ts +114 -0
- package/dist/local/stores/StoreManager.js +304 -0
- package/dist/local/stores/SyncActionStore.d.ts +99 -0
- package/dist/local/stores/SyncActionStore.js +506 -0
- package/dist/local/stores/openIDBWithTimeout.d.ts +65 -0
- package/dist/local/stores/openIDBWithTimeout.js +153 -0
- package/dist/local/stores/persistenceCleanup.d.ts +7 -0
- package/dist/local/stores/persistenceCleanup.js +26 -0
- package/dist/local/stores/persistenceIdentity.d.ts +27 -0
- package/dist/local/stores/persistenceIdentity.js +38 -0
- package/dist/local/stores/syncAction.d.ts +26 -0
- package/dist/local/stores/syncAction.js +16 -0
- package/dist/local/stores/v1PersistenceDeletion.d.ts +8 -0
- package/dist/local/stores/v1PersistenceDeletion.js +16 -0
- package/dist/local/sync/BootstrapFetcher.d.ts +284 -0
- package/dist/local/sync/BootstrapFetcher.js +964 -0
- package/dist/local/sync/ConnectionManager.d.ts +8 -0
- package/dist/local/sync/ConnectionManager.js +8 -0
- package/dist/local/sync/OnDemandLoader.d.ts +231 -0
- package/dist/local/sync/OnDemandLoader.js +743 -0
- package/dist/local/sync/SubscriptionManager.d.ts +159 -0
- package/dist/local/sync/SubscriptionManager.js +243 -0
- package/dist/local/sync/SyncWebSocket.d.ts +173 -0
- package/dist/local/sync/SyncWebSocket.js +438 -0
- package/dist/local/sync/bootstrapApply.d.ts +73 -0
- package/dist/local/sync/bootstrapApply.js +73 -0
- package/dist/local/sync/commitFrames.d.ts +8 -0
- package/dist/local/sync/commitFrames.js +8 -0
- package/dist/local/sync/connectionManagerLifecycle.d.ts +23 -0
- package/dist/local/sync/connectionManagerLifecycle.js +126 -0
- package/dist/local/sync/contextPorts.d.ts +18 -0
- package/dist/local/sync/contextPorts.js +31 -0
- package/dist/local/sync/createClaimStream.d.ts +64 -0
- package/dist/local/sync/createClaimStream.js +475 -0
- package/dist/local/sync/createSnapshot.d.ts +29 -0
- package/dist/local/sync/createSnapshot.js +116 -0
- package/dist/local/sync/credentialLifecycle.d.ts +7 -0
- package/dist/local/sync/credentialLifecycle.js +7 -0
- package/dist/local/sync/deltaPipeline.d.ts +116 -0
- package/dist/local/sync/deltaPipeline.js +357 -0
- package/dist/local/sync/groupChange.d.ts +116 -0
- package/dist/local/sync/groupChange.js +244 -0
- package/dist/local/sync/initialize.d.ts +27 -0
- package/dist/local/sync/initialize.js +137 -0
- package/dist/local/sync/participants.d.ts +132 -0
- package/dist/local/sync/participants.js +342 -0
- package/dist/local/sync/persistedPrefix.d.ts +12 -0
- package/dist/local/sync/persistedPrefix.js +22 -0
- package/dist/local/sync/reconnect.d.ts +23 -0
- package/dist/local/sync/reconnect.js +55 -0
- package/dist/local/sync/schemaDrift.d.ts +55 -0
- package/dist/local/sync/schemaDrift.js +53 -0
- package/dist/local/sync/schemas.d.ts +71 -0
- package/dist/local/sync/schemas.js +94 -0
- package/dist/local/sync/socketEventWiring.d.ts +31 -0
- package/dist/local/sync/socketEventWiring.js +130 -0
- package/dist/local/sync/syncCursor.d.ts +40 -0
- package/dist/local/sync/syncCursor.js +55 -0
- package/dist/local/sync/syncPlan.d.ts +54 -0
- package/dist/local/sync/syncPlan.js +50 -0
- package/dist/local/sync/terminalSessionLifecycle.d.ts +20 -0
- package/dist/local/sync/terminalSessionLifecycle.js +50 -0
- package/dist/local/sync/wsFrameHandlers.d.ts +8 -0
- package/dist/local/sync/wsFrameHandlers.js +8 -0
- package/dist/local/transactions/databaseCommitOutbox.d.ts +15 -0
- package/dist/local/transactions/databaseCommitOutbox.js +16 -0
- package/dist/local/transactions/localMutation.d.ts +10 -0
- package/dist/local/transactions/localMutation.js +37 -0
- package/dist/local/transactions/mutations/MutationQueue.d.ts +511 -0
- package/dist/local/transactions/mutations/MutationQueue.js +1498 -0
- package/dist/local/transactions/mutations/MutationStore.d.ts +20 -0
- package/dist/local/transactions/mutations/MutationStore.js +53 -0
- package/dist/local/transactions/mutations/UnconfirmedWrites.d.ts +82 -0
- package/dist/local/transactions/mutations/UnconfirmedWrites.js +104 -0
- package/dist/local/transactions/mutations/batchProcessing.d.ts +64 -0
- package/dist/local/transactions/mutations/batchProcessing.js +349 -0
- package/dist/local/transactions/mutations/coalesceRules.d.ts +58 -0
- package/dist/local/transactions/mutations/coalesceRules.js +140 -0
- package/dist/local/transactions/mutations/commitApi.d.ts +19 -0
- package/dist/local/transactions/mutations/commitApi.js +74 -0
- package/dist/local/transactions/mutations/commitLane.d.ts +70 -0
- package/dist/local/transactions/mutations/commitLane.js +140 -0
- package/dist/local/transactions/mutations/commitLatency.d.ts +52 -0
- package/dist/local/transactions/mutations/commitLatency.js +130 -0
- package/dist/local/transactions/mutations/commitPayload.d.ts +165 -0
- package/dist/local/transactions/mutations/commitPayload.js +152 -0
- package/dist/local/transactions/mutations/commitTransport.d.ts +36 -0
- package/dist/local/transactions/mutations/commitTransport.js +104 -0
- package/dist/local/transactions/mutations/deltaConfirmation.d.ts +63 -0
- package/dist/local/transactions/mutations/deltaConfirmation.js +235 -0
- package/dist/local/transactions/mutations/durableCommitRestore.d.ts +17 -0
- package/dist/local/transactions/mutations/durableCommitRestore.js +95 -0
- package/dist/local/transactions/mutations/durableWriteStore.d.ts +14 -0
- package/dist/local/transactions/mutations/durableWriteStore.js +12 -0
- package/dist/local/transactions/mutations/executionSelection.d.ts +6 -0
- package/dist/local/transactions/mutations/executionSelection.js +42 -0
- package/dist/local/transactions/mutations/failureHandling.d.ts +16 -0
- package/dist/local/transactions/mutations/failureHandling.js +130 -0
- package/dist/local/transactions/mutations/failurePolicy.d.ts +13 -0
- package/dist/local/transactions/mutations/failurePolicy.js +48 -0
- package/dist/local/transactions/mutations/localMutation.d.ts +58 -0
- package/dist/local/transactions/mutations/localMutation.js +75 -0
- package/dist/local/transactions/mutations/modelOperations.d.ts +44 -0
- package/dist/local/transactions/mutations/modelOperations.js +144 -0
- package/dist/local/transactions/mutations/mutationPersistence.d.ts +25 -0
- package/dist/local/transactions/mutations/mutationPersistence.js +188 -0
- package/dist/local/transactions/mutations/pendingDrain.d.ts +33 -0
- package/dist/local/transactions/mutations/pendingDrain.js +112 -0
- package/dist/local/transactions/mutations/processingScheduler.d.ts +14 -0
- package/dist/local/transactions/mutations/processingScheduler.js +24 -0
- package/dist/local/transactions/mutations/queueCoalescing.d.ts +13 -0
- package/dist/local/transactions/mutations/queueCoalescing.js +35 -0
- package/dist/local/transactions/mutations/replayValidation.d.ts +187 -0
- package/dist/local/transactions/mutations/replayValidation.js +164 -0
- package/dist/local/transactions/reconnectDrain.d.ts +11 -0
- package/dist/local/transactions/reconnectDrain.js +13 -0
- package/dist/local/utils/mobxSetup.d.ts +53 -0
- package/dist/local/utils/mobxSetup.js +330 -0
- package/dist/local/views/QueryView.d.ts +79 -0
- package/dist/local/views/QueryView.js +218 -0
- package/dist/local/views/ViewRegistry.d.ts +20 -0
- package/dist/local/views/ViewRegistry.js +57 -0
- package/dist/local/views/incrementalView.d.ts +45 -0
- package/dist/local/views/incrementalView.js +69 -0
- package/dist/plugin.d.ts +285 -0
- package/dist/plugin.js +106 -0
- package/dist/presenceStream.d.ts +69 -0
- package/dist/presenceStream.js +200 -0
- package/dist/react/AbloProvider.d.ts +242 -0
- package/dist/react/AbloProvider.js +456 -0
- package/dist/react/ClientSideSuspense.d.ts +36 -0
- package/dist/react/ClientSideSuspense.js +17 -0
- package/dist/react/DefaultFallback.d.ts +24 -0
- package/dist/react/DefaultFallback.js +43 -0
- package/dist/react/context.d.ts +55 -0
- package/dist/react/context.js +29 -0
- package/dist/react/createAbloReact.d.ts +50 -0
- package/dist/react/createAbloReact.js +48 -0
- package/dist/react/internalContext.d.ts +33 -0
- package/dist/react/internalContext.js +3 -0
- package/dist/react/useAblo.d.ts +96 -0
- package/dist/react/useAblo.js +120 -0
- package/dist/react/useCurrentUserId.d.ts +2 -0
- package/dist/react/useCurrentUserId.js +12 -0
- package/dist/react/useErrorListener.d.ts +2 -0
- package/dist/react/useErrorListener.js +14 -0
- package/dist/react/useMutationFailureListener.d.ts +8 -0
- package/dist/react/useMutationFailureListener.js +19 -0
- package/dist/react/useMutators.d.ts +56 -0
- package/dist/react/useMutators.js +84 -0
- package/dist/react/useSyncStatus.d.ts +19 -0
- package/dist/react/useSyncStatus.js +37 -0
- package/dist/react/useUndoScope.d.ts +34 -0
- package/dist/react/useUndoScope.js +73 -0
- package/dist/react.d.ts +18 -0
- package/dist/react.js +14 -0
- package/dist/reactRuntime.d.ts +4 -0
- package/dist/reactRuntime.js +2 -0
- package/dist/surface.d.ts +36 -0
- package/dist/surface.js +77 -0
- package/dist/useReactive.d.ts +6 -0
- package/dist/useReactive.js +43 -0
- package/package.json +119 -0
- package/src/Ablo.ts +456 -0
- package/src/client.ts +374 -0
- package/src/core.ts +104 -0
- package/src/humans.ts +61 -0
- package/src/index.ts +40 -0
- package/src/local/BaseSyncedStore.ts +1991 -0
- package/src/local/Database.ts +2052 -0
- package/src/local/InstanceCache.ts +1503 -0
- package/src/local/LazyReferenceCollection.ts +563 -0
- package/src/local/Model.ts +1124 -0
- package/src/local/ModelRegistry.ts +762 -0
- package/src/local/NetworkMonitor.ts +88 -0
- package/src/local/RuntimeContext.ts +141 -0
- package/src/local/SyncClient.ts +2131 -0
- package/src/local/adapters/alwaysOnline.ts +20 -0
- package/src/local/adapters/inMemoryStorage.ts +141 -0
- package/src/local/client/clientPrelude.ts +112 -0
- package/src/local/client/consoleLogger.ts +60 -0
- package/src/local/client/createInternalComponents.ts +163 -0
- package/src/local/client/createModelProxy.ts +1390 -0
- package/src/local/client/modelRegistration.ts +350 -0
- package/src/local/client/options.ts +526 -0
- package/src/local/client/reactiveEngine.ts +935 -0
- package/src/local/client/resourceTypes.ts +37 -0
- package/src/local/client/schemaConfig.ts +194 -0
- package/src/local/client/storeCluster.ts +172 -0
- package/src/local/client/storeLifecycle.ts +343 -0
- package/src/local/client/validateAbloOptions.ts +95 -0
- package/src/local/client/wsMutationExecutor.ts +110 -0
- package/src/local/context.ts +96 -0
- package/src/local/coordination/ClaimLog.ts +39 -0
- package/src/local/interfaces/index.ts +468 -0
- package/src/local/localModelContract.ts +15 -0
- package/src/local/logPosition.ts +84 -0
- package/src/local/mutationPersistence.ts +7 -0
- package/src/local/mutators/RecordingMutation.ts +222 -0
- package/src/local/mutators/Transaction.ts +97 -0
- package/src/local/mutators/UndoManager.ts +741 -0
- package/src/local/mutators/defineMutators.ts +76 -0
- package/src/local/mutators/inverseOp.ts +83 -0
- package/src/local/mutators/mutateActions.ts +167 -0
- package/src/local/mutators/readerActions.ts +99 -0
- package/src/local/mutators/undoApply.ts +141 -0
- package/src/local/persistence.ts +16 -0
- package/src/local/query/QueryProcessor.ts +347 -0
- package/src/local/query/client.ts +197 -0
- package/src/local/query/types.ts +102 -0
- package/src/local/schema/serialize.ts +1 -0
- package/src/local/store/queryApi.ts +56 -0
- package/src/local/storeContract.ts +146 -0
- package/src/local/stores/DatabaseManager.ts +507 -0
- package/src/local/stores/ObjectStore.ts +449 -0
- package/src/local/stores/ObjectStoreContract.ts +48 -0
- package/src/local/stores/StoreManager.ts +388 -0
- package/src/local/stores/SyncActionStore.ts +579 -0
- package/src/local/stores/openIDBWithTimeout.ts +195 -0
- package/src/local/stores/persistenceCleanup.ts +43 -0
- package/src/local/stores/persistenceIdentity.ts +83 -0
- package/src/local/stores/syncAction.ts +21 -0
- package/src/local/stores/v1PersistenceDeletion.ts +21 -0
- package/src/local/sync/BootstrapFetcher.ts +1224 -0
- package/src/local/sync/ConnectionManager.ts +15 -0
- package/src/local/sync/OnDemandLoader.ts +927 -0
- package/src/local/sync/SubscriptionManager.ts +300 -0
- package/src/local/sync/SyncWebSocket.ts +584 -0
- package/src/local/sync/bootstrapApply.ts +130 -0
- package/src/local/sync/commitFrames.ts +16 -0
- package/src/local/sync/connectionManagerLifecycle.ts +158 -0
- package/src/local/sync/contextPorts.ts +37 -0
- package/src/local/sync/createClaimStream.ts +668 -0
- package/src/local/sync/createSnapshot.ts +160 -0
- package/src/local/sync/credentialLifecycle.ts +18 -0
- package/src/local/sync/deltaPipeline.ts +473 -0
- package/src/local/sync/groupChange.ts +343 -0
- package/src/local/sync/initialize.ts +205 -0
- package/src/local/sync/participants.ts +564 -0
- package/src/local/sync/persistedPrefix.ts +27 -0
- package/src/local/sync/reconnect.ts +88 -0
- package/src/local/sync/schemaDrift.ts +86 -0
- package/src/local/sync/schemas.ts +118 -0
- package/src/local/sync/socketEventWiring.ts +196 -0
- package/src/local/sync/syncCursor.ts +62 -0
- package/src/local/sync/syncPlan.ts +89 -0
- package/src/local/sync/terminalSessionLifecycle.ts +66 -0
- package/src/local/sync/wsFrameHandlers.ts +20 -0
- package/src/local/transactions/databaseCommitOutbox.ts +33 -0
- package/src/local/transactions/localMutation.ts +58 -0
- package/src/local/transactions/mutations/MutationQueue.ts +1998 -0
- package/src/local/transactions/mutations/MutationStore.ts +65 -0
- package/src/local/transactions/mutations/UnconfirmedWrites.ts +133 -0
- package/src/local/transactions/mutations/batchProcessing.ts +469 -0
- package/src/local/transactions/mutations/coalesceRules.ts +192 -0
- package/src/local/transactions/mutations/commitApi.ts +97 -0
- package/src/local/transactions/mutations/commitLane.ts +191 -0
- package/src/local/transactions/mutations/commitLatency.ts +164 -0
- package/src/local/transactions/mutations/commitPayload.ts +281 -0
- package/src/local/transactions/mutations/commitTransport.ts +174 -0
- package/src/local/transactions/mutations/deltaConfirmation.ts +298 -0
- package/src/local/transactions/mutations/durableCommitRestore.ts +128 -0
- package/src/local/transactions/mutations/durableWriteStore.ts +21 -0
- package/src/local/transactions/mutations/executionSelection.ts +42 -0
- package/src/local/transactions/mutations/failureHandling.ts +154 -0
- package/src/local/transactions/mutations/failurePolicy.ts +61 -0
- package/src/local/transactions/mutations/localMutation.ts +135 -0
- package/src/local/transactions/mutations/modelOperations.ts +210 -0
- package/src/local/transactions/mutations/mutationPersistence.ts +231 -0
- package/src/local/transactions/mutations/pendingDrain.ts +160 -0
- package/src/local/transactions/mutations/processingScheduler.ts +35 -0
- package/src/local/transactions/mutations/queueCoalescing.ts +45 -0
- package/src/local/transactions/mutations/replayValidation.ts +192 -0
- package/src/local/transactions/reconnectDrain.ts +24 -0
- package/src/local/utils/mobxSetup.ts +388 -0
- package/src/local/views/QueryView.ts +311 -0
- package/src/local/views/ViewRegistry.ts +61 -0
- package/src/local/views/incrementalView.ts +92 -0
- package/src/plugin.ts +396 -0
- package/src/presenceStream.ts +279 -0
- package/src/react/AbloProvider.tsx +744 -0
- package/src/react/ClientSideSuspense.tsx +57 -0
- package/src/react/DefaultFallback.tsx +60 -0
- package/src/react/context.ts +89 -0
- package/src/react/createAbloReact.ts +116 -0
- package/src/react/internalContext.ts +38 -0
- package/src/react/useAblo.ts +280 -0
- package/src/react/useCurrentUserId.ts +17 -0
- package/src/react/useErrorListener.ts +22 -0
- package/src/react/useMutationFailureListener.ts +34 -0
- package/src/react/useMutators.ts +184 -0
- package/src/react/useSyncStatus.ts +42 -0
- package/src/react/useUndoScope.ts +143 -0
- package/src/react.ts +69 -0
- package/src/reactRuntime.ts +10 -0
- package/src/surface.ts +106 -0
- package/src/useReactive.ts +51 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles the delta types that change which sync groups a session can see. A
|
|
3
|
+
* sync group is a fan-out scope the server uses to decide which entities a
|
|
4
|
+
* client receives. When a session's membership changes, these handlers update
|
|
5
|
+
* the client's subscription list; when access is revoked, they clear cached
|
|
6
|
+
* data and trigger a full re-bootstrap so revoked rows cannot linger on the
|
|
7
|
+
* device.
|
|
8
|
+
*
|
|
9
|
+
* Every handler takes a {@link GroupChangeContext}, the narrow facade through
|
|
10
|
+
* which it reaches the client's local storage and connection lifecycle hooks.
|
|
11
|
+
*/
|
|
12
|
+
import { globalRuntime } from '../context.js';
|
|
13
|
+
/** The context's runtime, falling back to the module-global bridge. */
|
|
14
|
+
const runtimeOf = (ctx) => ctx.runtime ?? globalRuntime;
|
|
15
|
+
/**
|
|
16
|
+
* Marker returned when a group-change payload cannot be parsed, kept distinct
|
|
17
|
+
* from a valid null or absent payload, which the handlers accept normally.
|
|
18
|
+
*/
|
|
19
|
+
const MALFORMED_PAYLOAD = Symbol('malformed-group-change-payload');
|
|
20
|
+
/**
|
|
21
|
+
* Parses a group-change delta payload without ever throwing. The server sends
|
|
22
|
+
* these as JSON strings. If a frame is corrupt, this returns
|
|
23
|
+
* {@link MALFORMED_PAYLOAD} rather than raising, because an error escaping here
|
|
24
|
+
* would leave the delta pipeline after the watermark has already advanced. The
|
|
25
|
+
* delta is never re-delivered, so the security clear it carried would be lost.
|
|
26
|
+
*/
|
|
27
|
+
function parseGroupChangePayload(delta, runtime) {
|
|
28
|
+
if (typeof delta.data !== 'string')
|
|
29
|
+
return delta.data;
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(delta.data);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
runtime.logger.debug('[BaseSyncedStore] Malformed group-change payload', {
|
|
35
|
+
syncId: delta.id,
|
|
36
|
+
actionType: delta.actionType,
|
|
37
|
+
error: error instanceof Error ? error.message : String(error),
|
|
38
|
+
});
|
|
39
|
+
return MALFORMED_PAYLOAD;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Fallback for a group-change delta that could not be read. Because we know
|
|
44
|
+
* access changed but not how, this treats it as a revocation: it clears cached
|
|
45
|
+
* data from both local storage and the in-memory pool, then forces a full
|
|
46
|
+
* re-bootstrap from the server.
|
|
47
|
+
*/
|
|
48
|
+
async function clearForUnknownGroupChange(ctx, delta, kind) {
|
|
49
|
+
runtimeOf(ctx).logger.debug(`[BaseSyncedStore] Unreadable ${kind} payload — clearing cached data and re-bootstrapping`, { syncId: delta.id });
|
|
50
|
+
// Revoked data must not persist if the device goes offline before the
|
|
51
|
+
// re-bootstrap, the same reasoning as the explicit removed-groups path.
|
|
52
|
+
await ctx.database.clear();
|
|
53
|
+
ctx.objectPool.clear();
|
|
54
|
+
ctx.forceFullRebootstrap();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Handles a 'G' (group-change) delta. The server sends two shapes of this
|
|
58
|
+
* delta, told apart by the payload:
|
|
59
|
+
*
|
|
60
|
+
* Incremental — `{ group, userId }`: the recipient was added to a single
|
|
61
|
+
* sync group. No re-bootstrap follows; the newly visible entities arrive as
|
|
62
|
+
* ordinary 'C' (covering) deltas through the normal insert path.
|
|
63
|
+
*
|
|
64
|
+
* Full diff — `{ addedGroups, removedGroups }`: one delta carrying the whole
|
|
65
|
+
* membership change. This forces a full re-bootstrap (disconnect, reconnect,
|
|
66
|
+
* and refetch), clearing cached data first if any group was removed.
|
|
67
|
+
*/
|
|
68
|
+
export async function handleSyncGroupChange(ctx, delta) {
|
|
69
|
+
const raw = parseGroupChangePayload(delta, runtimeOf(ctx));
|
|
70
|
+
if (raw === MALFORMED_PAYLOAD) {
|
|
71
|
+
// The payload is unreadable, so we cannot tell which groups changed, and
|
|
72
|
+
// this delta will never be re-delivered because the watermark has already
|
|
73
|
+
// advanced. Fall back to the safe direction: assume a revocation, clear
|
|
74
|
+
// cached data, and rebuild from the server rather than throwing.
|
|
75
|
+
await clearForUnknownGroupChange(ctx, delta, 'sync-group change');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const rawObj = (raw ?? {});
|
|
79
|
+
// Detect incremental payload shape: { group, userId }
|
|
80
|
+
if (typeof rawObj.group === 'string' && typeof rawObj.userId === 'string') {
|
|
81
|
+
const incremental = {
|
|
82
|
+
group: rawObj.group,
|
|
83
|
+
userId: rawObj.userId,
|
|
84
|
+
};
|
|
85
|
+
await ctx.handleGroupAdded(incremental, delta.id);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Full-diff payload: { addedGroups, removedGroups }
|
|
89
|
+
const payload = {
|
|
90
|
+
removedGroups: rawObj.removedGroups ?? [],
|
|
91
|
+
addedGroups: rawObj.addedGroups ?? [],
|
|
92
|
+
};
|
|
93
|
+
runtimeOf(ctx).logger.info('[BaseSyncedStore] Sync group change received (legacy)', {
|
|
94
|
+
removedGroups: payload.removedGroups,
|
|
95
|
+
addedGroups: payload.addedGroups,
|
|
96
|
+
syncId: delta.id,
|
|
97
|
+
});
|
|
98
|
+
// If any groups were removed, clear cached data immediately so revoked data
|
|
99
|
+
// cannot persist should the device go offline before the re-bootstrap
|
|
100
|
+
// completes.
|
|
101
|
+
if (payload.removedGroups.length > 0) {
|
|
102
|
+
await ctx.database.clear();
|
|
103
|
+
ctx.objectPool.clear();
|
|
104
|
+
runtimeOf(ctx).logger.info('[BaseSyncedStore] Cleared cached data due to revoked sync groups', {
|
|
105
|
+
removedGroups: payload.removedGroups,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const updatedGroups = ctx.computeUpdatedSyncGroups(payload);
|
|
109
|
+
await ctx.database.updateWorkspaceMetadata({ subscribedSyncGroups: updatedGroups });
|
|
110
|
+
ctx.forceFullRebootstrap();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Handles an incremental group-added delta. It records the new sync group in
|
|
114
|
+
* the subscription metadata without forcing a re-bootstrap; the server then
|
|
115
|
+
* sends a 'C' (covering) delta for each newly visible entity, which flows
|
|
116
|
+
* through the normal insert path.
|
|
117
|
+
*/
|
|
118
|
+
export async function handleGroupAdded(ctx, payload, syncId) {
|
|
119
|
+
runtimeOf(ctx).logger.info('[BaseSyncedStore] Group added (incremental)', {
|
|
120
|
+
group: payload.group,
|
|
121
|
+
syncId,
|
|
122
|
+
});
|
|
123
|
+
const current = new Set(ctx.getSubscribedSyncGroups());
|
|
124
|
+
current.add(payload.group);
|
|
125
|
+
await ctx.database.updateWorkspaceMetadata({ subscribedSyncGroups: Array.from(current) });
|
|
126
|
+
// No forceFullRebootstrap() here; the covering deltas will bring the entities.
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Handles an 'S' (group-removed) delta, which signals the recipient has lost
|
|
130
|
+
* access to a sync group. The client does not track which entities belong to
|
|
131
|
+
* which group, so it cannot purge only the affected rows; instead it clears
|
|
132
|
+
* local state and forces a re-bootstrap with the updated group list.
|
|
133
|
+
*/
|
|
134
|
+
export async function handleGroupRemoved(ctx, delta) {
|
|
135
|
+
const raw = parseGroupChangePayload(delta, runtimeOf(ctx));
|
|
136
|
+
if (raw === MALFORMED_PAYLOAD) {
|
|
137
|
+
// The payload is unreadable: access was revoked but we cannot tell which
|
|
138
|
+
// group. Fall back to a full clear, the safe direction for an
|
|
139
|
+
// access-revocation delta, rather than throwing.
|
|
140
|
+
await clearForUnknownGroupChange(ctx, delta, 'group-removed');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const rawObj = (raw ?? {});
|
|
144
|
+
const groupKey = typeof rawObj.group === 'string' ? rawObj.group : undefined;
|
|
145
|
+
if (!groupKey) {
|
|
146
|
+
runtimeOf(ctx).logger.debug('[BaseSyncedStore] Group removed delta missing group key', {
|
|
147
|
+
syncId: delta.id,
|
|
148
|
+
});
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
runtimeOf(ctx).logger.info('[BaseSyncedStore] Group removed', {
|
|
152
|
+
group: groupKey,
|
|
153
|
+
syncId: delta.id,
|
|
154
|
+
});
|
|
155
|
+
// Clear cached data before the re-bootstrap so revoked-group data cannot
|
|
156
|
+
// persist if the device goes offline between receiving this delta and
|
|
157
|
+
// completing the re-bootstrap.
|
|
158
|
+
await ctx.database.clear();
|
|
159
|
+
ctx.objectPool.clear();
|
|
160
|
+
// Update subscription metadata so the re-bootstrap fetches the
|
|
161
|
+
// correct set of groups.
|
|
162
|
+
const current = new Set(ctx.getSubscribedSyncGroups());
|
|
163
|
+
current.delete(groupKey);
|
|
164
|
+
await ctx.database.updateWorkspaceMetadata({ subscribedSyncGroups: Array.from(current) });
|
|
165
|
+
ctx.forceFullRebootstrap();
|
|
166
|
+
}
|
|
167
|
+
/** Computes the new sync-group set after applying the additions and removals in a diff. */
|
|
168
|
+
export function computeUpdatedSyncGroups(ctx, payload) {
|
|
169
|
+
const current = new Set(ctx.getSubscribedSyncGroups());
|
|
170
|
+
for (const g of payload.removedGroups)
|
|
171
|
+
current.delete(g);
|
|
172
|
+
for (const g of payload.addedGroups)
|
|
173
|
+
current.add(g);
|
|
174
|
+
return Array.from(current);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Forces a full re-bootstrap by marking local storage as needing one,
|
|
178
|
+
* disconnecting, and emitting a connection lifecycle event that the reconnect
|
|
179
|
+
* path acts on. Does nothing for participants whose bootstrap mode is 'none':
|
|
180
|
+
* they never pull a baseline, so after a trigger such as a sync-group shrink or
|
|
181
|
+
* an access revocation they rely on covering deltas to repopulate the data they
|
|
182
|
+
* subscribe to.
|
|
183
|
+
*/
|
|
184
|
+
export function forceFullRebootstrap(ctx) {
|
|
185
|
+
if (ctx.getBootstrapMode() === 'none') {
|
|
186
|
+
runtimeOf(ctx).logger.info('[BaseSyncedStore] forceFullRebootstrap skipped (bootstrapMode=none)');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
ctx.database.markRequiresFullBootstrap();
|
|
190
|
+
ctx.disconnectWebSocket();
|
|
191
|
+
ctx.emitConnectionEvent('WS_DISCONNECTED');
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Resolves the sync-group list this session subscribes to, and is the single
|
|
195
|
+
* place that decision is made. The server-issued `context.syncGroups` is
|
|
196
|
+
* authoritative; when it is absent, the session subscribes to no explicit
|
|
197
|
+
* groups. {@link checkSyncGroupShrinkage} and connection setup both read
|
|
198
|
+
* through here, so the live subscription and the access-revocation check can
|
|
199
|
+
* never disagree.
|
|
200
|
+
*/
|
|
201
|
+
export function resolveSyncGroups(context) {
|
|
202
|
+
if (context.syncGroups && context.syncGroups.length > 0) {
|
|
203
|
+
return context.syncGroups;
|
|
204
|
+
}
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Compares the session's current sync groups against the set stored from the
|
|
209
|
+
* last session. If any group is now missing, access has narrowed, so this
|
|
210
|
+
* clears cached data and forces a full bootstrap before recording the new set.
|
|
211
|
+
*/
|
|
212
|
+
export async function checkSyncGroupShrinkage(ctx) {
|
|
213
|
+
const currentSyncGroups = ctx.getCurrentSyncGroups();
|
|
214
|
+
if (!currentSyncGroups)
|
|
215
|
+
return;
|
|
216
|
+
try {
|
|
217
|
+
const metadata = await ctx.database.getWorkspaceMetadata();
|
|
218
|
+
const stored = metadata?.subscribedSyncGroups ?? [];
|
|
219
|
+
if (stored.length === 0)
|
|
220
|
+
return;
|
|
221
|
+
const currentGroups = new Set(currentSyncGroups);
|
|
222
|
+
const removedGroups = stored.filter((g) => !currentGroups.has(g));
|
|
223
|
+
if (removedGroups.length > 0) {
|
|
224
|
+
runtimeOf(ctx).logger.info('[BaseSyncedStore] Sync groups shrank — forcing full bootstrap', {
|
|
225
|
+
removedGroups,
|
|
226
|
+
storedCount: stored.length,
|
|
227
|
+
currentCount: currentGroups.size,
|
|
228
|
+
});
|
|
229
|
+
// Clear cached data before the re-bootstrap so revoked-group data cannot
|
|
230
|
+
// persist if the device goes offline first.
|
|
231
|
+
await ctx.database.clear();
|
|
232
|
+
ctx.objectPool.clear();
|
|
233
|
+
ctx.database.markRequiresFullBootstrap();
|
|
234
|
+
}
|
|
235
|
+
await ctx.database.updateWorkspaceMetadata({
|
|
236
|
+
subscribedSyncGroups: Array.from(currentGroups),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
runtimeOf(ctx).logger.debug('[BaseSyncedStore] Failed to check sync group shrinkage', {
|
|
241
|
+
error: error instanceof Error ? error.message : String(error),
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RuntimeContext } from '../RuntimeContext.js';
|
|
2
|
+
import type { BootstrapRequirements, Database } from '../Database.js';
|
|
3
|
+
import type { SyncClient } from '../SyncClient.js';
|
|
4
|
+
import type { UserContext } from '../BaseSyncedStore.js';
|
|
5
|
+
import type { InstanceCache } from '../InstanceCache.js';
|
|
6
|
+
import type { DefaultCollaborationEvents, EventMap, SyncWebSocket } from './SyncWebSocket.js';
|
|
7
|
+
import type { SyncStatus } from '../storeContract.js';
|
|
8
|
+
export interface InitializeHost<TCollaboration extends EventMap<TCollaboration> = DefaultCollaborationEvents> {
|
|
9
|
+
initialized: boolean;
|
|
10
|
+
userContext: UserContext;
|
|
11
|
+
dataReady: boolean;
|
|
12
|
+
runtime: RuntimeContext;
|
|
13
|
+
database: Database;
|
|
14
|
+
syncClient: SyncClient;
|
|
15
|
+
objectPool: InstanceCache;
|
|
16
|
+
syncWebSocket: SyncWebSocket<TCollaboration>;
|
|
17
|
+
updateSyncStatus(updates: Partial<SyncStatus>): void;
|
|
18
|
+
setupWebSocketSync(context: UserContext, lastSyncId: number): void;
|
|
19
|
+
waitForWebSocketConnected(timeoutMs: number): Promise<boolean>;
|
|
20
|
+
performBackgroundBootstrap(requirements: Awaited<ReturnType<Database['requiredBootstrap']>>, context: UserContext, signal?: AbortSignal): Promise<void>;
|
|
21
|
+
executeBootstrapWithTimeout(fn: () => Promise<void>, context: UserContext, signal?: AbortSignal): Promise<void>;
|
|
22
|
+
resolveSyncGroups(context: UserContext): readonly string[];
|
|
23
|
+
}
|
|
24
|
+
export declare function initialize<TCollaboration extends EventMap<TCollaboration>>(host: InitializeHost<TCollaboration>, context: UserContext, signal?: AbortSignal): Generator<Promise<void | number | boolean | BootstrapRequirements>, {
|
|
25
|
+
success: boolean;
|
|
26
|
+
error?: Error;
|
|
27
|
+
}, void | number | boolean | BootstrapRequirements>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { AbloSessionError } from '@abloatai/transaction/errors';
|
|
2
|
+
export function* initialize(host, context, signal) {
|
|
3
|
+
if (host.initialized)
|
|
4
|
+
return { success: true };
|
|
5
|
+
host.userContext = context;
|
|
6
|
+
try {
|
|
7
|
+
host.updateSyncStatus({ state: 'syncing', progress: 0 });
|
|
8
|
+
// The commit outbox and offline mutation journal live in IndexedDB.
|
|
9
|
+
// Open it before SyncClient restores either one; reading first used to
|
|
10
|
+
// make persistence silently look empty on every cold start.
|
|
11
|
+
yield host.database.open({
|
|
12
|
+
participantId: context.userId,
|
|
13
|
+
organizationId: context.organizationId,
|
|
14
|
+
participantKind: context.kind ?? 'user',
|
|
15
|
+
projectId: context.projectId ?? context.organizationId,
|
|
16
|
+
environment: context.environment ?? null,
|
|
17
|
+
sandboxId: context.sandboxId ?? null,
|
|
18
|
+
});
|
|
19
|
+
// Propagate identity only after storage is ready, then restore sealed
|
|
20
|
+
// requests before accepting fresh mutations.
|
|
21
|
+
yield host.syncClient.initialize(context.userId, context.organizationId);
|
|
22
|
+
// Hydrate from IndexedDB (fast, cached data)
|
|
23
|
+
let hasLocalData = false;
|
|
24
|
+
try {
|
|
25
|
+
yield host.syncClient.hydrateFromDatabase();
|
|
26
|
+
hasLocalData = host.objectPool.size > 0;
|
|
27
|
+
}
|
|
28
|
+
catch (hydrateError) {
|
|
29
|
+
host.runtime.logger.debug('[sync-engine] IDB hydration failed', { error: hydrateError });
|
|
30
|
+
host.runtime.observability.captureBootstrapFailure(hydrateError, { type: 'hydration-from-idb' });
|
|
31
|
+
}
|
|
32
|
+
// Get sync baseline for WebSocket
|
|
33
|
+
const lastSyncId = (yield host.database.getLastSyncId());
|
|
34
|
+
host.syncClient.position.advancePersisted(lastSyncId || 0);
|
|
35
|
+
// If local data available, show UI immediately
|
|
36
|
+
if (hasLocalData) {
|
|
37
|
+
host.dataReady = true;
|
|
38
|
+
host.initialized = true;
|
|
39
|
+
host.updateSyncStatus({ state: 'syncing', progress: 50 });
|
|
40
|
+
}
|
|
41
|
+
// Setup WebSocket
|
|
42
|
+
host.setupWebSocketSync(context, lastSyncId);
|
|
43
|
+
// Bootstrap from server if needed.
|
|
44
|
+
//
|
|
45
|
+
// `bootstrapMode: 'none'` participants (agent-worker, headless
|
|
46
|
+
// task runners) skip baseline replication — they read via
|
|
47
|
+
// `model.get()` round-trips and rely on covering deltas
|
|
48
|
+
// from filtered subscriptions to populate the pool lazily. The
|
|
49
|
+
// WS is already open by `setupWebSocketSync` above, so live
|
|
50
|
+
// delta flow works regardless of this branch.
|
|
51
|
+
const requirements = (yield host.database.requiredBootstrap());
|
|
52
|
+
if (context.bootstrapMode === 'none') {
|
|
53
|
+
host.runtime.logger.info('[BaseSyncedStore] Bootstrap skipped (bootstrapMode=none)', { kind: context.kind ?? 'user' });
|
|
54
|
+
// `setupWebSocketSync` above creates the SyncWebSocket and
|
|
55
|
+
// initiates the upgrade, but it does NOT await the 'connected'
|
|
56
|
+
// event — it returns synchronously after wiring listeners.
|
|
57
|
+
// For bootstrapMode='none' consumers (agent-worker, headless
|
|
58
|
+
// task runners), this branch is the entire body of initialize()
|
|
59
|
+
// after the WS is set up, so `ready()` would otherwise resolve
|
|
60
|
+
// while the WS is still in 'connecting' state. The very next
|
|
61
|
+
// `commits.create` then throws "SyncWebSocket not connected".
|
|
62
|
+
//
|
|
63
|
+
// For bootstrapMode='full' consumers we don't need this await:
|
|
64
|
+
// `executeBootstrapWithTimeout` below sends the bootstrap RPC
|
|
65
|
+
// which inherently requires the WS to be open, so it surfaces
|
|
66
|
+
// a connection error if the upgrade hasn't completed.
|
|
67
|
+
//
|
|
68
|
+
// 5s bound is generous (typical connect is <100ms); past that
|
|
69
|
+
// we return anyway and let the next commit attempt fail loudly
|
|
70
|
+
// rather than block initialize() forever.
|
|
71
|
+
yield host.waitForWebSocketConnected(5000);
|
|
72
|
+
}
|
|
73
|
+
else if (requirements.type !== 'local') {
|
|
74
|
+
if (hasLocalData) {
|
|
75
|
+
// Background bootstrap — don't block UI. The method captures its own
|
|
76
|
+
// operational failures; this backstop covers escapes from the
|
|
77
|
+
// delta-queue replay in withDeltaQueuing's finally (and the error
|
|
78
|
+
// handler itself), which would otherwise vanish unhandled.
|
|
79
|
+
void host.performBackgroundBootstrap(requirements, context, signal).catch((error) => {
|
|
80
|
+
host.runtime.observability.captureBootstrapFailure(error, {
|
|
81
|
+
type: 'background-orchestration',
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// First load — must wait for server data
|
|
87
|
+
yield host.executeBootstrapWithTimeout(async () => {
|
|
88
|
+
await host.database.bootstrapFromServer(requirements, host.resolveSyncGroups(context));
|
|
89
|
+
}, context, signal);
|
|
90
|
+
yield host.syncClient.hydrateFromDatabase();
|
|
91
|
+
host.dataReady = true;
|
|
92
|
+
host.initialized = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!host.initialized)
|
|
96
|
+
host.initialized = true;
|
|
97
|
+
if (!host.dataReady) {
|
|
98
|
+
host.dataReady = true;
|
|
99
|
+
}
|
|
100
|
+
host.updateSyncStatus({ state: 'idle', progress: 100 });
|
|
101
|
+
return { success: true };
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const isAbort = error instanceof DOMException && error.name === 'AbortError';
|
|
105
|
+
if (isAbort) {
|
|
106
|
+
host.dataReady = false;
|
|
107
|
+
host.initialized = false;
|
|
108
|
+
host.updateSyncStatus({ state: 'idle', progress: 0 });
|
|
109
|
+
return { success: false, error: error };
|
|
110
|
+
}
|
|
111
|
+
const isSession = AbloSessionError.isSessionError(error);
|
|
112
|
+
host.runtime.observability.captureBootstrapFailure(error, { type: 'initialize' });
|
|
113
|
+
if (isSession) {
|
|
114
|
+
host.syncWebSocket.setSessionErrorDetected();
|
|
115
|
+
host.syncWebSocket.disconnect();
|
|
116
|
+
host.updateSyncStatus({ state: 'error', error: error });
|
|
117
|
+
return { success: false, error: error };
|
|
118
|
+
}
|
|
119
|
+
// Fallback: show local data if available
|
|
120
|
+
if (host.objectPool.size === 0) {
|
|
121
|
+
try {
|
|
122
|
+
yield host.syncClient.hydrateFromDatabase();
|
|
123
|
+
}
|
|
124
|
+
catch { }
|
|
125
|
+
}
|
|
126
|
+
if (host.objectPool.size > 0) {
|
|
127
|
+
host.dataReady = true;
|
|
128
|
+
host.initialized = true;
|
|
129
|
+
host.updateSyncStatus(host.syncWebSocket.isConnected()
|
|
130
|
+
? { state: 'idle', progress: 100 }
|
|
131
|
+
: { state: 'offline', offlineSince: new Date() });
|
|
132
|
+
return { success: true };
|
|
133
|
+
}
|
|
134
|
+
host.updateSyncStatus({ state: 'error', error: error });
|
|
135
|
+
return { success: false, error: error };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { JoinOptions } from '@abloatai/transaction/resources/modelOperations';
|
|
2
|
+
import type { SyncWebSocket } from './SyncWebSocket.js';
|
|
3
|
+
import type { Schema } from '@abloatai/transaction/schema/schema';
|
|
4
|
+
import type { Claim, Activity, ClaimTarget, ClaimStream, Peer, PresenceStream, PresenceTarget } from '@abloatai/transaction/types/streams';
|
|
5
|
+
import type { AttachableClaimStream } from './createClaimStream.js';
|
|
6
|
+
/**
|
|
7
|
+
* The scope a participant can be joined to. The usual form is an entity target
|
|
8
|
+
* (`{ type, id }`); raw sync-group strings are an advanced escape hatch for
|
|
9
|
+
* addressing a transport scope directly.
|
|
10
|
+
*/
|
|
11
|
+
export type ParticipantScope = ClaimTarget | readonly ClaimTarget[] | string | readonly string[] | {
|
|
12
|
+
readonly syncGroup: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly syncGroups: readonly string[];
|
|
15
|
+
} | Record<string, string | readonly string[] | undefined>;
|
|
16
|
+
export type ParticipantStatus = 'idle' | 'connecting' | 'connected' | 'error' | 'disconnected';
|
|
17
|
+
export interface EngineParticipant {
|
|
18
|
+
readonly presence: PresenceStream;
|
|
19
|
+
readonly claims: ClaimStream;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The options for a participant join. It extends the public per-model
|
|
23
|
+
* {@link JoinOptions} rather than restating its members, so the lease dial is
|
|
24
|
+
* declared once, in the core, and this surface adds only what a lower-level
|
|
25
|
+
* join can additionally say.
|
|
26
|
+
*/
|
|
27
|
+
export interface ParticipantJoinOptions extends JoinOptions {
|
|
28
|
+
/**
|
|
29
|
+
* The initial focus target, named in your schema's vocabulary and optionally
|
|
30
|
+
* narrowed to a field. When `scope` is omitted, this target also becomes the
|
|
31
|
+
* routing scope.
|
|
32
|
+
*/
|
|
33
|
+
readonly target?: PresenceTarget;
|
|
34
|
+
/** Alias for `target` when the participant is joined to a broader scope. */
|
|
35
|
+
readonly focus?: PresenceTarget;
|
|
36
|
+
/**
|
|
37
|
+
* The routing scope: one entity, many entities, or a raw sync-group escape
|
|
38
|
+
* hatch. Use it for "joined to the folder, focused on one file" shapes,
|
|
39
|
+
* where the participant listens more broadly than its focus target.
|
|
40
|
+
*/
|
|
41
|
+
readonly scope?: ParticipantScope;
|
|
42
|
+
/** Present a narrower capability for this logical participant. */
|
|
43
|
+
readonly capabilityToken?: string;
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Use `ttl`. Removed in 0.37.0.
|
|
46
|
+
*
|
|
47
|
+
* One lease, spelled two ways, and the seconds spelling was the one that
|
|
48
|
+
* misled: it accepted a duration string, so `ablo.<model>.join(ids, { ttl:
|
|
49
|
+
* '5m' })` reached this surface as `ttlSeconds: '5m'` — a field whose name
|
|
50
|
+
* asserts a unit its value did not carry. `ttl` takes the same values and is
|
|
51
|
+
* the spelling every other lease in the SDK already uses (`claim`'s `ttl`,
|
|
52
|
+
* `ClaimLeaseOptions.ttl`). The wire is unchanged: it has always carried
|
|
53
|
+
* seconds, and still does.
|
|
54
|
+
*/
|
|
55
|
+
readonly ttlSeconds?: number | string | null;
|
|
56
|
+
/**
|
|
57
|
+
* The activity to announce as soon as the claim is acknowledged. Defaults to
|
|
58
|
+
* `reading` when a `target` is present. Pass `false` to join without
|
|
59
|
+
* announcing anything.
|
|
60
|
+
*/
|
|
61
|
+
readonly activity?: 'reading' | 'viewing' | 'editing' | false;
|
|
62
|
+
readonly detail?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface ScopedPresence {
|
|
65
|
+
readonly self: Peer;
|
|
66
|
+
readonly focus: ClaimTarget | null;
|
|
67
|
+
readonly others: readonly Peer[];
|
|
68
|
+
update(activity: Activity): void;
|
|
69
|
+
reading(detail?: string): void;
|
|
70
|
+
reading(target: PresenceTarget, detail?: string): void;
|
|
71
|
+
viewing(detail?: string): void;
|
|
72
|
+
viewing(target: PresenceTarget, detail?: string): void;
|
|
73
|
+
editing(detail?: string): void;
|
|
74
|
+
editing(target: PresenceTarget, detail?: string): void;
|
|
75
|
+
idle(): void;
|
|
76
|
+
onChange(listener: () => void): () => void;
|
|
77
|
+
}
|
|
78
|
+
export interface ScopedClaimOptions {
|
|
79
|
+
/** Override the participant's focus target for this one claim. */
|
|
80
|
+
readonly target?: PresenceTarget;
|
|
81
|
+
/** Peer-visible description of the work. Defaults to `'editing'`. */
|
|
82
|
+
readonly description?: string;
|
|
83
|
+
/** How long the claim lives; the server expires it automatically after this. */
|
|
84
|
+
readonly ttl?: import('@abloatai/transaction/types/streams').Duration;
|
|
85
|
+
}
|
|
86
|
+
export interface ScopedClaims {
|
|
87
|
+
readonly focus: ClaimTarget | null;
|
|
88
|
+
readonly others: readonly Claim[];
|
|
89
|
+
/**
|
|
90
|
+
* Takes an exclusive claim on the participant's focus target, or on an
|
|
91
|
+
* explicit target passed via `opts.target`. While the claim is held, other
|
|
92
|
+
* participants that request an overlapping target are rejected.
|
|
93
|
+
*/
|
|
94
|
+
claim(opts?: ScopedClaimOptions): Claim;
|
|
95
|
+
onRejected(listener: Parameters<ClaimStream['onRejected']>[0]): () => void;
|
|
96
|
+
onChange(listener: () => void): () => void;
|
|
97
|
+
}
|
|
98
|
+
export interface ParticipantFocusOptions {
|
|
99
|
+
readonly activity?: 'reading' | 'viewing' | 'editing' | false;
|
|
100
|
+
readonly detail?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface JoinedParticipant {
|
|
103
|
+
/** The exact entity this participant is currently reading or editing. */
|
|
104
|
+
readonly target: ClaimTarget | null;
|
|
105
|
+
readonly focusTarget: ClaimTarget | null;
|
|
106
|
+
/** The transport scopes this participant is joined to, which govern what it sees and receives. */
|
|
107
|
+
readonly syncGroups: readonly string[];
|
|
108
|
+
readonly presence: ScopedPresence;
|
|
109
|
+
readonly claims: ScopedClaims;
|
|
110
|
+
readonly peers: readonly Peer[];
|
|
111
|
+
readonly activeClaims: readonly Claim[];
|
|
112
|
+
focus(target: PresenceTarget, options?: ParticipantFocusOptions): JoinedParticipant;
|
|
113
|
+
leave(): void;
|
|
114
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
export interface ParticipantManager {
|
|
117
|
+
join(target: PresenceTarget, options?: Omit<ParticipantJoinOptions, 'target'>): Promise<JoinedParticipant>;
|
|
118
|
+
join(options: ParticipantJoinOptions): Promise<JoinedParticipant>;
|
|
119
|
+
}
|
|
120
|
+
export interface ParticipantManagerConfig {
|
|
121
|
+
readonly ready: () => Promise<void>;
|
|
122
|
+
/** The connection, host-built and stable for the client's lifetime. */
|
|
123
|
+
readonly transport: SyncWebSocket;
|
|
124
|
+
readonly presence: PresenceStream;
|
|
125
|
+
readonly claims: AttachableClaimStream;
|
|
126
|
+
readonly schema?: Schema;
|
|
127
|
+
}
|
|
128
|
+
export declare function createParticipantManager(config: ParticipantManagerConfig): ParticipantManager;
|
|
129
|
+
export declare function resolveParticipantSyncGroups(scope: ParticipantScope | undefined, schema?: Schema): string[];
|
|
130
|
+
export declare function syncGroupFromEntityRef(ref: ClaimTarget, schema?: Schema): string;
|
|
131
|
+
export declare function parseParticipantTtlSeconds(value: number | string | null | undefined): number | undefined;
|
|
132
|
+
export declare function createParticipantClaimId(): string;
|