@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.28.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **Commits are now crash-durable — a sealed envelope replays the exact request after a restart, on both transports.** Before a batch reaches the wire, the WebSocket client seals it into one atomic outbox record: the stable idempotency key, the exact JSON-normalized ordered operations, and the source mutations it supersedes. Recovery replays the sealed request as it was sent — never re-projected from model state in the new process — and a multi-operation commit is only ever replayed whole, so an atomic A+B can't come back later as A and B separately.
|
|
8
|
+
|
|
9
|
+
- **The stateless HTTP client replays its outbox on startup.** It persists the exact request (method, path, body, idempotency key) and re-sends unacknowledged envelopes before its first new request. A definitive rejection (a 4xx other than 429) settles the envelope instead of retrying it.
|
|
10
|
+
|
|
11
|
+
- **New `commitOutbox` client option + `CommitOutboxStore` interface.** Browsers default to strict IndexedDB storage when persistence is on; Node agents and workers can inject workflow-, SQLite-, or filesystem-backed storage so commits survive process restarts. The client's transaction journal now writes with strict durability, so an acknowledged outbox record means disk-backed.
|
|
12
|
+
|
|
13
|
+
- **Replay is fenced and fails closed.** Reusing an idempotency key with a different request is rejected on both transports; replay is scoped to the actor and server that sealed the envelope and bounded to the server's idempotency retention, so a stale envelope is held for review instead of re-sent; a write queued behind an ambiguous predecessor waits for it to settle rather than overtaking it; and a persistence adapter that cannot guarantee durability reports failure instead of phantom success. Generated create ids are sealed with the request, so a crash mid-create recovers the same row.
|
|
14
|
+
|
|
15
|
+
- **`@abloatai/ablo/commit` publishes the transport-independent v2 commit contract.** Branded identifiers, ordered operations, explicit write preconditions (`unchanged_since`, `version_matches`, `claim_fence`), and a discriminated `CommitReceipt` — `committed`, `conflicted` (carrying the smallest current state needed to reconcile), or `rejected` (a typed error plus the capability a retry would need). This release publishes the contract so tooling and tests can validate against it today; the engine's live commit path still speaks the current protocol, and the cutover to v2 ships server-side.
|
|
16
|
+
|
|
17
|
+
- **New wire exports.** `@abloatai/ablo/wire` gains the matching `CommitRequestMessage` / `CommitResultMessage` frames, re-exports the current transport's operation schemas under `legacyCommit*` names, and exports `BootstrapReason` — the machine-readable reasons a live delta stream must resume via catch-up (`too_far_behind`, `too_many_deltas`, `missing_entities`, `stream_gap`).
|
|
18
|
+
|
|
19
|
+
- **Reactive reads are typed as what they actually return: snapshot rows, not model instances.** `useAblo` selectors now receive `AbloReads<Schema>` — model reads typed as the row's data fields plus schema computeds, without relation accessors or model methods. Reading `row.layers` inside a selector is a compile error instead of a silent `undefined` at runtime; compose relations through a dedicated hook or selector instead. The new `Row<'slides'>` / `InferRow` types are the snapshot-row companion to `Model<'slides'>`, mirroring what `toReactiveSnapshot()` produces. This is a type-level change only: selectors that compiled against relation accessors now fail to compile, and each of those reads was already returning `undefined` — the new errors point at real bugs. Runtime behavior is unchanged.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- **The resume cursor advances only through the contiguous durable prefix of a delta frame.** A frame spanning several local stores commits per store, and those transactions can fail independently — taking the maximum id from any successful store could permanently skip an earlier failed delta on every later catch-up.
|
|
24
|
+
|
|
25
|
+
- **Conflicting undo-scope options warn instead of being silently ignored.** A scope keeps the options it was created with; the silent version of that rule could leave a surface believing it enabled stream recording when it hadn't.
|
|
26
|
+
|
|
27
|
+
- **Docs and error copy name the real HTTP mount.** REST paths are documented as `/api/v1/...` — the OpenAPI server URLs carry the `/api` mount — and the `jwt_issuer_untrusted` message no longer points at an endpoint that doesn't exist.
|
|
28
|
+
|
|
29
|
+
## 0.27.0
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- **Claims can now be held for long-running work by heartbeating — on both transports.** A claim's TTL is crash cleanup, not a work estimate; work that outlives it (a 30-minute report, a long agent run) keeps its lease by beating. `claim({ heartbeat: true })` beats automatically until release; `held.heartbeat()` beats by hand. A lapsed lease answers the next beat with `AbloClaimedError` (`claim_lost`) — for a socketless worker, the failed beat _is_ the loss notification, and any write attempted under the old lease is independently rejected by its `readAt` guard.
|
|
34
|
+
|
|
35
|
+
- **Beats carry progress and pressure.** `heartbeat({ details })` stores lightweight progress as the claim's peer-visible `meta.progress` (last beat wins, via `claim.state`); every beat's answer reports `queueDepth` — how many participants wait in line behind the lease — observable per auto-beat with the new `onHeartbeat` claim option.
|
|
36
|
+
|
|
37
|
+
- **`ablo.claims.heartbeatAll({ ttl })`** extends every lease the credential holds in one request (`POST /api/v1/claims/heartbeat`) — the stateless twin of the WebSocket keepalive, for workers holding many rows.
|
|
38
|
+
|
|
39
|
+
- **Keepalive renewals extend but never shorten a lease**, so an explicit work-duration `ttl` now survives pings and brief reconnects instead of collapsing to the liveness window.
|
|
40
|
+
|
|
41
|
+
- **README.** The quick start leads with a runnable example, and a new _Background workers_ section shows the enqueue-on-your-own-queue / heartbeat-the-claim pattern end to end.
|
|
42
|
+
|
|
3
43
|
## 0.26.0
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
|
@@ -25,7 +65,7 @@
|
|
|
25
65
|
### Minor Changes
|
|
26
66
|
|
|
27
67
|
- ca30064: Logical replication is now the documented default storage path, with self-service data-source registration from the CLI.
|
|
28
|
-
- **`ablo connect --register`** — registers your database as an Ablo data source over logical replication in one step: it runs the same pre-flight replication probe `ablo connect` uses (server reachable, `REPLICATION` privilege, `wal_level=logical`, publication/slot creatable), and on success `POST`s the connection to the engine's `/v1/datasources`. The `ek_`-authed call scopes the source to your org automatically; the password is stored decomposed as a secret, never echoed back. This is the "registration is the enable" path — there is no separate tier or flag to pick.
|
|
68
|
+
- **`ablo connect --register`** — registers your database as an Ablo data source over logical replication in one step: it runs the same pre-flight replication probe `ablo connect` uses (server reachable, `REPLICATION` privilege, `wal_level=logical`, publication/slot creatable), and on success `POST`s the connection to the engine's `/api/v1/datasources`. The `ek_`-authed call scopes the source to your org automatically; the password is stored decomposed as a secret, never echoed back. This is the "registration is the enable" path — there is no separate tier or flag to pick.
|
|
29
69
|
- **`ablo init` leads with logical replication** — the default storage mode is now `replication` (was `endpoint`); the generated env + next-steps point at `ablo connect` / `ablo connect --register`. The signed-endpoint and direct modes remain as the explicit fallback / legacy options.
|
|
30
70
|
- **`ablo status`** — a data-plane diagnostic that probes whether your registered source is reachable and replicating (failure-only reporting, so it never falsely reports healthy).
|
|
31
71
|
- **`ablo push`** — minor guard/UX refinements (deploy-target clarity).
|
|
@@ -580,7 +620,7 @@
|
|
|
580
620
|
|
|
581
621
|
### Patch Changes
|
|
582
622
|
|
|
583
|
-
- `Model<'name'>` type helper via the `Register` binding — name your model in one parameter (`Model<'tasks'>`) instead of restating `typeof schema`; `Model<S, 'name'>` is also supported and `InferModel` is deprecated. CLI: retire the stale `dev` wording from the login outro and `push` header. Docs: cover the `Register` binding end-to-end and document the `pk_` publishable key + the `/v1/commits` HTTP path.
|
|
623
|
+
- `Model<'name'>` type helper via the `Register` binding — name your model in one parameter (`Model<'tasks'>`) instead of restating `typeof schema`; `Model<S, 'name'>` is also supported and `InferModel` is deprecated. CLI: retire the stale `dev` wording from the login outro and `push` header. Docs: cover the `Register` binding end-to-end and document the `pk_` publishable key + the `/api/v1/commits` HTTP path.
|
|
584
624
|
- 3024593: Fix `sessions.create({ user })` 403 — user sessions now mint via the sk\_-gated ephemeral-key door
|
|
585
625
|
- `sessions.create({ user })` mints an `ek_` user session via `/auth/ephemeral-keys` (was wrongly routed through `/auth/capability`, which rejects human participants — writes were being attributed to agents).
|
|
586
626
|
- Control-plane calls always present your original `sk_`, never the client's exchanged sync credential.
|
package/README.md
CHANGED
|
@@ -39,10 +39,10 @@ Under the hood, you define your data once with a Zod schema and get the same
|
|
|
39
39
|
typed model client for every actor — people, server actions, and agents:
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
-
await ablo.
|
|
43
|
-
await ablo.
|
|
44
|
-
await ablo.
|
|
45
|
-
await using
|
|
42
|
+
await ablo.weatherReports.create({ data }) // create
|
|
43
|
+
await ablo.weatherReports.retrieve({ id }) // read
|
|
44
|
+
await ablo.weatherReports.update({ id, data }) // update
|
|
45
|
+
await using claim = await ablo.weatherReports.claim({ id }) // hold for slow agent work
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
The schema is the public contract. It gives you typed model methods, realtime
|
|
@@ -63,8 +63,9 @@ yet? A **sandbox** `sk_test` key holds throwaway **test data** — like Stripe t
|
|
|
63
63
|
mode — so you can explore before pointing it at your Postgres. Test-mode only; in
|
|
64
64
|
production every row lives in your database.)
|
|
65
65
|
|
|
66
|
-
**Built for** collaborative editors, AI agent workflows,
|
|
67
|
-
|
|
66
|
+
**Built for** collaborative editors, AI agent workflows, background workers on
|
|
67
|
+
your own infrastructure, and internal tools — anywhere people and agents change
|
|
68
|
+
shared state and everyone has to see it live.
|
|
68
69
|
|
|
69
70
|
## Set up
|
|
70
71
|
|
|
@@ -111,62 +112,15 @@ instead of guessing:
|
|
|
111
112
|
|
|
112
113
|
## Quick Start
|
|
113
114
|
|
|
115
|
+
One schema, one client, one write path for humans and agents — this runs as-is
|
|
116
|
+
after `ablo push`:
|
|
117
|
+
|
|
114
118
|
```ts
|
|
115
119
|
import Ablo from '@abloatai/ablo';
|
|
116
120
|
import { defineSchema, model, z } from '@abloatai/ablo/schema';
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
The schema is registered once (init scaffolds `ablo/register.ts` for you), and
|
|
120
|
-
every type is one parameter away — no `typeof schema` re-stating, anywhere:
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
// ablo/register.ts — scaffolded by `npx ablo init`, sits beside ablo/schema.ts
|
|
124
|
-
import type { schema } from './schema';
|
|
125
|
-
declare module '@abloatai/ablo' {
|
|
126
|
-
interface Register { Schema: typeof schema }
|
|
127
|
-
}
|
|
128
|
-
export {};
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
It's a regular `.ts` module, not a hand-authored `.d.ts`. The top-level
|
|
132
|
-
`import type { schema }` makes the `declare module` block *merge* into (augment)
|
|
133
|
-
the SDK's `Register` interface instead of colliding with it — the same shape
|
|
134
|
-
[TanStack Router uses in `src/router.tsx`](https://tanstack.com/router/latest/docs/framework/react/guide/type-safety). Any `.ts` file in your
|
|
135
|
-
`tsconfig` `include` works; it never needs to be imported.
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
import type { Model } from '@abloatai/ablo/schema';
|
|
139
|
-
|
|
140
|
-
type WeatherReport = Model<'weatherReports'>; // fully typed from YOUR schema
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
(The same `Register` binding types every hook and client — it's the
|
|
144
|
-
TanStack-Router pattern: declare the source of truth once, everything
|
|
145
|
-
infers from it.)
|
|
146
121
|
|
|
147
|
-
### Naming the client type
|
|
148
|
-
|
|
149
|
-
When you need to pass the client around (a function parameter, a context value),
|
|
150
|
-
**infer the type from the value** — `type Sync = typeof sync`:
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
export const sync = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
154
|
-
export type Sync = typeof sync; // fully-typed, schema-aware
|
|
155
|
-
|
|
156
|
-
function persist(client: Sync) { /* ... */ }
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
This is the same idiom as tRPC's `type AppRouter = typeof appRouter` and
|
|
160
|
-
Drizzle's `typeof db` — the factory resolves the typed overload at the call
|
|
161
|
-
site, so `typeof sync` carries your schema. Do **not** write
|
|
162
|
-
`ReturnType<typeof Ablo>`: that collapses to the untyped last overload and
|
|
163
|
-
loses your model types. There is no bespoke client-type generic to import —
|
|
164
|
-
`typeof` your client value is the type.
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
122
|
const schema = defineSchema({
|
|
168
|
-
//
|
|
169
|
-
// provided automatically — don't declare them.
|
|
123
|
+
// id, createdAt, updatedAt, organizationId, createdBy come free on every model
|
|
170
124
|
weatherReports: model({
|
|
171
125
|
location: z.string(),
|
|
172
126
|
status: z.enum(['pending', 'ready']),
|
|
@@ -174,29 +128,21 @@ const schema = defineSchema({
|
|
|
174
128
|
}),
|
|
175
129
|
});
|
|
176
130
|
|
|
177
|
-
const ablo = Ablo({
|
|
178
|
-
schema,
|
|
179
|
-
apiKey: process.env.ABLO_API_KEY, // written to .env.local by `npx ablo push`
|
|
180
|
-
});
|
|
181
|
-
// Your Postgres is connected once via `npx ablo connect` (logical replication) —
|
|
182
|
-
// not passed here. Ablo tails its WAL; your rows never leave your database.
|
|
183
|
-
|
|
131
|
+
const ablo = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
184
132
|
await ablo.ready();
|
|
185
133
|
|
|
186
134
|
const created = await ablo.weatherReports.create({
|
|
187
|
-
data: {
|
|
188
|
-
location: 'Stockholm',
|
|
189
|
-
status: 'pending',
|
|
190
|
-
},
|
|
135
|
+
data: { location: 'Stockholm', status: 'pending' },
|
|
191
136
|
});
|
|
192
137
|
|
|
193
|
-
//
|
|
194
|
-
// claim is held nobody else can overwrite it; anyone else who tries waits in
|
|
195
|
-
// line and re-reads the result. This is the whole point of Ablo.
|
|
138
|
+
// Claim the row before slow work — anyone else waits in line, then re-reads.
|
|
196
139
|
await using claim = await ablo.weatherReports.claim({ id: created.id });
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
140
|
+
const forecast = await fetchForecast(claim.data.location); // slow: API or LLM call
|
|
141
|
+
await ablo.weatherReports.update({
|
|
142
|
+
id: created.id,
|
|
143
|
+
data: { status: 'ready', forecast },
|
|
144
|
+
claim, // the write completes the claimed work and releases the lease
|
|
145
|
+
});
|
|
200
146
|
|
|
201
147
|
const ready = ablo.weatherReports.get(created.id);
|
|
202
148
|
console.log({ id: ready?.id, status: ready?.status });
|
|
@@ -210,6 +156,38 @@ Expected output:
|
|
|
210
156
|
{ id: '...', status: 'ready' }
|
|
211
157
|
```
|
|
212
158
|
|
|
159
|
+
### TypeScript setup (once, scaffolded for you)
|
|
160
|
+
|
|
161
|
+
`npx ablo init` writes `ablo/register.ts` next to your schema. It binds your
|
|
162
|
+
schema to the SDK's types once — the same declaration-merging shape
|
|
163
|
+
[TanStack Router uses](https://tanstack.com/router/latest/docs/framework/react/guide/type-safety) —
|
|
164
|
+
so every hook and client infers from it:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
// ablo/register.ts — scaffolded by `npx ablo init`
|
|
168
|
+
import type { schema } from './schema';
|
|
169
|
+
declare module '@abloatai/ablo' {
|
|
170
|
+
interface Register { Schema: typeof schema }
|
|
171
|
+
}
|
|
172
|
+
export {};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import type { Model } from '@abloatai/ablo/schema';
|
|
177
|
+
|
|
178
|
+
type WeatherReport = Model<'weatherReports'>; // fully typed from your schema
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
To pass the client around, take the type from the value — the tRPC /
|
|
182
|
+
Drizzle idiom:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
export const sync = Ablo({ schema, apiKey: process.env.ABLO_API_KEY });
|
|
186
|
+
export type Sync = typeof sync;
|
|
187
|
+
|
|
188
|
+
function persist(client: Sync) { /* ... */ }
|
|
189
|
+
```
|
|
190
|
+
|
|
213
191
|
## Reading
|
|
214
192
|
|
|
215
193
|
Two ways to read, depending on whether you can wait. `get(id)` / `getAll({ where })`
|
|
@@ -262,7 +240,11 @@ meanwhile, or worse, acts on stale state. `claim` holds the row across that gap:
|
|
|
262
240
|
await using claim = await ablo.weatherReports.claim({ id: 'report_stockholm' });
|
|
263
241
|
const report = claim.data;
|
|
264
242
|
const forecast = await weatherAgent.getWeather(report.location);
|
|
265
|
-
await ablo.weatherReports.update({
|
|
243
|
+
await ablo.weatherReports.update({
|
|
244
|
+
id: report.id,
|
|
245
|
+
data: { forecast, status: 'ready' },
|
|
246
|
+
claim, // attribute the write to the held claim
|
|
247
|
+
});
|
|
266
248
|
```
|
|
267
249
|
|
|
268
250
|
If someone else holds the row, `claim()` waits in a fair queue, then re-reads —
|
|
@@ -311,6 +293,46 @@ try {
|
|
|
311
293
|
See [Coordination](./docs/coordination.md) for the full `claim` / `claim.state` /
|
|
312
294
|
`claim.queue` / `claim.release` reference.
|
|
313
295
|
|
|
296
|
+
## Background workers — jobs that run for minutes, not seconds
|
|
297
|
+
|
|
298
|
+
Your API route enqueues a job on your own queue (SQS, EventBridge, anything);
|
|
299
|
+
a worker on your own infrastructure does the slow part. **Keep that queue —
|
|
300
|
+
Ablo is the worker's data layer.** It covers the two things every queue leaves
|
|
301
|
+
to you: keeping the row safe, and showing progress live.
|
|
302
|
+
|
|
303
|
+
Long work holds its claim by **heartbeating** — the same pattern as an SQS
|
|
304
|
+
visibility heartbeat or a Temporal activity heartbeat:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
// on your worker — stateless HTTP, no socket to hold
|
|
308
|
+
await using claim = await ablo.weatherReports.claim({
|
|
309
|
+
id: msg.reportId,
|
|
310
|
+
ttl: '10m',
|
|
311
|
+
heartbeat: true, // beats automatically until release
|
|
312
|
+
onHeartbeatLost: () => abort(), // the lease is gone → stop working
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
for (const step of steps) {
|
|
316
|
+
await runStep(step);
|
|
317
|
+
// write progress to the row — every subscribed UI updates live
|
|
318
|
+
await ablo.weatherReports.update({ id: msg.reportId, data: { progress: step.pct }, claim });
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
- A worker that **crashes** stops beating; the row frees within one beat and
|
|
323
|
+
the next worker takes over.
|
|
324
|
+
- A worker that **wakes up late** learns it on its next beat
|
|
325
|
+
(`AbloClaimedError`), and the write path rejects its stale writes anyway.
|
|
326
|
+
- **Retries stay on your queue** — the redelivered job claims the now-free
|
|
327
|
+
row, reads its current state, and resumes.
|
|
328
|
+
- A worker holding **many rows** extends them all in one call:
|
|
329
|
+
`ablo.claims.heartbeatAll({ ttl: '5m' })`.
|
|
330
|
+
|
|
331
|
+
SQS's heartbeat protects the *message* from redelivery; Ablo's protects the
|
|
332
|
+
*row* from concurrent and stale writes. SQS is at-least-once, so two workers
|
|
333
|
+
will eventually get the same job — the claim is what keeps that from
|
|
334
|
+
corrupting data.
|
|
335
|
+
|
|
314
336
|
## React
|
|
315
337
|
|
|
316
338
|
In a React app it's the **same `ablo.<model>` API** — just mounted through a
|
|
@@ -420,7 +442,7 @@ HTTP endpoint when a server-to-server caller needs to write without opening a
|
|
|
420
442
|
WebSocket:
|
|
421
443
|
|
|
422
444
|
```bash
|
|
423
|
-
curl https://api.abloatai.com/v1/commits \
|
|
445
|
+
curl https://api.abloatai.com/api/v1/commits \
|
|
424
446
|
-H "Authorization: Bearer sk_test_..." \
|
|
425
447
|
-H "Content-Type: application/json" \
|
|
426
448
|
-d '{ "operations": [
|
|
@@ -445,14 +467,8 @@ connects:
|
|
|
445
467
|
| **Logical replication** (primary) | `npx ablo connect` prints the setup SQL (`wal_level=logical`, a publication, a `REPLICATION` role); `npx ablo connect --register` tells Ablo to replicate it. Ablo tails the WAL — it never runs DDL on, writes to, owns, or migrates your database. | Your database can grant a `REPLICATION` role (most can). |
|
|
446
468
|
| **Signed endpoint** (fallback) | Your app exposes one route built from an ORM adapter (`prismaDataSource` / `drizzleDataSource`); Ablo sends signed requests and your app touches its own database. Needs no database configuration. | Your database **can't** grant a replication role (a locked-down managed DB). |
|
|
447
469
|
|
|
448
|
-
|
|
449
|
-
coordination
|
|
450
|
-
connect your own Postgres. Test-mode only: in production your rows always live in
|
|
451
|
-
your database and Ablo holds just the transaction log, never your data.)
|
|
452
|
-
|
|
453
|
-
Your database is the system of record. The old `databaseUrl` dial-in (Ablo
|
|
454
|
-
holding a read/write connection) is **deprecated and being removed** — connect
|
|
455
|
-
via logical replication instead. See
|
|
470
|
+
Your database is the system of record — Ablo holds the transaction log and
|
|
471
|
+
coordination, never your rows. See
|
|
456
472
|
[Connect Your Database](./docs/data-sources.md).
|
|
457
473
|
|
|
458
474
|
## Configuration
|
|
@@ -466,7 +482,7 @@ Every other option has correct defaults:
|
|
|
466
482
|
| --- | --- | --- | --- |
|
|
467
483
|
| `schema` | `Schema` | — (required) | Typed model proxies (`ablo.<model>.*`) |
|
|
468
484
|
| `apiKey` | `string \| ApiKeySetter \| null` | `process.env.ABLO_API_KEY` | Server key — a string, or an async function for rotation |
|
|
469
|
-
| `databaseUrl` | `string \| null` | `—` |
|
|
485
|
+
| `databaseUrl` | `string \| null` | `—` | Deprecated. Connect via `npx ablo connect` instead — see [Connect Your Database](./docs/data-sources.md). |
|
|
470
486
|
|
|
471
487
|
Keep `apiKey` in trusted server runtimes. In the browser, `<AbloProvider>`
|
|
472
488
|
authenticates with the signed-in user's session; the raw-key path is gated
|
|
@@ -519,7 +535,7 @@ contract; there are no retry or timeout knobs to tune.
|
|
|
519
535
|
- [Guarantees](./docs/guarantees.md) — confirmed writes, stale-write protection, claim coordination, and agent lifecycle.
|
|
520
536
|
- [Integration Guide](./docs/integration-guide.md) — integrate React, your database, multiplayer, and agents.
|
|
521
537
|
- [React](./docs/react.md) — `<AbloProvider>`, `useAblo`, presence, status, and bootstrap gating.
|
|
522
|
-
- [Coordination](./docs/coordination.md) — `claim` / `claim.state` / `claim.queue` / `claim.release` reference: hold a row across slow agent work, and observe the line waiting behind it.
|
|
538
|
+
- [Coordination](./docs/coordination.md) — `claim` / `claim.state` / `claim.queue` / `claim.release` / `heartbeat` reference: hold a row across slow agent work — minutes or hours, via heartbeats — and observe the line waiting behind it.
|
|
523
539
|
- [Client Behavior](./docs/client-behavior.md) — options, errors, retries, timeouts, and public imports.
|
|
524
540
|
- [Connect Your Database](./docs/data-sources.md) — connect your Postgres by logical replication (`npx ablo connect`) or, as a fallback, a signed endpoint; your database is the system of record either way.
|
|
525
541
|
- [Existing Python Backend](./docs/examples/existing-python-backend.md) — migrate existing Python endpoints to multiplayer and agent-safe writes gradually.
|