@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
|
@@ -1,394 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* point; every parsed frame then passes through {@link dispatchWsFrame}.
|
|
2
|
+
* Moved to the settlement core with the duplex transport (ADR 0016): the
|
|
3
|
+
* inbound frame dispatch is the receiving half of the wire protocol, and the
|
|
4
|
+
* handlers already worked against the minimal `WsSession` port rather than
|
|
5
|
+
* the transport object. This path re-exports it so existing importers stay
|
|
6
|
+
* unchanged.
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
|
-
import { AbloConnectionError, CapabilityError, errorFromWire, } from '../errors.js';
|
|
11
|
-
import { commitAckSchema, legacyCompatibleCommitReceiptSchema, } from '../wire/commit.js';
|
|
12
|
-
import { subscriptionAckPayloadSchema } from '../coordination/schema.js';
|
|
13
|
-
import { formatConflict } from '../coordination/trace.js';
|
|
14
|
-
import { parseNotifications, recordClaim } from './commitFrames.js';
|
|
15
|
-
/** Narrow arbitrary wire data to a plain string-keyed record. */
|
|
16
|
-
export function isRecord(value) {
|
|
17
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* A type guard for the parsed result of an inbound message. A frame is any
|
|
21
|
-
* plain object whose `type`, when present, is a string. Validating the
|
|
22
|
-
* payload itself is left to each handler; delta payloads, for example, are
|
|
23
|
-
* checked against the canonical delta schema before they are applied.
|
|
24
|
-
*/
|
|
25
|
-
export function isWsInboundFrame(value) {
|
|
26
|
-
if (!isRecord(value))
|
|
27
|
-
return false;
|
|
28
|
-
const type = value.type;
|
|
29
|
-
return type === undefined || typeof type === 'string';
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Handles the acknowledgement of a `commit` request. The canonical wire
|
|
33
|
-
* shape is `MutationResultMessage`. The payload is parsed defensively
|
|
34
|
-
* rather than cast, since it is untrusted and may be malformed or sent by
|
|
35
|
-
* an older server.
|
|
36
|
-
*/
|
|
37
|
-
const handleMutationResult = (session, message) => {
|
|
38
|
-
const p = (message.payload ?? message);
|
|
39
|
-
const { clientTxId, success, error } = p;
|
|
40
|
-
// Defensive: validate notifications against the canonical schema —
|
|
41
|
-
// untrusted wire data from a possibly-older/newer server.
|
|
42
|
-
const notifications = parseNotifications(p?.notifications);
|
|
43
|
-
const missingIds = Array.isArray(p.missingIds)
|
|
44
|
-
? [
|
|
45
|
-
...new Set(p.missingIds.filter((id) => typeof id === 'string' && id.length > 0)),
|
|
46
|
-
]
|
|
47
|
-
: undefined;
|
|
48
|
-
const pending = typeof clientTxId === 'string'
|
|
49
|
-
? session.pendingMutations.get(clientTxId)
|
|
50
|
-
: undefined;
|
|
51
|
-
if (!pending)
|
|
52
|
-
return;
|
|
53
|
-
clearTimeout(pending.timeout);
|
|
54
|
-
// `pending` exists ⇒ clientTxId was a string key (the guard above).
|
|
55
|
-
session.pendingMutations.delete(clientTxId);
|
|
56
|
-
if (success) {
|
|
57
|
-
const parsedReceipt = legacyCompatibleCommitReceiptSchema.safeParse({
|
|
58
|
-
...p,
|
|
59
|
-
notifications,
|
|
60
|
-
missingIds,
|
|
61
|
-
});
|
|
62
|
-
if (!parsedReceipt.success) {
|
|
63
|
-
pending.reject(new AbloConnectionError('The sync server returned an invalid commit receipt; its outcome remains pending and is safe to retry.', { code: 'commit_no_result', cause: parsedReceipt.error }));
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const receipt = parsedReceipt.data;
|
|
67
|
-
// The write succeeded, but a guarded premise shifted underneath it.
|
|
68
|
-
// Emit the advisory signal so a caller can react, and still resolve
|
|
69
|
-
// the receipt, since the commit itself went through.
|
|
70
|
-
if (receipt.notifications && receipt.notifications.length > 0) {
|
|
71
|
-
const txId = receipt.clientTxId;
|
|
72
|
-
const event = {
|
|
73
|
-
clientTxId: txId,
|
|
74
|
-
rows: receipt.notifications.map((n) => ({
|
|
75
|
-
model: n.model,
|
|
76
|
-
id: n.id,
|
|
77
|
-
fields: n.conflictingFields,
|
|
78
|
-
writtenBy: n.writtenBy.kind,
|
|
79
|
-
})),
|
|
80
|
-
};
|
|
81
|
-
const message = formatConflict(event);
|
|
82
|
-
const ctx = getContext();
|
|
83
|
-
ctx.logger.warn(message);
|
|
84
|
-
ctx.observability.breadcrumb(message, 'sync.coordination', 'warning');
|
|
85
|
-
ctx.observability.captureConflict(event);
|
|
86
|
-
session.emit('conflict:notified', {
|
|
87
|
-
clientTxId: txId,
|
|
88
|
-
notifications: receipt.notifications,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
pending.resolve(commitAckSchema.parse({
|
|
92
|
-
status: receipt.status,
|
|
93
|
-
...(receipt.correlationId
|
|
94
|
-
? { correlationId: receipt.correlationId }
|
|
95
|
-
: {}),
|
|
96
|
-
lastSyncId: receipt.lastSyncId,
|
|
97
|
-
...(receipt.notifications && receipt.notifications.length > 0
|
|
98
|
-
? { notifications: receipt.notifications }
|
|
99
|
-
: {}),
|
|
100
|
-
...(receipt.missingIds && receipt.missingIds.length > 0
|
|
101
|
-
? { missingIds: receipt.missingIds }
|
|
102
|
-
: {}),
|
|
103
|
-
}));
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// Capture the full server error so the caller can see what actually
|
|
107
|
-
// rejected the mutation, rather than a generic "mutation failed on
|
|
108
|
-
// server". Object errors are stringified so structured server payloads,
|
|
109
|
-
// such as validation issues, survive being wrapped in an Error.
|
|
110
|
-
let errorMessage;
|
|
111
|
-
let errorCode;
|
|
112
|
-
let requiredCapability;
|
|
113
|
-
if (typeof error === 'string') {
|
|
114
|
-
errorMessage = error;
|
|
115
|
-
}
|
|
116
|
-
else if (error != null && typeof error === 'object') {
|
|
117
|
-
const obj = error;
|
|
118
|
-
if (typeof obj.code === 'string')
|
|
119
|
-
errorCode = obj.code;
|
|
120
|
-
if (typeof obj.message === 'string') {
|
|
121
|
-
errorMessage = obj.message;
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
try {
|
|
125
|
-
errorMessage = JSON.stringify(error);
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
errorMessage = String(error);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (obj.requiredCapability != null &&
|
|
132
|
-
typeof obj.requiredCapability === 'object' &&
|
|
133
|
-
typeof obj.requiredCapability.scope === 'string') {
|
|
134
|
-
requiredCapability = obj.requiredCapability;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
errorMessage = 'mutation failed on server';
|
|
139
|
-
}
|
|
140
|
-
// A stale-context rejection (the write read state that has since
|
|
141
|
-
// changed) or a foreign-claim conflict is a coordination collision.
|
|
142
|
-
// The success-with-notifications path above records the conflict, and a
|
|
143
|
-
// hard rejection must record it too, or the collision count would miss
|
|
144
|
-
// every rejected write. The conflicting rows ride along on the typed
|
|
145
|
-
// error's `conflicts` detail.
|
|
146
|
-
if (errorCode === 'stale_context' ||
|
|
147
|
-
errorCode === 'claim_conflict' ||
|
|
148
|
-
errorCode === 'entity_claimed' ||
|
|
149
|
-
errorCode?.startsWith('policy:') === true) {
|
|
150
|
-
const rawConflicts = error != null &&
|
|
151
|
-
typeof error === 'object' &&
|
|
152
|
-
Array.isArray(error.conflicts)
|
|
153
|
-
? error
|
|
154
|
-
.conflicts
|
|
155
|
-
: [];
|
|
156
|
-
const conflictEvent = {
|
|
157
|
-
clientTxId: typeof clientTxId === 'string' ? clientTxId : '',
|
|
158
|
-
rows: rawConflicts.map((r) => ({
|
|
159
|
-
model: typeof r.model === 'string' ? r.model : 'unknown',
|
|
160
|
-
id: typeof r.id === 'string' ? r.id : 'unknown',
|
|
161
|
-
fields: [],
|
|
162
|
-
})),
|
|
163
|
-
};
|
|
164
|
-
const ctx = getContext();
|
|
165
|
-
ctx.observability.breadcrumb(formatConflict(conflictEvent), 'sync.coordination', 'warning');
|
|
166
|
-
ctx.observability.captureConflict(conflictEvent);
|
|
167
|
-
}
|
|
168
|
-
// Build the proper typed AbloError from the wire code via the
|
|
169
|
-
// shared factory — the same code→class mapping the HTTP commit
|
|
170
|
-
// path uses (`translateHttpError`). This keeps rejected commits
|
|
171
|
-
// inside the typed hierarchy (capability denials →
|
|
172
|
-
// CapabilityError with `.requiredCapability`; foreign-claim
|
|
173
|
-
// conflicts → AbloClaimedError; everything else → the subclass
|
|
174
|
-
// its registry `httpStatus` implies) instead of a hand-rolled
|
|
175
|
-
// `new Error`, so callers can `instanceof`/`e.type` it and
|
|
176
|
-
// downstream retry logic can read the contract's retryability.
|
|
177
|
-
pending.reject(errorFromWire(errorMessage, {
|
|
178
|
-
code: errorCode,
|
|
179
|
-
requiredCapability,
|
|
180
|
-
}));
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
/**
|
|
184
|
-
* Handles the acknowledgement of a `claim` request. The frame has the shape
|
|
185
|
-
* `{ type: 'claim_ack', payload: { claimId, success, syncGroups?,
|
|
186
|
-
* ttlSeconds?, error? } }`.
|
|
187
|
-
*/
|
|
188
|
-
const handleClaimAck = (session, message) => {
|
|
189
|
-
const p = (message.payload ?? {});
|
|
190
|
-
const { claimId, success, syncGroups, ttlSeconds, error } = p;
|
|
191
|
-
const pending = typeof claimId === 'string'
|
|
192
|
-
? session.pendingClaims.get(claimId)
|
|
193
|
-
: undefined;
|
|
194
|
-
if (!pending)
|
|
195
|
-
return;
|
|
196
|
-
clearTimeout(pending.timeout);
|
|
197
|
-
// `pending` exists ⇒ claimId was a string key (the guard above).
|
|
198
|
-
session.pendingClaims.delete(claimId);
|
|
199
|
-
if (success) {
|
|
200
|
-
pending.resolve({
|
|
201
|
-
syncGroups: Array.isArray(syncGroups) ? syncGroups : [],
|
|
202
|
-
ttlSeconds: typeof ttlSeconds === 'number' ? ttlSeconds : undefined,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
const err = error;
|
|
207
|
-
const code = err?.code && typeof err.code === 'string'
|
|
208
|
-
? err.code
|
|
209
|
-
: 'claim_rejected';
|
|
210
|
-
const msg = err?.message && typeof err.message === 'string'
|
|
211
|
-
? err.message
|
|
212
|
-
: 'claim rejected by server';
|
|
213
|
-
// Capability denials get the typed CapabilityError so
|
|
214
|
-
// callers can read `.requiredCapability` and attenuate-
|
|
215
|
-
// and-retry the claim with a narrower token.
|
|
216
|
-
if (code === 'capability_scope_denied' ||
|
|
217
|
-
code === 'capability_invalid') {
|
|
218
|
-
const rc = error
|
|
219
|
-
?.requiredCapability;
|
|
220
|
-
const requiredCapability = rc != null &&
|
|
221
|
-
typeof rc === 'object' &&
|
|
222
|
-
typeof rc.scope === 'string'
|
|
223
|
-
? rc
|
|
224
|
-
: undefined;
|
|
225
|
-
pending.reject(new CapabilityError(code, msg, requiredCapability));
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
// Route through the shared factory so a failed claim_ack is a
|
|
229
|
-
// typed AbloError (registry code → right subclass), symmetric
|
|
230
|
-
// with the commit `mutation_result` path — never a bare Error.
|
|
231
|
-
pending.reject(errorFromWire(msg, { code }));
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
/**
|
|
236
|
-
* Handles the acknowledgement of an `update_subscription` request. The wire
|
|
237
|
-
* carries no correlation id, so the ack is matched to the oldest pending
|
|
238
|
-
* request in first-in, first-out order, since the server applies and
|
|
239
|
-
* acknowledges subscription updates in the order it receives them. The
|
|
240
|
-
* payload is validated against its canonical schema before use.
|
|
241
|
-
*/
|
|
242
|
-
const handleSubscriptionAck = (session, message) => {
|
|
243
|
-
const pending = session.shiftPendingSubscription();
|
|
244
|
-
if (!pending)
|
|
245
|
-
return;
|
|
246
|
-
clearTimeout(pending.timeout);
|
|
247
|
-
const parsed = subscriptionAckPayloadSchema.safeParse(message.payload);
|
|
248
|
-
if (!parsed.success) {
|
|
249
|
-
// Unreadable ack — resolve the pending request as a failure
|
|
250
|
-
// rather than hang it until timeout.
|
|
251
|
-
pending.reject(errorFromWire('malformed subscription_ack from server', {
|
|
252
|
-
code: 'malformed_subscription',
|
|
253
|
-
}));
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const ack = parsed.data;
|
|
257
|
-
if (ack.success) {
|
|
258
|
-
// Keep the reconnect URL aligned with current interest: a
|
|
259
|
-
// reconnect re-subscribes from `this.options.syncGroups`.
|
|
260
|
-
session.options.syncGroups = ack.syncGroups;
|
|
261
|
-
pending.resolve({ syncGroups: ack.syncGroups });
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
pending.reject(errorFromWire(ack.error?.message ?? 'update_subscription rejected by server', { code: ack.error?.code ?? 'malformed_subscription' }));
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
/**
|
|
268
|
-
* Handles a `delta` frame, which carries either a single delta or a
|
|
269
|
-
* `{ deltas: [...] }` batch. This only tells the two shapes apart; each
|
|
270
|
-
* delta is validated once downstream, so batch elements are passed along
|
|
271
|
-
* raw rather than parsed here.
|
|
272
|
-
*/
|
|
273
|
-
const handleDeltaFrame = (session, message) => {
|
|
274
|
-
const p = message.payload;
|
|
275
|
-
if (!isRecord(p))
|
|
276
|
-
return;
|
|
277
|
-
if (p.actionType || p.modelName) {
|
|
278
|
-
session.handleDelta(p);
|
|
279
|
-
}
|
|
280
|
-
else if (Array.isArray(p.deltas)) {
|
|
281
|
-
for (const d of p.deltas) {
|
|
282
|
-
session.handleDelta(d);
|
|
283
|
-
}
|
|
284
|
-
// `p.newVersions` from older servers is ignored; `sync_id` is the
|
|
285
|
-
// causality token.
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
/**
|
|
289
|
-
* Maps each frame type to its handler. Every named server frame this
|
|
290
|
-
* package understands is dispatched from this table; anything else falls
|
|
291
|
-
* through to the collaboration-event and unknown-type path in
|
|
292
|
-
* {@link dispatchWsFrame}.
|
|
293
|
-
*/
|
|
294
|
-
export const wsFrameHandlers = {
|
|
295
|
-
sync_response: (session, message) => { session.handleSyncResponse(message.payload); },
|
|
296
|
-
bootstrap_response: (session, message) => { session.handleBootstrapResponse(message.payload); },
|
|
297
|
-
presence_update: (session, message) => { session.handlePresenceUpdate(message); },
|
|
298
|
-
mutation_result: handleMutationResult,
|
|
299
|
-
claim_ack: handleClaimAck,
|
|
300
|
-
subscription_ack: handleSubscriptionAck,
|
|
301
|
-
claim_expired: (session, message) => {
|
|
302
|
-
// Server-initiated expiry notification. Emit as a typed
|
|
303
|
-
// event so consumers can react (re-claim with a fresh
|
|
304
|
-
// capability, or accept the drop). The claim is already
|
|
305
|
-
// inactive server-side by the time this arrives.
|
|
306
|
-
const p = (message.payload ?? {});
|
|
307
|
-
if (typeof p.claimId === 'string') {
|
|
308
|
-
recordClaim('expired', p);
|
|
309
|
-
session.emit('claim_expired', { claimId: p.claimId });
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
claim_rejected: (session, message) => {
|
|
313
|
-
// The server denied a claim because the target is already held by
|
|
314
|
-
// another participant. The payload is forwarded as-is for the claim
|
|
315
|
-
// stream consumer to interpret (peerId, target, and so on).
|
|
316
|
-
recordClaim('rejected', (message.payload ?? {}));
|
|
317
|
-
session.emit('claim_rejected', message.payload ?? {});
|
|
318
|
-
},
|
|
319
|
-
claim_acquired: (session, message) => {
|
|
320
|
-
// Opt-in fair queue: the target was free, so the lease is ours
|
|
321
|
-
// immediately (no waiting). Payload carries { claimId, target }.
|
|
322
|
-
recordClaim('acquired', (message.payload ?? {}));
|
|
323
|
-
session.emit('claim_acquired', message.payload ?? {});
|
|
324
|
-
},
|
|
325
|
-
claim_queue: (session, message) => {
|
|
326
|
-
// Per-entity wait-queue snapshot for reactive `queue(id)`. Not a
|
|
327
|
-
// single claim's state change, so it isn't logged — the per-claim
|
|
328
|
-
// `queued`/`granted` events already tell that story.
|
|
329
|
-
session.emit('claim_queue', message.payload ?? {});
|
|
330
|
-
},
|
|
331
|
-
claim_queued: (session, message) => {
|
|
332
|
-
// Opt-in fair queue: our claim is waiting in line. Payload
|
|
333
|
-
// carries { claimId, target, position }.
|
|
334
|
-
recordClaim('queued', (message.payload ?? {}));
|
|
335
|
-
session.emit('claim_queued', message.payload ?? {});
|
|
336
|
-
},
|
|
337
|
-
claim_granted: (session, message) => {
|
|
338
|
-
// Our queued claim reached the head — the lease is now ours.
|
|
339
|
-
recordClaim('granted', (message.payload ?? {}));
|
|
340
|
-
session.emit('claim_granted', message.payload ?? {});
|
|
341
|
-
},
|
|
342
|
-
claim_lost: (session, message) => {
|
|
343
|
-
// A held/granted claim was taken from us (TTL lapse, revoke).
|
|
344
|
-
recordClaim('lost', (message.payload ?? {}));
|
|
345
|
-
session.emit('claim_lost', message.payload ?? {});
|
|
346
|
-
},
|
|
347
|
-
claim_heartbeat_ack: (session, message) => {
|
|
348
|
-
// Reply to our `claim_heartbeat` — the claim stream correlates it back
|
|
349
|
-
// to the awaiting caller by claimId. Not logged per-frame: heartbeats
|
|
350
|
-
// are a cadence, and the interesting transitions (lost) surface through
|
|
351
|
-
// the caller's error path.
|
|
352
|
-
session.emit('claim_heartbeat_ack', message.payload ?? {});
|
|
353
|
-
},
|
|
354
|
-
delta: handleDeltaFrame,
|
|
355
|
-
};
|
|
356
|
-
/**
|
|
357
|
-
* Routes one parsed inbound frame to its handler. Keepalive frames are
|
|
358
|
-
* ignored, a missing `type` is treated as a bare delta, and any unknown
|
|
359
|
-
* type falls through to the collaboration-event map, whose wire names use
|
|
360
|
-
* underscores and whose event keys use colons.
|
|
361
|
-
*/
|
|
362
|
-
export function dispatchWsFrame(session, message) {
|
|
363
|
-
if (message.type === 'pong' || message.type === 'ping') {
|
|
364
|
-
// Ignore keepalive messages
|
|
365
|
-
getContext().logger.debug('Received keepalive', { type: message.type });
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (message.type === undefined) {
|
|
369
|
-
// A bare delta, validated downstream like every other delta.
|
|
370
|
-
if (message.actionType || message.modelName) {
|
|
371
|
-
session.handleDelta(message);
|
|
372
|
-
}
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
// Look up own properties only, so a wire type like 'toString' can't match
|
|
376
|
-
// an inherited Object.prototype member; such types fall through to the
|
|
377
|
-
// unknown-type path.
|
|
378
|
-
const handler = Object.prototype.hasOwnProperty.call(wsFrameHandlers, message.type)
|
|
379
|
-
? wsFrameHandlers[message.type]
|
|
380
|
-
: undefined;
|
|
381
|
-
if (handler) {
|
|
382
|
-
handler(session, message);
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
// Collaboration events use underscore wire format (e.g., 'sheet_selection')
|
|
386
|
-
// Convert to colon format for the event map (e.g., 'sheet:selection')
|
|
387
|
-
const eventKey = message.type?.replace(/_/g, ':');
|
|
388
|
-
if (eventKey && session.collaborationEventTypes.has(eventKey)) {
|
|
389
|
-
session.emit(eventKey, message.payload);
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
getContext().logger.debug('Received unknown message type', { message });
|
|
393
|
-
}
|
|
394
|
-
}
|
|
8
|
+
export { isRecord, readWsInboundFrame, wsFrameHandlers, dispatchWsFrame, } from '../transaction/transport/wsFrameHandlers.js';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* known point. These helpers produce the same shapes, so tests can exercise
|
|
6
6
|
* client sync logic without a live server.
|
|
7
7
|
*/
|
|
8
|
-
import type { BootstrapType } from '../../types/index.js';
|
|
8
|
+
import type { BootstrapType } from '../../transaction/types/index.js';
|
|
9
9
|
export type BootstrapModelData = Record<string, Record<string, unknown>[]>;
|
|
10
10
|
export interface BootstrapResponse {
|
|
11
11
|
type: BootstrapType;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* format the server sends: an insert, update, delete, archive, and so on.
|
|
5
5
|
* These helpers let tests construct deltas without a live server.
|
|
6
6
|
*/
|
|
7
|
-
import type { SyncActionType, SyncAction } from '../../
|
|
7
|
+
import type { SyncActionType, SyncAction } from '../../stores/syncAction.js';
|
|
8
8
|
/** Reset the delta counter (call in beforeEach for deterministic IDs) */
|
|
9
9
|
export declare function resetDeltaCounter(): void;
|
|
10
10
|
export interface CreateDeltaOptions {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response bodies for a fake HTTP server, built in the shapes the real one
|
|
3
|
+
* answers with.
|
|
4
|
+
*
|
|
5
|
+
* A test that hand-rolls `{ data, stamp }` is asserting against a server it
|
|
6
|
+
* invented. That is how a client and its server drift apart while every test
|
|
7
|
+
* stays green: the fixture and the client agree, and neither has met the
|
|
8
|
+
* route. Each builder here is `satisfies`-pinned to the wire schema the server
|
|
9
|
+
* answers with and the client parses — so a change to the contract breaks these
|
|
10
|
+
* fixtures at compile time, and the tests that use them describe a server that
|
|
11
|
+
* exists.
|
|
12
|
+
*
|
|
13
|
+
* Only the fields a test actually varies are parameters; everything else is a
|
|
14
|
+
* plausible default, because a fixture that makes you fill in `object: 'model'`
|
|
15
|
+
* teaches nothing and gets copy-pasted wrong.
|
|
16
|
+
*/
|
|
17
|
+
import type { ModelReadResponse, ModelListResponse, ClaimAcquiredResponse, ClaimQueuedResponse, ClaimListResponse, ClaimHeartbeatReply } from '../../transaction/wire/index.js';
|
|
18
|
+
import type { ModelClaim } from '../../transaction/coordination/index.js';
|
|
19
|
+
/** `GET /v1/models/{model}/{id}`. Pass `data: null` for a miss. */
|
|
20
|
+
export declare function modelReadResponse(args: {
|
|
21
|
+
model: string;
|
|
22
|
+
id: string;
|
|
23
|
+
data: unknown;
|
|
24
|
+
stamp?: number;
|
|
25
|
+
claims?: readonly ModelClaim[];
|
|
26
|
+
}): ModelReadResponse;
|
|
27
|
+
/** `GET /v1/models/{model}`. */
|
|
28
|
+
export declare function modelListResponse(args: {
|
|
29
|
+
model: string;
|
|
30
|
+
data: readonly unknown[];
|
|
31
|
+
hasMore?: boolean;
|
|
32
|
+
nextCursor?: string | null;
|
|
33
|
+
stamp?: number;
|
|
34
|
+
}): ModelListResponse;
|
|
35
|
+
/** One claim in the shape the HTTP claim routes return it. */
|
|
36
|
+
export declare function modelClaim(args: {
|
|
37
|
+
id: string;
|
|
38
|
+
model: string;
|
|
39
|
+
entityId: string;
|
|
40
|
+
actor?: string;
|
|
41
|
+
participantKind?: ModelClaim['participantKind'];
|
|
42
|
+
description?: string;
|
|
43
|
+
status?: 'active' | 'queued';
|
|
44
|
+
position?: number;
|
|
45
|
+
expiresAt?: number;
|
|
46
|
+
fenceToken?: number;
|
|
47
|
+
field?: string;
|
|
48
|
+
}): ModelClaim;
|
|
49
|
+
/** `POST /v1/models/{model}/{id}/claim` — 201, the lease is yours. */
|
|
50
|
+
export declare function claimAcquiredResponse(claim: ModelClaim): ClaimAcquiredResponse;
|
|
51
|
+
/** `POST /v1/models/{model}/{id}/claim` — 202, you are in the wait line. */
|
|
52
|
+
export declare function claimQueuedResponse(args: {
|
|
53
|
+
claimId: string;
|
|
54
|
+
position: number;
|
|
55
|
+
heldBy?: string;
|
|
56
|
+
expiresAt?: number;
|
|
57
|
+
}): ClaimQueuedResponse;
|
|
58
|
+
/** `GET /v1/claims`. */
|
|
59
|
+
export declare function claimListResponse(args?: {
|
|
60
|
+
claims?: readonly ModelClaim[];
|
|
61
|
+
queue?: readonly ModelClaim[];
|
|
62
|
+
}): ClaimListResponse;
|
|
63
|
+
/** `POST /v1/models/{model}/{id}/claim/heartbeat`. */
|
|
64
|
+
export declare function claimHeartbeatReply(args: {
|
|
65
|
+
claimId: string;
|
|
66
|
+
status?: 'held' | 'queued';
|
|
67
|
+
expiresAt?: number;
|
|
68
|
+
queueDepth?: number;
|
|
69
|
+
position?: number;
|
|
70
|
+
}): ClaimHeartbeatReply;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response bodies for a fake HTTP server, built in the shapes the real one
|
|
3
|
+
* answers with.
|
|
4
|
+
*
|
|
5
|
+
* A test that hand-rolls `{ data, stamp }` is asserting against a server it
|
|
6
|
+
* invented. That is how a client and its server drift apart while every test
|
|
7
|
+
* stays green: the fixture and the client agree, and neither has met the
|
|
8
|
+
* route. Each builder here is `satisfies`-pinned to the wire schema the server
|
|
9
|
+
* answers with and the client parses — so a change to the contract breaks these
|
|
10
|
+
* fixtures at compile time, and the tests that use them describe a server that
|
|
11
|
+
* exists.
|
|
12
|
+
*
|
|
13
|
+
* Only the fields a test actually varies are parameters; everything else is a
|
|
14
|
+
* plausible default, because a fixture that makes you fill in `object: 'model'`
|
|
15
|
+
* teaches nothing and gets copy-pasted wrong.
|
|
16
|
+
*/
|
|
17
|
+
/** `GET /v1/models/{model}/{id}`. Pass `data: null` for a miss. */
|
|
18
|
+
export function modelReadResponse(args) {
|
|
19
|
+
return {
|
|
20
|
+
object: 'model',
|
|
21
|
+
model: args.model,
|
|
22
|
+
id: args.id,
|
|
23
|
+
data: args.data,
|
|
24
|
+
stamp: args.stamp ?? 0,
|
|
25
|
+
claims: args.claims ?? [],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** `GET /v1/models/{model}`. */
|
|
29
|
+
export function modelListResponse(args) {
|
|
30
|
+
return {
|
|
31
|
+
object: 'list',
|
|
32
|
+
model: args.model,
|
|
33
|
+
data: [...args.data],
|
|
34
|
+
has_more: args.hasMore ?? false,
|
|
35
|
+
next_cursor: args.nextCursor ?? null,
|
|
36
|
+
stamp: args.stamp ?? 0,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** One claim in the shape the HTTP claim routes return it. */
|
|
40
|
+
export function modelClaim(args) {
|
|
41
|
+
return {
|
|
42
|
+
id: args.id,
|
|
43
|
+
actor: args.actor ?? 'user_fixture',
|
|
44
|
+
participantKind: args.participantKind ?? 'user',
|
|
45
|
+
description: args.description ?? 'editing',
|
|
46
|
+
...(args.field !== undefined ? { field: args.field } : {}),
|
|
47
|
+
...(args.status !== undefined ? { status: args.status } : {}),
|
|
48
|
+
...(args.position !== undefined ? { position: args.position } : {}),
|
|
49
|
+
expiresAt: args.expiresAt ?? Date.now() + 60_000,
|
|
50
|
+
...(args.fenceToken !== undefined ? { fenceToken: args.fenceToken } : {}),
|
|
51
|
+
target: { model: args.model, id: args.entityId },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** `POST /v1/models/{model}/{id}/claim` — 201, the lease is yours. */
|
|
55
|
+
export function claimAcquiredResponse(claim) {
|
|
56
|
+
return { id: claim.id, object: 'claim', claim };
|
|
57
|
+
}
|
|
58
|
+
/** `POST /v1/models/{model}/{id}/claim` — 202, you are in the wait line. */
|
|
59
|
+
export function claimQueuedResponse(args) {
|
|
60
|
+
return {
|
|
61
|
+
status: 'queued',
|
|
62
|
+
claimId: args.claimId,
|
|
63
|
+
position: args.position,
|
|
64
|
+
...(args.heldBy !== undefined ? { heldBy: args.heldBy } : {}),
|
|
65
|
+
...(args.expiresAt !== undefined ? { expiresAt: args.expiresAt } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** `GET /v1/claims`. */
|
|
69
|
+
export function claimListResponse(args = {}) {
|
|
70
|
+
return {
|
|
71
|
+
object: 'list',
|
|
72
|
+
claims: args.claims ?? [],
|
|
73
|
+
queue: args.queue ?? [],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** `POST /v1/models/{model}/{id}/claim/heartbeat`. */
|
|
77
|
+
export function claimHeartbeatReply(args) {
|
|
78
|
+
const status = args.status ?? 'held';
|
|
79
|
+
return {
|
|
80
|
+
object: 'claim_heartbeat',
|
|
81
|
+
claimId: args.claimId,
|
|
82
|
+
status,
|
|
83
|
+
...(status === 'held'
|
|
84
|
+
? {
|
|
85
|
+
expiresAt: args.expiresAt ?? Date.now() + 60_000,
|
|
86
|
+
...(args.queueDepth !== undefined ? { queueDepth: args.queueDepth } : {}),
|
|
87
|
+
}
|
|
88
|
+
: { position: args.position ?? 0 }),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Model } from '../../Model.js';
|
|
9
9
|
import { ModelRegistry } from '../../ModelRegistry.js';
|
|
10
|
-
import { PropertyType, LoadStrategy } from '../../types/index.js';
|
|
10
|
+
import { PropertyType, LoadStrategy } from '../../transaction/types/index.js';
|
|
11
11
|
// ─────────────────────────────────────────────
|
|
12
12
|
// Test Model Classes
|
|
13
13
|
// ─────────────────────────────────────────────
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Asynchronous helpers for tests whose assertions depend on timing — for
|
|
3
3
|
* flushing pending work, polling for a condition, or waiting a fixed delay.
|
|
4
4
|
*/
|
|
5
|
-
import { AbloConnectionError } from '../../errors.js';
|
|
5
|
+
import { AbloConnectionError } from '../../transaction/errors.js';
|
|
6
6
|
/**
|
|
7
7
|
* Flushes all pending microtasks, such as resolved promises and
|
|
8
8
|
* `queueMicrotask` callbacks. Useful for testing work the transaction queue
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* so tests can drive the delta-confirmation flow that depends on those ids.
|
|
7
7
|
*/
|
|
8
8
|
import type { MutationExecutor, MutationOperation, MutationOptions, CommitResult } from '../../interfaces/index.js';
|
|
9
|
-
import type { StaleNotification } from '../../coordination/schema.js';
|
|
9
|
+
import type { StaleNotification } from '../../transaction/coordination/schema.js';
|
|
10
10
|
export interface CapturedMutation {
|
|
11
11
|
method: string;
|
|
12
12
|
modelName?: string;
|
|
@@ -24,7 +24,7 @@ export interface MockMutationExecutorOptions {
|
|
|
24
24
|
shouldSucceed?: boolean;
|
|
25
25
|
/** A delay applied before each call resolves, in milliseconds, to simulate a slow network. */
|
|
26
26
|
latencyMs?: number;
|
|
27
|
-
/**
|
|
27
|
+
/** The settlement status each commit reports. Defaults to `'confirmed'`. */
|
|
28
28
|
status?: CommitResult['status'];
|
|
29
29
|
/** Optional server-issued source/WAL correlation returned with queued receipts. */
|
|
30
30
|
correlationId?: string;
|