@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
package/dist/Database.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* The local persistence layer for synced models. It stores rows in the
|
|
3
|
+
* browser's IndexedDB (or in-memory maps when run headlessly), applies inbound
|
|
4
|
+
* deltas to that store, and fetches the bootstrap snapshot from your sync
|
|
5
|
+
* server. {@link BaseSyncedStore} drives it, and {@link InstanceCache} holds the
|
|
6
|
+
* in-memory mirror of what this class persists.
|
|
4
7
|
*/
|
|
5
8
|
import { DatabaseManager } from './core/DatabaseManager.js';
|
|
6
9
|
import { StoreManager } from './core/StoreManager.js';
|
|
10
|
+
import { ModelRegistry } from './ModelRegistry.js';
|
|
7
11
|
import { LoadStrategy } from './types/index.js';
|
|
8
12
|
import { getContext } from './context.js';
|
|
9
13
|
import { AbloConnectionError, AbloValidationError } from './errors.js';
|
|
@@ -21,11 +25,11 @@ export class Database {
|
|
|
21
25
|
return this.bootstrapHelper;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
28
|
+
* Fetch the current rows of the given sync groups as a side-effect-free
|
|
29
|
+
* snapshot, used to hydrate a scope as the user enters it. Unlike
|
|
26
30
|
* {@link bootstrapFromServer}, it does not persist to IndexedDB and does not
|
|
27
|
-
*
|
|
28
|
-
*
|
|
31
|
+
* change the connection's subscribed sync groups. The caller applies the
|
|
32
|
+
* result to the pool through the scoped apply path.
|
|
29
33
|
*/
|
|
30
34
|
async fetchScopedBootstrapData(syncGroups) {
|
|
31
35
|
// No lastSyncId → a full snapshot of exactly these groups.
|
|
@@ -105,7 +109,7 @@ export class Database {
|
|
|
105
109
|
logPreservedFields(modelName, modelId, existing, delta) {
|
|
106
110
|
if (modelName === 'Activity')
|
|
107
111
|
return;
|
|
108
|
-
const requiredFields = this.essentialFields[modelName]
|
|
112
|
+
const requiredFields = this.essentialFields[modelName] ?? [];
|
|
109
113
|
const preserved = requiredFields.filter((field) => existing[field] !== undefined && delta[field] === undefined);
|
|
110
114
|
if (preserved.length > 0) {
|
|
111
115
|
getContext().logger.debug('[Database] UPDATE merged - preserved fields', {
|
|
@@ -155,17 +159,14 @@ export class Database {
|
|
|
155
159
|
getContext().logger.info(`Database opened: ${this.currentDbInfo.name} (${readiness.readyStores.length}/${readiness.totalStores} stores ready)`);
|
|
156
160
|
}
|
|
157
161
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
+
* Shrink a record before persisting it. Drops `undefined` fields, empty
|
|
163
|
+
* arrays, empty objects, and the redundant markers `__typename`, `__class`,
|
|
164
|
+
* `clientId`, and `syncStatus`. Explicit `null` values are preserved, since
|
|
165
|
+
* a null is a meaningful "clear this field" in a nullable column.
|
|
162
166
|
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* - Bootstrap data: Plain JSON from server
|
|
167
|
-
*
|
|
168
|
-
* Note: We do NOT drop required defaults; server provides them.
|
|
167
|
+
* By design this receives plain objects, never live observables: WebSocket
|
|
168
|
+
* deltas arrive already parsed, optimistic updates come through `toJSON()`,
|
|
169
|
+
* and bootstrap data is plain JSON from the server.
|
|
169
170
|
*/
|
|
170
171
|
compactRecord(_modelName, data) {
|
|
171
172
|
if (!data || typeof data !== 'object')
|
|
@@ -176,8 +177,8 @@ export class Database {
|
|
|
176
177
|
if (key === '__typename' || key === '__class' || key === 'clientId' || key === 'syncStatus') {
|
|
177
178
|
continue;
|
|
178
179
|
}
|
|
179
|
-
//
|
|
180
|
-
//
|
|
180
|
+
// Skip only `undefined`; preserve explicit `null`, which is a
|
|
181
|
+
// meaningful value for a nullable column.
|
|
181
182
|
if (value === undefined) {
|
|
182
183
|
continue;
|
|
183
184
|
}
|
|
@@ -271,26 +272,24 @@ export class Database {
|
|
|
271
272
|
// point). Invalid → 0 → full bootstrap, the safe degradation.
|
|
272
273
|
const metadataLastSyncId = syncPositionSchema.shape.persisted.safeParse(metadata?.lastSyncId).data ?? 0;
|
|
273
274
|
const dataAge = metadata?.updatedAt ? Date.now() - metadata.updatedAt.getTime() : Infinity;
|
|
274
|
-
// ──
|
|
275
|
+
// ── Cache-validity check ─────────────────────────────────────
|
|
275
276
|
//
|
|
276
277
|
// The cursor (lastSyncId) is only valid if the data it refers to
|
|
277
|
-
// actually exists in the stores. If
|
|
278
|
-
// fresh in-memory session), the metadata's lastSyncId is
|
|
279
|
-
// sending it to the server would trigger a partial bootstrap
|
|
280
|
-
// returns zero deltas because the gap is 0, leaving the client
|
|
281
|
-
// with an empty
|
|
278
|
+
// actually exists in the stores. If the local store was cleared (or
|
|
279
|
+
// this is a fresh in-memory session), the metadata's lastSyncId is
|
|
280
|
+
// stale — sending it to the server would trigger a partial bootstrap
|
|
281
|
+
// that returns zero deltas because the gap is 0, leaving the client
|
|
282
|
+
// with an empty InstanceCache.
|
|
282
283
|
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
// property by sampling the actual stores — if they're empty, the
|
|
286
|
-
// cursor is meaningless regardless of what metadata claims.
|
|
284
|
+
// The fix is to sample the actual stores: if they hold no rows, the
|
|
285
|
+
// cursor is meaningless regardless of what the metadata claims.
|
|
287
286
|
const dataExists = this.inMemory
|
|
288
287
|
? false // In-memory mode: no persistent data across sessions
|
|
289
288
|
: await this.storeManager.hasAnyData();
|
|
290
289
|
// The effective lastSyncId: only trust the metadata cursor when
|
|
291
290
|
// we've confirmed the data it refers to actually exists in the stores.
|
|
292
291
|
const lastSyncId = dataExists ? metadataLastSyncId : 0;
|
|
293
|
-
//
|
|
292
|
+
// Log the resolved database state for diagnostics.
|
|
294
293
|
getContext().logger.debug('[Database.requiredBootstrap] State check', {
|
|
295
294
|
readinessReady: readiness.ready,
|
|
296
295
|
hasMetadata: !!metadata,
|
|
@@ -311,7 +310,8 @@ export class Database {
|
|
|
311
310
|
getContext().logger.info('Offline detected with local data - using local bootstrap');
|
|
312
311
|
}
|
|
313
312
|
else {
|
|
314
|
-
//
|
|
313
|
+
// The server is the source of truth: always use a full bootstrap
|
|
314
|
+
// when online.
|
|
315
315
|
type = 'full';
|
|
316
316
|
getContext().logger.info('Full bootstrap - server is source of truth', {
|
|
317
317
|
reason: offline ? 'offline_no_data' : 'server_authoritative',
|
|
@@ -324,11 +324,13 @@ export class Database {
|
|
|
324
324
|
type,
|
|
325
325
|
modelsToLoad,
|
|
326
326
|
lastSyncId,
|
|
327
|
-
syncGroups: metadata?.syncGroups
|
|
327
|
+
syncGroups: metadata?.syncGroups ?? [],
|
|
328
328
|
};
|
|
329
329
|
}
|
|
330
330
|
/**
|
|
331
|
-
*
|
|
331
|
+
* Fetch a bootstrap snapshot (or delta batch) from the sync server and load
|
|
332
|
+
* it into the local store, then return a {@link BootstrapResult} the caller
|
|
333
|
+
* applies to the {@link InstanceCache}.
|
|
332
334
|
*/
|
|
333
335
|
async bootstrapFromServer(requirements,
|
|
334
336
|
/** Full sync-group subscription list — what the WS subscribes to
|
|
@@ -347,8 +349,8 @@ export class Database {
|
|
|
347
349
|
modelsToLoad: requirements.modelsToLoad,
|
|
348
350
|
});
|
|
349
351
|
try {
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
+
// Fetch before any destructive operation, so a failed network
|
|
353
|
+
// request can't leave the local store empty.
|
|
352
354
|
const startTime = typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
353
355
|
getContext().logger.info('Fetching bootstrap data from server (before clearing local data)', {
|
|
354
356
|
type: requirements.type,
|
|
@@ -360,16 +362,17 @@ export class Database {
|
|
|
360
362
|
lastSyncId: bootstrapData.lastSyncId,
|
|
361
363
|
hasModels: !!bootstrapData.models,
|
|
362
364
|
hasDeltas: !!bootstrapData.deltas,
|
|
363
|
-
deltaCount: bootstrapData.deltaCount
|
|
365
|
+
deltaCount: bootstrapData.deltaCount ?? 0,
|
|
364
366
|
});
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
+
// Clear only after a successful fetch, for transactional safety.
|
|
368
|
+
// Clear when the server says the response is a full snapshot,
|
|
369
|
+
// regardless of what type was requested.
|
|
367
370
|
if (bootstrapData.type === 'full') {
|
|
368
371
|
await this.clear();
|
|
369
372
|
}
|
|
370
373
|
// Handle partial bootstrap (delta batch)
|
|
371
374
|
if (bootstrapData.type === 'partial') {
|
|
372
|
-
const deltas = bootstrapData.deltas
|
|
375
|
+
const deltas = bootstrapData.deltas ?? [];
|
|
373
376
|
getContext().logger.info('Processing partial bootstrap with delta batch', {
|
|
374
377
|
deltaCount: deltas.length,
|
|
375
378
|
fromSyncId: requirements.lastSyncId,
|
|
@@ -378,7 +381,7 @@ export class Database {
|
|
|
378
381
|
// Apply deltas to IndexedDB using processDeltaBatch for better performance.
|
|
379
382
|
// Capture the return value so the pool can be updated by the caller —
|
|
380
383
|
// without this, partial-bootstrap DELETEs persist to IDB but don't
|
|
381
|
-
// evict entities from the in-memory
|
|
384
|
+
// evict entities from the in-memory InstanceCache, leaving ghost rows
|
|
382
385
|
// visible on the canvas until a full reload rebuilds the pool.
|
|
383
386
|
let deltasApplied = 0;
|
|
384
387
|
let deltaResults;
|
|
@@ -500,17 +503,16 @@ export class Database {
|
|
|
500
503
|
}
|
|
501
504
|
// bootstrapSpecificModels removed per request
|
|
502
505
|
/**
|
|
503
|
-
*
|
|
506
|
+
* Apply a single inbound delta from the WebSocket to the local store.
|
|
504
507
|
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
+
* This handles one delta at a time. To apply several, prefer
|
|
509
|
+
* {@link processDeltaBatch}, which commits them in one IndexedDB transaction
|
|
510
|
+
* rather than two transactions per delta.
|
|
508
511
|
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
* - Explicit null values ARE preserved: {position: null} clears the field
|
|
512
|
+
* Update deltas carry only the changed fields, so they are merged onto the
|
|
513
|
+
* existing record rather than replacing it. That preserves fields the delta
|
|
514
|
+
* omits (such as deckId or title), and an explicit null is kept as a value,
|
|
515
|
+
* clearing that field.
|
|
514
516
|
*/
|
|
515
517
|
async processDelta(delta) {
|
|
516
518
|
const { actionType, modelName, modelId, data, syncId } = delta;
|
|
@@ -518,7 +520,7 @@ export class Database {
|
|
|
518
520
|
if (!store) {
|
|
519
521
|
return { action: 'verify', modelName, modelId };
|
|
520
522
|
}
|
|
521
|
-
//
|
|
523
|
+
// Idempotency gate: ignore already-applied deltas by comparing with the persisted lastSyncId
|
|
522
524
|
try {
|
|
523
525
|
const lastApplied = await this.getLastSyncId();
|
|
524
526
|
const incomingId = typeof syncId === 'number' ? syncId : undefined;
|
|
@@ -571,11 +573,12 @@ export class Database {
|
|
|
571
573
|
return { action: 'add', modelName, modelId, data: compacted };
|
|
572
574
|
}
|
|
573
575
|
case 'U': {
|
|
574
|
-
//
|
|
575
|
-
// Read existing record first
|
|
576
|
+
// Update: merge onto the existing record (partial-delta pattern).
|
|
577
|
+
// Read the existing record first.
|
|
576
578
|
const existing = await store.get(modelId);
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
+
// Skip the update when there's no existing record to merge with:
|
|
580
|
+
// building a record from partial update data would corrupt it
|
|
581
|
+
// (missing deckId, and so on).
|
|
579
582
|
if (!existing) {
|
|
580
583
|
getContext().observability.breadcrumb('Skipping UPDATE delta - no existing record to merge with', 'sync.database', 'warning', {
|
|
581
584
|
modelName,
|
|
@@ -618,7 +621,7 @@ export class Database {
|
|
|
618
621
|
getContext().observability.breadcrumb(`IndexedDB delete failed for ${modelName}:${modelId}`, 'sync.database', 'error', {
|
|
619
622
|
error: err instanceof Error ? err.message : String(err),
|
|
620
623
|
});
|
|
621
|
-
// Surface failure so caller does not mutate
|
|
624
|
+
// Surface failure so caller does not mutate InstanceCache inconsistently
|
|
622
625
|
throw err;
|
|
623
626
|
}
|
|
624
627
|
return { action: 'remove', modelName, modelId };
|
|
@@ -658,27 +661,20 @@ export class Database {
|
|
|
658
661
|
}
|
|
659
662
|
}
|
|
660
663
|
/**
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
* 2. Opening a single transaction per store for all writes
|
|
666
|
-
* 3. Merging UPDATE deltas with existing data to preserve unmodified fields
|
|
667
|
-
* 4. Updating metadata only once at the end with highest syncId
|
|
668
|
-
*
|
|
669
|
-
* Performance impact: 186 deltas goes from ~372 transactions to just 1 transaction
|
|
664
|
+
* Apply many deltas to the local store in as few IndexedDB transactions as
|
|
665
|
+
* possible. Deltas are grouped by store, and each store's writes commit in a
|
|
666
|
+
* single transaction, so a batch of 186 deltas becomes roughly one
|
|
667
|
+
* transaction per store instead of two per delta.
|
|
670
668
|
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
* - Handles explicit null: {field: null} clears the field correctly
|
|
669
|
+
* The method reads the existing records for update deltas up front, then
|
|
670
|
+
* merges each update onto its existing record so fields the delta omits are
|
|
671
|
+
* preserved and an explicit null still clears its field. It advances the
|
|
672
|
+
* persisted sync cursor once, to the highest committed sync id.
|
|
676
673
|
*
|
|
677
|
-
*
|
|
678
|
-
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
* - Prevents 404 errors from fetching already-deleted entities
|
|
674
|
+
* Conflict resolution follows a delete-wins rule: it first indexes the
|
|
675
|
+
* delete deltas by entity, then skips any insert or update whose sync id is
|
|
676
|
+
* at or below a delete for the same entity. This avoids resurrecting a
|
|
677
|
+
* deleted entity and avoids fetching one that no longer exists.
|
|
682
678
|
*/
|
|
683
679
|
async processDeltaBatch(deltas) {
|
|
684
680
|
if ((!this.workspaceDb && !this.inMemory) || this.isClosing || deltas.length === 0) {
|
|
@@ -721,14 +717,11 @@ export class Database {
|
|
|
721
717
|
}
|
|
722
718
|
// Prepare results aligned with input order
|
|
723
719
|
const results = new Array(deltas.length);
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
//
|
|
727
|
-
//
|
|
728
|
-
|
|
729
|
-
// for entities that have been cascade-deleted (where DELETE delta exists).
|
|
730
|
-
// ========================================================================
|
|
731
|
-
const deleteSyncIds = new Map(); // key: "ModelName:modelId" -> DELETE syncId
|
|
720
|
+
// Build a delete index for conflict resolution. When a delete has a sync
|
|
721
|
+
// id at or above a later insert or update for the same entity, that entity
|
|
722
|
+
// is not (re)created — which drops stale updates for cascade-deleted
|
|
723
|
+
// entities.
|
|
724
|
+
const deleteSyncIds = new Map(); // key: "ModelName:modelId" -> delete syncId
|
|
732
725
|
for (const delta of deltas) {
|
|
733
726
|
if (delta.actionType === 'D' && delta.syncId) {
|
|
734
727
|
const key = `${delta.modelName}:${delta.modelId}`;
|
|
@@ -748,18 +741,17 @@ export class Database {
|
|
|
748
741
|
}
|
|
749
742
|
// Group deltas by store for efficient transaction management.
|
|
750
743
|
//
|
|
751
|
-
//
|
|
752
|
-
//
|
|
753
|
-
//
|
|
754
|
-
//
|
|
744
|
+
// The method tracks two high-water marks: `highestSyncId` for the total
|
|
745
|
+
// range seen, and `highestPersistedSyncId`, accumulated only from deltas
|
|
746
|
+
// whose store transaction actually committed. The cursor advance (at
|
|
747
|
+
// `updateWorkspaceMetadata`) uses only the persisted one.
|
|
755
748
|
//
|
|
756
|
-
// Without this split, a single store-level
|
|
757
|
-
//
|
|
758
|
-
//
|
|
759
|
-
//
|
|
760
|
-
//
|
|
761
|
-
//
|
|
762
|
-
// recover it" failure mode.
|
|
749
|
+
// Without this split, a single store-level failure (a compacted record
|
|
750
|
+
// missing a required field, a validation abort) would advance the cursor
|
|
751
|
+
// past deltas that never wrote to IndexedDB. The next partial bootstrap
|
|
752
|
+
// would ask "what's new since {advanced cursor}?", the skipped rows would
|
|
753
|
+
// fall into the already-seen range forever, and the local store would stay
|
|
754
|
+
// permanently behind the server with no way to recover on reload.
|
|
763
755
|
const deltasByStore = new Map();
|
|
764
756
|
let highestSyncId = 0;
|
|
765
757
|
let highestPersistedSyncId = 0;
|
|
@@ -772,9 +764,8 @@ export class Database {
|
|
|
772
764
|
if (typeof deltaSyncIdNum === 'number' && !isNaN(deltaSyncIdNum) && deltaSyncIdNum > highestSyncId) {
|
|
773
765
|
highestSyncId = deltaSyncIdNum;
|
|
774
766
|
}
|
|
775
|
-
//
|
|
776
|
-
//
|
|
777
|
-
// ========================================================================
|
|
767
|
+
// Conflict check: skip an insert or update when a delete for the same
|
|
768
|
+
// entity has an equal or higher sync id.
|
|
778
769
|
if (delta.actionType === 'U' ||
|
|
779
770
|
delta.actionType === 'I' ||
|
|
780
771
|
delta.actionType === 'C' ||
|
|
@@ -783,7 +774,7 @@ export class Database {
|
|
|
783
774
|
const deleteSyncId = deleteSyncIds.get(key);
|
|
784
775
|
if (deleteSyncId !== undefined) {
|
|
785
776
|
// DELETE exists for this entity
|
|
786
|
-
const deltaSyncId = delta.syncId
|
|
777
|
+
const deltaSyncId = delta.syncId ?? 0;
|
|
787
778
|
if (deleteSyncId >= deltaSyncId) {
|
|
788
779
|
// DELETE has equal or higher syncId - skip this UPDATE/INSERT
|
|
789
780
|
getContext().logger.debug('[Database.processDeltaBatch] Skipping stale delta (DELETE wins)', {
|
|
@@ -822,8 +813,8 @@ export class Database {
|
|
|
822
813
|
if (!store)
|
|
823
814
|
continue;
|
|
824
815
|
try {
|
|
825
|
-
//
|
|
826
|
-
// Step 1: Identify which deltas need existing data (
|
|
816
|
+
// Batch read-modify-write.
|
|
817
|
+
// Step 1: Identify which deltas need existing data (updates)
|
|
827
818
|
const updateDeltas = storeDeltas.filter(({ delta }) => delta.actionType === 'U');
|
|
828
819
|
const updateIds = updateDeltas.map(({ delta }) => delta.modelId);
|
|
829
820
|
// Step 2: Batch read all existing records in a SINGLE IDB transaction
|
|
@@ -848,8 +839,9 @@ export class Database {
|
|
|
848
839
|
}
|
|
849
840
|
}
|
|
850
841
|
}
|
|
851
|
-
//
|
|
852
|
-
// Track
|
|
842
|
+
// Self-heal by fetching missing records for update deltas.
|
|
843
|
+
// Track ids that failed to fetch (a 404 means the entity was deleted,
|
|
844
|
+
// so its delta is skipped).
|
|
853
845
|
const failedToFetch = new Set();
|
|
854
846
|
if (missingIds.size > 0) {
|
|
855
847
|
getContext().logger.info(`[Database.processDeltaBatch] Found ${missingIds.size} missing records for ${modelName}, fetching from server...`);
|
|
@@ -923,13 +915,11 @@ export class Database {
|
|
|
923
915
|
});
|
|
924
916
|
break;
|
|
925
917
|
case 'U': {
|
|
926
|
-
//
|
|
918
|
+
// Update: merge the delta onto the existing record (already fetched).
|
|
927
919
|
const existing = existingRecords.get(modelId);
|
|
928
|
-
//
|
|
929
|
-
//
|
|
930
|
-
//
|
|
931
|
-
// Per Linear's architecture, skip it instead of creating incomplete data.
|
|
932
|
-
// ========================================================================
|
|
920
|
+
// Skip a stale update: if the entity is neither in the local
|
|
921
|
+
// store nor fetchable from the server (a 404), it was deleted,
|
|
922
|
+
// so skip it rather than create an incomplete record.
|
|
933
923
|
if (!existing && failedToFetch.has(modelId)) {
|
|
934
924
|
getContext().logger.debug('[Database.processDeltaBatch] Skipping UPDATE for deleted entity', {
|
|
935
925
|
modelName,
|
|
@@ -938,8 +928,9 @@ export class Database {
|
|
|
938
928
|
stagedResults.push({ action: 'verify', modelName, modelId, idx });
|
|
939
929
|
break; // Skip this delta
|
|
940
930
|
}
|
|
941
|
-
//
|
|
942
|
-
//
|
|
931
|
+
// Skip the update when there's no existing record to merge with:
|
|
932
|
+
// building a record from partial update data would corrupt it
|
|
933
|
+
// (missing deckId, and so on).
|
|
943
934
|
if (!existing) {
|
|
944
935
|
getContext().observability.breadcrumb('Batch: Skipping UPDATE delta - no existing record', 'sync.database', 'warning', {
|
|
945
936
|
modelName,
|
|
@@ -989,12 +980,12 @@ export class Database {
|
|
|
989
980
|
}
|
|
990
981
|
// Wait for transaction to complete
|
|
991
982
|
await new Promise((resolve, reject) => {
|
|
992
|
-
tx.oncomplete = () => resolve();
|
|
993
|
-
tx.onerror = () => reject(tx.error);
|
|
983
|
+
tx.oncomplete = () => { resolve(); };
|
|
984
|
+
tx.onerror = () => { reject(tx.error); };
|
|
994
985
|
});
|
|
995
986
|
// Only commit staged results to the global results if the transaction succeeded.
|
|
996
|
-
//
|
|
997
|
-
//
|
|
987
|
+
// Advance `highestPersistedSyncId` only for deltas in this successful
|
|
988
|
+
// transaction, so the cursor can't advance past rows that never wrote to IDB.
|
|
998
989
|
for (const r of stagedResults) {
|
|
999
990
|
// Resolve the originating delta so we can carry its
|
|
1000
991
|
// transactionId through to the result. Echo detection in
|
|
@@ -1103,13 +1094,7 @@ export class Database {
|
|
|
1103
1094
|
const store = this.getRequiredStore(modelName);
|
|
1104
1095
|
return await store.getAllFromIndex(indexName, value);
|
|
1105
1096
|
}
|
|
1106
|
-
/**
|
|
1107
|
-
* Update workspace metadata
|
|
1108
|
-
*/
|
|
1109
|
-
/**
|
|
1110
|
-
* Get the last sync ID from workspace metadata
|
|
1111
|
-
*/
|
|
1112
|
-
/** Read workspace metadata from IDB (returns null if db not open). */
|
|
1097
|
+
/** Read workspace metadata from IndexedDB. Returns null when the database is not open. */
|
|
1113
1098
|
async getWorkspaceMetadata() {
|
|
1114
1099
|
if (this.inMemory)
|
|
1115
1100
|
return this.inMemoryMetadata;
|
|
@@ -1122,13 +1107,7 @@ export class Database {
|
|
|
1122
1107
|
return 0;
|
|
1123
1108
|
}
|
|
1124
1109
|
const metadata = await this.databaseManager.getWorkspaceMetadata(this.workspaceDb);
|
|
1125
|
-
return metadata?.lastSyncId
|
|
1126
|
-
}
|
|
1127
|
-
async getVersionVector() {
|
|
1128
|
-
if (!this.workspaceDb)
|
|
1129
|
-
return null;
|
|
1130
|
-
const metadata = await this.databaseManager.getWorkspaceMetadata(this.workspaceDb);
|
|
1131
|
-
return (metadata?.versions || null);
|
|
1110
|
+
return metadata?.lastSyncId ?? 0;
|
|
1132
1111
|
}
|
|
1133
1112
|
async updateWorkspaceMetadata(metadata) {
|
|
1134
1113
|
// In-memory mode: store in local variable
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* InstanceCache is the in-memory cache of live model instances, keyed by id and
|
|
3
|
+
* deduplicated so each entity has a single instance. It maintains type and
|
|
4
|
+
* foreign-key indexes for fast lookups, evicts entries under a size cap, and
|
|
5
|
+
* notifies subscribers and query views as models are added, updated, or
|
|
6
|
+
* removed. It holds a {@link ModelRegistry} to map between model names and
|
|
7
|
+
* constructor classes, but performs no persistence of its own.
|
|
6
8
|
*/
|
|
7
9
|
import { Model } from './Model.js';
|
|
8
10
|
import { ModelRegistry } from './ModelRegistry.js';
|
|
@@ -23,9 +25,10 @@ interface DeltaInfo {
|
|
|
23
25
|
syncId?: number;
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
26
|
-
*
|
|
28
|
+
* The in-memory cache of model instances, keyed by id and deduplicated so each
|
|
29
|
+
* entity resolves to a single instance.
|
|
27
30
|
*/
|
|
28
|
-
export declare class
|
|
31
|
+
export declare class InstanceCache {
|
|
29
32
|
private entries;
|
|
30
33
|
private typeIndex;
|
|
31
34
|
private accessTimes;
|
|
@@ -45,12 +48,6 @@ export declare class ObjectPool {
|
|
|
45
48
|
subscribe<T extends Model>(modelClass: ModelConstructor<T>, callback: (model: T) => void): () => void;
|
|
46
49
|
private notifySubscribers;
|
|
47
50
|
constructor(config?: PoolConfig, modelRegistry?: ModelRegistry);
|
|
48
|
-
/**
|
|
49
|
-
* 🔧 PRODUCTION FIX: Initialize type indexes for all registered models
|
|
50
|
-
* This prevents the "No type index found" error in production where constructor
|
|
51
|
-
* references are lost due to minification.
|
|
52
|
-
*/
|
|
53
|
-
private initializeTypeIndexes;
|
|
54
51
|
private resolveModel;
|
|
55
52
|
get<T extends Model = Model>(id: string): T | undefined;
|
|
56
53
|
/**
|
|
@@ -115,7 +112,7 @@ export declare class ObjectPool {
|
|
|
115
112
|
/**
|
|
116
113
|
* Throw (instead of warn + return null) when the wire names a model
|
|
117
114
|
* this client never registered. Passed by the developer-await read
|
|
118
|
-
* path (`
|
|
115
|
+
* path (`OnDemandLoader`'s network leg) so a schema collision
|
|
119
116
|
* — the org's pushed schema names `Document` but this client only
|
|
120
117
|
* registered `documents` — surfaces AT the row that failed, with the
|
|
121
118
|
* known-model list and `ablo status` pointer, instead of bubbling up
|