@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,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages the client-side IndexedDB databases the sync engine keeps in the
|
|
3
|
+
* browser. There are two tiers. A single registry database, `ablo_databases`,
|
|
4
|
+
* records metadata about every workspace database. Each user-and-workspace pair
|
|
5
|
+
* then gets its own data database, named `ablo_<hash>`, that holds the synced
|
|
6
|
+
* rows. {@link DatabaseManager} creates, versions, and deletes both tiers.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { globalRuntime } from '../context.js';
|
|
10
|
+
import type { RuntimeContext } from '../RuntimeContext.js';
|
|
11
|
+
import {
|
|
12
|
+
openIDBWithTimeout,
|
|
13
|
+
deleteIDBWithTimeout,
|
|
14
|
+
IDBOpenTimeoutError,
|
|
15
|
+
} from './openIDBWithTimeout.js';
|
|
16
|
+
import { AbloConnectionError } from '@abloatai/transaction/errors';
|
|
17
|
+
import { getActiveRegistry, hasActiveRegistry } from '../ModelRegistry.js';
|
|
18
|
+
import {
|
|
19
|
+
PERSISTENCE_NAMESPACE_VERSION,
|
|
20
|
+
persistenceDatabaseName,
|
|
21
|
+
persistenceIdentityMatches,
|
|
22
|
+
type PersistenceIdentity,
|
|
23
|
+
} from './persistenceIdentity.js';
|
|
24
|
+
|
|
25
|
+
export type { PersistenceIdentity } from './persistenceIdentity.js';
|
|
26
|
+
|
|
27
|
+
export interface DatabaseInfo {
|
|
28
|
+
name: string;
|
|
29
|
+
namespaceVersion: number;
|
|
30
|
+
userId: string;
|
|
31
|
+
workspaceId: string;
|
|
32
|
+
participantKind: string;
|
|
33
|
+
projectId: string | null;
|
|
34
|
+
environment: 'sandbox' | 'production' | null;
|
|
35
|
+
sandboxId: string | null;
|
|
36
|
+
schemaHash: string;
|
|
37
|
+
schemaVersion: number;
|
|
38
|
+
userVersion?: number;
|
|
39
|
+
createdAt: Date;
|
|
40
|
+
updatedAt: Date;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface WorkspaceMetadata {
|
|
44
|
+
lastSyncId: number;
|
|
45
|
+
firstSyncId: number;
|
|
46
|
+
backendDatabaseVersion: number;
|
|
47
|
+
subscribedSyncGroups: string[];
|
|
48
|
+
updatedAt: Date;
|
|
49
|
+
schemaHash?: string;
|
|
50
|
+
syncGroups?: string[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function indexedDbError(error: DOMException | null, operation: string): Error {
|
|
54
|
+
return error ?? new Error(`IndexedDB ${operation} failed`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* DatabaseManager - Manages Ablo's two-tier database architecture
|
|
59
|
+
*
|
|
60
|
+
* Key responsibilities:
|
|
61
|
+
* - Manages ablo_databases (database registry)
|
|
62
|
+
* - Creates workspace-specific databases (ablo_hash)
|
|
63
|
+
* - Handles database migration and versioning
|
|
64
|
+
* - Provides database info and metadata management
|
|
65
|
+
*/
|
|
66
|
+
export class DatabaseManager {
|
|
67
|
+
private metaDb: IDBDatabase | null = null;
|
|
68
|
+
private readonly metaDbName = 'ablo_databases';
|
|
69
|
+
|
|
70
|
+
constructor(private readonly runtime: RuntimeContext = globalRuntime) {}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Initialize the meta database (ablo_databases)
|
|
74
|
+
*/
|
|
75
|
+
async initializeMetaDatabase(): Promise<void> {
|
|
76
|
+
const open = (): Promise<IDBDatabase> =>
|
|
77
|
+
openIDBWithTimeout(this.metaDbName, 1, {
|
|
78
|
+
onUpgrade: (request) => {
|
|
79
|
+
const db = request.result;
|
|
80
|
+
if (!db.objectStoreNames.contains('databases')) {
|
|
81
|
+
const store = db.createObjectStore('databases', { keyPath: 'name' });
|
|
82
|
+
store.createIndex('userId', 'userId');
|
|
83
|
+
store.createIndex('workspaceId', 'workspaceId');
|
|
84
|
+
store.createIndex('schemaHash', 'schemaHash');
|
|
85
|
+
store.createIndex('updatedAt', 'updatedAt');
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
this.metaDb = await open();
|
|
92
|
+
} catch (error) {
|
|
93
|
+
// Self-heal a wedged meta DB. When `ablo_databases`'s backing store gets
|
|
94
|
+
// stuck (a corrupted store, or a leaked connection from a prior
|
|
95
|
+
// timed-out open), every open of that name hangs with no event and the
|
|
96
|
+
// app is permanently bricked until the user manually clears site data —
|
|
97
|
+
// the "open did not resolve within 10000ms" dead end. The registry this
|
|
98
|
+
// DB holds is rebuildable from the server on the next bootstrap, so it is
|
|
99
|
+
// safe to delete and re-create. Try exactly once: delete, then re-open.
|
|
100
|
+
if (!(error instanceof IDBOpenTimeoutError)) throw error;
|
|
101
|
+
|
|
102
|
+
this.runtime.logger.debug(
|
|
103
|
+
'[sync-engine] meta DB open timed out — attempting self-heal (delete + retry)',
|
|
104
|
+
{ db: this.metaDbName, reason: error.reason },
|
|
105
|
+
);
|
|
106
|
+
this.runtime.observability.captureBootstrapFailure(error, {
|
|
107
|
+
type: 'meta-db-open-timeout',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const deleted = await deleteIDBWithTimeout(this.metaDbName);
|
|
111
|
+
if (!deleted) {
|
|
112
|
+
// The delete itself was blocked/stuck — a live connection in another
|
|
113
|
+
// window or a deadlocked backing store. We cannot recover in-page;
|
|
114
|
+
// rethrow so the provider surfaces the real (now actionable) error.
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
// Fresh store — this open creates `ablo_databases` from scratch.
|
|
118
|
+
this.metaDb = await open();
|
|
119
|
+
this.runtime.logger.info('[sync-engine] meta DB self-heal succeeded');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Calculate database info for a user/workspace combination
|
|
125
|
+
*/
|
|
126
|
+
async calculateDatabaseInfo(
|
|
127
|
+
identity: PersistenceIdentity,
|
|
128
|
+
userVersion = 1
|
|
129
|
+
): Promise<DatabaseInfo> {
|
|
130
|
+
// Get schema hash from the active ModelRegistry
|
|
131
|
+
const schemaHash = hasActiveRegistry()
|
|
132
|
+
? getActiveRegistry().getSchemaHash()
|
|
133
|
+
: 'no-registry-hash';
|
|
134
|
+
|
|
135
|
+
// Generate database name from userId, workspaceId, and versions
|
|
136
|
+
const dbName = await persistenceDatabaseName(identity, userVersion);
|
|
137
|
+
|
|
138
|
+
// Check if we need to increment schema version
|
|
139
|
+
const existingInfo = await this.getDatabaseInfo(dbName);
|
|
140
|
+
if (existingInfo && !persistenceIdentityMatches(existingInfo, identity)) {
|
|
141
|
+
throw new AbloConnectionError(
|
|
142
|
+
'Local database identity mismatch. Refusing to open persisted data ' +
|
|
143
|
+
'owned by a different authenticated plane.',
|
|
144
|
+
{ code: 'db_identity_mismatch' },
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
let schemaVersion = 1;
|
|
148
|
+
|
|
149
|
+
if (existingInfo && existingInfo.schemaHash !== schemaHash) {
|
|
150
|
+
schemaVersion = (existingInfo.schemaVersion || 1) + 1;
|
|
151
|
+
} else if (existingInfo) {
|
|
152
|
+
schemaVersion = existingInfo.schemaVersion || 1;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Record the existing databases for this user so duplicates can be detected.
|
|
156
|
+
const allUserDatabases = await this.getDatabasesForUser(identity.participantId);
|
|
157
|
+
const allIndexedDBs = (await indexedDB.databases?.()) || [];
|
|
158
|
+
const abloDatabases = allIndexedDBs.filter((db: IDBDatabaseInfo) =>
|
|
159
|
+
db.name?.startsWith('ablo_')
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
this.runtime.observability.breadcrumb('Database info calculated', 'sync.database', 'info', {
|
|
163
|
+
dbName,
|
|
164
|
+
schemaVersion,
|
|
165
|
+
existingDbCount: allUserDatabases.length,
|
|
166
|
+
abloDbCount: abloDatabases.length,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
name: dbName,
|
|
171
|
+
namespaceVersion: PERSISTENCE_NAMESPACE_VERSION,
|
|
172
|
+
userId: identity.participantId,
|
|
173
|
+
workspaceId: identity.organizationId,
|
|
174
|
+
participantKind: identity.participantKind,
|
|
175
|
+
projectId: identity.projectId,
|
|
176
|
+
environment: identity.environment,
|
|
177
|
+
sandboxId: identity.sandboxId,
|
|
178
|
+
schemaHash,
|
|
179
|
+
schemaVersion,
|
|
180
|
+
userVersion,
|
|
181
|
+
createdAt: existingInfo?.createdAt ?? new Date(),
|
|
182
|
+
updatedAt: new Date(),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Register database info in ablo_databases
|
|
188
|
+
*/
|
|
189
|
+
async registerDatabase(info: DatabaseInfo): Promise<void> {
|
|
190
|
+
const metaDb = this.metaDb;
|
|
191
|
+
if (!metaDb) {
|
|
192
|
+
throw new AbloConnectionError('Meta database not initialized', {
|
|
193
|
+
code: 'meta_db_not_initialized',
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
const tx = metaDb.transaction(['databases'], 'readwrite');
|
|
199
|
+
const store = tx.objectStore('databases');
|
|
200
|
+
|
|
201
|
+
const request = store.put(info);
|
|
202
|
+
|
|
203
|
+
tx.oncomplete = () => {
|
|
204
|
+
resolve();
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
tx.onerror = () => { reject(indexedDbError(tx.error, 'registry transaction')); };
|
|
208
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'registry write')); };
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get database info by name
|
|
214
|
+
*/
|
|
215
|
+
async getDatabaseInfo(name: string): Promise<DatabaseInfo | null> {
|
|
216
|
+
const metaDb = this.metaDb;
|
|
217
|
+
if (!metaDb) return null;
|
|
218
|
+
|
|
219
|
+
return new Promise((resolve, reject) => {
|
|
220
|
+
const tx = metaDb.transaction(['databases'], 'readonly');
|
|
221
|
+
const store = tx.objectStore('databases');
|
|
222
|
+
const request = store.get(name);
|
|
223
|
+
|
|
224
|
+
request.onsuccess = () => { resolve(request.result ?? null); };
|
|
225
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'registry read')); };
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Remove only the named ownership records; the shared registry stays live. */
|
|
230
|
+
async unregisterDatabases(names: readonly string[]): Promise<void> {
|
|
231
|
+
const metaDb = this.metaDb;
|
|
232
|
+
if (!metaDb || names.length === 0) return;
|
|
233
|
+
return new Promise((resolve, reject) => {
|
|
234
|
+
const tx = metaDb.transaction(['databases'], 'readwrite');
|
|
235
|
+
const store = tx.objectStore('databases');
|
|
236
|
+
for (const name of new Set(names)) store.delete(name);
|
|
237
|
+
tx.oncomplete = () => { resolve(); };
|
|
238
|
+
tx.onerror = () => { reject(indexedDbError(tx.error, 'registry cleanup')); };
|
|
239
|
+
tx.onabort = () => { reject(indexedDbError(tx.error, 'registry cleanup')); };
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get all databases for a user
|
|
245
|
+
*/
|
|
246
|
+
async getDatabasesForUser(userId: string): Promise<DatabaseInfo[]> {
|
|
247
|
+
const metaDb = this.metaDb;
|
|
248
|
+
if (!metaDb) return [];
|
|
249
|
+
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
const tx = metaDb.transaction(['databases'], 'readonly');
|
|
252
|
+
const store = tx.objectStore('databases');
|
|
253
|
+
const index = store.index('userId');
|
|
254
|
+
const request = index.getAll(userId);
|
|
255
|
+
|
|
256
|
+
request.onsuccess = () => { resolve(request.result || []); };
|
|
257
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'user database lookup')); };
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Open workspace-specific database
|
|
263
|
+
*/
|
|
264
|
+
async openWorkspaceDatabase(
|
|
265
|
+
dbInfo: DatabaseInfo,
|
|
266
|
+
createStoresFn?: (db: IDBDatabase, tx: IDBTransaction) => Promise<void>
|
|
267
|
+
): Promise<IDBDatabase> {
|
|
268
|
+
try {
|
|
269
|
+
return await openIDBWithTimeout(dbInfo.name, dbInfo.schemaVersion, {
|
|
270
|
+
onUpgrade: (request, event) => {
|
|
271
|
+
const db = request.result;
|
|
272
|
+
const tx = (event.target as IDBOpenDBRequest).transaction;
|
|
273
|
+
// IndexedDB rule: only awaits on IndexedDB requests keep an upgrade
|
|
274
|
+
// transaction alive. Any other await — a fetch, a timer — commits the
|
|
275
|
+
// transaction early, and later operations then throw
|
|
276
|
+
// `TransactionInactiveError`. StoreManager.createStores runs only
|
|
277
|
+
// synchronous createObjectStore / createIndex calls under an `async`
|
|
278
|
+
// keyword, so calling it without awaiting is safe here.
|
|
279
|
+
if (createStoresFn && tx) {
|
|
280
|
+
try {
|
|
281
|
+
void createStoresFn(db, tx).catch((err) => {
|
|
282
|
+
this.runtime.observability.captureBootstrapFailure(err, {
|
|
283
|
+
type: 'store-creation',
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
} catch (err) {
|
|
287
|
+
this.runtime.observability.captureBootstrapFailure(err, {
|
|
288
|
+
type: 'store-creation',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
} catch (error) {
|
|
295
|
+
this.runtime.observability.captureBootstrapFailure(error, {
|
|
296
|
+
type: 'database-open',
|
|
297
|
+
});
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Read workspace metadata from __meta table
|
|
304
|
+
*/
|
|
305
|
+
async getWorkspaceMetadata(db: IDBDatabase): Promise<WorkspaceMetadata | null> {
|
|
306
|
+
return new Promise((resolve, reject) => {
|
|
307
|
+
const tx = db.transaction(['__meta'], 'readonly');
|
|
308
|
+
const store = tx.objectStore('__meta');
|
|
309
|
+
const request = store.get('metadata');
|
|
310
|
+
|
|
311
|
+
request.onsuccess = () => {
|
|
312
|
+
const data = request.result;
|
|
313
|
+
if (!data) {
|
|
314
|
+
resolve(null);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const meta = {
|
|
319
|
+
lastSyncId: data.lastSyncId ?? 0,
|
|
320
|
+
firstSyncId: data.firstSyncId ?? 0,
|
|
321
|
+
backendDatabaseVersion: data.backendDatabaseVersion ?? 1,
|
|
322
|
+
subscribedSyncGroups: data.subscribedSyncGroups ?? [],
|
|
323
|
+
updatedAt: data.updatedAt ? new Date(data.updatedAt) : new Date(),
|
|
324
|
+
schemaHash: data.schemaHash,
|
|
325
|
+
syncGroups: data.syncGroups,
|
|
326
|
+
// Older persisted records may still carry an extra `versions` key
|
|
327
|
+
// that is no longer used; it is tolerated by simply not reading it here.
|
|
328
|
+
} as WorkspaceMetadata;
|
|
329
|
+
resolve(meta);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'workspace metadata read')); };
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Write workspace metadata to __meta table
|
|
338
|
+
*/
|
|
339
|
+
async setWorkspaceMetadata(db: IDBDatabase, metadata: WorkspaceMetadata): Promise<void> {
|
|
340
|
+
return new Promise((resolve, reject) => {
|
|
341
|
+
const tx = db.transaction(['__meta'], 'readwrite');
|
|
342
|
+
const store = tx.objectStore('__meta');
|
|
343
|
+
const request = store.put(metadata, 'metadata');
|
|
344
|
+
|
|
345
|
+
tx.oncomplete = () => { resolve(); };
|
|
346
|
+
tx.onerror = () => { reject(indexedDbError(tx.error, 'workspace metadata transaction')); };
|
|
347
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'workspace metadata write')); };
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Check if a model is persisted (all instances loaded)
|
|
353
|
+
*/
|
|
354
|
+
async isModelPersisted(db: IDBDatabase, modelName: string): Promise<boolean> {
|
|
355
|
+
return new Promise((resolve, reject) => {
|
|
356
|
+
const tx = db.transaction(['__meta'], 'readonly');
|
|
357
|
+
const store = tx.objectStore('__meta');
|
|
358
|
+
const request = store.get(modelName);
|
|
359
|
+
|
|
360
|
+
request.onsuccess = () => {
|
|
361
|
+
const data = request.result;
|
|
362
|
+
resolve(data?.persisted === true);
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'model persistence read')); };
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Mark a model as persisted
|
|
371
|
+
*/
|
|
372
|
+
async setModelPersisted(db: IDBDatabase, modelName: string, persisted: boolean): Promise<void> {
|
|
373
|
+
return new Promise((resolve, reject) => {
|
|
374
|
+
const tx = db.transaction(['__meta'], 'readwrite');
|
|
375
|
+
const store = tx.objectStore('__meta');
|
|
376
|
+
|
|
377
|
+
const persistenceData = {
|
|
378
|
+
persisted,
|
|
379
|
+
modelName,
|
|
380
|
+
timestamp: Date.now(),
|
|
381
|
+
updatedAt: new Date().toISOString(),
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const request = store.put(persistenceData, modelName);
|
|
385
|
+
|
|
386
|
+
tx.oncomplete = () => { resolve(); };
|
|
387
|
+
tx.onerror = () => { reject(indexedDbError(tx.error, 'model persistence transaction')); };
|
|
388
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'model persistence write')); };
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Get all model persistence states
|
|
394
|
+
*/
|
|
395
|
+
async getAllModelPersistenceStates(db: IDBDatabase): Promise<Record<string, boolean>> {
|
|
396
|
+
return new Promise((resolve, reject) => {
|
|
397
|
+
const tx = db.transaction(['__meta'], 'readonly');
|
|
398
|
+
const store = tx.objectStore('__meta');
|
|
399
|
+
const request = store.getAll();
|
|
400
|
+
|
|
401
|
+
request.onsuccess = () => {
|
|
402
|
+
const states: Record<string, boolean> = {};
|
|
403
|
+
|
|
404
|
+
for (const item of request.result) {
|
|
405
|
+
// Skip metadata entry
|
|
406
|
+
if (item.key === 'metadata') continue;
|
|
407
|
+
|
|
408
|
+
if (item.modelName) {
|
|
409
|
+
states[item.modelName] = item.persisted === true;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
resolve(states);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'model persistence scan')); };
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Delete a workspace database
|
|
422
|
+
*/
|
|
423
|
+
async deleteWorkspaceDatabase(dbInfo: DatabaseInfo): Promise<boolean> {
|
|
424
|
+
const deleted = await deleteIDBWithTimeout(dbInfo.name);
|
|
425
|
+
if (!deleted) {
|
|
426
|
+
this.runtime.observability.breadcrumb(
|
|
427
|
+
`Database deletion failed or was blocked: ${dbInfo.name}`,
|
|
428
|
+
'sync.database',
|
|
429
|
+
'error',
|
|
430
|
+
);
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (this.metaDb) {
|
|
435
|
+
const metaDb = this.metaDb;
|
|
436
|
+
await new Promise<void>((resolve, reject) => {
|
|
437
|
+
const tx = metaDb.transaction(['databases'], 'readwrite');
|
|
438
|
+
tx.objectStore('databases').delete(dbInfo.name);
|
|
439
|
+
tx.oncomplete = () => { resolve(); };
|
|
440
|
+
tx.onerror = () => { reject(indexedDbError(tx.error, 'registry delete')); };
|
|
441
|
+
tx.onabort = () => { reject(indexedDbError(tx.error, 'registry delete')); };
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Get comprehensive database statistics
|
|
449
|
+
*/
|
|
450
|
+
async getDatabaseStatistics(): Promise<{
|
|
451
|
+
metaDatabaseSize: number;
|
|
452
|
+
totalWorkspaceDatabases: number;
|
|
453
|
+
databasesByUser: Record<string, number>;
|
|
454
|
+
schemaVersions: Record<string, number>;
|
|
455
|
+
}> {
|
|
456
|
+
const metaDb = this.metaDb;
|
|
457
|
+
if (!metaDb) {
|
|
458
|
+
return {
|
|
459
|
+
metaDatabaseSize: 0,
|
|
460
|
+
totalWorkspaceDatabases: 0,
|
|
461
|
+
databasesByUser: {},
|
|
462
|
+
schemaVersions: {},
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return new Promise((resolve, reject) => {
|
|
467
|
+
const tx = metaDb.transaction(['databases'], 'readonly');
|
|
468
|
+
const store = tx.objectStore('databases');
|
|
469
|
+
const request = store.getAll();
|
|
470
|
+
|
|
471
|
+
request.onsuccess = () => {
|
|
472
|
+
const databases = request.result;
|
|
473
|
+
|
|
474
|
+
const databasesByUser: Record<string, number> = {};
|
|
475
|
+
const schemaVersions: Record<string, number> = {};
|
|
476
|
+
|
|
477
|
+
for (const db of databases) {
|
|
478
|
+
// Count by user
|
|
479
|
+
databasesByUser[db.userId] = (databasesByUser[db.userId] ?? 0) + 1;
|
|
480
|
+
|
|
481
|
+
// Count schema versions
|
|
482
|
+
const versionKey = `v${db.schemaVersion}`;
|
|
483
|
+
schemaVersions[versionKey] = (schemaVersions[versionKey] ?? 0) + 1;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
resolve({
|
|
487
|
+
metaDatabaseSize: databases.length,
|
|
488
|
+
totalWorkspaceDatabases: databases.length,
|
|
489
|
+
databasesByUser,
|
|
490
|
+
schemaVersions,
|
|
491
|
+
});
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
request.onerror = () => { reject(indexedDbError(request.error, 'registry statistics read')); };
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Close all database connections
|
|
500
|
+
*/
|
|
501
|
+
async close(): Promise<void> {
|
|
502
|
+
if (this.metaDb) {
|
|
503
|
+
this.metaDb.close();
|
|
504
|
+
this.metaDb = null;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|