@abloatai/ablo 0.34.1 → 0.35.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 +2 -1
- package/CHANGELOG.md +674 -5
- package/README.md +39 -22
- package/dist/BaseSyncedStore.d.ts +152 -44
- package/dist/BaseSyncedStore.js +300 -184
- package/dist/Database.d.ts +9 -24
- package/dist/Database.js +37 -22
- package/dist/InstanceCache.d.ts +25 -4
- package/dist/InstanceCache.js +48 -15
- package/dist/LazyReferenceCollection.d.ts +3 -3
- package/dist/LazyReferenceCollection.js +4 -4
- package/dist/Model.d.ts +6 -6
- package/dist/Model.js +10 -10
- package/dist/ModelRegistry.d.ts +4 -4
- package/dist/ModelRegistry.js +3 -3
- package/dist/{SyncEngineContext.d.ts → RuntimeContext.d.ts} +20 -13
- package/dist/{SyncEngineContext.js → RuntimeContext.js} +11 -12
- package/dist/SyncClient.d.ts +42 -32
- package/dist/SyncClient.js +166 -110
- package/dist/ai-sdk/coordinatedTool.d.ts +2 -2
- package/dist/ai-sdk/coordinatedTool.js +1 -1
- package/dist/ai-sdk/coordinationContext.d.ts +2 -2
- package/dist/ai-sdk/coordinationContext.js +1 -1
- package/dist/ai-sdk/wrap.d.ts +3 -3
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/index.d.ts +1 -156
- package/dist/auth/index.js +8 -301
- package/dist/cli.cjs +3344 -1073
- package/dist/client/Ablo.d.ts +42 -287
- package/dist/client/Ablo.js +118 -963
- package/dist/client/abloClient.d.ts +309 -0
- package/dist/client/abloClient.js +13 -0
- package/dist/client/clientPrelude.d.ts +52 -0
- package/dist/client/clientPrelude.js +60 -0
- package/dist/client/consoleLogger.d.ts +2 -2
- package/dist/client/coreClient.d.ts +60 -0
- package/dist/client/coreClient.js +118 -0
- package/dist/client/createInternalComponents.d.ts +4 -4
- package/dist/client/createInternalComponents.js +9 -8
- package/dist/client/createModelProxy.d.ts +78 -373
- package/dist/client/createModelProxy.js +114 -86
- package/dist/client/humans.d.ts +48 -0
- package/dist/client/humans.js +52 -0
- package/dist/client/modelRegistration.d.ts +1 -1
- package/dist/client/modelRegistration.js +9 -9
- package/dist/client/options.d.ts +73 -17
- package/dist/client/reactiveEngine.d.ts +48 -0
- package/dist/client/reactiveEngine.js +910 -0
- package/dist/client/resourceTypes.d.ts +9 -250
- package/dist/client/resourceTypes.js +8 -5
- package/dist/client/schemaConfig.d.ts +4 -4
- package/dist/client/schemaConfig.js +6 -2
- package/dist/client/validateAbloOptions.d.ts +3 -2
- package/dist/client/validateAbloOptions.js +1 -1
- package/dist/client/wsMutationExecutor.d.ts +3 -3
- package/dist/client/wsMutationExecutor.js +3 -3
- package/dist/context.d.ts +9 -9
- package/dist/context.js +10 -9
- package/dist/coordination/ClaimLog.d.ts +26 -0
- package/dist/coordination/ClaimLog.js +32 -0
- package/dist/coordination/index.d.ts +1 -15
- package/dist/coordination/index.js +8 -31
- package/dist/core/DatabaseManager.js +1 -1
- package/dist/core/QueryView.d.ts +1 -1
- package/dist/core/QueryView.js +1 -1
- package/dist/core/StoreManager.d.ts +4 -23
- package/dist/core/StoreManager.js +5 -55
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/core/storeContract.d.ts +2 -2
- package/dist/docs/catalog.d.ts +72 -0
- package/dist/docs/catalog.js +227 -0
- package/dist/docs/index.d.ts +10 -0
- package/dist/docs/index.js +10 -0
- package/dist/environment.d.ts +1 -40
- package/dist/environment.js +8 -37
- package/dist/index.d.ts +40 -34
- package/dist/index.js +26 -20
- package/dist/interfaces/index.d.ts +44 -134
- package/dist/keys/index.d.ts +1 -77
- package/dist/keys/index.js +8 -190
- package/dist/mutators/{RecordingTransaction.d.ts → RecordingMutation.d.ts} +4 -4
- package/dist/mutators/{RecordingTransaction.js → RecordingMutation.js} +2 -2
- package/dist/mutators/Transaction.d.ts +1 -1
- package/dist/mutators/Transaction.js +1 -1
- package/dist/mutators/UndoManager.d.ts +6 -6
- package/dist/mutators/UndoManager.js +5 -5
- package/dist/mutators/defineMutators.d.ts +3 -3
- package/dist/mutators/defineMutators.js +1 -1
- package/dist/mutators/inverseOp.js +2 -2
- package/dist/mutators/mutateActions.d.ts +3 -3
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +1 -1
- package/dist/mutators/undoApply.d.ts +1 -1
- package/dist/mutators/undoApply.js +1 -1
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +1 -1
- package/dist/query/client.d.ts +2 -2
- package/dist/query/client.js +4 -4
- package/dist/query/types.d.ts +6 -41
- package/dist/query/types.js +2 -2
- package/dist/react/AbloProvider.d.ts +6 -8
- package/dist/react/AbloProvider.js +5 -7
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js +1 -1
- package/dist/react/index.d.ts +5 -5
- package/dist/react/index.js +3 -3
- package/dist/react/internalContext.d.ts +1 -1
- package/dist/react/useAblo.d.ts +3 -3
- package/dist/react/useAblo.js +1 -1
- package/dist/react/useCurrentUserId.js +1 -1
- package/dist/react/useErrorListener.js +1 -1
- package/dist/react/useMutationFailureListener.d.ts +2 -2
- package/dist/react/useMutationFailureListener.js +1 -1
- package/dist/react/useMutators.d.ts +3 -3
- package/dist/react/useMutators.js +3 -3
- package/dist/react/useUndoScope.d.ts +5 -5
- package/dist/react/useUndoScope.js +1 -1
- package/dist/schema/coordination.d.ts +69 -10
- package/dist/schema/coordination.js +86 -9
- package/dist/schema/ddl.js +2 -2
- package/dist/schema/diff.d.ts +1 -1
- package/dist/schema/generate.js +1 -1
- package/dist/schema/index.d.ts +10 -10
- package/dist/schema/index.js +18 -18
- package/dist/schema/queries.d.ts +27 -27
- package/dist/schema/queries.js +23 -23
- package/dist/schema/select.d.ts +3 -3
- package/dist/schema/select.js +3 -3
- package/dist/schema/serialize.d.ts +15 -6
- package/dist/schema/serialize.js +17 -3
- package/dist/schema/sugar.d.ts +6 -7
- package/dist/schema/sugar.js +9 -12
- package/dist/schema/syncDeltaRow.d.ts +4 -152
- package/dist/schema/syncDeltaRow.js +4 -105
- package/dist/server/adapter.d.ts +18 -1
- package/dist/server/commit.d.ts +10 -16
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +1 -1
- package/dist/source/adapters/drizzle.d.ts +1 -1
- package/dist/source/adapters/drizzle.js +2 -2
- package/dist/source/adapters/kysely.d.ts +1 -1
- package/dist/source/adapters/kysely.js +1 -1
- package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
- package/dist/source/adapters/kyselyMutationCore.js +2 -2
- package/dist/source/adapters/memory.js +1 -1
- package/dist/source/adapters/prisma.d.ts +8 -3
- package/dist/source/adapters/prisma.js +1 -1
- package/dist/source/connector.js +1 -1
- package/dist/source/connectorProtocol.d.ts +2 -8
- package/dist/source/connectorProtocol.js +3 -2
- package/dist/source/contract.d.ts +29 -17
- package/dist/source/contract.js +27 -22
- package/dist/source/factory.d.ts +1 -1
- package/dist/source/footprint.d.ts +111 -0
- package/dist/source/footprint.js +0 -0
- package/dist/source/idempotency.js +2 -2
- package/dist/source/index.d.ts +1 -0
- package/dist/source/index.js +3 -0
- package/dist/source/next.d.ts +1 -1
- package/dist/source/signing.d.ts +9 -2
- package/dist/source/signing.js +4 -1
- package/dist/source/types.d.ts +6 -4
- package/dist/source/types.js +1 -1
- package/dist/stores/ObjectStore.d.ts +1 -1
- package/dist/stores/SyncActionStore.d.ts +1 -1
- package/dist/stores/SyncActionStore.js +2 -10
- package/dist/stores/syncAction.d.ts +26 -0
- package/dist/stores/syncAction.js +16 -0
- package/dist/surface.d.ts +3 -3
- package/dist/surface.js +6 -4
- package/dist/sync/BootstrapFetcher.d.ts +123 -6
- package/dist/sync/BootstrapFetcher.js +492 -66
- package/dist/sync/ConnectionManager.d.ts +6 -198
- package/dist/sync/ConnectionManager.js +6 -677
- package/dist/sync/OnDemandLoader.d.ts +2 -2
- package/dist/sync/OnDemandLoader.js +60 -21
- package/dist/sync/SubscriptionManager.d.ts +13 -2
- package/dist/sync/SubscriptionManager.js +23 -5
- package/dist/sync/SyncWebSocket.d.ts +27 -510
- package/dist/sync/SyncWebSocket.js +76 -954
- package/dist/sync/awaitClaimGrant.d.ts +4 -44
- package/dist/sync/awaitClaimGrant.js +4 -109
- package/dist/sync/commitFrames.d.ts +6 -40
- package/dist/sync/commitFrames.js +6 -97
- package/dist/sync/contextPorts.d.ts +18 -0
- package/dist/sync/contextPorts.js +31 -0
- package/dist/sync/createClaimStream.d.ts +5 -49
- package/dist/sync/createClaimStream.js +5 -469
- package/dist/sync/createPresenceStream.d.ts +26 -4
- package/dist/sync/createPresenceStream.js +28 -20
- package/dist/sync/createSnapshot.d.ts +2 -2
- package/dist/sync/createSnapshot.js +1 -1
- package/dist/sync/credentialLifecycle.d.ts +5 -173
- package/dist/sync/credentialLifecycle.js +5 -320
- package/dist/sync/deltaPipeline.d.ts +1 -1
- package/dist/sync/participants.d.ts +5 -4
- package/dist/sync/participants.js +29 -22
- package/dist/sync/schemaDrift.d.ts +55 -0
- package/dist/sync/schemaDrift.js +53 -0
- package/dist/sync/schemas.d.ts +21 -32
- package/dist/sync/schemas.js +26 -17
- package/dist/sync/syncPlan.d.ts +3 -3
- package/dist/sync/wsFrameHandlers.d.ts +6 -114
- package/dist/sync/wsFrameHandlers.js +6 -392
- package/dist/testing/fixtures/bootstrap.d.ts +1 -1
- package/dist/testing/fixtures/deltas.d.ts +1 -1
- package/dist/testing/fixtures/httpResponses.d.ts +70 -0
- package/dist/testing/fixtures/httpResponses.js +90 -0
- package/dist/testing/fixtures/models.js +1 -1
- package/dist/testing/helpers/wait.js +1 -1
- package/dist/testing/mocks/MockMutationExecutor.d.ts +2 -2
- package/dist/testing/mocks/MockMutationExecutor.js +8 -14
- package/dist/testing/mocks/MockSyncContext.d.ts +11 -11
- package/dist/testing/mocks/MockSyncContext.js +10 -9
- package/dist/testing/mocks/MockSyncStore.js +1 -1
- package/dist/testing/mocks/MockWebSocket.d.ts +2 -2
- package/dist/transaction/ablo.d.ts +88 -0
- package/dist/transaction/ablo.js +33 -0
- package/dist/{client/auth.d.ts → transaction/auth/apiKey.d.ts} +43 -8
- package/dist/{client/auth.js → transaction/auth/apiKey.js} +19 -0
- package/dist/transaction/auth/bootstrapScope.d.ts +15 -0
- package/dist/transaction/auth/bootstrapScope.js +1 -0
- package/dist/transaction/auth/capability.d.ts +177 -0
- package/dist/transaction/auth/capability.js +199 -0
- package/dist/{auth → transaction/auth}/credentialSource.d.ts +8 -1
- package/dist/{client → transaction/auth}/identity.d.ts +8 -7
- package/dist/{client → transaction/auth}/identity.js +1 -1
- package/dist/transaction/auth/index.d.ts +162 -0
- package/dist/transaction/auth/index.js +304 -0
- package/dist/{auth → transaction/auth}/schemas.d.ts +1 -1
- package/dist/{auth → transaction/auth}/schemas.js +13 -13
- package/dist/{client → transaction/auth}/sessionMint.d.ts +8 -8
- package/dist/{client → transaction/auth}/sessionMint.js +4 -7
- package/dist/transaction/coordination/awaitClaimGrant.d.ts +49 -0
- package/dist/transaction/coordination/awaitClaimGrant.js +112 -0
- package/dist/transaction/coordination/claimMeta.d.ts +49 -0
- package/dist/transaction/coordination/claimMeta.js +52 -0
- package/dist/transaction/coordination/createClaimStream.d.ts +64 -0
- package/dist/transaction/coordination/createClaimStream.js +475 -0
- package/dist/transaction/coordination/events.d.ts +74 -0
- package/dist/transaction/coordination/events.js +7 -0
- package/dist/transaction/coordination/index.d.ts +19 -0
- package/dist/transaction/coordination/index.js +44 -0
- package/dist/transaction/coordination/locator.d.ts +83 -0
- package/dist/transaction/coordination/locator.js +82 -0
- package/dist/transaction/coordination/schema.d.ts +1473 -0
- package/dist/{coordination → transaction/coordination}/schema.js +490 -55
- package/dist/transaction/coordination/targetConflict.d.ts +2 -0
- package/dist/transaction/coordination/targetConflict.js +103 -0
- package/dist/{coordination → transaction/coordination}/trace.d.ts +7 -18
- package/dist/{coordination → transaction/coordination}/trace.js +18 -25
- package/dist/transaction/durableWrites.d.ts +62 -0
- package/dist/{client → transaction}/durableWrites.js +28 -3
- package/dist/transaction/environment.d.ts +105 -0
- package/dist/transaction/environment.js +108 -0
- package/dist/{errorCodes.d.ts → transaction/errorCodes.d.ts} +11 -11
- package/dist/{errorCodes.js → transaction/errorCodes.js} +35 -12
- package/dist/{errors.d.ts → transaction/errors.d.ts} +37 -13
- package/dist/{errors.js → transaction/errors.js} +85 -16
- package/dist/transaction/index.d.ts +20 -0
- package/dist/transaction/index.js +20 -0
- package/dist/transaction/keys/index.d.ts +87 -0
- package/dist/transaction/keys/index.js +207 -0
- package/dist/transaction/log/syncDeltaRow.d.ts +158 -0
- package/dist/transaction/log/syncDeltaRow.js +95 -0
- package/dist/{sync/syncPosition.d.ts → transaction/logPosition.d.ts} +22 -8
- package/dist/{sync/syncPosition.js → transaction/logPosition.js} +15 -6
- package/dist/transaction/logger.d.ts +16 -0
- package/dist/transaction/logger.js +7 -0
- package/dist/transaction/observability.d.ts +53 -0
- package/dist/transaction/observability.js +19 -0
- package/dist/transaction/plugin.d.ts +192 -0
- package/dist/transaction/plugin.js +87 -0
- package/dist/{policy → transaction/policy}/types.d.ts +3 -3
- package/dist/{policy → transaction/policy}/types.js +2 -0
- package/dist/transaction/resources/httpResources.d.ts +266 -0
- package/dist/transaction/resources/httpResources.js +7 -0
- package/dist/transaction/resources/modelOperations.d.ts +319 -0
- package/dist/transaction/resources/modelOperations.js +12 -0
- package/dist/transaction/resources/mutationOptions.d.ts +66 -0
- package/dist/transaction/resources/mutationOptions.js +9 -0
- package/dist/transaction/resources/where.d.ts +85 -0
- package/dist/transaction/resources/where.js +70 -0
- package/dist/{client → transaction/resources}/writeOptionsSchema.d.ts +2 -6
- package/dist/{client → transaction/resources}/writeOptionsSchema.js +9 -5
- package/dist/{schema → transaction/schema}/field.d.ts +5 -5
- package/dist/{schema → transaction/schema}/field.js +5 -5
- package/dist/transaction/schema/loadStrategy.d.ts +45 -0
- package/dist/transaction/schema/loadStrategy.js +46 -0
- package/dist/{schema → transaction/schema}/model.d.ts +50 -35
- package/dist/{schema → transaction/schema}/model.js +30 -20
- package/dist/transaction/schema/openapi.d.ts +57 -0
- package/dist/transaction/schema/openapi.js +340 -0
- package/dist/{schema → transaction/schema}/relation.d.ts +14 -14
- package/dist/{schema → transaction/schema}/relation.js +7 -7
- package/dist/{schema → transaction/schema}/residency.d.ts +0 -9
- package/dist/{schema → transaction/schema}/residency.js +0 -5
- package/dist/{schema → transaction/schema}/roles.d.ts +5 -5
- package/dist/{schema → transaction/schema}/roles.js +5 -5
- package/dist/{schema → transaction/schema}/schema.d.ts +12 -10
- package/dist/{schema → transaction/schema}/schema.js +4 -3
- package/dist/{schema → transaction/schema}/tenancy.d.ts +1 -1
- package/dist/{schema → transaction/schema}/tenancy.js +7 -4
- package/dist/transaction/transactionLayer.d.ts +82 -0
- package/dist/transaction/transactionLayer.js +24 -0
- package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.d.ts +4 -5
- package/dist/{transactions → transaction/transactions/settlement}/commitEnvelope.js +9 -13
- package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.d.ts +9 -2
- package/dist/{transactions → transaction/transactions/settlement}/httpCommitEnvelope.js +5 -9
- package/dist/{transactions/durableWriteStore.d.ts → transaction/transactions/settlement/pendingWrite.d.ts} +10 -36
- package/dist/transaction/transactions/settlement/pendingWrite.js +20 -0
- package/dist/transaction/transport/commitFrames.d.ts +90 -0
- package/dist/transaction/transport/commitFrames.js +134 -0
- package/dist/transaction/transport/connectionManager.d.ts +215 -0
- package/dist/transaction/transport/connectionManager.js +673 -0
- package/dist/transaction/transport/credentialLifecycle.d.ts +177 -0
- package/dist/transaction/transport/credentialLifecycle.js +324 -0
- package/dist/{sync → transaction/transport}/heartbeat.d.ts +3 -1
- package/dist/{sync → transaction/transport}/heartbeat.js +6 -4
- package/dist/{client → transaction/transport}/httpClient.d.ts +59 -16
- package/dist/{client → transaction/transport}/httpClient.js +5 -5
- package/dist/transaction/transport/httpOptions.d.ts +33 -0
- package/dist/transaction/transport/httpOptions.js +12 -0
- package/dist/{client → transaction/transport}/httpTransport.js +171 -85
- package/dist/{sync/NetworkProbe.d.ts → transaction/transport/networkProbe.d.ts} +7 -4
- package/dist/{sync/NetworkProbe.js → transaction/transport/networkProbe.js} +14 -13
- package/dist/transaction/transport/wsFrameHandlers.d.ts +128 -0
- package/dist/transaction/transport/wsFrameHandlers.js +429 -0
- package/dist/transaction/transport/wsTransport.d.ts +576 -0
- package/dist/transaction/transport/wsTransport.js +1017 -0
- package/dist/transaction/types/assertExact.d.ts +17 -0
- package/dist/transaction/types/assertExact.js +1 -0
- package/dist/{types → transaction/types}/global.d.ts +17 -2
- package/dist/{types → transaction/types}/global.js +2 -1
- package/dist/{types → transaction/types}/index.d.ts +14 -46
- package/dist/{types → transaction/types}/index.js +7 -16
- package/dist/{types → transaction/types}/streams.d.ts +63 -45
- package/dist/{utils → transaction/utils}/json.d.ts +18 -0
- package/dist/transaction/utils/json.js +276 -0
- package/dist/transaction/wire/accountResponses.d.ts +351 -0
- package/dist/transaction/wire/accountResponses.js +255 -0
- package/dist/transaction/wire/auth.d.ts +49 -0
- package/dist/transaction/wire/auth.js +57 -0
- package/dist/transaction/wire/claimEvent.d.ts +76 -0
- package/dist/transaction/wire/claimEvent.js +73 -0
- package/dist/transaction/wire/claims.d.ts +463 -0
- package/dist/transaction/wire/claims.js +229 -0
- package/dist/{wire → transaction/wire}/commit.d.ts +125 -193
- package/dist/{wire → transaction/wire}/commit.js +68 -47
- package/dist/{wire → transaction/wire}/delta.d.ts +66 -17
- package/dist/{wire → transaction/wire}/delta.js +37 -13
- package/dist/transaction/wire/errorEnvelope.d.ts +72 -0
- package/dist/{wire → transaction/wire}/errorEnvelope.js +36 -5
- package/dist/transaction/wire/feedCursor.d.ts +60 -0
- package/dist/transaction/wire/feedCursor.js +82 -0
- package/dist/transaction/wire/feedEvent.d.ts +177 -0
- package/dist/transaction/wire/feedEvent.js +39 -0
- package/dist/transaction/wire/frames.d.ts +194 -0
- package/dist/transaction/wire/frames.js +50 -0
- package/dist/transaction/wire/inboundFrames.d.ts +552 -0
- package/dist/transaction/wire/inboundFrames.js +116 -0
- package/dist/transaction/wire/index.d.ts +50 -0
- package/dist/transaction/wire/index.js +74 -0
- package/dist/{wire → transaction/wire}/listEnvelope.d.ts +13 -14
- package/dist/transaction/wire/listEnvelope.js +42 -0
- package/dist/transaction/wire/modelResponses.d.ts +85 -0
- package/dist/transaction/wire/modelResponses.js +43 -0
- package/dist/transactions/{TransactionQueue.d.ts → mutations/MutationQueue.d.ts} +79 -38
- package/dist/transactions/{TransactionQueue.js → mutations/MutationQueue.js} +110 -59
- package/dist/transactions/{TransactionStore.d.ts → mutations/MutationStore.d.ts} +8 -8
- package/dist/transactions/{TransactionStore.js → mutations/MutationStore.js} +2 -2
- package/dist/transactions/{coalesceRules.d.ts → mutations/coalesceRules.d.ts} +10 -10
- package/dist/transactions/{coalesceRules.js → mutations/coalesceRules.js} +1 -1
- package/dist/transactions/mutations/commitLatency.d.ts +52 -0
- package/dist/transactions/mutations/commitLatency.js +130 -0
- package/dist/transactions/{commitOutboxStore.d.ts → mutations/commitOutboxStore.d.ts} +1 -5
- package/dist/transactions/{commitOutboxStore.js → mutations/commitOutboxStore.js} +1 -1
- package/dist/transactions/{commitPayload.d.ts → mutations/commitPayload.d.ts} +16 -15
- package/dist/transactions/{commitPayload.js → mutations/commitPayload.js} +12 -12
- package/dist/transactions/{deltaConfirmation.d.ts → mutations/deltaConfirmation.d.ts} +11 -11
- package/dist/transactions/{deltaConfirmation.js → mutations/deltaConfirmation.js} +7 -7
- package/dist/transactions/mutations/durableWriteStore.d.ts +14 -0
- package/dist/transactions/mutations/durableWriteStore.js +12 -0
- package/dist/transactions/{optimisticApply.d.ts → mutations/optimisticApply.d.ts} +7 -7
- package/dist/transactions/{replayValidation.d.ts → mutations/replayValidation.d.ts} +3 -3
- package/dist/transactions/{replayValidation.js → mutations/replayValidation.js} +4 -3
- package/dist/utils/mobxSetup.d.ts +1 -1
- package/dist/utils/mobxSetup.js +5 -2
- package/dist/webhooks/events.d.ts +2 -2
- package/dist/wire/index.d.ts +1 -34
- package/dist/wire/index.js +8 -49
- package/docs/agent-messaging.md +3 -3
- package/docs/agents.md +19 -12
- package/docs/api-keys.md +8 -4
- package/docs/api.md +22 -18
- package/docs/audit.md +2 -0
- package/docs/cli.md +31 -3
- package/docs/client-behavior.md +8 -6
- package/docs/concurrency-convention.md +30 -24
- package/docs/coordination.md +48 -38
- package/docs/data-sources.md +3 -1
- package/docs/debugging.md +5 -3
- package/docs/deployment.md +267 -0
- package/docs/examples/agent-human.md +49 -42
- package/docs/examples/ai-sdk-tool.md +69 -44
- package/docs/examples/existing-python-backend.md +8 -6
- package/docs/examples/nextjs.md +129 -47
- package/docs/examples/scoped-agent.md +45 -44
- package/docs/examples/server-agent.md +46 -26
- package/docs/groups.md +32 -29
- package/docs/guarantees.md +4 -2
- package/docs/how-it-works.md +9 -7
- package/docs/idempotency.md +126 -0
- package/docs/identity.md +58 -54
- package/docs/index.md +172 -86
- package/docs/integration-guide.md +17 -16
- package/docs/interaction-model.md +6 -4
- package/docs/mcp.md +41 -16
- package/docs/migration.md +63 -5
- package/docs/operating-on-your-database.md +3 -1
- package/docs/projects.md +2 -0
- package/docs/quickstart.md +22 -5
- package/docs/react.md +12 -10
- package/docs/schema-contract.md +5 -3
- package/docs/session-settings.md +108 -0
- package/docs/sessions.md +3 -1
- package/docs/webhooks.md +3 -1
- package/llms.txt +47 -17
- package/package.json +10 -8
- package/dist/agent/Agent.d.ts +0 -366
- package/dist/agent/Agent.js +0 -514
- package/dist/agent/index.d.ts +0 -115
- package/dist/agent/index.js +0 -128
- package/dist/agent/session.d.ts +0 -93
- package/dist/agent/session.js +0 -149
- package/dist/agent/types.d.ts +0 -68
- package/dist/agent/types.js +0 -9
- package/dist/client/durableWrites.d.ts +0 -21
- package/dist/coordination/schema.d.ts +0 -722
- package/dist/schema/openapi.d.ts +0 -29
- package/dist/schema/openapi.js +0 -124
- package/dist/transactions/durableWriteStore.js +0 -30
- package/dist/utils/json.js +0 -88
- package/dist/wire/errorEnvelope.d.ts +0 -55
- package/dist/wire/frames.d.ts +0 -197
- package/dist/wire/frames.js +0 -49
- package/dist/wire/listEnvelope.js +0 -18
- /package/dist/{client → transaction/auth}/credentialEndpoint.d.ts +0 -0
- /package/dist/{client → transaction/auth}/credentialEndpoint.js +0 -0
- /package/dist/{auth → transaction/auth}/credentialPolicy.d.ts +0 -0
- /package/dist/{auth → transaction/auth}/credentialPolicy.js +0 -0
- /package/dist/{auth → transaction/auth}/credentialSource.js +0 -0
- /package/dist/{client → transaction/auth}/hostedEndpoints.d.ts +0 -0
- /package/dist/{client → transaction/auth}/hostedEndpoints.js +0 -0
- /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.d.ts +0 -0
- /package/dist/{client → transaction/coordination}/claimHeartbeatLoop.js +0 -0
- /package/dist/{client → transaction}/persistence.d.ts +0 -0
- /package/dist/{client → transaction}/persistence.js +0 -0
- /package/dist/{client → transaction/resources}/functionalUpdate.d.ts +0 -0
- /package/dist/{client → transaction/resources}/functionalUpdate.js +0 -0
- /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.d.ts +0 -0
- /package/dist/{transactions → transaction/transactions/settlement}/idempotencyKey.js +0 -0
- /package/dist/{client → transaction/transport}/httpTransport.d.ts +0 -0
- /package/dist/{types → transaction/types}/modelData.d.ts +0 -0
- /package/dist/{types → transaction/types}/modelData.js +0 -0
- /package/dist/{types → transaction/types}/participant.d.ts +0 -0
- /package/dist/{types → transaction/types}/participant.js +0 -0
- /package/dist/{types → transaction/types}/streams.js +0 -0
- /package/dist/{utils → transaction/utils}/asyncIterator.d.ts +0 -0
- /package/dist/{utils → transaction/utils}/asyncIterator.js +0 -0
- /package/dist/{utils → transaction/utils}/duration.d.ts +0 -0
- /package/dist/{utils → transaction/utils}/duration.js +0 -0
- /package/dist/{wire → transaction/wire}/bootstrapReason.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/bootstrapReason.js +0 -0
- /package/dist/{wire → transaction/wire}/protocol.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/protocol.js +0 -0
- /package/dist/{wire → transaction/wire}/protocolVersion.d.ts +0 -0
- /package/dist/{wire → transaction/wire}/protocolVersion.js +0 -0
- /package/dist/transactions/{UnconfirmedWrites.d.ts → mutations/UnconfirmedWrites.d.ts} +0 -0
- /package/dist/transactions/{UnconfirmedWrites.js → mutations/UnconfirmedWrites.js} +0 -0
- /package/dist/transactions/{optimisticApply.js → mutations/optimisticApply.js} +0 -0
package/dist/Database.d.ts
CHANGED
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { type DatabaseInfo, type WorkspaceMetadata } from './core/DatabaseManager.js';
|
|
9
9
|
import { ModelRegistry } from './ModelRegistry.js';
|
|
10
|
-
import { LoadStrategy } from './types/index.js';
|
|
10
|
+
import { LoadStrategy } from './transaction/types/index.js';
|
|
11
11
|
import type { BootstrapFetcher, BootstrapData } from './sync/BootstrapFetcher.js';
|
|
12
12
|
import { InMemoryObjectStore } from './adapters/inMemoryStorage.js';
|
|
13
|
+
import type { SyncDeltaAction } from './transaction/wire/delta.js';
|
|
14
|
+
import type { OnStaleMode } from './transaction/coordination/schema.js';
|
|
15
|
+
import type { BootstrapType } from './transaction/types/index.js';
|
|
13
16
|
/** Generic record type for model data */
|
|
14
17
|
type ModelData = Record<string, unknown>;
|
|
15
18
|
/** Persisted mutation in a transaction */
|
|
@@ -20,7 +23,7 @@ interface PersistedMutation {
|
|
|
20
23
|
timestamp: string;
|
|
21
24
|
writeOptions?: {
|
|
22
25
|
readAt?: number | null;
|
|
23
|
-
onStale?:
|
|
26
|
+
onStale?: OnStaleMode | null;
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
/** Persisted transaction for offline/retry support.
|
|
@@ -45,20 +48,7 @@ interface PersistedTransaction {
|
|
|
45
48
|
};
|
|
46
49
|
[key: string]: unknown;
|
|
47
50
|
}
|
|
48
|
-
|
|
49
|
-
* How a session establishes its baseline state at startup.
|
|
50
|
-
*
|
|
51
|
-
* 'full' — Fetch a complete snapshot from the server, clear the local store,
|
|
52
|
-
* load the snapshot, and adopt its `lastSyncId`.
|
|
53
|
-
*
|
|
54
|
-
* 'partial' — Fetch only the deltas since the stored `lastSyncId` and apply
|
|
55
|
-
* them on top of the existing local data.
|
|
56
|
-
*
|
|
57
|
-
* 'local' — Skip the server entirely: hydrate the {@link InstanceCache} from the
|
|
58
|
-
* local store, connect the WebSocket with the stored `lastSyncId`, and
|
|
59
|
-
* receive deltas from there onward. Used when offline with valid local data.
|
|
60
|
-
*/
|
|
61
|
-
export type BootstrapType = 'full' | 'partial' | 'local';
|
|
51
|
+
export type { BootstrapType };
|
|
62
52
|
export interface BootstrapRequirements {
|
|
63
53
|
type: BootstrapType;
|
|
64
54
|
modelsToLoad: string[];
|
|
@@ -191,7 +181,7 @@ export declare class Database {
|
|
|
191
181
|
*
|
|
192
182
|
* Update deltas carry only the changed fields, so they are merged onto the
|
|
193
183
|
* existing record rather than replacing it. That preserves fields the delta
|
|
194
|
-
* omits (such as
|
|
184
|
+
* omits (such as reportId or title), and an explicit null is kept as a value,
|
|
195
185
|
* clearing that field.
|
|
196
186
|
*/
|
|
197
187
|
processDelta(delta: {
|
|
@@ -202,7 +192,7 @@ export declare class Database {
|
|
|
202
192
|
* but the switch returns a no-op verify if one slips through (e.g.
|
|
203
193
|
* replayed from the bootstrap queue) rather than crashing the engine.
|
|
204
194
|
*/
|
|
205
|
-
actionType:
|
|
195
|
+
actionType: SyncDeltaAction;
|
|
206
196
|
modelName: string;
|
|
207
197
|
modelId: string;
|
|
208
198
|
data: ModelData | null;
|
|
@@ -235,7 +225,7 @@ export declare class Database {
|
|
|
235
225
|
* shouldn't reach batch processing, but the switch inside returns
|
|
236
226
|
* no-op verify for them if one slips through.
|
|
237
227
|
*/
|
|
238
|
-
actionType:
|
|
228
|
+
actionType: SyncDeltaAction;
|
|
239
229
|
modelName: string;
|
|
240
230
|
modelId: string;
|
|
241
231
|
data: ModelData | null;
|
|
@@ -319,10 +309,6 @@ export declare class Database {
|
|
|
319
309
|
database: DatabaseInfo | null;
|
|
320
310
|
stores: {
|
|
321
311
|
totalStores: number;
|
|
322
|
-
storeTypes: {
|
|
323
|
-
full: number;
|
|
324
|
-
partial: number;
|
|
325
|
-
};
|
|
326
312
|
readiness: {
|
|
327
313
|
ready: number;
|
|
328
314
|
notReady: number;
|
|
@@ -347,4 +333,3 @@ export declare class Database {
|
|
|
347
333
|
includeWriteJournal?: boolean;
|
|
348
334
|
}): Promise<void>;
|
|
349
335
|
}
|
|
350
|
-
export {};
|
package/dist/Database.js
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
import { DatabaseManager } from './core/DatabaseManager.js';
|
|
9
9
|
import { StoreManager } from './core/StoreManager.js';
|
|
10
10
|
import { ModelRegistry } from './ModelRegistry.js';
|
|
11
|
-
import { LoadStrategy } from './types/index.js';
|
|
11
|
+
import { LoadStrategy } from './transaction/types/index.js';
|
|
12
12
|
import { getContext } from './context.js';
|
|
13
|
-
import { AbloConnectionError, AbloValidationError } from './errors.js';
|
|
13
|
+
import { AbloConnectionError, AbloValidationError } from './transaction/errors.js';
|
|
14
14
|
import { InMemoryObjectStore } from './adapters/inMemoryStorage.js';
|
|
15
|
-
import {
|
|
15
|
+
import { logPositionSchema } from './transaction/logPosition.js';
|
|
16
16
|
import { highestPersistedPrefixSyncId } from './sync/persistedPrefix.js';
|
|
17
17
|
/**
|
|
18
18
|
* Request identity excludes local timing metadata for re-entrant seals: a
|
|
@@ -208,8 +208,8 @@ export class Database {
|
|
|
208
208
|
// Register database
|
|
209
209
|
await this.databaseManager.registerDatabase(this.currentDbInfo);
|
|
210
210
|
// Open workspace database
|
|
211
|
-
this.workspaceDb = await this.databaseManager.openWorkspaceDatabase(this.currentDbInfo, async (db
|
|
212
|
-
await this.storeManager.createStores(db
|
|
211
|
+
this.workspaceDb = await this.databaseManager.openWorkspaceDatabase(this.currentDbInfo, async (db) => {
|
|
212
|
+
await this.storeManager.createStores(db);
|
|
213
213
|
});
|
|
214
214
|
// Initialize stores
|
|
215
215
|
await this.storeManager.initializeStores(this.workspaceDb);
|
|
@@ -328,7 +328,7 @@ export class Database {
|
|
|
328
328
|
// (a corrupted negative/float cursor would previously pass `|| 0`,
|
|
329
329
|
// which only catches falsy, and get sent to the server as the resume
|
|
330
330
|
// point). Invalid → 0 → full bootstrap, the safe degradation.
|
|
331
|
-
const metadataLastSyncId =
|
|
331
|
+
const metadataLastSyncId = logPositionSchema.shape.persisted.safeParse(metadata?.lastSyncId).data ?? 0;
|
|
332
332
|
const dataAge = metadata?.updatedAt ? Date.now() - metadata.updatedAt.getTime() : Infinity;
|
|
333
333
|
// ── Cache-validity check ─────────────────────────────────────
|
|
334
334
|
//
|
|
@@ -444,13 +444,18 @@ export class Database {
|
|
|
444
444
|
let deltasApplied = 0;
|
|
445
445
|
let deltaResults;
|
|
446
446
|
if (deltas.length > 0) {
|
|
447
|
-
//
|
|
447
|
+
// Narrow the wire delta to what processDelta reads. The field names
|
|
448
|
+
// are the wire's own — the only change is `id` becoming `syncId`.
|
|
449
|
+
// A group-change frame carries its payload as a JSON string, decoded
|
|
450
|
+
// here exactly as the live delta path does in BaseSyncedStore.
|
|
448
451
|
const formattedDeltas = deltas.map((delta) => ({
|
|
449
452
|
syncId: delta.id,
|
|
450
|
-
actionType: delta.
|
|
453
|
+
actionType: delta.actionType,
|
|
451
454
|
modelName: delta.modelName,
|
|
452
|
-
modelId: delta.
|
|
453
|
-
data: delta.data
|
|
455
|
+
modelId: delta.modelId,
|
|
456
|
+
data: typeof delta.data === 'string'
|
|
457
|
+
? JSON.parse(delta.data)
|
|
458
|
+
: delta.data,
|
|
454
459
|
}));
|
|
455
460
|
// Use batch processing for better performance
|
|
456
461
|
const batch = await this.processDeltaBatch(formattedDeltas);
|
|
@@ -520,6 +525,13 @@ export class Database {
|
|
|
520
525
|
});
|
|
521
526
|
}
|
|
522
527
|
}
|
|
528
|
+
// The model is marked persisted below whether or not every item landed,
|
|
529
|
+
// because a partial store is still what the next sync reconciles
|
|
530
|
+
// against. Counted and surfaced here so a partial does not read as a
|
|
531
|
+
// clean bootstrap.
|
|
532
|
+
if (writeErrors > 0) {
|
|
533
|
+
getContext().observability.breadcrumb(`Stored ${modelName} with ${writeErrors} of ${modelData.length} items dropped`, 'sync.database', 'warning');
|
|
534
|
+
}
|
|
523
535
|
// Mark model as persisted after successful write
|
|
524
536
|
try {
|
|
525
537
|
await this.setModelPersisted(modelName, true);
|
|
@@ -569,7 +581,7 @@ export class Database {
|
|
|
569
581
|
*
|
|
570
582
|
* Update deltas carry only the changed fields, so they are merged onto the
|
|
571
583
|
* existing record rather than replacing it. That preserves fields the delta
|
|
572
|
-
* omits (such as
|
|
584
|
+
* omits (such as reportId or title), and an explicit null is kept as a value,
|
|
573
585
|
* clearing that field.
|
|
574
586
|
*/
|
|
575
587
|
async processDelta(delta) {
|
|
@@ -636,7 +648,7 @@ export class Database {
|
|
|
636
648
|
const existing = await store.get(modelId);
|
|
637
649
|
// Skip the update when there's no existing record to merge with:
|
|
638
650
|
// building a record from partial update data would corrupt it
|
|
639
|
-
// (missing
|
|
651
|
+
// (missing reportId, and so on).
|
|
640
652
|
if (!existing) {
|
|
641
653
|
getContext().observability.breadcrumb('Skipping UPDATE delta - no existing record to merge with', 'sync.database', 'warning', {
|
|
642
654
|
modelName,
|
|
@@ -712,10 +724,14 @@ export class Database {
|
|
|
712
724
|
case 'S':
|
|
713
725
|
getContext().observability.breadcrumb(`Group membership delta (${actionType}) reached processDelta — should be handled upstream`, 'sync.database', 'warning', { modelName, modelId: modelId.slice(0, 12), actionType });
|
|
714
726
|
return { action: 'verify', modelName, modelId, data: null };
|
|
715
|
-
default:
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
727
|
+
default: {
|
|
728
|
+
// The switch above is exhaustive over the declared action types, so
|
|
729
|
+
// this branch is only reachable when a value escapes the type — hence
|
|
730
|
+
// stringifying whatever actually arrived rather than the `never`.
|
|
731
|
+
const _exhaustive = actionType;
|
|
732
|
+
void _exhaustive;
|
|
733
|
+
throw new AbloValidationError(`Unknown action type: ${JSON.stringify(actionType)}`, { code: 'db_unknown_action_type' });
|
|
734
|
+
}
|
|
719
735
|
}
|
|
720
736
|
}
|
|
721
737
|
/**
|
|
@@ -826,8 +842,7 @@ export class Database {
|
|
|
826
842
|
// entity has an equal or higher sync id.
|
|
827
843
|
if (delta.actionType === 'U' ||
|
|
828
844
|
delta.actionType === 'I' ||
|
|
829
|
-
delta.actionType === 'C'
|
|
830
|
-
delta.actionType === 'M') {
|
|
845
|
+
delta.actionType === 'C') {
|
|
831
846
|
const key = `${delta.modelName}:${delta.modelId}`;
|
|
832
847
|
const deleteSyncId = deleteSyncIds.get(key);
|
|
833
848
|
if (deleteSyncId !== undefined) {
|
|
@@ -892,7 +907,7 @@ export class Database {
|
|
|
892
907
|
}
|
|
893
908
|
}
|
|
894
909
|
}
|
|
895
|
-
catch
|
|
910
|
+
catch {
|
|
896
911
|
getContext().observability.breadcrumb(`Batch read failed for ${modelName}, falling back to individual reads`, 'sync.database', 'warning');
|
|
897
912
|
// Fallback: mark all as missing for self-healing
|
|
898
913
|
for (const id of updateIds) {
|
|
@@ -991,7 +1006,7 @@ export class Database {
|
|
|
991
1006
|
}
|
|
992
1007
|
// Skip the update when there's no existing record to merge with:
|
|
993
1008
|
// building a record from partial update data would corrupt it
|
|
994
|
-
// (missing
|
|
1009
|
+
// (missing reportId, and so on).
|
|
995
1010
|
if (!existing) {
|
|
996
1011
|
getContext().observability.breadcrumb('Batch: Skipping UPDATE delta - no existing record', 'sync.database', 'warning', {
|
|
997
1012
|
modelName,
|
|
@@ -1063,7 +1078,7 @@ export class Database {
|
|
|
1063
1078
|
}
|
|
1064
1079
|
}
|
|
1065
1080
|
catch (err) {
|
|
1066
|
-
// Surface the IDB error directly — `
|
|
1081
|
+
// Surface the IDB error directly — `captureMutationFailure`
|
|
1067
1082
|
// routes to Sentry, but during interactive debugging the console
|
|
1068
1083
|
// needs to show the specific failure (e.g. `ConstraintError`,
|
|
1069
1084
|
// `DataError`, `AbortError`) so we can find what's wrong with
|
|
@@ -1082,7 +1097,7 @@ export class Database {
|
|
|
1082
1097
|
: typeof delta.data,
|
|
1083
1098
|
})),
|
|
1084
1099
|
});
|
|
1085
|
-
getContext().observability.
|
|
1100
|
+
getContext().observability.captureMutationFailure({
|
|
1086
1101
|
context: 'batch-indexeddb-operation',
|
|
1087
1102
|
modelName,
|
|
1088
1103
|
error: idbErr,
|
package/dist/InstanceCache.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Model } from './Model.js';
|
|
10
10
|
import { ModelRegistry } from './ModelRegistry.js';
|
|
11
|
-
import { ModelScope } from './types/index.js';
|
|
11
|
+
import { ModelScope } from './transaction/types/index.js';
|
|
12
12
|
import { ViewRegistry } from './core/ViewRegistry.js';
|
|
13
13
|
import { QueryView, type QueryViewOptions } from './core/QueryView.js';
|
|
14
14
|
/** Constructor type for Model subclasses - uses abstract to handle variance */
|
|
@@ -50,6 +50,27 @@ export declare class InstanceCache {
|
|
|
50
50
|
constructor(config?: PoolConfig, modelRegistry?: ModelRegistry);
|
|
51
51
|
private resolveModel;
|
|
52
52
|
get<T extends Model = Model>(id: string): T | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Look a row up **within one model**.
|
|
55
|
+
*
|
|
56
|
+
* The pool is a single id space: `get(id)` returns whatever row carries that
|
|
57
|
+
* id, whatever model it belongs to. That is the correct storage shape — ids
|
|
58
|
+
* are globally unique, the same premise as Relay's Global Object
|
|
59
|
+
* Identification — but it means an *untyped* lookup cannot stand in for a
|
|
60
|
+
* typed one. Apollo and EmberData avoid the question by keying their identity
|
|
61
|
+
* maps on `Type:id`; with unique ids the equivalent guarantee comes from
|
|
62
|
+
* stating the expected model at the lookup instead.
|
|
63
|
+
*
|
|
64
|
+
* Returns `undefined` for a row belonging to another model: from the asking
|
|
65
|
+
* model's perspective that id is simply absent. Callers that must tell "not
|
|
66
|
+
* here" apart from "here, but another model's" should compare against
|
|
67
|
+
* {@link get}.
|
|
68
|
+
*
|
|
69
|
+
* Prefer this over `get()` anywhere the caller knows which model it wants —
|
|
70
|
+
* `get()` returning another model's row has caused three product bugs, most
|
|
71
|
+
* recently a resize gesture that reverted after every commit.
|
|
72
|
+
*/
|
|
73
|
+
getOfType<T extends Model = Model>(id: string, modelName: string): T | undefined;
|
|
53
74
|
/**
|
|
54
75
|
* Add model with deduplication support
|
|
55
76
|
*/
|
|
@@ -97,7 +118,7 @@ export declare class InstanceCache {
|
|
|
97
118
|
* data. Cleaner than `createFromData({ __typename, ...data })` — the
|
|
98
119
|
* typename lives in the arg list, not hidden inside the data object.
|
|
99
120
|
*
|
|
100
|
-
* Used for optimistic local writes: `pool.create('
|
|
121
|
+
* Used for optimistic local writes: `pool.create('Section', { id, reportId, ... })`.
|
|
101
122
|
* For hydration from server deltas (where `__typename` already rides on
|
|
102
123
|
* the payload), use `createFromData(data)` directly — that path is kept
|
|
103
124
|
* because the wire format attaches the discriminator to the data itself.
|
|
@@ -178,8 +199,8 @@ export declare class InstanceCache {
|
|
|
178
199
|
* Register a foreign key field for indexing on a model type.
|
|
179
200
|
* Call once during app initialization (e.g., after model registration).
|
|
180
201
|
*
|
|
181
|
-
* Example: registerForeignKey('
|
|
182
|
-
* This enables getByForeignKey('
|
|
202
|
+
* Example: registerForeignKey('Block', 'sectionId')
|
|
203
|
+
* This enables getByForeignKey('Block', 'sectionId', someSectionId) → O(1) lookup
|
|
183
204
|
*/
|
|
184
205
|
registerForeignKey(modelName: string, fieldName: string): void;
|
|
185
206
|
/**
|
package/dist/InstanceCache.js
CHANGED
|
@@ -10,8 +10,8 @@ import { makeObservable, observable, action, computed, runInAction } from 'mobx'
|
|
|
10
10
|
import { Model } from './Model.js';
|
|
11
11
|
import { ModelRegistry } from './ModelRegistry.js';
|
|
12
12
|
import { getContext } from './context.js';
|
|
13
|
-
import { AbloValidationError } from './errors.js';
|
|
14
|
-
import { ModelScope } from './types/index.js';
|
|
13
|
+
import { AbloValidationError } from './transaction/errors.js';
|
|
14
|
+
import { ModelScope } from './transaction/types/index.js';
|
|
15
15
|
import { ViewRegistry } from './core/ViewRegistry.js';
|
|
16
16
|
import { QueryView } from './core/QueryView.js';
|
|
17
17
|
// Re-exported so `import { ModelScope } from './InstanceCache.js'` resolves
|
|
@@ -36,7 +36,7 @@ export class InstanceCache {
|
|
|
36
36
|
// reactivity source; there are no computed getters with conditional cache
|
|
37
37
|
// invalidation to get wrong.
|
|
38
38
|
// Foreign key indexes: Map<"ModelType:fieldName", Map<fieldValue, ObservableSet<modelId>>>
|
|
39
|
-
// Enables O(1) lookups like "all
|
|
39
|
+
// Enables O(1) lookups like "all Block models where sectionId = X"
|
|
40
40
|
// instead of scanning all models of a type and filtering.
|
|
41
41
|
foreignKeyIndexes = new Map();
|
|
42
42
|
// Registry of which fields to index: Map<modelName, fieldName[]>
|
|
@@ -187,6 +187,39 @@ export class InstanceCache {
|
|
|
187
187
|
this.metrics.hits++;
|
|
188
188
|
return model ?? undefined;
|
|
189
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Look a row up **within one model**.
|
|
192
|
+
*
|
|
193
|
+
* The pool is a single id space: `get(id)` returns whatever row carries that
|
|
194
|
+
* id, whatever model it belongs to. That is the correct storage shape — ids
|
|
195
|
+
* are globally unique, the same premise as Relay's Global Object
|
|
196
|
+
* Identification — but it means an *untyped* lookup cannot stand in for a
|
|
197
|
+
* typed one. Apollo and EmberData avoid the question by keying their identity
|
|
198
|
+
* maps on `Type:id`; with unique ids the equivalent guarantee comes from
|
|
199
|
+
* stating the expected model at the lookup instead.
|
|
200
|
+
*
|
|
201
|
+
* Returns `undefined` for a row belonging to another model: from the asking
|
|
202
|
+
* model's perspective that id is simply absent. Callers that must tell "not
|
|
203
|
+
* here" apart from "here, but another model's" should compare against
|
|
204
|
+
* {@link get}.
|
|
205
|
+
*
|
|
206
|
+
* Prefer this over `get()` anywhere the caller knows which model it wants —
|
|
207
|
+
* `get()` returning another model's row has caused three product bugs, most
|
|
208
|
+
* recently a resize gesture that reverted after every commit.
|
|
209
|
+
*/
|
|
210
|
+
// `T` appears only in the return position, which is normally a caller-chosen
|
|
211
|
+
// cast in disguise. It is sound here precisely because `modelName` is checked
|
|
212
|
+
// at runtime below before the row is handed back, so the caller's expected
|
|
213
|
+
// type and the row's registered identity cannot disagree.
|
|
214
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
215
|
+
getOfType(id, modelName) {
|
|
216
|
+
const model = this.get(id);
|
|
217
|
+
if (!model)
|
|
218
|
+
return undefined;
|
|
219
|
+
// Checked, so the assertion below is sound: `typeIndex` and
|
|
220
|
+
// `getModelName()` are the same registered-name identity.
|
|
221
|
+
return model.getModelName() === modelName ? model : undefined;
|
|
222
|
+
}
|
|
190
223
|
/**
|
|
191
224
|
* Add model with deduplication support
|
|
192
225
|
*/
|
|
@@ -341,13 +374,13 @@ export class InstanceCache {
|
|
|
341
374
|
this.addToTypeIndex(id, modelType);
|
|
342
375
|
// Populate the foreign-key indexes. The single-item `add()` path
|
|
343
376
|
// does this; `addBatch()` used to skip it, which meant every
|
|
344
|
-
//
|
|
345
|
-
// loader (`
|
|
377
|
+
// block / ledger cell / message that came in through a bulk
|
|
378
|
+
// loader (`ensureReportBlocks`, `prefetchSectionBlocks`, bootstrap
|
|
346
379
|
// hydration) was in the pool but invisible to `hasMany` lookups
|
|
347
|
-
// — `
|
|
380
|
+
// — `section.blocks` returned `[]` until the user clicked a block
|
|
348
381
|
// and something else ran a non-batch `add` that happened to
|
|
349
382
|
// populate the FK index as a side effect. The UX symptom was
|
|
350
|
-
// "
|
|
383
|
+
// "sections show empty until you click on one." Adding this one
|
|
351
384
|
// line closes the gap.
|
|
352
385
|
this.addToForeignKeyIndex(id, model, modelType);
|
|
353
386
|
this.metrics.additions++;
|
|
@@ -461,7 +494,7 @@ export class InstanceCache {
|
|
|
461
494
|
// FK cleanup silently no-ops — leaving ghost ids in the FK index.
|
|
462
495
|
// That causes `getByForeignKey(..., parentId)` to report
|
|
463
496
|
// `matched > returned` (dropped-no-entry) and, on the UI, keeps the
|
|
464
|
-
// stale
|
|
497
|
+
// stale block visible until the next reload rebuilds the index
|
|
465
498
|
// from fresh data. Do the FK/type cleanup first, then delete the
|
|
466
499
|
// entry.
|
|
467
500
|
runInAction(() => {
|
|
@@ -598,7 +631,7 @@ export class InstanceCache {
|
|
|
598
631
|
* data. Cleaner than `createFromData({ __typename, ...data })` — the
|
|
599
632
|
* typename lives in the arg list, not hidden inside the data object.
|
|
600
633
|
*
|
|
601
|
-
* Used for optimistic local writes: `pool.create('
|
|
634
|
+
* Used for optimistic local writes: `pool.create('Section', { id, reportId, ... })`.
|
|
602
635
|
* For hydration from server deltas (where `__typename` already rides on
|
|
603
636
|
* the payload), use `createFromData(data)` directly — that path is kept
|
|
604
637
|
* because the wire format attaches the discriminator to the data itself.
|
|
@@ -643,7 +676,7 @@ export class InstanceCache {
|
|
|
643
676
|
existing.updateFromData(data);
|
|
644
677
|
return existing;
|
|
645
678
|
}
|
|
646
|
-
// Different type with same ID - this is a shared PK scenario (e.g.,
|
|
679
|
+
// Different type with same ID - this is a shared PK scenario (e.g., two models sharing one row id)
|
|
647
680
|
// Don't return existing, create new model (will use composite key for storage)
|
|
648
681
|
}
|
|
649
682
|
// Log model creation attempt
|
|
@@ -658,7 +691,7 @@ export class InstanceCache {
|
|
|
658
691
|
// Internal construction failure — captured via observability below and
|
|
659
692
|
// re-fetched on resync; the stack is forensic → debug.
|
|
660
693
|
getContext().logger.debug(`[InstanceCache.createFromData] FAILED ${modelName}`, { errorMessage, stack: error instanceof Error ? error.stack : undefined });
|
|
661
|
-
getContext().observability.
|
|
694
|
+
getContext().observability.captureMutationFailure({
|
|
662
695
|
context: 'createFromData',
|
|
663
696
|
modelName,
|
|
664
697
|
modelId: data.id,
|
|
@@ -849,7 +882,7 @@ export class InstanceCache {
|
|
|
849
882
|
// caused silent data loss — any model actively being rendered
|
|
850
883
|
// through a schema-driven dynamic class (i.e., most of them)
|
|
851
884
|
// would be demoted, collected, and the next render's
|
|
852
|
-
// `weakRef.deref()` returned undefined, so
|
|
885
|
+
// `weakRef.deref()` returned undefined, so blocks / cells /
|
|
853
886
|
// messages "disappeared" after ~10 min of idle.
|
|
854
887
|
//
|
|
855
888
|
// The `hasObservedCollections()` guard used by the eviction
|
|
@@ -934,8 +967,8 @@ export class InstanceCache {
|
|
|
934
967
|
* Register a foreign key field for indexing on a model type.
|
|
935
968
|
* Call once during app initialization (e.g., after model registration).
|
|
936
969
|
*
|
|
937
|
-
* Example: registerForeignKey('
|
|
938
|
-
* This enables getByForeignKey('
|
|
970
|
+
* Example: registerForeignKey('Block', 'sectionId')
|
|
971
|
+
* This enables getByForeignKey('Block', 'sectionId', someSectionId) → O(1) lookup
|
|
939
972
|
*/
|
|
940
973
|
registerForeignKey(modelName, fieldName) {
|
|
941
974
|
const fields = this.foreignKeyConfig.get(modelName) ?? [];
|
|
@@ -977,7 +1010,7 @@ export class InstanceCache {
|
|
|
977
1010
|
// entry for this specific parent id (entity genuinely has no
|
|
978
1011
|
// children). These used to `console.warn` diagnostic dumps on every
|
|
979
1012
|
// call, which turned into hundreds of log lines per second during
|
|
980
|
-
// cursor hover / rapid re-renders on
|
|
1013
|
+
// cursor hover / rapid re-renders on a busy page. If a caller
|
|
981
1014
|
// needs visibility into "why is this empty," wire an opt-in
|
|
982
1015
|
// `logger.debug` at the specific call site rather than re-adding
|
|
983
1016
|
// a blanket warn here.
|
|
@@ -86,9 +86,9 @@ export declare class LazyReferenceCollection<T extends Model> {
|
|
|
86
86
|
* so any pool.remove invalidates the computed and re-renders the
|
|
87
87
|
* consumer with the deleted item gone.
|
|
88
88
|
*
|
|
89
|
-
* Without this, deleting a
|
|
90
|
-
* but the
|
|
91
|
-
* showing the deleted
|
|
89
|
+
* Without this, deleting a block would pool.remove() cleanly
|
|
90
|
+
* but the view — which reads `section.blocks.value` — would keep
|
|
91
|
+
* showing the deleted block until a full reload rebuilt the
|
|
92
92
|
* collection.
|
|
93
93
|
*/
|
|
94
94
|
get value(): T[];
|
|
@@ -7,7 +7,7 @@ import { makeObservable, observable, action, computed, onBecomeObserved, onBecom
|
|
|
7
7
|
import { Database } from './Database.js';
|
|
8
8
|
import { InstanceCache } from './InstanceCache.js';
|
|
9
9
|
import { getActiveRegistry } from './ModelRegistry.js';
|
|
10
|
-
import { AbloValidationError } from './errors.js';
|
|
10
|
+
import { AbloValidationError } from './transaction/errors.js';
|
|
11
11
|
/**
|
|
12
12
|
* A lazy-loaded one-to-many relationship between a parent {@link Model} and
|
|
13
13
|
* its children. It reads from the local store first and falls back to the
|
|
@@ -136,9 +136,9 @@ export class LazyReferenceCollection {
|
|
|
136
136
|
* so any pool.remove invalidates the computed and re-renders the
|
|
137
137
|
* consumer with the deleted item gone.
|
|
138
138
|
*
|
|
139
|
-
* Without this, deleting a
|
|
140
|
-
* but the
|
|
141
|
-
* showing the deleted
|
|
139
|
+
* Without this, deleting a block would pool.remove() cleanly
|
|
140
|
+
* but the view — which reads `section.blocks.value` — would keep
|
|
141
|
+
* showing the deleted block until a full reload rebuilt the
|
|
142
142
|
* collection.
|
|
143
143
|
*/
|
|
144
144
|
get value() {
|
package/dist/Model.d.ts
CHANGED
|
@@ -120,10 +120,10 @@ export declare abstract class Model {
|
|
|
120
120
|
* narrow the return to their concrete store type.
|
|
121
121
|
*
|
|
122
122
|
* @example
|
|
123
|
-
* // In a
|
|
124
|
-
* const store =
|
|
123
|
+
* // In a Section model getter
|
|
124
|
+
* const store = Section.getStore();
|
|
125
125
|
* if (!store) return [];
|
|
126
|
-
* return store.getByForeignKey<
|
|
126
|
+
* return store.getByForeignKey<Block>('Block', 'sectionId', this.id);
|
|
127
127
|
*/
|
|
128
128
|
static getStore<T extends SyncStoreRef = SyncStoreRef>(): T | null;
|
|
129
129
|
/**
|
|
@@ -159,7 +159,7 @@ export declare abstract class Model {
|
|
|
159
159
|
*
|
|
160
160
|
* This per-instance baseline is needed because application code can edit a
|
|
161
161
|
* model in two ways that coexist: a direct property write
|
|
162
|
-
* (`
|
|
162
|
+
* (`section.title = 'foo'`) and a recorded mutation. A design in which every
|
|
163
163
|
* write went through a single recorded path would not need it, since the
|
|
164
164
|
* last acknowledged state would already be the authoritative baseline.
|
|
165
165
|
*/
|
|
@@ -172,8 +172,8 @@ export declare abstract class Model {
|
|
|
172
172
|
* Capture a before-image for `keys` — the single source of truth for the
|
|
173
173
|
* "previous value" that undo inverses are built from. Both undo paths call
|
|
174
174
|
* this so they can never drift: the stream path
|
|
175
|
-
* (`
|
|
176
|
-
* (`
|
|
175
|
+
* (`MutationQueue.extractPreviousData`) and the manual-record path
|
|
176
|
+
* (`RecordingMutation.snapshotFields`).
|
|
177
177
|
*
|
|
178
178
|
* Resolution order per key:
|
|
179
179
|
* 1. `modifiedProperties.get(key).old` — first-old-wins pre-session
|
package/dist/Model.js
CHANGED
|
@@ -11,7 +11,7 @@ import { v4 as uuid } from 'uuid';
|
|
|
11
11
|
import { M1 } from './utils/mobxSetup.js';
|
|
12
12
|
import { getActiveRegistry, hasActiveRegistry } from './ModelRegistry.js';
|
|
13
13
|
import { getContext } from './context.js';
|
|
14
|
-
import { AbloValidationError } from './errors.js';
|
|
14
|
+
import { AbloValidationError } from './transaction/errors.js';
|
|
15
15
|
/**
|
|
16
16
|
* Validation error for model validation failures
|
|
17
17
|
*/
|
|
@@ -78,7 +78,7 @@ export class Model {
|
|
|
78
78
|
// A record that arrives WITH `createdAt` but WITHOUT `updatedAt` is
|
|
79
79
|
// server/IDB data whose update timestamp didn't survive the wire —
|
|
80
80
|
// falling back to "now" here fabricated an edit time for every such
|
|
81
|
-
// record on every bootstrap (the
|
|
81
|
+
// record on every bootstrap (the reports gallery sorted everything to
|
|
82
82
|
// "edited just now"). Fall back to createdAt instead; only a genuinely
|
|
83
83
|
// new local model (no dates at all) stamps the current time.
|
|
84
84
|
this.updatedAt = data.updatedAt
|
|
@@ -113,10 +113,10 @@ export class Model {
|
|
|
113
113
|
* narrow the return to their concrete store type.
|
|
114
114
|
*
|
|
115
115
|
* @example
|
|
116
|
-
* // In a
|
|
117
|
-
* const store =
|
|
116
|
+
* // In a Section model getter
|
|
117
|
+
* const store = Section.getStore();
|
|
118
118
|
* if (!store) return [];
|
|
119
|
-
* return store.getByForeignKey<
|
|
119
|
+
* return store.getByForeignKey<Block>('Block', 'sectionId', this.id);
|
|
120
120
|
*/
|
|
121
121
|
static getStore() {
|
|
122
122
|
return Model.store;
|
|
@@ -142,9 +142,9 @@ export class Model {
|
|
|
142
142
|
// Preserve the earliest captured `old` for this field until the entry
|
|
143
143
|
// is cleared (by `clearChanges` on sync-ack or by a mutator consuming
|
|
144
144
|
// it). Consecutive in-place mutations between mutator invocations —
|
|
145
|
-
// e.g. a drag loop writing `
|
|
145
|
+
// e.g. a drag loop writing `block.position = ...` on every frame —
|
|
146
146
|
// would otherwise overwrite `.old` with each frame's predecessor,
|
|
147
|
-
// destroying the pre-session baseline that `
|
|
147
|
+
// destroying the pre-session baseline that `RecordingMutation`
|
|
148
148
|
// relies on to record a correct undo inverse. `.new` always reflects
|
|
149
149
|
// the latest value so the transaction queue's `getChanges()` keeps
|
|
150
150
|
// sending the right payload to the server.
|
|
@@ -194,7 +194,7 @@ export class Model {
|
|
|
194
194
|
*
|
|
195
195
|
* This per-instance baseline is needed because application code can edit a
|
|
196
196
|
* model in two ways that coexist: a direct property write
|
|
197
|
-
* (`
|
|
197
|
+
* (`section.title = 'foo'`) and a recorded mutation. A design in which every
|
|
198
198
|
* write went through a single recorded path would not need it, since the
|
|
199
199
|
* last acknowledged state would already be the authoritative baseline.
|
|
200
200
|
*/
|
|
@@ -214,8 +214,8 @@ export class Model {
|
|
|
214
214
|
* Capture a before-image for `keys` — the single source of truth for the
|
|
215
215
|
* "previous value" that undo inverses are built from. Both undo paths call
|
|
216
216
|
* this so they can never drift: the stream path
|
|
217
|
-
* (`
|
|
218
|
-
* (`
|
|
217
|
+
* (`MutationQueue.extractPreviousData`) and the manual-record path
|
|
218
|
+
* (`RecordingMutation.snapshotFields`).
|
|
219
219
|
*
|
|
220
220
|
* Resolution order per key:
|
|
221
221
|
* 1. `modifiedProperties.get(key).old` — first-old-wins pre-session
|
package/dist/ModelRegistry.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* classes. References resolve lazily, so a model may declare a reference to
|
|
8
8
|
* another model that is registered later.
|
|
9
9
|
*/
|
|
10
|
-
import { type ModelMetadata, type PropertyMetadata, type ReferenceMetadata, LoadStrategy } from './types/index.js';
|
|
10
|
+
import { type ModelMetadata, type PropertyMetadata, type ReferenceMetadata, LoadStrategy } from './transaction/types/index.js';
|
|
11
11
|
import type { Model } from './Model.js';
|
|
12
12
|
import type { ConcreteModelConstructor } from './BaseSyncedStore.js';
|
|
13
13
|
/**
|
|
@@ -51,9 +51,9 @@ export interface SerializedReferenceMetadata extends Omit<ExtendedReferenceMetad
|
|
|
51
51
|
* child's pending transactions can be cancelled.
|
|
52
52
|
*/
|
|
53
53
|
export interface BackReferenceMetadata {
|
|
54
|
-
/** The parent model name (e.g., '
|
|
54
|
+
/** The parent model name (e.g., 'Report') */
|
|
55
55
|
parentModel: string;
|
|
56
|
-
/** The foreign key property on this model (e.g., '
|
|
56
|
+
/** The foreign key property on this model (e.g., 'reportId') */
|
|
57
57
|
foreignKey: string;
|
|
58
58
|
/** Whether to cascade-cancel transactions when parent is deleted */
|
|
59
59
|
cascadeDelete: boolean;
|
|
@@ -107,7 +107,7 @@ export declare class ModelRegistry {
|
|
|
107
107
|
* transactions for every child model that declares a back-reference to that
|
|
108
108
|
* parent.
|
|
109
109
|
*
|
|
110
|
-
* @param childModelName - The model that holds a foreign key to the parent (e.g., '
|
|
110
|
+
* @param childModelName - The model that holds a foreign key to the parent (e.g., 'Section')
|
|
111
111
|
* @param metadata - The back-reference configuration
|
|
112
112
|
*/
|
|
113
113
|
registerBackReference(childModelName: string, metadata: BackReferenceMetadata): void;
|
package/dist/ModelRegistry.js
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* another model that is registered later.
|
|
9
9
|
*/
|
|
10
10
|
// Removed Node.js crypto import for browser compatibility
|
|
11
|
-
import { PropertyType, LoadStrategy, } from './types/index.js';
|
|
11
|
+
import { PropertyType, LoadStrategy, } from './transaction/types/index.js';
|
|
12
12
|
import { getContext } from './context.js';
|
|
13
|
-
import { AbloValidationError } from './errors.js';
|
|
13
|
+
import { AbloValidationError } from './transaction/errors.js';
|
|
14
14
|
/**
|
|
15
15
|
* Module-level active registry. Set by createSyncEngine so that Model instances
|
|
16
16
|
* (which don't receive DI) can look up metadata without static maps.
|
|
@@ -248,7 +248,7 @@ export class ModelRegistry {
|
|
|
248
248
|
* transactions for every child model that declares a back-reference to that
|
|
249
249
|
* parent.
|
|
250
250
|
*
|
|
251
|
-
* @param childModelName - The model that holds a foreign key to the parent (e.g., '
|
|
251
|
+
* @param childModelName - The model that holds a foreign key to the parent (e.g., 'Section')
|
|
252
252
|
* @param metadata - The back-reference configuration
|
|
253
253
|
*/
|
|
254
254
|
registerBackReference(childModelName, metadata) {
|