@abloatai/ablo 0.25.0 → 0.27.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/AGENTS.md +5 -3
- package/CHANGELOG.md +34 -0
- package/README.md +104 -88
- package/dist/BaseSyncedStore.d.ts +140 -266
- package/dist/BaseSyncedStore.js +338 -739
- package/dist/Database.d.ts +62 -77
- package/dist/Database.js +106 -127
- package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
- package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
- package/dist/LazyReferenceCollection.d.ts +11 -15
- package/dist/LazyReferenceCollection.js +16 -15
- package/dist/Model.d.ts +37 -52
- package/dist/Model.js +52 -69
- package/dist/ModelRegistry.d.ts +46 -25
- package/dist/ModelRegistry.js +32 -30
- package/dist/NetworkMonitor.d.ts +5 -6
- package/dist/NetworkMonitor.js +6 -7
- package/dist/SyncClient.d.ts +119 -109
- package/dist/SyncClient.js +303 -224
- package/dist/SyncEngineContext.d.ts +1 -3
- package/dist/SyncEngineContext.js +1 -2
- package/dist/adapters/alwaysOnline.d.ts +6 -8
- package/dist/adapters/alwaysOnline.js +6 -8
- package/dist/adapters/inMemoryStorage.d.ts +9 -9
- package/dist/adapters/inMemoryStorage.js +9 -9
- package/dist/agent/Agent.d.ts +39 -31
- package/dist/agent/Agent.js +35 -23
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +5 -5
- package/dist/agent/session.d.ts +47 -44
- package/dist/agent/session.js +37 -48
- package/dist/agent/types.d.ts +26 -31
- package/dist/agent/types.js +6 -7
- package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
- package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
- package/dist/ai-sdk/coordinationContext.d.ts +46 -0
- package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
- package/dist/ai-sdk/index.d.ts +25 -22
- package/dist/ai-sdk/index.js +25 -22
- package/dist/ai-sdk/wrap.d.ts +7 -8
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/credentialPolicy.d.ts +74 -71
- package/dist/auth/credentialPolicy.js +51 -56
- package/dist/auth/credentialSource.d.ts +7 -18
- package/dist/auth/credentialSource.js +10 -18
- package/dist/auth/index.d.ts +59 -58
- package/dist/auth/index.js +34 -40
- package/dist/auth/schemas.d.ts +5 -4
- package/dist/auth/schemas.js +5 -4
- package/dist/batching/index.d.ts +19 -21
- package/dist/batching/index.js +14 -17
- package/dist/cli.cjs +483 -369
- package/dist/client/Ablo.d.ts +107 -836
- package/dist/client/Ablo.js +174 -833
- package/dist/client/ApiClient.d.ts +44 -20
- package/dist/client/ApiClient.js +193 -44
- package/dist/client/auth.d.ts +51 -60
- package/dist/client/auth.js +137 -110
- package/dist/client/claimHeartbeatLoop.d.ts +50 -0
- package/dist/client/claimHeartbeatLoop.js +88 -0
- package/dist/client/consoleLogger.d.ts +35 -0
- package/dist/client/consoleLogger.js +44 -0
- package/dist/client/createInternalComponents.d.ts +14 -17
- package/dist/client/createInternalComponents.js +26 -31
- package/dist/client/createModelProxy.d.ts +130 -120
- package/dist/client/createModelProxy.js +158 -124
- package/dist/client/credentialEndpoint.d.ts +61 -0
- package/dist/client/credentialEndpoint.js +86 -0
- package/dist/client/functionalUpdate.d.ts +29 -27
- package/dist/client/functionalUpdate.js +21 -21
- package/dist/client/hostedEndpoints.d.ts +21 -0
- package/dist/client/hostedEndpoints.js +21 -0
- package/dist/client/httpClient.d.ts +58 -54
- package/dist/client/httpClient.js +29 -31
- package/dist/client/identity.d.ts +15 -20
- package/dist/client/identity.js +49 -59
- package/dist/client/modelRegistration.d.ts +10 -0
- package/dist/client/modelRegistration.js +301 -0
- package/dist/client/options.d.ts +373 -0
- package/dist/client/options.js +6 -0
- package/dist/client/registerDataSource.d.ts +9 -9
- package/dist/client/registerDataSource.js +15 -16
- package/dist/client/resourceTypes.d.ts +333 -0
- package/dist/client/resourceTypes.js +7 -0
- package/dist/client/schemaConfig.d.ts +44 -0
- package/dist/client/schemaConfig.js +176 -0
- package/dist/client/sessionMint.d.ts +17 -13
- package/dist/client/sessionMint.js +26 -31
- package/dist/client/validateAbloOptions.d.ts +12 -14
- package/dist/client/validateAbloOptions.js +9 -10
- package/dist/client/writeOptionsSchema.d.ts +18 -16
- package/dist/client/writeOptionsSchema.js +23 -20
- package/dist/client/wsMutationExecutor.d.ts +28 -0
- package/dist/client/wsMutationExecutor.js +71 -0
- package/dist/context.d.ts +6 -4
- package/dist/context.js +6 -7
- package/dist/coordination/index.d.ts +13 -4
- package/dist/coordination/index.js +29 -4
- package/dist/coordination/schema.d.ts +176 -128
- package/dist/coordination/schema.js +197 -133
- package/dist/coordination/trace.d.ts +9 -11
- package/dist/coordination/trace.js +13 -15
- package/dist/core/DatabaseManager.d.ts +5 -8
- package/dist/core/DatabaseManager.js +38 -40
- package/dist/core/QueryProcessor.d.ts +7 -9
- package/dist/core/QueryProcessor.js +27 -34
- package/dist/core/QueryView.d.ts +17 -5
- package/dist/core/QueryView.js +6 -7
- package/dist/core/StoreManager.d.ts +14 -16
- package/dist/core/StoreManager.js +26 -25
- package/dist/core/ViewRegistry.d.ts +5 -5
- package/dist/core/ViewRegistry.js +4 -4
- package/dist/core/index.d.ts +18 -13
- package/dist/core/index.js +32 -26
- package/dist/core/openIDBWithTimeout.d.ts +38 -36
- package/dist/core/openIDBWithTimeout.js +57 -54
- package/dist/core/queryUtils.d.ts +45 -0
- package/dist/core/queryUtils.js +69 -0
- package/dist/core/storeContract.d.ts +145 -0
- package/dist/core/storeContract.js +12 -0
- package/dist/environment.d.ts +28 -0
- package/dist/environment.js +21 -0
- package/dist/errorCodes.d.ts +118 -101
- package/dist/errorCodes.js +277 -260
- package/dist/errors.d.ts +170 -165
- package/dist/errors.js +161 -151
- package/dist/index.d.ts +30 -27
- package/dist/index.js +90 -82
- package/dist/interfaces/index.d.ts +108 -133
- package/dist/interfaces/index.js +5 -4
- package/dist/keys/index.d.ts +27 -29
- package/dist/keys/index.js +59 -49
- package/dist/mutators/RecordingTransaction.d.ts +16 -16
- package/dist/mutators/RecordingTransaction.js +31 -37
- package/dist/mutators/Transaction.d.ts +18 -26
- package/dist/mutators/Transaction.js +14 -20
- package/dist/mutators/UndoManager.d.ts +122 -131
- package/dist/mutators/UndoManager.js +149 -155
- package/dist/mutators/defineMutators.d.ts +24 -37
- package/dist/mutators/defineMutators.js +14 -20
- package/dist/mutators/inverseOp.d.ts +12 -15
- package/dist/mutators/inverseOp.js +12 -15
- package/dist/mutators/mutateActions.d.ts +10 -9
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +9 -8
- package/dist/mutators/readerActions.js +2 -2
- package/dist/mutators/undoApply.d.ts +31 -27
- package/dist/mutators/undoApply.js +26 -24
- package/dist/policy/index.d.ts +5 -3
- package/dist/policy/index.js +5 -3
- package/dist/policy/types.d.ts +105 -101
- package/dist/policy/types.js +67 -66
- package/dist/query/client.d.ts +32 -16
- package/dist/query/client.js +103 -72
- package/dist/query/types.d.ts +37 -60
- package/dist/query/types.js +13 -33
- package/dist/react/AbloProvider.d.ts +7 -11
- package/dist/react/AbloProvider.js +24 -17
- package/dist/react/context.d.ts +27 -146
- package/dist/react/context.js +9 -10
- package/dist/react/index.d.ts +41 -42
- package/dist/react/index.js +37 -38
- package/dist/react/internalContext.d.ts +17 -19
- package/dist/react/useAblo.d.ts +23 -22
- package/dist/react/useAblo.js +17 -15
- package/dist/react/useCurrentUserId.d.ts +8 -7
- package/dist/react/useCurrentUserId.js +8 -7
- package/dist/react/useErrorListener.d.ts +7 -7
- package/dist/react/useErrorListener.js +11 -12
- package/dist/react/useMutationFailureListener.d.ts +8 -8
- package/dist/react/useMutationFailureListener.js +9 -9
- package/dist/react/useMutators.d.ts +11 -11
- package/dist/react/useMutators.js +10 -4
- package/dist/react/useReactive.js +2 -3
- package/dist/react/useSyncStatus.d.ts +4 -6
- package/dist/react/useUndoScope.d.ts +7 -9
- package/dist/react/useUndoScope.js +3 -3
- package/dist/schema/coordination.d.ts +21 -25
- package/dist/schema/coordination.js +21 -25
- package/dist/schema/ddl.d.ts +43 -39
- package/dist/schema/ddl.js +75 -68
- package/dist/schema/ddlLock.d.ts +35 -0
- package/dist/schema/ddlLock.js +46 -0
- package/dist/schema/diff.d.ts +99 -61
- package/dist/schema/diff.js +43 -34
- package/dist/schema/field.d.ts +37 -42
- package/dist/schema/field.js +36 -49
- package/dist/schema/generate.d.ts +12 -12
- package/dist/schema/generate.js +12 -12
- package/dist/schema/index.d.ts +5 -4
- package/dist/schema/index.js +29 -21
- package/dist/schema/model.d.ts +121 -146
- package/dist/schema/model.js +24 -35
- package/dist/schema/openapi.d.ts +10 -9
- package/dist/schema/openapi.js +7 -1
- package/dist/schema/queries.d.ts +30 -32
- package/dist/schema/queries.js +24 -25
- package/dist/schema/relation.d.ts +89 -99
- package/dist/schema/relation.js +13 -13
- package/dist/schema/residency.d.ts +38 -0
- package/dist/schema/residency.js +30 -0
- package/dist/schema/roles.d.ts +45 -27
- package/dist/schema/roles.js +52 -21
- package/dist/schema/schema.d.ts +36 -45
- package/dist/schema/schema.js +42 -39
- package/dist/schema/select.d.ts +13 -13
- package/dist/schema/select.js +13 -13
- package/dist/schema/serialize.d.ts +36 -39
- package/dist/schema/serialize.js +27 -31
- package/dist/schema/sugar.d.ts +17 -32
- package/dist/schema/sugar.js +14 -29
- package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
- package/dist/schema/syncDeltaRow.js +89 -0
- package/dist/schema/tenancy.d.ts +44 -46
- package/dist/schema/tenancy.js +46 -48
- package/dist/server/adapter.d.ts +58 -58
- package/dist/server/adapter.js +13 -14
- package/dist/server/commit.d.ts +60 -64
- package/dist/server/index.d.ts +9 -10
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +70 -0
- package/dist/server/readConfig.js +8 -0
- package/dist/server/storageMode.d.ts +23 -0
- package/dist/server/storageMode.js +17 -0
- package/dist/source/adapter.d.ts +31 -26
- package/dist/source/adapter.js +10 -10
- package/dist/source/adapters/drizzle.d.ts +28 -23
- package/dist/source/adapters/drizzle.js +34 -28
- package/dist/source/adapters/kysely.d.ts +27 -25
- package/dist/source/adapters/kysely.js +28 -26
- package/dist/source/adapters/memory.d.ts +8 -7
- package/dist/source/adapters/memory.js +10 -9
- package/dist/source/adapters/prisma.d.ts +13 -12
- package/dist/source/adapters/prisma.js +27 -29
- package/dist/source/conformance.d.ts +18 -11
- package/dist/source/conformance.js +27 -19
- package/dist/source/connector.d.ts +31 -32
- package/dist/source/connector.js +30 -28
- package/dist/source/connectorProtocol.d.ts +160 -0
- package/dist/source/connectorProtocol.js +162 -0
- package/dist/source/contract.d.ts +26 -27
- package/dist/source/contract.js +28 -29
- package/dist/source/factory.d.ts +94 -0
- package/dist/source/factory.js +268 -0
- package/dist/source/index.d.ts +10 -462
- package/dist/source/index.js +17 -421
- package/dist/source/migrations.d.ts +9 -9
- package/dist/source/migrations.js +9 -9
- package/dist/source/next.d.ts +10 -11
- package/dist/source/next.js +7 -8
- package/dist/source/pushQueue.d.ts +70 -48
- package/dist/source/pushQueue.js +36 -29
- package/dist/source/signing.d.ts +88 -0
- package/dist/source/signing.js +159 -0
- package/dist/source/types.d.ts +351 -0
- package/dist/source/types.js +43 -0
- package/dist/stores/ObjectStore.d.ts +11 -12
- package/dist/stores/ObjectStore.js +34 -35
- package/dist/stores/ObjectStoreContract.d.ts +12 -15
- package/dist/stores/SyncActionStore.d.ts +8 -12
- package/dist/stores/SyncActionStore.js +77 -46
- package/dist/surface.d.ts +28 -21
- package/dist/surface.js +28 -20
- package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
- package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
- package/dist/sync/ConnectionManager.d.ts +47 -50
- package/dist/sync/ConnectionManager.js +74 -70
- package/dist/sync/NetworkProbe.d.ts +27 -31
- package/dist/sync/NetworkProbe.js +67 -72
- package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
- package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
- package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
- package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
- package/dist/sync/SyncWebSocket.d.ts +175 -250
- package/dist/sync/SyncWebSocket.js +431 -769
- package/dist/sync/awaitClaimGrant.d.ts +18 -18
- package/dist/sync/awaitClaimGrant.js +38 -30
- package/dist/sync/bootstrapApply.d.ts +70 -0
- package/dist/sync/bootstrapApply.js +73 -0
- package/dist/sync/commitFrames.d.ts +44 -0
- package/dist/sync/commitFrames.js +94 -0
- package/dist/sync/createClaimStream.d.ts +23 -22
- package/dist/sync/createClaimStream.js +108 -25
- package/dist/sync/createPresenceStream.d.ts +19 -18
- package/dist/sync/createPresenceStream.js +25 -26
- package/dist/sync/createSnapshot.d.ts +13 -17
- package/dist/sync/createSnapshot.js +20 -26
- package/dist/sync/credentialLifecycle.d.ts +175 -0
- package/dist/sync/credentialLifecycle.js +322 -0
- package/dist/sync/deltaPipeline.d.ts +113 -0
- package/dist/sync/deltaPipeline.js +261 -0
- package/dist/sync/groupChange.d.ts +113 -0
- package/dist/sync/groupChange.js +242 -0
- package/dist/sync/heartbeat.d.ts +63 -0
- package/dist/sync/heartbeat.js +91 -0
- package/dist/sync/participants.d.ts +27 -27
- package/dist/sync/schemas.d.ts +3 -2
- package/dist/sync/schemas.js +14 -10
- package/dist/sync/syncCursor.d.ts +40 -0
- package/dist/sync/syncCursor.js +55 -0
- package/dist/sync/syncPlan.d.ts +54 -0
- package/dist/sync/syncPlan.js +50 -0
- package/dist/sync/syncPosition.d.ts +54 -49
- package/dist/sync/syncPosition.js +57 -52
- package/dist/sync/wsFrameHandlers.d.ts +116 -0
- package/dist/sync/wsFrameHandlers.js +374 -0
- package/dist/testing/fixtures/bootstrap.d.ts +21 -17
- package/dist/testing/fixtures/bootstrap.js +12 -6
- package/dist/testing/fixtures/deltas.d.ts +31 -34
- package/dist/testing/fixtures/deltas.js +30 -33
- package/dist/testing/fixtures/models.d.ts +11 -10
- package/dist/testing/fixtures/models.js +12 -10
- package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
- package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
- package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
- package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
- package/dist/testing/helpers/wait.d.ts +13 -8
- package/dist/testing/helpers/wait.js +13 -8
- package/dist/testing/index.d.ts +4 -4
- package/dist/testing/index.js +3 -3
- package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
- package/dist/testing/mocks/MockMutationExecutor.js +15 -14
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
- package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
- package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
- package/dist/testing/mocks/MockSyncContext.js +16 -45
- package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
- package/dist/testing/mocks/MockSyncStore.js +11 -11
- package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
- package/dist/testing/mocks/MockWebSocket.js +22 -21
- package/dist/transactions/TransactionQueue.d.ts +190 -221
- package/dist/transactions/TransactionQueue.js +424 -822
- package/dist/transactions/TransactionStore.d.ts +20 -0
- package/dist/transactions/TransactionStore.js +53 -0
- package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
- package/dist/transactions/UnconfirmedWrites.js +104 -0
- package/dist/transactions/coalesceRules.d.ts +58 -0
- package/dist/transactions/coalesceRules.js +140 -0
- package/dist/transactions/commitPayload.d.ts +130 -0
- package/dist/transactions/commitPayload.js +143 -0
- package/dist/transactions/deltaConfirmation.d.ts +58 -0
- package/dist/transactions/deltaConfirmation.js +215 -0
- package/dist/transactions/optimisticApply.d.ts +49 -0
- package/dist/transactions/optimisticApply.js +65 -0
- package/dist/transactions/replayValidation.d.ts +99 -0
- package/dist/transactions/replayValidation.js +111 -0
- package/dist/types/global.d.ts +46 -41
- package/dist/types/global.js +20 -19
- package/dist/types/index.d.ts +74 -80
- package/dist/types/index.js +22 -27
- package/dist/types/modelData.d.ts +10 -0
- package/dist/types/modelData.js +9 -0
- package/dist/types/participant.d.ts +20 -0
- package/dist/types/participant.js +10 -0
- package/dist/types/streams.d.ts +216 -209
- package/dist/types/streams.js +7 -7
- package/dist/utils/asyncIterator.d.ts +25 -32
- package/dist/utils/asyncIterator.js +25 -32
- package/dist/utils/duration.d.ts +12 -15
- package/dist/utils/duration.js +12 -15
- package/dist/utils/mobxSetup.d.ts +53 -0
- package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
- package/dist/webhooks/events.d.ts +21 -16
- package/dist/webhooks/events.js +10 -8
- package/dist/webhooks/index.d.ts +5 -7
- package/dist/webhooks/index.js +5 -7
- package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
- package/dist/wire/delta.js +114 -0
- package/dist/wire/errorEnvelope.d.ts +35 -27
- package/dist/wire/errorEnvelope.js +38 -32
- package/dist/wire/frames.d.ts +150 -67
- package/dist/wire/frames.js +48 -1
- package/dist/wire/index.d.ts +18 -13
- package/dist/wire/index.js +36 -13
- package/dist/wire/listEnvelope.d.ts +16 -23
- package/dist/wire/listEnvelope.js +7 -6
- package/dist/wire/protocol.d.ts +38 -0
- package/dist/wire/protocol.js +38 -0
- package/dist/wire/protocolVersion.d.ts +60 -0
- package/dist/wire/protocolVersion.js +67 -0
- package/docs/api-keys.md +4 -3
- package/docs/coordination.md +59 -0
- package/docs/examples/existing-python-backend.md +3 -3
- package/docs/identity.md +4 -4
- package/docs/integration-guide.md +1 -1
- package/docs/react.md +1 -1
- package/docs/sessions.md +5 -7
- package/package.json +24 -21
- package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
- package/dist/ai-sdk/coordination-context.d.ts +0 -52
- package/dist/client/index.d.ts +0 -36
- package/dist/client/index.js +0 -33
- package/dist/config/index.d.ts +0 -10
- package/dist/config/index.js +0 -12
- package/dist/core/query-utils.d.ts +0 -34
- package/dist/core/query-utils.js +0 -59
- package/dist/interfaces/headless.d.ts +0 -95
- package/dist/interfaces/headless.js +0 -41
- package/dist/query/index.d.ts +0 -6
- package/dist/query/index.js +0 -5
- package/dist/realtime/index.d.ts +0 -10
- package/dist/realtime/index.js +0 -9
- package/dist/schema/plane.d.ts +0 -23
- package/dist/schema/plane.js +0 -19
- package/dist/schema/sync-delta-row.js +0 -103
- package/dist/schema/sync-delta-wire.js +0 -102
- package/dist/server/next.d.ts +0 -51
- package/dist/server/next.js +0 -47
- package/dist/server/read-config.d.ts +0 -67
- package/dist/server/read-config.js +0 -8
- package/dist/server/storage-mode.d.ts +0 -1
- package/dist/server/storage-mode.js +0 -18
- package/dist/source/connector-protocol.d.ts +0 -159
- package/dist/source/connector-protocol.js +0 -161
- package/dist/sync/OfflineFlush.d.ts +0 -9
- package/dist/sync/OfflineFlush.js +0 -22
- package/dist/sync/OfflineTransactionStore.d.ts +0 -37
- package/dist/sync/OfflineTransactionStore.js +0 -263
- package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
- package/dist/transactions/OptimisticEchoTracker.js +0 -104
- package/dist/transactions/index.d.ts +0 -16
- package/dist/transactions/index.js +0 -7
- package/dist/transactions/mutation-error-handler.d.ts +0 -5
- package/dist/transactions/mutation-error-handler.js +0 -39
- package/dist/utils/mobx-setup.d.ts +0 -42
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Follows Ablo's architecture for database management.
|
|
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.
|
|
9
7
|
*/
|
|
10
8
|
import { getContext } from '../context.js';
|
|
11
9
|
import { openIDBWithTimeout, deleteIDBWithTimeout, IDBOpenTimeoutError, } from './openIDBWithTimeout.js';
|
|
@@ -90,7 +88,7 @@ export class DatabaseManager {
|
|
|
90
88
|
else if (existingInfo) {
|
|
91
89
|
schemaVersion = existingInfo.schemaVersion || 1;
|
|
92
90
|
}
|
|
93
|
-
//
|
|
91
|
+
// Record the existing databases for this user so duplicates can be detected.
|
|
94
92
|
const allUserDatabases = await this.getDatabasesForUser(userId);
|
|
95
93
|
const allIndexedDBs = (await indexedDB.databases?.()) || [];
|
|
96
94
|
const abloDatabases = allIndexedDBs.filter((db) => db.name?.startsWith('ablo_'));
|
|
@@ -107,7 +105,7 @@ export class DatabaseManager {
|
|
|
107
105
|
schemaHash,
|
|
108
106
|
schemaVersion,
|
|
109
107
|
userVersion,
|
|
110
|
-
createdAt: existingInfo?.createdAt
|
|
108
|
+
createdAt: existingInfo?.createdAt ?? new Date(),
|
|
111
109
|
updatedAt: new Date(),
|
|
112
110
|
};
|
|
113
111
|
}
|
|
@@ -117,7 +115,7 @@ export class DatabaseManager {
|
|
|
117
115
|
generateDatabaseName(userId, workspaceId, userVersion = 1) {
|
|
118
116
|
// Combine userId, workspaceId, and userVersion for unique database
|
|
119
117
|
const combined = `${userId}:${workspaceId}:${userVersion}`;
|
|
120
|
-
//
|
|
118
|
+
// Hash the combined key into a compact, deterministic identifier.
|
|
121
119
|
let hash = 0;
|
|
122
120
|
for (let i = 0; i < combined.length; i++) {
|
|
123
121
|
hash = (hash << 5) - hash + combined.charCodeAt(i);
|
|
@@ -143,8 +141,8 @@ export class DatabaseManager {
|
|
|
143
141
|
tx.oncomplete = () => {
|
|
144
142
|
resolve();
|
|
145
143
|
};
|
|
146
|
-
tx.onerror = () => reject(tx.error);
|
|
147
|
-
request.onerror = () => reject(request.error);
|
|
144
|
+
tx.onerror = () => { reject(tx.error); };
|
|
145
|
+
request.onerror = () => { reject(request.error); };
|
|
148
146
|
});
|
|
149
147
|
}
|
|
150
148
|
/**
|
|
@@ -157,8 +155,8 @@ export class DatabaseManager {
|
|
|
157
155
|
const tx = this.metaDb.transaction(['databases'], 'readonly');
|
|
158
156
|
const store = tx.objectStore('databases');
|
|
159
157
|
const request = store.get(name);
|
|
160
|
-
request.onsuccess = () => resolve(request.result
|
|
161
|
-
request.onerror = () => reject(request.error);
|
|
158
|
+
request.onsuccess = () => { resolve(request.result ?? null); };
|
|
159
|
+
request.onerror = () => { reject(request.error); };
|
|
162
160
|
});
|
|
163
161
|
}
|
|
164
162
|
/**
|
|
@@ -172,8 +170,8 @@ export class DatabaseManager {
|
|
|
172
170
|
const store = tx.objectStore('databases');
|
|
173
171
|
const index = store.index('userId');
|
|
174
172
|
const request = index.getAll(userId);
|
|
175
|
-
request.onsuccess = () => resolve(request.result || []);
|
|
176
|
-
request.onerror = () => reject(request.error);
|
|
173
|
+
request.onsuccess = () => { resolve(request.result || []); };
|
|
174
|
+
request.onerror = () => { reject(request.error); };
|
|
177
175
|
});
|
|
178
176
|
}
|
|
179
177
|
/**
|
|
@@ -185,13 +183,12 @@ export class DatabaseManager {
|
|
|
185
183
|
onUpgrade: (request, event) => {
|
|
186
184
|
const db = request.result;
|
|
187
185
|
const tx = event.target.transaction;
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
// without awaiting is safe and matches the VCS-slot semantics.
|
|
186
|
+
// IndexedDB rule: only awaits on IndexedDB requests keep an upgrade
|
|
187
|
+
// transaction alive. Any other await — a fetch, a timer — commits the
|
|
188
|
+
// transaction early, and later operations then throw
|
|
189
|
+
// `TransactionInactiveError`. StoreManager.createStores runs only
|
|
190
|
+
// synchronous createObjectStore / createIndex calls under an `async`
|
|
191
|
+
// keyword, so calling it without awaiting is safe here.
|
|
195
192
|
if (createStoresFn && tx) {
|
|
196
193
|
try {
|
|
197
194
|
void createStoresFn(db, tx).catch((err) => {
|
|
@@ -231,18 +228,19 @@ export class DatabaseManager {
|
|
|
231
228
|
return;
|
|
232
229
|
}
|
|
233
230
|
const meta = {
|
|
234
|
-
lastSyncId: data.lastSyncId
|
|
235
|
-
firstSyncId: data.firstSyncId
|
|
236
|
-
backendDatabaseVersion: data.backendDatabaseVersion
|
|
237
|
-
subscribedSyncGroups: data.subscribedSyncGroups
|
|
231
|
+
lastSyncId: data.lastSyncId ?? 0,
|
|
232
|
+
firstSyncId: data.firstSyncId ?? 0,
|
|
233
|
+
backendDatabaseVersion: data.backendDatabaseVersion ?? 1,
|
|
234
|
+
subscribedSyncGroups: data.subscribedSyncGroups ?? [],
|
|
238
235
|
updatedAt: data.updatedAt ? new Date(data.updatedAt) : new Date(),
|
|
239
236
|
schemaHash: data.schemaHash,
|
|
240
237
|
syncGroups: data.syncGroups,
|
|
241
|
-
|
|
238
|
+
// Older persisted records may still carry an extra `versions` key
|
|
239
|
+
// that is no longer used; it is tolerated by simply not reading it here.
|
|
242
240
|
};
|
|
243
241
|
resolve(meta);
|
|
244
242
|
};
|
|
245
|
-
request.onerror = () => reject(request.error);
|
|
243
|
+
request.onerror = () => { reject(request.error); };
|
|
246
244
|
});
|
|
247
245
|
}
|
|
248
246
|
/**
|
|
@@ -253,9 +251,9 @@ export class DatabaseManager {
|
|
|
253
251
|
const tx = db.transaction(['__meta'], 'readwrite');
|
|
254
252
|
const store = tx.objectStore('__meta');
|
|
255
253
|
const request = store.put(metadata, 'metadata');
|
|
256
|
-
tx.oncomplete = () => resolve();
|
|
257
|
-
tx.onerror = () => reject(tx.error);
|
|
258
|
-
request.onerror = () => reject(request.error);
|
|
254
|
+
tx.oncomplete = () => { resolve(); };
|
|
255
|
+
tx.onerror = () => { reject(tx.error); };
|
|
256
|
+
request.onerror = () => { reject(request.error); };
|
|
259
257
|
});
|
|
260
258
|
}
|
|
261
259
|
/**
|
|
@@ -270,7 +268,7 @@ export class DatabaseManager {
|
|
|
270
268
|
const data = request.result;
|
|
271
269
|
resolve(data?.persisted === true);
|
|
272
270
|
};
|
|
273
|
-
request.onerror = () => reject(request.error);
|
|
271
|
+
request.onerror = () => { reject(request.error); };
|
|
274
272
|
});
|
|
275
273
|
}
|
|
276
274
|
/**
|
|
@@ -287,9 +285,9 @@ export class DatabaseManager {
|
|
|
287
285
|
updatedAt: new Date().toISOString(),
|
|
288
286
|
};
|
|
289
287
|
const request = store.put(persistenceData, modelName);
|
|
290
|
-
tx.oncomplete = () => resolve();
|
|
291
|
-
tx.onerror = () => reject(tx.error);
|
|
292
|
-
request.onerror = () => reject(request.error);
|
|
288
|
+
tx.oncomplete = () => { resolve(); };
|
|
289
|
+
tx.onerror = () => { reject(tx.error); };
|
|
290
|
+
request.onerror = () => { reject(request.error); };
|
|
293
291
|
});
|
|
294
292
|
}
|
|
295
293
|
/**
|
|
@@ -312,7 +310,7 @@ export class DatabaseManager {
|
|
|
312
310
|
}
|
|
313
311
|
resolve(states);
|
|
314
312
|
};
|
|
315
|
-
request.onerror = () => reject(request.error);
|
|
313
|
+
request.onerror = () => { reject(request.error); };
|
|
316
314
|
});
|
|
317
315
|
}
|
|
318
316
|
/**
|
|
@@ -362,10 +360,10 @@ export class DatabaseManager {
|
|
|
362
360
|
const schemaVersions = {};
|
|
363
361
|
for (const db of databases) {
|
|
364
362
|
// Count by user
|
|
365
|
-
databasesByUser[db.userId] = (databasesByUser[db.userId]
|
|
363
|
+
databasesByUser[db.userId] = (databasesByUser[db.userId] ?? 0) + 1;
|
|
366
364
|
// Count schema versions
|
|
367
365
|
const versionKey = `v${db.schemaVersion}`;
|
|
368
|
-
schemaVersions[versionKey] = (schemaVersions[versionKey]
|
|
366
|
+
schemaVersions[versionKey] = (schemaVersions[versionKey] ?? 0) + 1;
|
|
369
367
|
}
|
|
370
368
|
resolve({
|
|
371
369
|
metaDatabaseSize: databases.length,
|
|
@@ -374,7 +372,7 @@ export class DatabaseManager {
|
|
|
374
372
|
schemaVersions,
|
|
375
373
|
});
|
|
376
374
|
};
|
|
377
|
-
request.onerror = () => reject(request.error);
|
|
375
|
+
request.onerror = () => { reject(request.error); };
|
|
378
376
|
});
|
|
379
377
|
}
|
|
380
378
|
/**
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* This extracts query processing logic from SyncedStore for proper separation of concerns
|
|
2
|
+
* Runs in-memory queries over a set of models — filtering by predicate,
|
|
3
|
+
* sorting, paginating, and caching the results. A caller hands
|
|
4
|
+
* {@link QueryProcessor} the candidate models and the query options, and it
|
|
5
|
+
* returns a {@link QueryResult}. It keeps two caches: a string-keyed cache for
|
|
6
|
+
* plain queries, and a structural-identity cache for predicate queries, whose
|
|
7
|
+
* closures cannot be turned into a stable string key.
|
|
10
8
|
*/
|
|
11
9
|
import type { Model } from '../Model.js';
|
|
12
|
-
import type { ModelScope } from '../
|
|
10
|
+
import type { ModelScope } from '../InstanceCache.js';
|
|
13
11
|
export interface QueryOptions<T extends Model> {
|
|
14
12
|
predicate?: (model: T) => boolean;
|
|
15
13
|
/** Stable key to distinguish different predicates for the same model type.
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* This extracts query processing logic from SyncedStore for proper separation of concerns
|
|
2
|
+
* Runs in-memory queries over a set of models — filtering by predicate,
|
|
3
|
+
* sorting, paginating, and caching the results. A caller hands
|
|
4
|
+
* {@link QueryProcessor} the candidate models and the query options, and it
|
|
5
|
+
* returns a {@link QueryResult}. It keeps two caches: a string-keyed cache for
|
|
6
|
+
* plain queries, and a structural-identity cache for predicate queries, whose
|
|
7
|
+
* closures cannot be turned into a stable string key.
|
|
10
8
|
*/
|
|
11
9
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - No regex compilation or full cache iteration needed
|
|
10
|
+
* The default in-memory cache. It keeps a reverse index from model type to the
|
|
11
|
+
* cache keys for that type, so invalidating one model type costs work
|
|
12
|
+
* proportional to that type's keys rather than a scan of the whole cache. A
|
|
13
|
+
* regex fallback still covers the rare pattern that is not a plain model-type
|
|
14
|
+
* match.
|
|
18
15
|
*/
|
|
19
16
|
class BasicQueryCache {
|
|
20
17
|
cache = new Map();
|
|
@@ -48,9 +45,8 @@ class BasicQueryCache {
|
|
|
48
45
|
return;
|
|
49
46
|
}
|
|
50
47
|
// Fast path: Check if pattern is a simple model type match like ".*ModelType.*"
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
53
|
-
const modelType = simpleMatch[1];
|
|
48
|
+
const modelType = /^\.\*(\w+)\.\*$/.exec(pattern)?.[1];
|
|
49
|
+
if (modelType !== undefined) {
|
|
54
50
|
const keysToDelete = this.modelTypeIndex.get(modelType);
|
|
55
51
|
if (keysToDelete) {
|
|
56
52
|
for (const key of keysToDelete) {
|
|
@@ -88,20 +84,19 @@ class BasicQueryCache {
|
|
|
88
84
|
* Cache key format: "operation:ModelType:options"
|
|
89
85
|
*/
|
|
90
86
|
extractModelType(key) {
|
|
91
|
-
|
|
92
|
-
return
|
|
87
|
+
// A missing second segment reads as undefined, so `?? null` yields null.
|
|
88
|
+
return key.split(':')[1] ?? null;
|
|
93
89
|
}
|
|
94
90
|
}
|
|
95
91
|
export class QueryProcessor {
|
|
96
92
|
cache;
|
|
97
93
|
enableCache;
|
|
98
|
-
// Stable-reference cache for predicate queries.
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
// when the
|
|
103
|
-
//
|
|
104
|
-
// Value: previous result + its ID fingerprint
|
|
94
|
+
// Stable-reference cache for predicate queries. A string cache key cannot
|
|
95
|
+
// capture a closure, so predicate queries use a separate identity-based
|
|
96
|
+
// cache keyed on the deterministic part of the query (model name plus
|
|
97
|
+
// serializable options). Each entry stores the previous result and a
|
|
98
|
+
// fingerprint of its model ids; when the ids are unchanged, the processor
|
|
99
|
+
// returns the previous array reference so observers do not re-render.
|
|
105
100
|
predicateResultCache = new Map();
|
|
106
101
|
constructor(config = {}) {
|
|
107
102
|
this.enableCache = config.enableCache ?? true;
|
|
@@ -137,10 +132,9 @@ export class QueryProcessor {
|
|
|
137
132
|
hasMore: offset + limit < total,
|
|
138
133
|
fromCache: false,
|
|
139
134
|
};
|
|
140
|
-
// For predicate queries:
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
// observers won't re-render when the result is structurally identical.
|
|
135
|
+
// For predicate queries: compare by structural identity. Return the
|
|
136
|
+
// previous array reference when the model ids are unchanged, so observers
|
|
137
|
+
// don't re-render on a structurally identical result.
|
|
144
138
|
if (options.predicate && this.enableCache) {
|
|
145
139
|
const ids = data.map((m) => m.id).join(',');
|
|
146
140
|
const cached = this.predicateResultCache.get(cacheKey);
|
|
@@ -151,7 +145,7 @@ export class QueryProcessor {
|
|
|
151
145
|
// New result — store for future comparison
|
|
152
146
|
this.predicateResultCache.set(cacheKey, { ids, result });
|
|
153
147
|
}
|
|
154
|
-
// For non-predicate queries: use string-based cache
|
|
148
|
+
// For non-predicate queries: use the string-based cache.
|
|
155
149
|
if (!options.predicate && this.enableCache) {
|
|
156
150
|
this.cache.set(cacheKey, result);
|
|
157
151
|
}
|
|
@@ -229,9 +223,8 @@ export class QueryProcessor {
|
|
|
229
223
|
this.cache.invalidate(pattern);
|
|
230
224
|
// Also invalidate predicate result cache for this model type
|
|
231
225
|
if (pattern) {
|
|
232
|
-
const
|
|
233
|
-
if (
|
|
234
|
-
const modelType = simpleMatch[1];
|
|
226
|
+
const modelType = /^\.\*(\w+)\.\*$/.exec(pattern)?.[1];
|
|
227
|
+
if (modelType !== undefined) {
|
|
235
228
|
for (const key of this.predicateResultCache.keys()) {
|
|
236
229
|
if (key.includes(modelType)) {
|
|
237
230
|
this.predicateResultCache.delete(key);
|
package/dist/core/QueryView.d.ts
CHANGED
|
@@ -9,10 +9,22 @@
|
|
|
9
9
|
* directly and receive granular updates (splice/push, never replacement).
|
|
10
10
|
*/
|
|
11
11
|
import { type IObservableArray } from 'mobx';
|
|
12
|
+
import { type Model } from '../Model.js';
|
|
12
13
|
import { ModelScope } from '../types/index.js';
|
|
13
|
-
import type { ObjectPool } from '../ObjectPool.js';
|
|
14
14
|
import type { ViewRegistry } from './ViewRegistry.js';
|
|
15
|
-
import type { IncrementalView } from './
|
|
15
|
+
import type { IncrementalView } from './queryUtils.js';
|
|
16
|
+
/**
|
|
17
|
+
* The slice of the object pool that a {@link QueryView} reads. It is a minimal
|
|
18
|
+
* structural interface rather than the concrete pool class, which lets a query
|
|
19
|
+
* view avoid importing the pool and so breaks what would otherwise be an import
|
|
20
|
+
* cycle — the pool imports {@link QueryView} to construct one. The concrete
|
|
21
|
+
* pool satisfies this interface structurally.
|
|
22
|
+
*/
|
|
23
|
+
export interface QueryViewPool {
|
|
24
|
+
hasForeignKeyIndex(typename: string, fieldName: string): boolean;
|
|
25
|
+
getByForeignKey(modelName: string, fieldName: string, fieldValue: string): Model[];
|
|
26
|
+
getByTypeName(modelName: string, scope?: ModelScope): Model[];
|
|
27
|
+
}
|
|
16
28
|
export interface QueryViewOptions<T> {
|
|
17
29
|
where?: Partial<T>;
|
|
18
30
|
filter?: (entity: T) => boolean;
|
|
@@ -20,8 +32,8 @@ export interface QueryViewOptions<T> {
|
|
|
20
32
|
order?: 'asc' | 'desc';
|
|
21
33
|
limit?: number;
|
|
22
34
|
offset?: number;
|
|
23
|
-
/** Lifecycle filter — `live` (default), `archived`, or `all`.
|
|
24
|
-
*
|
|
35
|
+
/** Lifecycle filter — `live` (the default), `archived`, or `all`. It is
|
|
36
|
+
* named `state` rather than `scope` so it does not collide with the
|
|
25
37
|
* sync-group `scope`. */
|
|
26
38
|
state?: ModelScope;
|
|
27
39
|
}
|
|
@@ -47,7 +59,7 @@ export declare class QueryView<T extends Record<string, unknown>> implements Inc
|
|
|
47
59
|
private readonly fkField;
|
|
48
60
|
private readonly fkValue;
|
|
49
61
|
private disposed;
|
|
50
|
-
constructor(typename: string, pool:
|
|
62
|
+
constructor(typename: string, pool: QueryViewPool, registry: ViewRegistry, options?: QueryViewOptions<T>);
|
|
51
63
|
private initialScan;
|
|
52
64
|
handleAdded(model: Record<string, unknown>): void;
|
|
53
65
|
handleUpdated(model: Record<string, unknown>): void;
|
package/dist/core/QueryView.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { observable, runInAction } from 'mobx';
|
|
12
12
|
import { modelAsRow } from '../Model.js';
|
|
13
13
|
import { ModelScope } from '../types/index.js';
|
|
14
|
-
import { compareValues, binaryInsertionIndex, findIndexById, } from './
|
|
14
|
+
import { compareValues, binaryInsertionIndex, findIndexById, } from './queryUtils.js';
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
16
16
|
// QueryView
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
@@ -54,10 +54,9 @@ export class QueryView {
|
|
|
54
54
|
// Check for FK-index optimization: single-field where with an indexed FK
|
|
55
55
|
this.fkField = null;
|
|
56
56
|
this.fkValue = null;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const [field, value] = this.whereEntries[0];
|
|
57
|
+
const soleWhereEntry = this.whereEntries && this.whereEntries.length === 1 ? this.whereEntries[0] : undefined;
|
|
58
|
+
if (soleWhereEntry && typeof soleWhereEntry[1] === 'string') {
|
|
59
|
+
const [field, value] = soleWhereEntry;
|
|
61
60
|
if (pool.hasForeignKeyIndex(typename, field)) {
|
|
62
61
|
this.fkField = field;
|
|
63
62
|
this.fkValue = value;
|
|
@@ -120,7 +119,7 @@ export class QueryView {
|
|
|
120
119
|
if (this.disposed)
|
|
121
120
|
return;
|
|
122
121
|
const entity = model;
|
|
123
|
-
const id = entity
|
|
122
|
+
const id = entity.id;
|
|
124
123
|
const idx = id !== undefined ? this.findIndexById(id) : -1;
|
|
125
124
|
const matchesNow = this.matchesFilter(entity);
|
|
126
125
|
runInAction(() => {
|
|
@@ -169,7 +168,7 @@ export class QueryView {
|
|
|
169
168
|
// -----------------------------------------------------------------------
|
|
170
169
|
/** Check whether an entity passes both `where` and `filter`. */
|
|
171
170
|
matchesFilter(entity) {
|
|
172
|
-
// Note: scope is tracked per-entry in the
|
|
171
|
+
// Note: scope is tracked per-entry in the InstanceCache, not on the model.
|
|
173
172
|
// The initial scan handles scope via getByTypeName(typename, scope).
|
|
174
173
|
// Incremental notifications from the pool are scope-appropriate since
|
|
175
174
|
// add/upsert/remove reflect the pool's authoritative scope tracking.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Manages the {@link ObjectStore} instances the sync engine keeps in the
|
|
3
|
+
* browser — one per registered model — alongside the single
|
|
4
|
+
* {@link SyncActionStore} for pending changes. It creates each store from the
|
|
5
|
+
* model's metadata, tracks readiness, and provisions the underlying IndexedDB
|
|
6
|
+
* object stores. A model's load strategy (instant, lazy, or partial) decides
|
|
7
|
+
* how and when its data is loaded.
|
|
7
8
|
*/
|
|
8
9
|
import { ModelRegistry } from '../ModelRegistry.js';
|
|
9
10
|
import { ObjectStore } from '../stores/ObjectStore.js';
|
|
@@ -63,15 +64,12 @@ export declare class StoreManager {
|
|
|
63
64
|
totalStores: number;
|
|
64
65
|
}>;
|
|
65
66
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* the
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* Samples up to 3 stores to avoid a full scan. If any store has records,
|
|
74
|
-
* returns true (we have cached data worth preserving).
|
|
67
|
+
* Reports whether any data store holds at least one record. This is a
|
|
68
|
+
* cache-validity check: if the stores are empty, the sync cursor
|
|
69
|
+
* (`lastSyncId`) is meaningless no matter what the metadata says, because the
|
|
70
|
+
* cursor and the data must travel together — no data means no cursor, which
|
|
71
|
+
* forces a full bootstrap. To stay cheap it samples up to three stores rather
|
|
72
|
+
* than scanning them all, and returns true as soon as one has records.
|
|
75
73
|
*/
|
|
76
74
|
hasAnyData(): Promise<boolean>;
|
|
77
75
|
/**
|
|
@@ -120,12 +118,12 @@ export declare class StoreManager {
|
|
|
120
118
|
notReady: number;
|
|
121
119
|
};
|
|
122
120
|
totalRecords: number;
|
|
123
|
-
storeDetails:
|
|
121
|
+
storeDetails: {
|
|
124
122
|
modelName: string;
|
|
125
123
|
storeName: string;
|
|
126
124
|
strategy: LoadStrategy;
|
|
127
125
|
ready: boolean;
|
|
128
126
|
count: number;
|
|
129
|
-
}
|
|
127
|
+
}[];
|
|
130
128
|
}>;
|
|
131
129
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Manages the {@link ObjectStore} instances the sync engine keeps in the
|
|
3
|
+
* browser — one per registered model — alongside the single
|
|
4
|
+
* {@link SyncActionStore} for pending changes. It creates each store from the
|
|
5
|
+
* model's metadata, tracks readiness, and provisions the underlying IndexedDB
|
|
6
|
+
* object stores. A model's load strategy (instant, lazy, or partial) decides
|
|
7
|
+
* how and when its data is loaded.
|
|
7
8
|
*/
|
|
9
|
+
import { ModelRegistry } from '../ModelRegistry.js';
|
|
8
10
|
import { ObjectStore } from '../stores/ObjectStore.js';
|
|
9
11
|
import { SyncActionStore } from '../stores/SyncActionStore.js';
|
|
10
12
|
import { LoadStrategy } from '../types/index.js';
|
|
@@ -69,7 +71,7 @@ export class StoreManager {
|
|
|
69
71
|
}
|
|
70
72
|
// Use model name directly as store name
|
|
71
73
|
const storeName = modelName;
|
|
72
|
-
// Create ObjectStore
|
|
74
|
+
// Create the ObjectStore. One store type currently serves every load strategy.
|
|
73
75
|
const store = new ObjectStore(this.db, modelName, storeName, metadata);
|
|
74
76
|
this.stores.set(modelName, store);
|
|
75
77
|
}
|
|
@@ -121,7 +123,7 @@ export class StoreManager {
|
|
|
121
123
|
}
|
|
122
124
|
// Create __meta table for model persistence state and database metadata
|
|
123
125
|
if (!db.objectStoreNames.contains('__meta')) {
|
|
124
|
-
|
|
126
|
+
db.createObjectStore('__meta');
|
|
125
127
|
getContext().logger.debug('Created __meta table');
|
|
126
128
|
}
|
|
127
129
|
// Create __transactions table for unsent transactions
|
|
@@ -183,22 +185,22 @@ export class StoreManager {
|
|
|
183
185
|
};
|
|
184
186
|
}
|
|
185
187
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* the
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* Samples up to 3 stores to avoid a full scan. If any store has records,
|
|
194
|
-
* returns true (we have cached data worth preserving).
|
|
188
|
+
* Reports whether any data store holds at least one record. This is a
|
|
189
|
+
* cache-validity check: if the stores are empty, the sync cursor
|
|
190
|
+
* (`lastSyncId`) is meaningless no matter what the metadata says, because the
|
|
191
|
+
* cursor and the data must travel together — no data means no cursor, which
|
|
192
|
+
* forces a full bootstrap. To stay cheap it samples up to three stores rather
|
|
193
|
+
* than scanning them all, and returns true as soon as one has records.
|
|
195
194
|
*/
|
|
196
195
|
async hasAnyData() {
|
|
197
196
|
const storeEntries = Array.from(this.stores);
|
|
198
197
|
// Sample a few stores — don't check all 30+ if the first one has data
|
|
199
198
|
const samplesToCheck = Math.min(storeEntries.length, 3);
|
|
200
199
|
for (let i = 0; i < samplesToCheck; i++) {
|
|
201
|
-
const
|
|
200
|
+
const entry = storeEntries[i];
|
|
201
|
+
if (!entry)
|
|
202
|
+
break;
|
|
203
|
+
const [, store] = entry;
|
|
202
204
|
try {
|
|
203
205
|
const count = await store.count();
|
|
204
206
|
if (count > 0)
|
|
@@ -277,8 +279,8 @@ export class StoreManager {
|
|
|
277
279
|
* Clear all stores
|
|
278
280
|
*/
|
|
279
281
|
async clearAllStores() {
|
|
280
|
-
// Lifecycle chatter (logout / identity switch / reset)
|
|
281
|
-
// `debug` so it
|
|
282
|
+
// Lifecycle chatter (logout / identity switch / reset), not a warning.
|
|
283
|
+
// Logged at `debug` so it stays silent under the default `warn` threshold.
|
|
282
284
|
getContext().logger.debug('Clearing all stores');
|
|
283
285
|
const promises = Array.from(this.stores.values()).map((store) => store.clear());
|
|
284
286
|
await Promise.all(promises);
|
|
@@ -293,12 +295,11 @@ export class StoreManager {
|
|
|
293
295
|
for (const store of this.stores.values()) {
|
|
294
296
|
store.markAsClosing();
|
|
295
297
|
}
|
|
296
|
-
// SyncActionStore is a standalone store
|
|
297
|
-
// and has no markAsClosing equivalent
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
// explicitly to SyncActionStore rather than reintroducing the cast.
|
|
298
|
+
// SyncActionStore is a standalone store that does not extend ObjectStore
|
|
299
|
+
// and has no markAsClosing equivalent, so it is intentionally skipped here.
|
|
300
|
+
// If closing-state coordination is ever needed for sync actions, add it
|
|
301
|
+
// explicitly to SyncActionStore rather than casting to reach a method that
|
|
302
|
+
// may not exist.
|
|
302
303
|
getContext().logger.debug('All stores marked as closing');
|
|
303
304
|
}
|
|
304
305
|
/**
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ViewRegistry — tracks active QueryViews per typename.
|
|
3
3
|
*
|
|
4
|
-
* When the
|
|
4
|
+
* When the InstanceCache mutates a model, it calls notifyAdded / notifyUpdated /
|
|
5
5
|
* notifyRemoved on the registry, which fans the event out to every active
|
|
6
6
|
* QueryView subscribed to that typename.
|
|
7
7
|
*/
|
|
8
8
|
import { type Model } from '../Model.js';
|
|
9
|
-
import type { IncrementalView } from './
|
|
9
|
+
import type { IncrementalView } from './queryUtils.js';
|
|
10
10
|
export declare class ViewRegistry {
|
|
11
11
|
private views;
|
|
12
12
|
register(typename: string, view: IncrementalView): void;
|
|
13
13
|
unregister(typename: string, view: IncrementalView): void;
|
|
14
|
-
/** Called by
|
|
14
|
+
/** Called by InstanceCache after a model is added to the pool. */
|
|
15
15
|
notifyAdded(typename: string, model: Model): void;
|
|
16
|
-
/** Called by
|
|
16
|
+
/** Called by InstanceCache after a model is updated in the pool. */
|
|
17
17
|
notifyUpdated(typename: string, model: Model): void;
|
|
18
|
-
/** Called by
|
|
18
|
+
/** Called by InstanceCache after a model is removed from the pool. */
|
|
19
19
|
notifyRemoved(typename: string, modelId: string): void;
|
|
20
20
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ViewRegistry — tracks active QueryViews per typename.
|
|
3
3
|
*
|
|
4
|
-
* When the
|
|
4
|
+
* When the InstanceCache mutates a model, it calls notifyAdded / notifyUpdated /
|
|
5
5
|
* notifyRemoved on the registry, which fans the event out to every active
|
|
6
6
|
* QueryView subscribed to that typename.
|
|
7
7
|
*/
|
|
@@ -25,7 +25,7 @@ export class ViewRegistry {
|
|
|
25
25
|
this.views.delete(typename);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
/** Called by
|
|
28
|
+
/** Called by InstanceCache after a model is added to the pool. */
|
|
29
29
|
notifyAdded(typename, model) {
|
|
30
30
|
const set = this.views.get(typename);
|
|
31
31
|
if (!set)
|
|
@@ -34,7 +34,7 @@ export class ViewRegistry {
|
|
|
34
34
|
view.handleAdded(modelAsRow(model));
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
/** Called by
|
|
37
|
+
/** Called by InstanceCache after a model is updated in the pool. */
|
|
38
38
|
notifyUpdated(typename, model) {
|
|
39
39
|
const set = this.views.get(typename);
|
|
40
40
|
if (!set)
|
|
@@ -43,7 +43,7 @@ export class ViewRegistry {
|
|
|
43
43
|
view.handleUpdated(modelAsRow(model));
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
/** Called by
|
|
46
|
+
/** Called by InstanceCache after a model is removed from the pool. */
|
|
47
47
|
notifyRemoved(typename, modelId) {
|
|
48
48
|
const set = this.views.get(typename);
|
|
49
49
|
if (!set)
|