@abloatai/ablo 0.26.0 → 0.28.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/CHANGELOG.md +42 -2
- package/README.md +102 -86
- package/dist/BaseSyncedStore.d.ts +85 -88
- package/dist/BaseSyncedStore.js +134 -151
- package/dist/Database.d.ts +68 -69
- package/dist/Database.js +316 -135
- package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
- package/dist/{ObjectPool.js → InstanceCache.js} +85 -83
- package/dist/LazyReferenceCollection.d.ts +11 -15
- package/dist/LazyReferenceCollection.js +12 -16
- package/dist/Model.d.ts +54 -52
- package/dist/Model.js +78 -62
- package/dist/ModelRegistry.d.ts +21 -19
- package/dist/ModelRegistry.js +23 -27
- package/dist/NetworkMonitor.d.ts +5 -6
- package/dist/NetworkMonitor.js +5 -6
- package/dist/SyncClient.d.ts +122 -118
- package/dist/SyncClient.js +541 -245
- package/dist/adapters/alwaysOnline.d.ts +6 -8
- package/dist/adapters/alwaysOnline.js +6 -8
- package/dist/adapters/inMemoryStorage.d.ts +10 -9
- package/dist/adapters/inMemoryStorage.js +21 -9
- package/dist/agent/Agent.d.ts +27 -32
- package/dist/agent/Agent.js +18 -19
- 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} +26 -33
- package/dist/ai-sdk/index.d.ts +25 -22
- package/dist/ai-sdk/index.js +25 -22
- package/dist/ai-sdk/wrap.d.ts +6 -7
- package/dist/ai-sdk/wrap.js +1 -1
- package/dist/auth/credentialPolicy.d.ts +69 -74
- package/dist/auth/credentialPolicy.js +51 -56
- package/dist/auth/credentialSource.d.ts +6 -5
- package/dist/auth/credentialSource.js +9 -10
- package/dist/auth/index.d.ts +59 -58
- package/dist/auth/index.js +31 -37
- 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 +173 -121
- package/dist/client/Ablo.d.ts +97 -74
- package/dist/client/Ablo.js +129 -163
- package/dist/client/ApiClient.d.ts +30 -19
- package/dist/client/ApiClient.js +442 -81
- package/dist/client/auth.d.ts +47 -47
- package/dist/client/auth.js +108 -117
- package/dist/client/claimHeartbeatLoop.d.ts +50 -0
- package/dist/client/claimHeartbeatLoop.js +88 -0
- package/dist/client/consoleLogger.d.ts +5 -6
- package/dist/client/consoleLogger.js +5 -6
- package/dist/client/createInternalComponents.d.ts +16 -17
- package/dist/client/createInternalComponents.js +26 -31
- package/dist/client/createModelProxy.d.ts +130 -120
- package/dist/client/createModelProxy.js +152 -122
- package/dist/client/credentialEndpoint.d.ts +40 -42
- package/dist/client/credentialEndpoint.js +35 -36
- package/dist/client/functionalUpdate.d.ts +29 -27
- package/dist/client/functionalUpdate.js +21 -21
- package/dist/client/hostedEndpoints.d.ts +9 -12
- package/dist/client/hostedEndpoints.js +9 -12
- package/dist/client/httpClient.d.ts +59 -53
- package/dist/client/httpClient.js +29 -31
- package/dist/client/identity.d.ts +15 -20
- package/dist/client/identity.js +47 -58
- package/dist/client/modelRegistration.d.ts +5 -9
- package/dist/client/modelRegistration.js +78 -87
- package/dist/client/options.d.ts +157 -157
- package/dist/client/options.js +3 -7
- package/dist/client/registerDataSource.d.ts +9 -9
- package/dist/client/registerDataSource.js +15 -16
- package/dist/client/resourceTypes.d.ts +64 -75
- package/dist/client/resourceTypes.js +4 -10
- package/dist/client/schemaConfig.d.ts +31 -43
- package/dist/client/schemaConfig.js +38 -50
- package/dist/client/sessionMint.d.ts +16 -12
- package/dist/client/sessionMint.js +26 -31
- package/dist/client/validateAbloOptions.d.ts +12 -14
- package/dist/client/validateAbloOptions.js +8 -9
- package/dist/client/writeOptionsSchema.d.ts +18 -16
- package/dist/client/writeOptionsSchema.js +23 -20
- package/dist/client/wsMutationExecutor.d.ts +16 -20
- package/dist/client/wsMutationExecutor.js +18 -23
- package/dist/commit/contract.d.ts +493 -0
- package/dist/commit/contract.js +187 -0
- package/dist/commit/index.d.ts +6 -0
- package/dist/commit/index.js +5 -0
- package/dist/context.d.ts +6 -4
- package/dist/context.js +6 -4
- package/dist/coordination/index.d.ts +10 -8
- package/dist/coordination/index.js +14 -12
- package/dist/coordination/schema.d.ts +176 -128
- package/dist/coordination/schema.js +197 -133
- package/dist/coordination/trace.d.ts +9 -10
- package/dist/coordination/trace.js +13 -14
- package/dist/core/DatabaseManager.d.ts +5 -7
- package/dist/core/DatabaseManager.js +15 -19
- package/dist/core/QueryProcessor.d.ts +7 -9
- package/dist/core/QueryProcessor.js +22 -28
- package/dist/core/QueryView.d.ts +8 -8
- package/dist/core/QueryView.js +2 -2
- package/dist/core/StoreManager.d.ts +14 -14
- package/dist/core/StoreManager.js +33 -24
- package/dist/core/ViewRegistry.d.ts +5 -5
- package/dist/core/ViewRegistry.js +4 -4
- package/dist/core/index.d.ts +17 -12
- package/dist/core/index.js +32 -26
- package/dist/core/openIDBWithTimeout.d.ts +38 -36
- package/dist/core/openIDBWithTimeout.js +42 -43
- package/dist/core/queryUtils.d.ts +45 -0
- package/dist/core/queryUtils.js +69 -0
- package/dist/core/storeContract.d.ts +63 -61
- package/dist/core/storeContract.js +8 -12
- package/dist/environment.d.ts +28 -0
- package/dist/environment.js +21 -0
- package/dist/errorCodes.d.ts +107 -99
- package/dist/errorCodes.js +137 -134
- package/dist/errors.d.ts +160 -166
- package/dist/errors.js +155 -158
- package/dist/index.d.ts +36 -27
- package/dist/index.js +91 -86
- package/dist/interfaces/index.d.ts +102 -113
- package/dist/interfaces/index.js +5 -4
- package/dist/keys/index.d.ts +27 -29
- package/dist/keys/index.js +41 -40
- 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 +124 -131
- package/dist/mutators/UndoManager.js +177 -156
- package/dist/mutators/defineMutators.d.ts +23 -34
- 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 +104 -100
- package/dist/policy/types.js +67 -66
- package/dist/query/client.d.ts +28 -23
- package/dist/query/client.js +45 -43
- package/dist/query/types.d.ts +37 -60
- package/dist/query/types.js +13 -33
- package/dist/react/AbloProvider.d.ts +1 -1
- package/dist/react/AbloProvider.js +2 -2
- package/dist/react/context.d.ts +25 -28
- 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 +28 -25
- package/dist/react/useAblo.js +41 -17
- 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 +10 -11
- package/dist/react/useMutationFailureListener.d.ts +8 -8
- package/dist/react/useMutationFailureListener.js +8 -8
- package/dist/react/useMutators.d.ts +11 -11
- package/dist/react/useMutators.js +3 -3
- package/dist/react/useReactive.js +2 -2
- package/dist/react/useSyncStatus.d.ts +4 -6
- package/dist/react/useUndoScope.d.ts +7 -9
- package/dist/react/useUndoScope.js +1 -1
- 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 +20 -24
- package/dist/schema/ddlLock.js +18 -23
- 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 +35 -48
- package/dist/schema/generate.d.ts +12 -12
- package/dist/schema/generate.js +12 -12
- package/dist/schema/index.d.ts +3 -3
- package/dist/schema/index.js +21 -23
- package/dist/schema/model.d.ts +118 -143
- package/dist/schema/model.js +22 -33
- package/dist/schema/openapi.d.ts +10 -9
- package/dist/schema/openapi.js +5 -3
- package/dist/schema/queries.d.ts +29 -31
- package/dist/schema/queries.js +23 -25
- package/dist/schema/relation.d.ts +89 -99
- package/dist/schema/relation.js +13 -13
- package/dist/schema/residency.d.ts +16 -13
- package/dist/schema/residency.js +16 -13
- package/dist/schema/roles.d.ts +36 -43
- package/dist/schema/roles.js +31 -37
- package/dist/schema/schema.d.ts +64 -43
- package/dist/schema/schema.js +31 -32
- package/dist/schema/select.d.ts +13 -13
- package/dist/schema/select.js +13 -13
- package/dist/schema/serialize.d.ts +28 -31
- 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} +26 -49
- 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 +30 -25
- package/dist/source/adapter.js +10 -10
- package/dist/source/adapters/drizzle.d.ts +28 -23
- package/dist/source/adapters/drizzle.js +30 -25
- package/dist/source/adapters/kysely.d.ts +27 -25
- package/dist/source/adapters/kysely.js +24 -23
- package/dist/source/adapters/memory.d.ts +8 -7
- package/dist/source/adapters/memory.js +9 -8
- package/dist/source/adapters/prisma.d.ts +13 -12
- package/dist/source/adapters/prisma.js +22 -25
- package/dist/source/conformance.d.ts +18 -11
- package/dist/source/conformance.js +17 -11
- package/dist/source/connector.d.ts +31 -32
- package/dist/source/connector.js +28 -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 +46 -58
- package/dist/source/factory.js +22 -27
- package/dist/source/index.d.ts +7 -9
- package/dist/source/index.js +12 -14
- package/dist/source/migrations.d.ts +9 -9
- package/dist/source/migrations.js +9 -9
- package/dist/source/next.d.ts +9 -10
- package/dist/source/next.js +6 -7
- package/dist/source/pushQueue.d.ts +69 -47
- package/dist/source/pushQueue.js +32 -28
- package/dist/source/signing.d.ts +46 -17
- package/dist/source/signing.js +28 -11
- package/dist/source/types.d.ts +121 -104
- package/dist/source/types.js +13 -14
- package/dist/stores/ObjectStore.d.ts +24 -12
- package/dist/stores/ObjectStore.js +38 -16
- package/dist/stores/ObjectStoreContract.d.ts +14 -15
- package/dist/stores/SyncActionStore.d.ts +7 -11
- package/dist/stores/SyncActionStore.js +13 -17
- package/dist/surface.d.ts +28 -21
- package/dist/surface.js +29 -20
- package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
- package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
- package/dist/sync/ConnectionManager.d.ts +39 -50
- package/dist/sync/ConnectionManager.js +55 -66
- package/dist/sync/NetworkProbe.d.ts +24 -29
- package/dist/sync/NetworkProbe.js +63 -69
- package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
- package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
- package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
- package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
- package/dist/sync/SyncWebSocket.d.ts +141 -166
- package/dist/sync/SyncWebSocket.js +191 -223
- package/dist/sync/awaitClaimGrant.d.ts +18 -18
- package/dist/sync/awaitClaimGrant.js +11 -11
- package/dist/sync/bootstrapApply.d.ts +34 -24
- package/dist/sync/bootstrapApply.js +27 -19
- package/dist/sync/commitFrames.d.ts +21 -20
- package/dist/sync/commitFrames.js +18 -18
- package/dist/sync/createClaimStream.d.ts +23 -22
- package/dist/sync/createClaimStream.js +105 -23
- package/dist/sync/createPresenceStream.d.ts +19 -18
- package/dist/sync/createPresenceStream.js +25 -26
- package/dist/sync/createSnapshot.d.ts +12 -14
- package/dist/sync/createSnapshot.js +20 -26
- package/dist/sync/credentialLifecycle.d.ts +104 -104
- package/dist/sync/credentialLifecycle.js +140 -147
- package/dist/sync/deltaPipeline.d.ts +36 -34
- package/dist/sync/deltaPipeline.js +64 -65
- package/dist/sync/groupChange.d.ts +63 -61
- package/dist/sync/groupChange.js +74 -78
- package/dist/sync/heartbeat.d.ts +34 -33
- package/dist/sync/heartbeat.js +31 -31
- package/dist/sync/participants.d.ts +19 -19
- package/dist/sync/persistedPrefix.d.ts +12 -0
- package/dist/sync/persistedPrefix.js +22 -0
- package/dist/sync/schemas.d.ts +3 -2
- package/dist/sync/schemas.js +14 -10
- package/dist/sync/syncCursor.d.ts +17 -21
- package/dist/sync/syncCursor.js +17 -21
- package/dist/sync/syncPlan.d.ts +28 -36
- package/dist/sync/syncPlan.js +18 -19
- package/dist/sync/syncPosition.d.ts +54 -49
- package/dist/sync/syncPosition.js +57 -52
- package/dist/sync/wsFrameHandlers.d.ts +35 -36
- package/dist/sync/wsFrameHandlers.js +63 -67
- package/dist/testing/fixtures/bootstrap.d.ts +12 -6
- package/dist/testing/fixtures/bootstrap.js +12 -6
- package/dist/testing/fixtures/deltas.d.ts +30 -33
- package/dist/testing/fixtures/deltas.js +30 -33
- package/dist/testing/fixtures/models.d.ts +11 -10
- package/dist/testing/fixtures/models.js +11 -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 -15
- package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
- package/dist/testing/helpers/wait.d.ts +13 -8
- package/dist/testing/helpers/wait.js +13 -8
- package/dist/testing/index.d.ts +5 -3
- package/dist/testing/index.js +3 -2
- package/dist/testing/mocks/FakeDatabase.d.ts +18 -0
- package/dist/testing/mocks/FakeDatabase.js +10 -0
- 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 +20 -17
- package/dist/testing/mocks/MockSyncContext.js +15 -13
- package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
- package/dist/testing/mocks/MockSyncStore.js +11 -11
- package/dist/testing/mocks/MockWebSocket.d.ts +28 -23
- package/dist/testing/mocks/MockWebSocket.js +22 -21
- package/dist/transactions/TransactionQueue.d.ts +244 -181
- package/dist/transactions/TransactionQueue.js +929 -423
- package/dist/transactions/TransactionStore.d.ts +6 -4
- package/dist/transactions/TransactionStore.js +6 -4
- package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
- package/dist/transactions/UnconfirmedWrites.js +104 -0
- package/dist/transactions/coalesceRules.d.ts +41 -17
- package/dist/transactions/coalesceRules.js +40 -17
- package/dist/transactions/commitEnvelope.d.ts +132 -0
- package/dist/transactions/commitEnvelope.js +139 -0
- package/dist/transactions/commitOutboxStore.d.ts +32 -0
- package/dist/transactions/commitOutboxStore.js +26 -0
- package/dist/transactions/commitPayload.d.ts +63 -52
- package/dist/transactions/commitPayload.js +54 -57
- package/dist/transactions/deltaConfirmation.d.ts +20 -22
- package/dist/transactions/deltaConfirmation.js +37 -45
- package/dist/transactions/httpCommitEnvelope.d.ts +43 -0
- package/dist/transactions/httpCommitEnvelope.js +179 -0
- package/dist/transactions/optimisticApply.d.ts +49 -0
- package/dist/transactions/optimisticApply.js +65 -0
- package/dist/transactions/replayValidation.d.ts +182 -0
- package/dist/transactions/replayValidation.js +156 -0
- package/dist/types/global.d.ts +46 -41
- package/dist/types/global.js +20 -19
- package/dist/types/index.d.ts +71 -77
- package/dist/types/index.js +22 -22
- package/dist/types/modelData.d.ts +6 -8
- package/dist/types/modelData.js +5 -7
- package/dist/types/participant.d.ts +10 -11
- package/dist/types/participant.js +6 -8
- package/dist/types/streams.d.ts +208 -195
- 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} +42 -98
- 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/wire/bootstrapReason.d.ts +9 -0
- package/dist/wire/bootstrapReason.js +8 -0
- 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 +30 -31
- package/dist/wire/errorEnvelope.js +34 -40
- package/dist/wire/frames.d.ts +315 -86
- package/dist/wire/frames.js +47 -33
- package/dist/wire/index.d.ts +18 -14
- package/dist/wire/index.js +32 -27
- package/dist/wire/listEnvelope.d.ts +16 -23
- package/dist/wire/listEnvelope.js +7 -6
- package/dist/wire/protocol.d.ts +25 -32
- package/dist/wire/protocol.js +25 -32
- package/dist/wire/protocolVersion.d.ts +44 -40
- package/dist/wire/protocolVersion.js +44 -40
- package/docs/api.md +10 -10
- package/docs/coordination.md +59 -0
- package/docs/mcp.md +1 -1
- package/package.json +17 -11
- package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
- package/dist/ai-sdk/coordination-context.d.ts +0 -52
- package/dist/core/query-utils.d.ts +0 -34
- package/dist/core/query-utils.js +0 -59
- package/dist/schema/sync-delta-row.js +0 -103
- package/dist/schema/sync-delta-wire.js +0 -102
- 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 -8
- package/dist/server/storage-mode.js +0 -28
- package/dist/source/connector-protocol.d.ts +0 -159
- package/dist/source/connector-protocol.js +0 -161
- package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
- package/dist/transactions/OptimisticEchoTracker.js +0 -104
- package/dist/transactions/mutation-error-handler.d.ts +0 -5
- package/dist/transactions/mutation-error-handler.js +0 -39
- package/dist/transactions/optimistic.d.ts +0 -24
- package/dist/transactions/optimistic.js +0 -45
- package/dist/transactions/persistedReplay.d.ts +0 -93
- package/dist/transactions/persistedReplay.js +0 -105
- 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))
|
|
@@ -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))
|
|
@@ -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) {
|
|
@@ -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
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);
|
|
@@ -146,7 +143,7 @@ export function prismaDataSource(prisma, schema, options = {}) {
|
|
|
146
143
|
const row = await applyOperation(tx, op);
|
|
147
144
|
rows.push(row);
|
|
148
145
|
const entityId = String(row.id ?? rowId(op));
|
|
149
|
-
// Transactional outbox: one event per
|
|
146
|
+
// Transactional outbox: one event per operation, written in this same transaction.
|
|
150
147
|
await tx.$executeRawUnsafe(`INSERT INTO ablo_outbox (id, model, entity_id, type, data, client_tx_id, occurred_at)
|
|
151
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());
|
|
152
149
|
}
|
|
@@ -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.
|
|
@@ -1,26 +1,32 @@
|
|
|
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 assert from 'node:assert/strict';
|
|
20
22
|
const change = (clientTxId, ops) => ({
|
|
21
23
|
clientTxId,
|
|
22
24
|
operations: ops,
|
|
23
25
|
});
|
|
26
|
+
/**
|
|
27
|
+
* Builds the list of conformance checks for an adapter. Call this to run the checks
|
|
28
|
+
* yourself, or use {@link runDataSourceTests} to register them with a test runner.
|
|
29
|
+
*/
|
|
24
30
|
export function dataSourceConformanceChecks(make) {
|
|
25
31
|
return [
|
|
26
32
|
{
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Opens the connector's side of the Data Source reverse channel. You run this
|
|
3
|
+
* process next to your database; it dials an outbound WebSocket to Ablo and serves
|
|
4
|
+
* the load, list, and commit requests over that socket, so a handler with no
|
|
5
|
+
* public URL never needs to receive inbound webhooks. It is the counterpart to
|
|
6
|
+
* `createPushQueue`, which gives the outbound events feed the same treatment, and
|
|
7
|
+
* it speaks the frames defined in `connectorProtocol.ts`.
|
|
3
8
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
* Ablo Cloud and serves the `commit`/`load`/`list` leg over that socket instead
|
|
7
|
-
* of receiving inbound webhooks. This is the symmetric primitive to
|
|
8
|
-
* `createPushQueue` (which already gives the `events` leg an outbound transport)
|
|
9
|
-
* and mirrors the Stripe CLI's `stripe listen`.
|
|
10
|
-
*
|
|
11
|
-
* The connector does NOT reimplement any handler logic. It wraps the SAME
|
|
12
|
-
* `(request: Request) => Promise<Response>` the customer's deployed route uses:
|
|
9
|
+
* The connector reimplements none of the handler logic. It wraps the same
|
|
10
|
+
* `(request: Request) => Promise<Response>` your deployed route already uses:
|
|
13
11
|
*
|
|
14
12
|
* import { dataSource, createSourceConnector } from '@abloatai/ablo';
|
|
15
13
|
* import { sourceOptions } from './ablo.source'; // shared with route.ts
|
|
@@ -20,23 +18,24 @@
|
|
|
20
18
|
* });
|
|
21
19
|
* await connector.run(controller.signal);
|
|
22
20
|
*
|
|
23
|
-
* Each
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* Each incoming `request` frame is replayed into a `Request` that carries the
|
|
22
|
+
* original signature headers, so the handler verifies it through the same
|
|
23
|
+
* `verifyAbloSourceRequest` it uses on the webhook path. The transport changes;
|
|
24
|
+
* the trust model does not.
|
|
27
25
|
*/
|
|
28
26
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
27
|
+
* The reconnect backoff, in milliseconds, indexed by the number of consecutive
|
|
28
|
+
* failed connect attempts. A long-lived control socket should recover quickly and
|
|
29
|
+
* then settle at a steady interval, so this is a short curve that caps rather than
|
|
30
|
+
* growing without bound. The final entry repeats for any further attempts, and a
|
|
31
|
+
* connection that reaches `ready` resets the count to zero.
|
|
34
32
|
*/
|
|
35
33
|
export declare const DEFAULT_RECONNECT_SCHEDULE: readonly number[];
|
|
36
34
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
35
|
+
* The minimal WebSocket surface the connector needs, matching the standard
|
|
36
|
+
* `globalThis.WebSocket` API that browsers and current Node versions provide. The
|
|
37
|
+
* `ws` package's default export also satisfies it. Supply your own implementation
|
|
38
|
+
* to substitute a fake in tests.
|
|
40
39
|
*/
|
|
41
40
|
export interface ConnectorWebSocket {
|
|
42
41
|
send(data: string): void;
|
|
@@ -57,18 +56,18 @@ export type ConnectorWebSocketFactory = (url: string, protocols: readonly string
|
|
|
57
56
|
export type ConnectorStatus = 'connecting' | 'ready' | 'disconnected';
|
|
58
57
|
export interface SourceConnectorOptions {
|
|
59
58
|
/**
|
|
60
|
-
* Ablo project API key.
|
|
61
|
-
*
|
|
62
|
-
* reverse
|
|
59
|
+
* Your Ablo project API key. A test key (`sk_test_*`) works by default for local
|
|
60
|
+
* development and sandboxes; a live key (`sk_live_*`) is accepted only once the
|
|
61
|
+
* source has opted the reverse channel in for production use.
|
|
63
62
|
*/
|
|
64
63
|
readonly apiKey: string;
|
|
65
64
|
/**
|
|
66
|
-
* The
|
|
67
|
-
* `abloSource(options)`. The connector feeds it
|
|
68
|
-
*
|
|
65
|
+
* The Data Source handler to serve, as returned by `dataSource(options)` or
|
|
66
|
+
* `abloSource(options)`. The connector feeds it each request and relays the
|
|
67
|
+
* response back untouched; it never inspects or alters either one.
|
|
69
68
|
*/
|
|
70
69
|
readonly handler: (request: Request) => Promise<Response>;
|
|
71
|
-
/** Ablo
|
|
70
|
+
/** The Ablo base URL to dial. Defaults to `https://api.abloatai.com`. */
|
|
72
71
|
readonly baseURL?: string;
|
|
73
72
|
/** Inject a WebSocket implementation. Default `globalThis.WebSocket`. */
|
|
74
73
|
readonly webSocket?: ConnectorWebSocketFactory;
|
|
@@ -87,9 +86,9 @@ export interface SourceConnectorOptions {
|
|
|
87
86
|
}
|
|
88
87
|
export interface SourceConnector {
|
|
89
88
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* WebSocket implementation available
|
|
89
|
+
* Runs the connect, serve, and reconnect loop until `signal` aborts, then
|
|
90
|
+
* resolves. It rejects only on a fatal condition that cannot be retried, such as
|
|
91
|
+
* no WebSocket implementation being available.
|
|
93
92
|
*/
|
|
94
93
|
run(signal: AbortSignal): Promise<void>;
|
|
95
94
|
}
|