@abloatai/ablo 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -3
- package/CHANGELOG.md +34 -0
- package/README.md +104 -88
- package/dist/BaseSyncedStore.d.ts +140 -266
- package/dist/BaseSyncedStore.js +338 -739
- package/dist/Database.d.ts +62 -77
- package/dist/Database.js +106 -127
- package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
- package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
- package/dist/LazyReferenceCollection.d.ts +11 -15
- package/dist/LazyReferenceCollection.js +16 -15
- package/dist/Model.d.ts +37 -52
- package/dist/Model.js +52 -69
- package/dist/ModelRegistry.d.ts +46 -25
- package/dist/ModelRegistry.js +32 -30
- package/dist/NetworkMonitor.d.ts +5 -6
- package/dist/NetworkMonitor.js +6 -7
- package/dist/SyncClient.d.ts +119 -109
- package/dist/SyncClient.js +303 -224
- package/dist/SyncEngineContext.d.ts +1 -3
- package/dist/SyncEngineContext.js +1 -2
- package/dist/adapters/alwaysOnline.d.ts +6 -8
- package/dist/adapters/alwaysOnline.js +6 -8
- package/dist/adapters/inMemoryStorage.d.ts +9 -9
- package/dist/adapters/inMemoryStorage.js +9 -9
- package/dist/agent/Agent.d.ts +39 -31
- package/dist/agent/Agent.js +35 -23
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +5 -5
- package/dist/agent/session.d.ts +47 -44
- package/dist/agent/session.js +37 -48
- package/dist/agent/types.d.ts +26 -31
- package/dist/agent/types.js +6 -7
- package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
- package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
- package/dist/ai-sdk/coordinationContext.d.ts +46 -0
- package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
- package/dist/ai-sdk/index.d.ts +25 -22
- package/dist/ai-sdk/index.js +25 -22
- package/dist/ai-sdk/wrap.d.ts +7 -8
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/credentialPolicy.d.ts +74 -71
- package/dist/auth/credentialPolicy.js +51 -56
- package/dist/auth/credentialSource.d.ts +7 -18
- package/dist/auth/credentialSource.js +10 -18
- package/dist/auth/index.d.ts +59 -58
- package/dist/auth/index.js +34 -40
- package/dist/auth/schemas.d.ts +5 -4
- package/dist/auth/schemas.js +5 -4
- package/dist/batching/index.d.ts +19 -21
- package/dist/batching/index.js +14 -17
- package/dist/cli.cjs +483 -369
- package/dist/client/Ablo.d.ts +107 -836
- package/dist/client/Ablo.js +174 -833
- package/dist/client/ApiClient.d.ts +44 -20
- package/dist/client/ApiClient.js +193 -44
- package/dist/client/auth.d.ts +51 -60
- package/dist/client/auth.js +137 -110
- package/dist/client/claimHeartbeatLoop.d.ts +50 -0
- package/dist/client/claimHeartbeatLoop.js +88 -0
- package/dist/client/consoleLogger.d.ts +35 -0
- package/dist/client/consoleLogger.js +44 -0
- package/dist/client/createInternalComponents.d.ts +14 -17
- package/dist/client/createInternalComponents.js +26 -31
- package/dist/client/createModelProxy.d.ts +130 -120
- package/dist/client/createModelProxy.js +158 -124
- package/dist/client/credentialEndpoint.d.ts +61 -0
- package/dist/client/credentialEndpoint.js +86 -0
- package/dist/client/functionalUpdate.d.ts +29 -27
- package/dist/client/functionalUpdate.js +21 -21
- package/dist/client/hostedEndpoints.d.ts +21 -0
- package/dist/client/hostedEndpoints.js +21 -0
- package/dist/client/httpClient.d.ts +58 -54
- package/dist/client/httpClient.js +29 -31
- package/dist/client/identity.d.ts +15 -20
- package/dist/client/identity.js +49 -59
- package/dist/client/modelRegistration.d.ts +10 -0
- package/dist/client/modelRegistration.js +301 -0
- package/dist/client/options.d.ts +373 -0
- package/dist/client/options.js +6 -0
- package/dist/client/registerDataSource.d.ts +9 -9
- package/dist/client/registerDataSource.js +15 -16
- package/dist/client/resourceTypes.d.ts +333 -0
- package/dist/client/resourceTypes.js +7 -0
- package/dist/client/schemaConfig.d.ts +44 -0
- package/dist/client/schemaConfig.js +176 -0
- package/dist/client/sessionMint.d.ts +17 -13
- package/dist/client/sessionMint.js +26 -31
- package/dist/client/validateAbloOptions.d.ts +12 -14
- package/dist/client/validateAbloOptions.js +9 -10
- package/dist/client/writeOptionsSchema.d.ts +18 -16
- package/dist/client/writeOptionsSchema.js +23 -20
- package/dist/client/wsMutationExecutor.d.ts +28 -0
- package/dist/client/wsMutationExecutor.js +71 -0
- package/dist/context.d.ts +6 -4
- package/dist/context.js +6 -7
- package/dist/coordination/index.d.ts +13 -4
- package/dist/coordination/index.js +29 -4
- package/dist/coordination/schema.d.ts +176 -128
- package/dist/coordination/schema.js +197 -133
- package/dist/coordination/trace.d.ts +9 -11
- package/dist/coordination/trace.js +13 -15
- package/dist/core/DatabaseManager.d.ts +5 -8
- package/dist/core/DatabaseManager.js +38 -40
- package/dist/core/QueryProcessor.d.ts +7 -9
- package/dist/core/QueryProcessor.js +27 -34
- package/dist/core/QueryView.d.ts +17 -5
- package/dist/core/QueryView.js +6 -7
- package/dist/core/StoreManager.d.ts +14 -16
- package/dist/core/StoreManager.js +26 -25
- package/dist/core/ViewRegistry.d.ts +5 -5
- package/dist/core/ViewRegistry.js +4 -4
- package/dist/core/index.d.ts +18 -13
- package/dist/core/index.js +32 -26
- package/dist/core/openIDBWithTimeout.d.ts +38 -36
- package/dist/core/openIDBWithTimeout.js +57 -54
- package/dist/core/queryUtils.d.ts +45 -0
- package/dist/core/queryUtils.js +69 -0
- package/dist/core/storeContract.d.ts +145 -0
- package/dist/core/storeContract.js +12 -0
- package/dist/environment.d.ts +28 -0
- package/dist/environment.js +21 -0
- package/dist/errorCodes.d.ts +118 -101
- package/dist/errorCodes.js +277 -260
- package/dist/errors.d.ts +170 -165
- package/dist/errors.js +161 -151
- package/dist/index.d.ts +30 -27
- package/dist/index.js +90 -82
- package/dist/interfaces/index.d.ts +108 -133
- package/dist/interfaces/index.js +5 -4
- package/dist/keys/index.d.ts +27 -29
- package/dist/keys/index.js +59 -49
- package/dist/mutators/RecordingTransaction.d.ts +16 -16
- package/dist/mutators/RecordingTransaction.js +31 -37
- package/dist/mutators/Transaction.d.ts +18 -26
- package/dist/mutators/Transaction.js +14 -20
- package/dist/mutators/UndoManager.d.ts +122 -131
- package/dist/mutators/UndoManager.js +149 -155
- package/dist/mutators/defineMutators.d.ts +24 -37
- package/dist/mutators/defineMutators.js +14 -20
- package/dist/mutators/inverseOp.d.ts +12 -15
- package/dist/mutators/inverseOp.js +12 -15
- package/dist/mutators/mutateActions.d.ts +10 -9
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +9 -8
- package/dist/mutators/readerActions.js +2 -2
- package/dist/mutators/undoApply.d.ts +31 -27
- package/dist/mutators/undoApply.js +26 -24
- package/dist/policy/index.d.ts +5 -3
- package/dist/policy/index.js +5 -3
- package/dist/policy/types.d.ts +105 -101
- package/dist/policy/types.js +67 -66
- package/dist/query/client.d.ts +32 -16
- package/dist/query/client.js +103 -72
- package/dist/query/types.d.ts +37 -60
- package/dist/query/types.js +13 -33
- package/dist/react/AbloProvider.d.ts +7 -11
- package/dist/react/AbloProvider.js +24 -17
- package/dist/react/context.d.ts +27 -146
- package/dist/react/context.js +9 -10
- package/dist/react/index.d.ts +41 -42
- package/dist/react/index.js +37 -38
- package/dist/react/internalContext.d.ts +17 -19
- package/dist/react/useAblo.d.ts +23 -22
- package/dist/react/useAblo.js +17 -15
- package/dist/react/useCurrentUserId.d.ts +8 -7
- package/dist/react/useCurrentUserId.js +8 -7
- package/dist/react/useErrorListener.d.ts +7 -7
- package/dist/react/useErrorListener.js +11 -12
- package/dist/react/useMutationFailureListener.d.ts +8 -8
- package/dist/react/useMutationFailureListener.js +9 -9
- package/dist/react/useMutators.d.ts +11 -11
- package/dist/react/useMutators.js +10 -4
- package/dist/react/useReactive.js +2 -3
- package/dist/react/useSyncStatus.d.ts +4 -6
- package/dist/react/useUndoScope.d.ts +7 -9
- package/dist/react/useUndoScope.js +3 -3
- package/dist/schema/coordination.d.ts +21 -25
- package/dist/schema/coordination.js +21 -25
- package/dist/schema/ddl.d.ts +43 -39
- package/dist/schema/ddl.js +75 -68
- package/dist/schema/ddlLock.d.ts +35 -0
- package/dist/schema/ddlLock.js +46 -0
- package/dist/schema/diff.d.ts +99 -61
- package/dist/schema/diff.js +43 -34
- package/dist/schema/field.d.ts +37 -42
- package/dist/schema/field.js +36 -49
- package/dist/schema/generate.d.ts +12 -12
- package/dist/schema/generate.js +12 -12
- package/dist/schema/index.d.ts +5 -4
- package/dist/schema/index.js +29 -21
- package/dist/schema/model.d.ts +121 -146
- package/dist/schema/model.js +24 -35
- package/dist/schema/openapi.d.ts +10 -9
- package/dist/schema/openapi.js +7 -1
- package/dist/schema/queries.d.ts +30 -32
- package/dist/schema/queries.js +24 -25
- package/dist/schema/relation.d.ts +89 -99
- package/dist/schema/relation.js +13 -13
- package/dist/schema/residency.d.ts +38 -0
- package/dist/schema/residency.js +30 -0
- package/dist/schema/roles.d.ts +45 -27
- package/dist/schema/roles.js +52 -21
- package/dist/schema/schema.d.ts +36 -45
- package/dist/schema/schema.js +42 -39
- package/dist/schema/select.d.ts +13 -13
- package/dist/schema/select.js +13 -13
- package/dist/schema/serialize.d.ts +36 -39
- package/dist/schema/serialize.js +27 -31
- package/dist/schema/sugar.d.ts +17 -32
- package/dist/schema/sugar.js +14 -29
- package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
- package/dist/schema/syncDeltaRow.js +89 -0
- package/dist/schema/tenancy.d.ts +44 -46
- package/dist/schema/tenancy.js +46 -48
- package/dist/server/adapter.d.ts +58 -58
- package/dist/server/adapter.js +13 -14
- package/dist/server/commit.d.ts +60 -64
- package/dist/server/index.d.ts +9 -10
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +70 -0
- package/dist/server/readConfig.js +8 -0
- package/dist/server/storageMode.d.ts +23 -0
- package/dist/server/storageMode.js +17 -0
- package/dist/source/adapter.d.ts +31 -26
- package/dist/source/adapter.js +10 -10
- package/dist/source/adapters/drizzle.d.ts +28 -23
- package/dist/source/adapters/drizzle.js +34 -28
- package/dist/source/adapters/kysely.d.ts +27 -25
- package/dist/source/adapters/kysely.js +28 -26
- package/dist/source/adapters/memory.d.ts +8 -7
- package/dist/source/adapters/memory.js +10 -9
- package/dist/source/adapters/prisma.d.ts +13 -12
- package/dist/source/adapters/prisma.js +27 -29
- package/dist/source/conformance.d.ts +18 -11
- package/dist/source/conformance.js +27 -19
- package/dist/source/connector.d.ts +31 -32
- package/dist/source/connector.js +30 -28
- package/dist/source/connectorProtocol.d.ts +160 -0
- package/dist/source/connectorProtocol.js +162 -0
- package/dist/source/contract.d.ts +26 -27
- package/dist/source/contract.js +28 -29
- package/dist/source/factory.d.ts +94 -0
- package/dist/source/factory.js +268 -0
- package/dist/source/index.d.ts +10 -462
- package/dist/source/index.js +17 -421
- package/dist/source/migrations.d.ts +9 -9
- package/dist/source/migrations.js +9 -9
- package/dist/source/next.d.ts +10 -11
- package/dist/source/next.js +7 -8
- package/dist/source/pushQueue.d.ts +70 -48
- package/dist/source/pushQueue.js +36 -29
- package/dist/source/signing.d.ts +88 -0
- package/dist/source/signing.js +159 -0
- package/dist/source/types.d.ts +351 -0
- package/dist/source/types.js +43 -0
- package/dist/stores/ObjectStore.d.ts +11 -12
- package/dist/stores/ObjectStore.js +34 -35
- package/dist/stores/ObjectStoreContract.d.ts +12 -15
- package/dist/stores/SyncActionStore.d.ts +8 -12
- package/dist/stores/SyncActionStore.js +77 -46
- package/dist/surface.d.ts +28 -21
- package/dist/surface.js +28 -20
- package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
- package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
- package/dist/sync/ConnectionManager.d.ts +47 -50
- package/dist/sync/ConnectionManager.js +74 -70
- package/dist/sync/NetworkProbe.d.ts +27 -31
- package/dist/sync/NetworkProbe.js +67 -72
- package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
- package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
- package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
- package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
- package/dist/sync/SyncWebSocket.d.ts +175 -250
- package/dist/sync/SyncWebSocket.js +431 -769
- package/dist/sync/awaitClaimGrant.d.ts +18 -18
- package/dist/sync/awaitClaimGrant.js +38 -30
- package/dist/sync/bootstrapApply.d.ts +70 -0
- package/dist/sync/bootstrapApply.js +73 -0
- package/dist/sync/commitFrames.d.ts +44 -0
- package/dist/sync/commitFrames.js +94 -0
- package/dist/sync/createClaimStream.d.ts +23 -22
- package/dist/sync/createClaimStream.js +108 -25
- package/dist/sync/createPresenceStream.d.ts +19 -18
- package/dist/sync/createPresenceStream.js +25 -26
- package/dist/sync/createSnapshot.d.ts +13 -17
- package/dist/sync/createSnapshot.js +20 -26
- package/dist/sync/credentialLifecycle.d.ts +175 -0
- package/dist/sync/credentialLifecycle.js +322 -0
- package/dist/sync/deltaPipeline.d.ts +113 -0
- package/dist/sync/deltaPipeline.js +261 -0
- package/dist/sync/groupChange.d.ts +113 -0
- package/dist/sync/groupChange.js +242 -0
- package/dist/sync/heartbeat.d.ts +63 -0
- package/dist/sync/heartbeat.js +91 -0
- package/dist/sync/participants.d.ts +27 -27
- package/dist/sync/schemas.d.ts +3 -2
- package/dist/sync/schemas.js +14 -10
- package/dist/sync/syncCursor.d.ts +40 -0
- package/dist/sync/syncCursor.js +55 -0
- package/dist/sync/syncPlan.d.ts +54 -0
- package/dist/sync/syncPlan.js +50 -0
- package/dist/sync/syncPosition.d.ts +54 -49
- package/dist/sync/syncPosition.js +57 -52
- package/dist/sync/wsFrameHandlers.d.ts +116 -0
- package/dist/sync/wsFrameHandlers.js +374 -0
- package/dist/testing/fixtures/bootstrap.d.ts +21 -17
- package/dist/testing/fixtures/bootstrap.js +12 -6
- package/dist/testing/fixtures/deltas.d.ts +31 -34
- package/dist/testing/fixtures/deltas.js +30 -33
- package/dist/testing/fixtures/models.d.ts +11 -10
- package/dist/testing/fixtures/models.js +12 -10
- package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
- package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
- package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
- package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
- package/dist/testing/helpers/wait.d.ts +13 -8
- package/dist/testing/helpers/wait.js +13 -8
- package/dist/testing/index.d.ts +4 -4
- package/dist/testing/index.js +3 -3
- package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
- package/dist/testing/mocks/MockMutationExecutor.js +15 -14
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
- package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
- package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
- package/dist/testing/mocks/MockSyncContext.js +16 -45
- package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
- package/dist/testing/mocks/MockSyncStore.js +11 -11
- package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
- package/dist/testing/mocks/MockWebSocket.js +22 -21
- package/dist/transactions/TransactionQueue.d.ts +190 -221
- package/dist/transactions/TransactionQueue.js +424 -822
- package/dist/transactions/TransactionStore.d.ts +20 -0
- package/dist/transactions/TransactionStore.js +53 -0
- package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
- package/dist/transactions/UnconfirmedWrites.js +104 -0
- package/dist/transactions/coalesceRules.d.ts +58 -0
- package/dist/transactions/coalesceRules.js +140 -0
- package/dist/transactions/commitPayload.d.ts +130 -0
- package/dist/transactions/commitPayload.js +143 -0
- package/dist/transactions/deltaConfirmation.d.ts +58 -0
- package/dist/transactions/deltaConfirmation.js +215 -0
- package/dist/transactions/optimisticApply.d.ts +49 -0
- package/dist/transactions/optimisticApply.js +65 -0
- package/dist/transactions/replayValidation.d.ts +99 -0
- package/dist/transactions/replayValidation.js +111 -0
- package/dist/types/global.d.ts +46 -41
- package/dist/types/global.js +20 -19
- package/dist/types/index.d.ts +74 -80
- package/dist/types/index.js +22 -27
- package/dist/types/modelData.d.ts +10 -0
- package/dist/types/modelData.js +9 -0
- package/dist/types/participant.d.ts +20 -0
- package/dist/types/participant.js +10 -0
- package/dist/types/streams.d.ts +216 -209
- package/dist/types/streams.js +7 -7
- package/dist/utils/asyncIterator.d.ts +25 -32
- package/dist/utils/asyncIterator.js +25 -32
- package/dist/utils/duration.d.ts +12 -15
- package/dist/utils/duration.js +12 -15
- package/dist/utils/mobxSetup.d.ts +53 -0
- package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
- package/dist/webhooks/events.d.ts +21 -16
- package/dist/webhooks/events.js +10 -8
- package/dist/webhooks/index.d.ts +5 -7
- package/dist/webhooks/index.js +5 -7
- package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
- package/dist/wire/delta.js +114 -0
- package/dist/wire/errorEnvelope.d.ts +35 -27
- package/dist/wire/errorEnvelope.js +38 -32
- package/dist/wire/frames.d.ts +150 -67
- package/dist/wire/frames.js +48 -1
- package/dist/wire/index.d.ts +18 -13
- package/dist/wire/index.js +36 -13
- package/dist/wire/listEnvelope.d.ts +16 -23
- package/dist/wire/listEnvelope.js +7 -6
- package/dist/wire/protocol.d.ts +38 -0
- package/dist/wire/protocol.js +38 -0
- package/dist/wire/protocolVersion.d.ts +60 -0
- package/dist/wire/protocolVersion.js +67 -0
- package/docs/api-keys.md +4 -3
- package/docs/coordination.md +59 -0
- package/docs/examples/existing-python-backend.md +3 -3
- package/docs/identity.md +4 -4
- package/docs/integration-guide.md +1 -1
- package/docs/react.md +1 -1
- package/docs/sessions.md +5 -7
- package/package.json +24 -21
- package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
- package/dist/ai-sdk/coordination-context.d.ts +0 -52
- package/dist/client/index.d.ts +0 -36
- package/dist/client/index.js +0 -33
- package/dist/config/index.d.ts +0 -10
- package/dist/config/index.js +0 -12
- package/dist/core/query-utils.d.ts +0 -34
- package/dist/core/query-utils.js +0 -59
- package/dist/interfaces/headless.d.ts +0 -95
- package/dist/interfaces/headless.js +0 -41
- package/dist/query/index.d.ts +0 -6
- package/dist/query/index.js +0 -5
- package/dist/realtime/index.d.ts +0 -10
- package/dist/realtime/index.js +0 -9
- package/dist/schema/plane.d.ts +0 -23
- package/dist/schema/plane.js +0 -19
- package/dist/schema/sync-delta-row.js +0 -103
- package/dist/schema/sync-delta-wire.js +0 -102
- package/dist/server/next.d.ts +0 -51
- package/dist/server/next.js +0 -47
- package/dist/server/read-config.d.ts +0 -67
- package/dist/server/read-config.js +0 -8
- package/dist/server/storage-mode.d.ts +0 -1
- package/dist/server/storage-mode.js +0 -18
- package/dist/source/connector-protocol.d.ts +0 -159
- package/dist/source/connector-protocol.js +0 -161
- package/dist/sync/OfflineFlush.d.ts +0 -9
- package/dist/sync/OfflineFlush.js +0 -22
- package/dist/sync/OfflineTransactionStore.d.ts +0 -37
- package/dist/sync/OfflineTransactionStore.js +0 -263
- package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
- package/dist/transactions/OptimisticEchoTracker.js +0 -104
- package/dist/transactions/index.d.ts +0 -16
- package/dist/transactions/index.js +0 -7
- package/dist/transactions/mutation-error-handler.d.ts +0 -5
- package/dist/transactions/mutation-error-handler.js +0 -39
- package/dist/utils/mobx-setup.d.ts +0 -42
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Drizzle
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - `db.
|
|
6
|
-
*
|
|
2
|
+
* The Drizzle adapter for the data-source interface. It implements the same
|
|
3
|
+
* {@link DataSourceAdapter} contract as {@link prismaDataSource} and passes the
|
|
4
|
+
* same conformance suite, built against Drizzle's query API:
|
|
5
|
+
* - `db.transaction(async (tx) => …)` runs an interactive transaction that
|
|
6
|
+
* commits or rolls back as a unit.
|
|
7
|
+
* - `db.execute(sql`…`)` runs parameterized raw SQL; `sql.identifier()` safely
|
|
8
|
+
* quotes dynamic table and column names, and `sql`${value}`` parameterizes
|
|
9
|
+
* values.
|
|
7
10
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* field
|
|
11
|
-
*
|
|
11
|
+
* Table and column names come from your schema, not from a hand-written Drizzle
|
|
12
|
+
* table. Because this adapter issues raw SQL, it would otherwise bypass any
|
|
13
|
+
* field-to-column translation, so it derives every name from the same rule the
|
|
14
|
+
* table provisioner uses:
|
|
12
15
|
* table = `model.tableName ?? key`
|
|
13
|
-
* column = `fieldMeta.column ?? camelToSnake(field)` (
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* the physical columns it
|
|
16
|
+
* column = `fieldMeta.column ?? camelToSnake(field)` (plus the tenancy column)
|
|
17
|
+
* This keeps the tables `ablo migrate` creates (for example `operator_id`) and the
|
|
18
|
+
* columns this adapter reads and writes in agreement. You define the schema once
|
|
19
|
+
* and point the engine at your Postgres database. The adapter is the translation
|
|
20
|
+
* boundary: the rows it accepts and returns, and the outbox `data` it writes, are
|
|
21
|
+
* keyed by field name, while the physical columns it touches are snake_case.
|
|
19
22
|
*
|
|
20
|
-
*
|
|
21
|
-
* 1. Interactive `db.transaction`
|
|
22
|
-
* `neon-http` driver
|
|
23
|
-
* (WebSocket) or `pg
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Two things to know about drivers:
|
|
24
|
+
* 1. Interactive `db.transaction` needs a driver that supports it. Neon's
|
|
25
|
+
* `neon-http` driver is single-shot and does not, so use `neon-serverless`
|
|
26
|
+
* (over WebSocket) or `pg`; under `neon-http` the commit path throws at
|
|
27
|
+
* runtime.
|
|
28
|
+
* 2. The `db.execute` result shape is driver-specific — `postgres-js` returns an
|
|
29
|
+
* array-like row list, while `node-postgres` returns `{ rows }`. `rowsOf`
|
|
26
30
|
* normalizes both.
|
|
27
31
|
*
|
|
28
|
-
*
|
|
29
|
-
* adapter
|
|
32
|
+
* Every write goes through `sql` and `db.execute` rather than the fluent builder,
|
|
33
|
+
* which keeps the adapter one small, fully typed unit with no per-driver builder
|
|
34
|
+
* generics.
|
|
30
35
|
*/
|
|
31
36
|
import { AbloValidationError } from '../../errors.js';
|
|
32
37
|
import { sql } from 'drizzle-orm';
|
|
@@ -82,14 +87,14 @@ export function drizzleDataSource(db, schema) {
|
|
|
82
87
|
};
|
|
83
88
|
const columnFor = (mc, field) => mc.fieldToColumn.get(field) ?? camelToSnake(field);
|
|
84
89
|
const fieldFor = (mc, column) => mc.columnToField.get(column) ?? snakeToCamel(column);
|
|
85
|
-
/** Field-keyed
|
|
90
|
+
/** Field-keyed row to column-keyed row, for INSERT and UPDATE values. */
|
|
86
91
|
const toColumns = (mc, row) => {
|
|
87
92
|
const out = {};
|
|
88
93
|
for (const k of Object.keys(row))
|
|
89
94
|
out[columnFor(mc, k)] = row[k];
|
|
90
95
|
return out;
|
|
91
96
|
};
|
|
92
|
-
/** Column-keyed (RETURNING
|
|
97
|
+
/** Column-keyed row (from `RETURNING *` or `SELECT *`) back to a field-keyed row, for reads and results. */
|
|
93
98
|
const toFields = (mc, row) => {
|
|
94
99
|
const out = {};
|
|
95
100
|
for (const k of Object.keys(row))
|
|
@@ -144,8 +149,9 @@ export function drizzleDataSource(db, schema) {
|
|
|
144
149
|
async commit(change) {
|
|
145
150
|
return db.transaction(async (tx) => {
|
|
146
151
|
const cached = rowsOf(await tx.execute(sql `SELECT response FROM ablo_idempotency WHERE client_tx_id = ${change.clientTxId} LIMIT 1`));
|
|
147
|
-
|
|
148
|
-
|
|
152
|
+
const cachedRow = cached[0];
|
|
153
|
+
if (cachedRow)
|
|
154
|
+
return { rows: cachedRow.response };
|
|
149
155
|
const rows = [];
|
|
150
156
|
for (const [index, op] of change.operations.entries()) {
|
|
151
157
|
const row = await applyOperation(tx, op);
|
|
@@ -180,7 +186,7 @@ export function drizzleDataSource(db, schema) {
|
|
|
180
186
|
occurredAt: r.occurred_at != null ? Number(r.occurred_at) : null,
|
|
181
187
|
cursor: String(r.cursor),
|
|
182
188
|
}));
|
|
183
|
-
return { events, nextCursor: events.
|
|
189
|
+
return { events, nextCursor: events.at(-1)?.cursor ?? null };
|
|
184
190
|
},
|
|
185
191
|
};
|
|
186
192
|
}
|
|
@@ -1,36 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Kysely
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
2
|
+
* The Kysely adapter for the data-source interface. It implements the same
|
|
3
|
+
* {@link DataSourceAdapter} contract as {@link prismaDataSource} and
|
|
4
|
+
* {@link drizzleDataSource} and passes the same conformance suite, built against
|
|
5
|
+
* Kysely's query builder:
|
|
6
|
+
* - `db.transaction().execute(async (trx) => …)` runs an interactive transaction.
|
|
7
|
+
* - `insertInto` / `updateTable` / `deleteFrom` / `selectFrom` with
|
|
8
|
+
* `returningAll()` form the fluent query. Table and column names are plain
|
|
9
|
+
* strings, so the adapter needs no raw-SQL tag and imports nothing from
|
|
10
|
+
* `kysely`; it depends only on the structural {@link KyselyLike} shape, the
|
|
11
|
+
* same approach the Prisma adapter takes with {@link PrismaLike}.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* give it through
|
|
14
|
-
*
|
|
15
|
-
* provisioner uses (`generateProvisionPlan`):
|
|
13
|
+
* Table and column names come from your schema. Kysely passes the column names you
|
|
14
|
+
* give it straight through to SQL, so, like the Drizzle adapter, this one derives
|
|
15
|
+
* every name from the same rule the table provisioner uses:
|
|
16
16
|
* table = `model.tableName ?? key`
|
|
17
|
-
* column = `fieldMeta.column ?? camelToSnake(field)` (
|
|
18
|
-
*
|
|
19
|
-
* The adapter is the translation boundary:
|
|
20
|
-
*
|
|
17
|
+
* column = `fieldMeta.column ?? camelToSnake(field)` (plus the tenancy column)
|
|
18
|
+
* This keeps the tables `ablo migrate` creates (for example `operator_id`) and the
|
|
19
|
+
* columns this adapter uses in agreement. The adapter is the translation boundary:
|
|
20
|
+
* the rows it accepts and returns are keyed by field name, while the physical
|
|
21
|
+
* columns are snake_case.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
* as JSON strings
|
|
24
|
-
* `jsonb` column, so the
|
|
25
|
-
* `::jsonb` cast
|
|
23
|
+
* A note on JSON columns: the outbox `data` and idempotency `response` values are
|
|
24
|
+
* passed as JSON strings. Postgres infers the parameter type from the target
|
|
25
|
+
* `jsonb` column, so the conversion happens on the server and works across drivers,
|
|
26
|
+
* without the `::jsonb` cast that only raw SQL allows.
|
|
26
27
|
*/
|
|
27
28
|
import type { DataSourceAdapter, Row } from '../adapter.js';
|
|
28
29
|
import type { Schema, SchemaRecord } from '../../schema/schema.js';
|
|
29
30
|
/**
|
|
30
|
-
* The subset of a Kysely instance
|
|
31
|
-
*
|
|
32
|
-
* `Kysely<DB>`
|
|
33
|
-
* under TypeScript's method bivariance,
|
|
31
|
+
* The subset of a Kysely instance, or transaction handle, that the adapter calls.
|
|
32
|
+
* It is structural by design: declaring the members with method shorthand lets a
|
|
33
|
+
* real `Kysely<DB>` — whose parameters are narrowed to `keyof DB` — stay assignable
|
|
34
|
+
* under TypeScript's method-parameter bivariance, the same way {@link PrismaLike}
|
|
35
|
+
* accepts a real `PrismaClient`.
|
|
34
36
|
*/
|
|
35
37
|
export interface KyselyLike {
|
|
36
38
|
selectFrom(table: string): KyselySelectBuilder;
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Kysely
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
2
|
+
* The Kysely adapter for the data-source interface. It implements the same
|
|
3
|
+
* {@link DataSourceAdapter} contract as {@link prismaDataSource} and
|
|
4
|
+
* {@link drizzleDataSource} and passes the same conformance suite, built against
|
|
5
|
+
* Kysely's query builder:
|
|
6
|
+
* - `db.transaction().execute(async (trx) => …)` runs an interactive transaction.
|
|
7
|
+
* - `insertInto` / `updateTable` / `deleteFrom` / `selectFrom` with
|
|
8
|
+
* `returningAll()` form the fluent query. Table and column names are plain
|
|
9
|
+
* strings, so the adapter needs no raw-SQL tag and imports nothing from
|
|
10
|
+
* `kysely`; it depends only on the structural {@link KyselyLike} shape, the
|
|
11
|
+
* same approach the Prisma adapter takes with {@link PrismaLike}.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* give it through
|
|
14
|
-
*
|
|
15
|
-
* provisioner uses (`generateProvisionPlan`):
|
|
13
|
+
* Table and column names come from your schema. Kysely passes the column names you
|
|
14
|
+
* give it straight through to SQL, so, like the Drizzle adapter, this one derives
|
|
15
|
+
* every name from the same rule the table provisioner uses:
|
|
16
16
|
* table = `model.tableName ?? key`
|
|
17
|
-
* column = `fieldMeta.column ?? camelToSnake(field)` (
|
|
18
|
-
*
|
|
19
|
-
* The adapter is the translation boundary:
|
|
20
|
-
*
|
|
17
|
+
* column = `fieldMeta.column ?? camelToSnake(field)` (plus the tenancy column)
|
|
18
|
+
* This keeps the tables `ablo migrate` creates (for example `operator_id`) and the
|
|
19
|
+
* columns this adapter uses in agreement. The adapter is the translation boundary:
|
|
20
|
+
* the rows it accepts and returns are keyed by field name, while the physical
|
|
21
|
+
* columns are snake_case.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
* as JSON strings
|
|
24
|
-
* `jsonb` column, so the
|
|
25
|
-
* `::jsonb` cast
|
|
23
|
+
* A note on JSON columns: the outbox `data` and idempotency `response` values are
|
|
24
|
+
* passed as JSON strings. Postgres infers the parameter type from the target
|
|
25
|
+
* `jsonb` column, so the conversion happens on the server and works across drivers,
|
|
26
|
+
* without the `::jsonb` cast that only raw SQL allows.
|
|
26
27
|
*/
|
|
27
28
|
import { AbloValidationError } from '../../errors.js';
|
|
28
29
|
import { outboxEventSchema } from '../contract.js';
|
|
@@ -75,14 +76,14 @@ export function kyselyDataSource(db, schema) {
|
|
|
75
76
|
};
|
|
76
77
|
const columnFor = (mc, field) => mc.fieldToColumn.get(field) ?? camelToSnake(field);
|
|
77
78
|
const fieldFor = (mc, column) => mc.columnToField.get(column) ?? snakeToCamel(column);
|
|
78
|
-
/** Field-keyed
|
|
79
|
+
/** Field-keyed row to column-keyed row, for INSERT and UPDATE values. */
|
|
79
80
|
const toColumns = (mc, row) => {
|
|
80
81
|
const out = {};
|
|
81
82
|
for (const k of Object.keys(row))
|
|
82
83
|
out[columnFor(mc, k)] = row[k];
|
|
83
84
|
return out;
|
|
84
85
|
};
|
|
85
|
-
/** Column-keyed (RETURNING
|
|
86
|
+
/** Column-keyed row (from `RETURNING *` or `SELECT *`) back to a field-keyed row. */
|
|
86
87
|
const toFields = (mc, row) => {
|
|
87
88
|
const out = {};
|
|
88
89
|
for (const k of Object.keys(row))
|
|
@@ -153,8 +154,9 @@ export function kyselyDataSource(db, schema) {
|
|
|
153
154
|
.where('client_tx_id', '=', change.clientTxId)
|
|
154
155
|
.limit(1)
|
|
155
156
|
.execute();
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
const cachedRow = cached[0];
|
|
158
|
+
if (cachedRow) {
|
|
159
|
+
const response = cachedRow.response;
|
|
158
160
|
return {
|
|
159
161
|
rows: (typeof response === 'string' ? JSON.parse(response) : response),
|
|
160
162
|
};
|
|
@@ -204,7 +206,7 @@ export function kyselyDataSource(db, schema) {
|
|
|
204
206
|
occurredAt: r.occurred_at != null ? Number(r.occurred_at) : null,
|
|
205
207
|
cursor: String(r.cursor),
|
|
206
208
|
}));
|
|
207
|
-
return { events, nextCursor: events.
|
|
209
|
+
return { events, nextCursor: events.at(-1)?.cursor ?? null };
|
|
208
210
|
},
|
|
209
211
|
};
|
|
210
212
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
* passes the same suite this one passes.
|
|
2
|
+
* The in-memory reference implementation of {@link DataSourceAdapter}. It is the
|
|
3
|
+
* simplest correct adapter: a stand-in you can commit to and read from in tests
|
|
4
|
+
* without a database, and the fixture the conformance suite runs against to confirm
|
|
5
|
+
* the suite exercises real behavior. An adapter for a given object-relational
|
|
6
|
+
* mapper is complete when it passes the same suite this one passes.
|
|
7
7
|
*
|
|
8
|
-
* It models the
|
|
9
|
-
*
|
|
8
|
+
* It models the semantics minimally but faithfully: one row store per model, an
|
|
9
|
+
* idempotency ledger keyed by `clientTxId`, and an append-only outbox with a
|
|
10
|
+
* monotonic cursor.
|
|
10
11
|
*/
|
|
11
12
|
import type { DataSourceAdapter } from '../adapter.js';
|
|
12
13
|
export declare function memoryDataSource(): DataSourceAdapter;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
* passes the same suite this one passes.
|
|
2
|
+
* The in-memory reference implementation of {@link DataSourceAdapter}. It is the
|
|
3
|
+
* simplest correct adapter: a stand-in you can commit to and read from in tests
|
|
4
|
+
* without a database, and the fixture the conformance suite runs against to confirm
|
|
5
|
+
* the suite exercises real behavior. An adapter for a given object-relational
|
|
6
|
+
* mapper is complete when it passes the same suite this one passes.
|
|
7
7
|
*
|
|
8
|
-
* It models the
|
|
9
|
-
*
|
|
8
|
+
* It models the semantics minimally but faithfully: one row store per model, an
|
|
9
|
+
* idempotency ledger keyed by `clientTxId`, and an append-only outbox with a
|
|
10
|
+
* monotonic cursor.
|
|
10
11
|
*/
|
|
11
12
|
import { AbloValidationError } from '../../errors.js';
|
|
12
13
|
function rowId(op) {
|
|
@@ -63,7 +64,7 @@ export function memoryDataSource() {
|
|
|
63
64
|
return {
|
|
64
65
|
capabilities: { transactions: true, propose: false, schemaIntrospection: false },
|
|
65
66
|
migrations() {
|
|
66
|
-
//
|
|
67
|
+
// Nothing to create in memory. A database-backed adapter returns the SQL for its ablo_idempotency and ablo_outbox tables here.
|
|
67
68
|
return [];
|
|
68
69
|
},
|
|
69
70
|
async read(req) {
|
|
@@ -108,7 +109,7 @@ export function memoryDataSource() {
|
|
|
108
109
|
const page = outbox.filter((e) => Number(e.cursor) > after).slice(0, limit);
|
|
109
110
|
return {
|
|
110
111
|
events: page,
|
|
111
|
-
nextCursor: page.
|
|
112
|
+
nextCursor: page.at(-1)?.cursor ?? null,
|
|
112
113
|
};
|
|
113
114
|
},
|
|
114
115
|
};
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Prisma
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* The Prisma adapter for the data-source interface. It implements
|
|
3
|
+
* {@link DataSourceAdapter} against a Prisma client and passes the same conformance
|
|
4
|
+
* suite as the in-memory reference and the other adapters.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* them: `commit` runs the
|
|
8
|
-
* `ablo_idempotency` record
|
|
9
|
-
* the
|
|
6
|
+
* The adapter owns the transactional outbox and idempotency bookkeeping, so you
|
|
7
|
+
* never write them: `commit` runs the row mutations, the `ablo_outbox` append, and
|
|
8
|
+
* the `ablo_idempotency` record inside a single `prisma.$transaction`, and
|
|
9
|
+
* `migrations` returns the SQL that creates those two tables.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* a fake, while a real `PrismaClient` satisfies
|
|
11
|
+
* It takes no dependency on `@prisma/client`. The client is accepted structurally
|
|
12
|
+
* as {@link PrismaLike}, so this module compiles without Prisma installed and can
|
|
13
|
+
* be tested with a fake, while a real `PrismaClient` satisfies the shape at the
|
|
14
|
+
* call site.
|
|
14
15
|
*/
|
|
15
16
|
import type { DataSourceAdapter, Row } from '../adapter.js';
|
|
16
17
|
import type { SchemaRecord, Schema } from '../../schema/schema.js';
|
|
17
|
-
/** A Prisma model delegate
|
|
18
|
+
/** A Prisma model delegate — the subset of its methods the adapter calls. */
|
|
18
19
|
export interface PrismaDelegate {
|
|
19
20
|
findUnique(args: {
|
|
20
21
|
where: {
|
|
@@ -46,7 +47,7 @@ export interface PrismaRaw {
|
|
|
46
47
|
$executeRawUnsafe(query: string, ...values: unknown[]): Promise<number>;
|
|
47
48
|
$queryRawUnsafe<T = unknown>(query: string, ...values: unknown[]): Promise<T>;
|
|
48
49
|
}
|
|
49
|
-
/** A Prisma client
|
|
50
|
+
/** A Prisma client, or its interactive-transaction client, as a structural shape that needs no `@prisma/client` import. */
|
|
50
51
|
export interface PrismaLike extends PrismaRaw {
|
|
51
52
|
$transaction<T>(fn: (tx: PrismaLike & PrismaRaw) => Promise<T>): Promise<T>;
|
|
52
53
|
}
|
|
@@ -1,34 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Prisma
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* The Prisma adapter for the data-source interface. It implements
|
|
3
|
+
* {@link DataSourceAdapter} against a Prisma client and passes the same conformance
|
|
4
|
+
* suite as the in-memory reference and the other adapters.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* them: `commit` runs the
|
|
8
|
-
* `ablo_idempotency` record
|
|
9
|
-
* the
|
|
6
|
+
* The adapter owns the transactional outbox and idempotency bookkeeping, so you
|
|
7
|
+
* never write them: `commit` runs the row mutations, the `ablo_outbox` append, and
|
|
8
|
+
* the `ablo_idempotency` record inside a single `prisma.$transaction`, and
|
|
9
|
+
* `migrations` returns the SQL that creates those two tables.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* a fake, while a real `PrismaClient` satisfies
|
|
11
|
+
* It takes no dependency on `@prisma/client`. The client is accepted structurally
|
|
12
|
+
* as {@link PrismaLike}, so this module compiles without Prisma installed and can
|
|
13
|
+
* be tested with a fake, while a real `PrismaClient` satisfies the shape at the
|
|
14
|
+
* call site.
|
|
14
15
|
*/
|
|
15
16
|
import { AbloValidationError } from '../../errors.js';
|
|
16
17
|
import { outboxEventSchema } from '../contract.js';
|
|
17
18
|
import { adapterTableMigrations } from '../migrations.js';
|
|
18
|
-
const lowerFirst = (s) => (s ? s
|
|
19
|
+
const lowerFirst = (s) => (s ? s.charAt(0).toLowerCase() + s.slice(1) : s);
|
|
19
20
|
/**
|
|
20
|
-
*
|
|
21
|
-
* the adapter
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* Dynamic property access on a statically-keyed type cannot be typed without an
|
|
29
|
-
* assertion; this is the reflection boundary, validated at runtime (`findMany` is
|
|
30
|
-
* a function) right after. `ablo generate` removes even this by emitting a typed
|
|
31
|
-
* `model → delegate` map, at which point this helper is replaced by a lookup.
|
|
21
|
+
* Resolves a model's Prisma delegate by name. This is the one unavoidable cast in
|
|
22
|
+
* the adapter, and it reflects a real limit of the type system rather than a
|
|
23
|
+
* shortcut. Writes inside `prisma.$transaction(tx => …)` must go through the
|
|
24
|
+
* transactional client `tx`, and the model is known only as a runtime string.
|
|
25
|
+
* Prisma keys its client by fixed property names (`{ task: TaskDelegate; … }`), so
|
|
26
|
+
* a dynamic `tx[name]` lookup is `unknown` to the compiler: there is no static key
|
|
27
|
+
* to infer from a string. The cast is checked at runtime immediately afterward by
|
|
28
|
+
* confirming that `findMany` is a function on the resolved delegate.
|
|
32
29
|
*/
|
|
33
30
|
function delegateFor(client, name) {
|
|
34
31
|
const delegate = client[name];
|
|
@@ -37,7 +34,7 @@ function delegateFor(client, name) {
|
|
|
37
34
|
}
|
|
38
35
|
return delegate;
|
|
39
36
|
}
|
|
40
|
-
/**
|
|
37
|
+
/** Translates a source-query `where` tuple set into a Prisma `where` object. */
|
|
41
38
|
function toPrismaWhere(where) {
|
|
42
39
|
const out = {};
|
|
43
40
|
for (const clause of where ?? []) {
|
|
@@ -104,7 +101,7 @@ function rowId(op) {
|
|
|
104
101
|
}
|
|
105
102
|
export function prismaDataSource(prisma, schema, options = {}) {
|
|
106
103
|
const delegateName = options.delegateName ?? lowerFirst;
|
|
107
|
-
void schema; //
|
|
104
|
+
void schema; // held for typed reads and model validation
|
|
108
105
|
const applyOperation = async (tx, op) => {
|
|
109
106
|
const delegate = delegateFor(tx, delegateName(op.model));
|
|
110
107
|
const id = rowId(op);
|
|
@@ -138,14 +135,15 @@ export function prismaDataSource(prisma, schema, options = {}) {
|
|
|
138
135
|
return prisma.$transaction(async (tx) => {
|
|
139
136
|
// Idempotency: a duplicate clientTxId returns the original rows, no re-apply.
|
|
140
137
|
const cached = await tx.$queryRawUnsafe(`SELECT response FROM ablo_idempotency WHERE client_tx_id = $1 LIMIT 1`, change.clientTxId);
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
const cachedRow = cached[0];
|
|
139
|
+
if (cachedRow)
|
|
140
|
+
return { rows: cachedRow.response };
|
|
143
141
|
const rows = [];
|
|
144
142
|
for (const [index, op] of change.operations.entries()) {
|
|
145
143
|
const row = await applyOperation(tx, op);
|
|
146
144
|
rows.push(row);
|
|
147
145
|
const entityId = String(row.id ?? rowId(op));
|
|
148
|
-
// Transactional outbox: one event per
|
|
146
|
+
// Transactional outbox: one event per operation, written in this same transaction.
|
|
149
147
|
await tx.$executeRawUnsafe(`INSERT INTO ablo_outbox (id, model, entity_id, type, data, client_tx_id, occurred_at)
|
|
150
148
|
VALUES ($1, $2, $3, $4, $5::jsonb, $6, $7)`, `${change.clientTxId}:${index}`, op.model, entityId, op.type, JSON.stringify(op.type === 'DELETE' ? null : row), change.clientTxId, Date.now());
|
|
151
149
|
}
|
|
@@ -170,7 +168,7 @@ export function prismaDataSource(prisma, schema, options = {}) {
|
|
|
170
168
|
}));
|
|
171
169
|
return {
|
|
172
170
|
events,
|
|
173
|
-
nextCursor: events.
|
|
171
|
+
nextCursor: events.at(-1)?.cursor ?? null,
|
|
174
172
|
};
|
|
175
173
|
},
|
|
176
174
|
};
|
|
@@ -1,28 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* The conformance suite for data-source adapters: a shared set of tests that checks
|
|
3
|
+
* whether an adapter is correct. Every adapter in this package (Prisma, Drizzle,
|
|
4
|
+
* Kysely) and any adapter you write yourself runs this suite to confirm it upholds
|
|
5
|
+
* the guarantees {@link DataSourceAdapter} promises. An adapter is complete when it
|
|
6
|
+
* passes, not merely when it compiles.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* failure.
|
|
10
|
-
* pass, so it
|
|
8
|
+
* The suite is runner-agnostic: each check is a plain async function that throws,
|
|
9
|
+
* via `node:assert`, on failure. {@link runDataSourceTests} registers the checks
|
|
10
|
+
* with whichever `it` or `test` function you pass, so it runs under vitest, jest,
|
|
11
|
+
* or `node:test`:
|
|
11
12
|
*
|
|
12
13
|
* import { it } from 'vitest';
|
|
13
14
|
* runDataSourceTests(memoryDataSource, it);
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
* the transactional outbox
|
|
17
|
-
*
|
|
16
|
+
* The checks cover the adapter contract: commit idempotency, read-after-write, and
|
|
17
|
+
* the transactional outbox with its cursor. They do not cover request-signature or
|
|
18
|
+
* scope rejection, which the HTTP handler enforces before the adapter is ever
|
|
19
|
+
* called and which is tested separately.
|
|
18
20
|
*/
|
|
19
21
|
import type { DataSourceAdapter } from './adapter.js';
|
|
22
|
+
/** A factory that returns a fresh adapter. Each check calls it to start from clean state. */
|
|
20
23
|
export type MakeAdapter = () => DataSourceAdapter | Promise<DataSourceAdapter>;
|
|
21
24
|
/** A single conformance check. `run` throws on failure. */
|
|
22
25
|
export interface ConformanceCheck {
|
|
23
26
|
readonly name: string;
|
|
24
27
|
run(): Promise<void>;
|
|
25
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds the list of conformance checks for an adapter. Call this to run the checks
|
|
31
|
+
* yourself, or use {@link runDataSourceTests} to register them with a test runner.
|
|
32
|
+
*/
|
|
26
33
|
export declare function dataSourceConformanceChecks(make: MakeAdapter): ConformanceCheck[];
|
|
27
34
|
/**
|
|
28
35
|
* Register the conformance checks with a test runner's `it`/`test` function.
|