@abloatai/transaction 0.37.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/CONVENTIONS.md +83 -0
- package/README.md +48 -0
- package/dist/ablo.d.ts +90 -0
- package/dist/ablo.d.ts.map +1 -0
- package/dist/ablo.js +34 -0
- package/dist/ablo.js.map +1 -0
- package/dist/ai-sdk/coordinatedTool.d.ts +123 -0
- package/dist/ai-sdk/coordinatedTool.d.ts.map +1 -0
- package/dist/ai-sdk/coordinatedTool.js +135 -0
- package/dist/ai-sdk/coordinatedTool.js.map +1 -0
- package/dist/ai-sdk/index.d.ts +2 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +2 -0
- package/dist/ai-sdk/index.js.map +1 -0
- package/dist/auth/apiKey.d.ts +154 -0
- package/dist/auth/apiKey.d.ts.map +1 -0
- package/dist/auth/apiKey.js +408 -0
- package/dist/auth/apiKey.js.map +1 -0
- package/dist/auth/bootstrapScope.d.ts +16 -0
- package/dist/auth/bootstrapScope.d.ts.map +1 -0
- package/dist/auth/bootstrapScope.js +2 -0
- package/dist/auth/bootstrapScope.js.map +1 -0
- package/dist/auth/browserCredentialSafety.d.ts +7 -0
- package/dist/auth/browserCredentialSafety.d.ts.map +1 -0
- package/dist/auth/browserCredentialSafety.js +29 -0
- package/dist/auth/browserCredentialSafety.js.map +1 -0
- package/dist/auth/capability.d.ts +241 -0
- package/dist/auth/capability.d.ts.map +1 -0
- package/dist/auth/capability.js +253 -0
- package/dist/auth/capability.js.map +1 -0
- package/dist/auth/capabilityLifecycle.d.ts +47 -0
- package/dist/auth/capabilityLifecycle.d.ts.map +1 -0
- package/dist/auth/capabilityLifecycle.js +108 -0
- package/dist/auth/capabilityLifecycle.js.map +1 -0
- package/dist/auth/credentialEndpoint.d.ts +10 -0
- package/dist/auth/credentialEndpoint.d.ts.map +1 -0
- package/dist/auth/credentialEndpoint.js +58 -0
- package/dist/auth/credentialEndpoint.js.map +1 -0
- package/dist/auth/credentialEndpointProtocol.d.ts +24 -0
- package/dist/auth/credentialEndpointProtocol.d.ts.map +1 -0
- package/dist/auth/credentialEndpointProtocol.js +34 -0
- package/dist/auth/credentialEndpointProtocol.js.map +1 -0
- package/dist/auth/credentialKind.d.ts +4 -0
- package/dist/auth/credentialKind.d.ts.map +1 -0
- package/dist/auth/credentialKind.js +15 -0
- package/dist/auth/credentialKind.js.map +1 -0
- package/dist/auth/credentialPolicy.d.ts +141 -0
- package/dist/auth/credentialPolicy.d.ts.map +1 -0
- package/dist/auth/credentialPolicy.js +113 -0
- package/dist/auth/credentialPolicy.js.map +1 -0
- package/dist/auth/credentialResult.d.ts +7 -0
- package/dist/auth/credentialResult.d.ts.map +1 -0
- package/dist/auth/credentialResult.js +9 -0
- package/dist/auth/credentialResult.js.map +1 -0
- package/dist/auth/credentialSource.d.ts +31 -0
- package/dist/auth/credentialSource.d.ts.map +1 -0
- package/dist/auth/credentialSource.js +56 -0
- package/dist/auth/credentialSource.js.map +1 -0
- package/dist/auth/hostedEndpoints.d.ts +22 -0
- package/dist/auth/hostedEndpoints.d.ts.map +1 -0
- package/dist/auth/hostedEndpoints.js +22 -0
- package/dist/auth/hostedEndpoints.js.map +1 -0
- package/dist/auth/identity.d.ts +62 -0
- package/dist/auth/identity.d.ts.map +1 -0
- package/dist/auth/identity.js +224 -0
- package/dist/auth/identity.js.map +1 -0
- package/dist/auth/index.d.ts +189 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +312 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/schemas.d.ts +41 -0
- package/dist/auth/schemas.d.ts.map +1 -0
- package/dist/auth/schemas.js +69 -0
- package/dist/auth/schemas.js.map +1 -0
- package/dist/auth/sessionMint.d.ts +29 -0
- package/dist/auth/sessionMint.d.ts.map +1 -0
- package/dist/auth/sessionMint.js +92 -0
- package/dist/auth/sessionMint.js.map +1 -0
- package/dist/auth/token.d.ts +4 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +4 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/batching/index.d.ts +56 -0
- package/dist/batching/index.d.ts.map +1 -0
- package/dist/batching/index.js +148 -0
- package/dist/batching/index.js.map +1 -0
- package/dist/coordination/awaitClaimGrant.d.ts +57 -0
- package/dist/coordination/awaitClaimGrant.d.ts.map +1 -0
- package/dist/coordination/awaitClaimGrant.js +138 -0
- package/dist/coordination/awaitClaimGrant.js.map +1 -0
- package/dist/coordination/claimHeartbeatLoop.d.ts +85 -0
- package/dist/coordination/claimHeartbeatLoop.d.ts.map +1 -0
- package/dist/coordination/claimHeartbeatLoop.js +109 -0
- package/dist/coordination/claimHeartbeatLoop.js.map +1 -0
- package/dist/coordination/claimMeta.d.ts +50 -0
- package/dist/coordination/claimMeta.d.ts.map +1 -0
- package/dist/coordination/claimMeta.js +53 -0
- package/dist/coordination/claimMeta.js.map +1 -0
- package/dist/coordination/events.d.ts +75 -0
- package/dist/coordination/events.d.ts.map +1 -0
- package/dist/coordination/events.js +8 -0
- package/dist/coordination/events.js.map +1 -0
- package/dist/coordination/index.d.ts +20 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +46 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/locator.d.ts +106 -0
- package/dist/coordination/locator.d.ts.map +1 -0
- package/dist/coordination/locator.js +110 -0
- package/dist/coordination/locator.js.map +1 -0
- package/dist/coordination/schema.d.ts +1332 -0
- package/dist/coordination/schema.d.ts.map +1 -0
- package/dist/coordination/schema.js +1137 -0
- package/dist/coordination/schema.js.map +1 -0
- package/dist/coordination/targetConflict.d.ts +3 -0
- package/dist/coordination/targetConflict.d.ts.map +1 -0
- package/dist/coordination/targetConflict.js +74 -0
- package/dist/coordination/targetConflict.js.map +1 -0
- package/dist/coordination/trace.d.ts +79 -0
- package/dist/coordination/trace.d.ts.map +1 -0
- package/dist/coordination/trace.js +139 -0
- package/dist/coordination/trace.js.map +1 -0
- package/dist/docs/catalog.d.ts +73 -0
- package/dist/docs/catalog.d.ts.map +1 -0
- package/dist/docs/catalog.js +231 -0
- package/dist/docs/catalog.js.map +1 -0
- package/dist/docs/index.d.ts +11 -0
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +11 -0
- package/dist/docs/index.js.map +1 -0
- package/dist/durableWrites.d.ts +63 -0
- package/dist/durableWrites.d.ts.map +1 -0
- package/dist/durableWrites.js +72 -0
- package/dist/durableWrites.js.map +1 -0
- package/dist/environment.d.ts +106 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +109 -0
- package/dist/environment.js.map +1 -0
- package/dist/errorCodes.d.ts +411 -0
- package/dist/errorCodes.d.ts.map +1 -0
- package/dist/errorCodes.js +500 -0
- package/dist/errorCodes.js.map +1 -0
- package/dist/errors.d.ts +429 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +687 -0
- package/dist/errors.js.map +1 -0
- package/dist/footprint.d.ts +112 -0
- package/dist/footprint.d.ts.map +1 -0
- package/dist/footprint.js +0 -0
- package/dist/footprint.js.map +1 -0
- package/dist/headlessClient.d.ts +10 -0
- package/dist/headlessClient.d.ts.map +1 -0
- package/dist/headlessClient.js +114 -0
- package/dist/headlessClient.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/keys/index.d.ts +88 -0
- package/dist/keys/index.d.ts.map +1 -0
- package/dist/keys/index.js +208 -0
- package/dist/keys/index.js.map +1 -0
- package/dist/log/syncDeltaRow.d.ts +159 -0
- package/dist/log/syncDeltaRow.d.ts.map +1 -0
- package/dist/log/syncDeltaRow.js +96 -0
- package/dist/log/syncDeltaRow.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +8 -0
- package/dist/logger.js.map +1 -0
- package/dist/observability.d.ts +54 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +20 -0
- package/dist/observability.js.map +1 -0
- package/dist/policy/types.d.ts +218 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +127 -0
- package/dist/policy/types.js.map +1 -0
- package/dist/resources/functionalUpdate.d.ts +80 -0
- package/dist/resources/functionalUpdate.d.ts.map +1 -0
- package/dist/resources/functionalUpdate.js +88 -0
- package/dist/resources/functionalUpdate.js.map +1 -0
- package/dist/resources/httpResources.d.ts +449 -0
- package/dist/resources/httpResources.d.ts.map +1 -0
- package/dist/resources/httpResources.js +8 -0
- package/dist/resources/httpResources.js.map +1 -0
- package/dist/resources/modelOperations.d.ts +380 -0
- package/dist/resources/modelOperations.d.ts.map +1 -0
- package/dist/resources/modelOperations.js +13 -0
- package/dist/resources/modelOperations.js.map +1 -0
- package/dist/resources/mutationOptions.d.ts +67 -0
- package/dist/resources/mutationOptions.d.ts.map +1 -0
- package/dist/resources/mutationOptions.js +10 -0
- package/dist/resources/mutationOptions.js.map +1 -0
- package/dist/resources/where.d.ts +102 -0
- package/dist/resources/where.d.ts.map +1 -0
- package/dist/resources/where.js +116 -0
- package/dist/resources/where.js.map +1 -0
- package/dist/resources/writeOptionsSchema.d.ts +48 -0
- package/dist/resources/writeOptionsSchema.d.ts.map +1 -0
- package/dist/resources/writeOptionsSchema.js +74 -0
- package/dist/resources/writeOptionsSchema.js.map +1 -0
- package/dist/schema/coordination.d.ts +113 -0
- package/dist/schema/coordination.d.ts.map +1 -0
- package/dist/schema/coordination.js +134 -0
- package/dist/schema/coordination.js.map +1 -0
- package/dist/schema/ddl.d.ts +98 -0
- package/dist/schema/ddl.d.ts.map +1 -0
- package/dist/schema/ddl.js +492 -0
- package/dist/schema/ddl.js.map +1 -0
- package/dist/schema/ddlLock.d.ts +36 -0
- package/dist/schema/ddlLock.d.ts.map +1 -0
- package/dist/schema/ddlLock.js +47 -0
- package/dist/schema/ddlLock.js.map +1 -0
- package/dist/schema/diff.d.ts +226 -0
- package/dist/schema/diff.d.ts.map +1 -0
- package/dist/schema/diff.js +290 -0
- package/dist/schema/diff.js.map +1 -0
- package/dist/schema/field.d.ts +121 -0
- package/dist/schema/field.d.ts.map +1 -0
- package/dist/schema/field.js +266 -0
- package/dist/schema/field.js.map +1 -0
- package/dist/schema/fieldRef.d.ts +58 -0
- package/dist/schema/fieldRef.d.ts.map +1 -0
- package/dist/schema/fieldRef.js +26 -0
- package/dist/schema/fieldRef.js.map +1 -0
- package/dist/schema/generate.d.ts +20 -0
- package/dist/schema/generate.d.ts.map +1 -0
- package/dist/schema/generate.js +87 -0
- package/dist/schema/generate.js.map +1 -0
- package/dist/schema/index.d.ts +43 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +81 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/loadStrategy.d.ts +46 -0
- package/dist/schema/loadStrategy.d.ts.map +1 -0
- package/dist/schema/loadStrategy.js +47 -0
- package/dist/schema/loadStrategy.js.map +1 -0
- package/dist/schema/model.d.ts +380 -0
- package/dist/schema/model.d.ts.map +1 -0
- package/dist/schema/model.js +124 -0
- package/dist/schema/model.js.map +1 -0
- package/dist/schema/openapi.d.ts +59 -0
- package/dist/schema/openapi.d.ts.map +1 -0
- package/dist/schema/openapi.js +508 -0
- package/dist/schema/openapi.js.map +1 -0
- package/dist/schema/queries.d.ts +202 -0
- package/dist/schema/queries.d.ts.map +1 -0
- package/dist/schema/queries.js +144 -0
- package/dist/schema/queries.js.map +1 -0
- package/dist/schema/relation.d.ts +205 -0
- package/dist/schema/relation.d.ts.map +1 -0
- package/dist/schema/relation.js +105 -0
- package/dist/schema/relation.js.map +1 -0
- package/dist/schema/residency.d.ts +30 -0
- package/dist/schema/residency.d.ts.map +1 -0
- package/dist/schema/residency.js +26 -0
- package/dist/schema/residency.js.map +1 -0
- package/dist/schema/roles.d.ts +250 -0
- package/dist/schema/roles.d.ts.map +1 -0
- package/dist/schema/roles.js +231 -0
- package/dist/schema/roles.js.map +1 -0
- package/dist/schema/schema.d.ts +352 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +326 -0
- package/dist/schema/schema.js.map +1 -0
- package/dist/schema/select.d.ts +41 -0
- package/dist/schema/select.d.ts.map +1 -0
- package/dist/schema/select.js +91 -0
- package/dist/schema/select.js.map +1 -0
- package/dist/schema/serialize.d.ts +116 -0
- package/dist/schema/serialize.d.ts.map +1 -0
- package/dist/schema/serialize.js +278 -0
- package/dist/schema/serialize.js.map +1 -0
- package/dist/schema/sugar.d.ts +110 -0
- package/dist/schema/sugar.d.ts.map +1 -0
- package/dist/schema/sugar.js +84 -0
- package/dist/schema/sugar.js.map +1 -0
- package/dist/schema/tenancy.d.ts +140 -0
- package/dist/schema/tenancy.d.ts.map +1 -0
- package/dist/schema/tenancy.js +191 -0
- package/dist/schema/tenancy.js.map +1 -0
- package/dist/server/adapter.d.ts +174 -0
- package/dist/server/adapter.d.ts.map +1 -0
- package/dist/server/adapter.js +19 -0
- package/dist/server/adapter.js.map +1 -0
- package/dist/server/commit.d.ts +108 -0
- package/dist/server/commit.d.ts.map +1 -0
- package/dist/server/commit.js +2 -0
- package/dist/server/commit.js.map +1 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/readConfig.d.ts +81 -0
- package/dist/server/readConfig.d.ts.map +1 -0
- package/dist/server/readConfig.js +9 -0
- package/dist/server/readConfig.js.map +1 -0
- package/dist/server/storageMode.d.ts +24 -0
- package/dist/server/storageMode.d.ts.map +1 -0
- package/dist/server/storageMode.js +18 -0
- package/dist/server/storageMode.js.map +1 -0
- package/dist/source/adapter.d.ts +84 -0
- package/dist/source/adapter.d.ts.map +1 -0
- package/dist/source/adapter.js +25 -0
- package/dist/source/adapter.js.map +1 -0
- package/dist/source/adapters/drizzle.d.ts +49 -0
- package/dist/source/adapters/drizzle.d.ts.map +1 -0
- package/dist/source/adapters/drizzle.js +220 -0
- package/dist/source/adapters/drizzle.js.map +1 -0
- package/dist/source/adapters/kysely.d.ts +43 -0
- package/dist/source/adapters/kysely.d.ts.map +1 -0
- package/dist/source/adapters/kysely.js +206 -0
- package/dist/source/adapters/kysely.js.map +1 -0
- package/dist/source/adapters/kyselyMutationCore.d.ts +77 -0
- package/dist/source/adapters/kyselyMutationCore.d.ts.map +1 -0
- package/dist/source/adapters/kyselyMutationCore.js +126 -0
- package/dist/source/adapters/kyselyMutationCore.js.map +1 -0
- package/dist/source/adapters/memory.d.ts +14 -0
- package/dist/source/adapters/memory.d.ts.map +1 -0
- package/dist/source/adapters/memory.js +131 -0
- package/dist/source/adapters/memory.js.map +1 -0
- package/dist/source/adapters/prisma.d.ts +64 -0
- package/dist/source/adapters/prisma.d.ts.map +1 -0
- package/dist/source/adapters/prisma.js +203 -0
- package/dist/source/adapters/prisma.js.map +1 -0
- package/dist/source/conformance.d.ts +38 -0
- package/dist/source/conformance.d.ts.map +1 -0
- package/dist/source/conformance.js +216 -0
- package/dist/source/conformance.js.map +1 -0
- package/dist/source/connector.d.ts +96 -0
- package/dist/source/connector.d.ts.map +1 -0
- package/dist/source/connector.js +267 -0
- package/dist/source/connector.js.map +1 -0
- package/dist/source/connectorProtocol.d.ts +155 -0
- package/dist/source/connectorProtocol.d.ts.map +1 -0
- package/dist/source/connectorProtocol.js +164 -0
- package/dist/source/connectorProtocol.js.map +1 -0
- package/dist/source/contract.d.ts +196 -0
- package/dist/source/contract.d.ts.map +1 -0
- package/dist/source/contract.js +165 -0
- package/dist/source/contract.js.map +1 -0
- package/dist/source/drizzle.d.ts +2 -0
- package/dist/source/drizzle.d.ts.map +1 -0
- package/dist/source/drizzle.js +2 -0
- package/dist/source/drizzle.js.map +1 -0
- package/dist/source/factory.d.ts +93 -0
- package/dist/source/factory.d.ts.map +1 -0
- package/dist/source/factory.js +287 -0
- package/dist/source/factory.js.map +1 -0
- package/dist/source/idempotency.d.ts +62 -0
- package/dist/source/idempotency.d.ts.map +1 -0
- package/dist/source/idempotency.js +145 -0
- package/dist/source/idempotency.js.map +1 -0
- package/dist/source/index.d.ts +24 -0
- package/dist/source/index.d.ts.map +1 -0
- package/dist/source/index.js +29 -0
- package/dist/source/index.js.map +1 -0
- package/dist/source/kysely.d.ts +3 -0
- package/dist/source/kysely.d.ts.map +1 -0
- package/dist/source/kysely.js +3 -0
- package/dist/source/kysely.js.map +1 -0
- package/dist/source/migrations.d.ts +22 -0
- package/dist/source/migrations.d.ts.map +1 -0
- package/dist/source/migrations.js +104 -0
- package/dist/source/migrations.js.map +1 -0
- package/dist/source/next.d.ts +33 -0
- package/dist/source/next.d.ts.map +1 -0
- package/dist/source/next.js +26 -0
- package/dist/source/next.js.map +1 -0
- package/dist/source/pushQueue.d.ts +135 -0
- package/dist/source/pushQueue.d.ts.map +1 -0
- package/dist/source/pushQueue.js +257 -0
- package/dist/source/pushQueue.js.map +1 -0
- package/dist/source/signing.d.ts +93 -0
- package/dist/source/signing.d.ts.map +1 -0
- package/dist/source/signing.js +163 -0
- package/dist/source/signing.js.map +1 -0
- package/dist/source/types.d.ts +402 -0
- package/dist/source/types.d.ts.map +1 -0
- package/dist/source/types.js +60 -0
- package/dist/source/types.js.map +1 -0
- package/dist/syncLog/contract.d.ts +21 -0
- package/dist/syncLog/contract.d.ts.map +1 -0
- package/dist/syncLog/contract.js +20 -0
- package/dist/syncLog/contract.js.map +1 -0
- package/dist/syncLog/index.d.ts +2 -0
- package/dist/syncLog/index.d.ts.map +1 -0
- package/dist/syncLog/index.js +2 -0
- package/dist/syncLog/index.js.map +1 -0
- package/dist/testing/fixtures/httpResponses.d.ts +74 -0
- package/dist/testing/fixtures/httpResponses.d.ts.map +1 -0
- package/dist/testing/fixtures/httpResponses.js +102 -0
- package/dist/testing/fixtures/httpResponses.js.map +1 -0
- package/dist/transactionLayer.d.ts +110 -0
- package/dist/transactionLayer.d.ts.map +1 -0
- package/dist/transactionLayer.js +25 -0
- package/dist/transactionLayer.js.map +1 -0
- package/dist/transactions/settlement/commitEnvelope.d.ts +144 -0
- package/dist/transactions/settlement/commitEnvelope.d.ts.map +1 -0
- package/dist/transactions/settlement/commitEnvelope.js +162 -0
- package/dist/transactions/settlement/commitEnvelope.js.map +1 -0
- package/dist/transactions/settlement/httpCommitEnvelope.d.ts +54 -0
- package/dist/transactions/settlement/httpCommitEnvelope.d.ts.map +1 -0
- package/dist/transactions/settlement/httpCommitEnvelope.js +208 -0
- package/dist/transactions/settlement/httpCommitEnvelope.js.map +1 -0
- package/dist/transactions/settlement/idempotencyKey.d.ts +11 -0
- package/dist/transactions/settlement/idempotencyKey.d.ts.map +1 -0
- package/dist/transactions/settlement/idempotencyKey.js +10 -0
- package/dist/transactions/settlement/idempotencyKey.js.map +1 -0
- package/dist/transactions/settlement/pendingWrite.d.ts +113 -0
- package/dist/transactions/settlement/pendingWrite.d.ts.map +1 -0
- package/dist/transactions/settlement/pendingWrite.js +21 -0
- package/dist/transactions/settlement/pendingWrite.js.map +1 -0
- package/dist/transport/commitFrames.d.ts +91 -0
- package/dist/transport/commitFrames.d.ts.map +1 -0
- package/dist/transport/commitFrames.js +135 -0
- package/dist/transport/commitFrames.js.map +1 -0
- package/dist/transport/connectionManager.d.ts +216 -0
- package/dist/transport/connectionManager.d.ts.map +1 -0
- package/dist/transport/connectionManager.js +674 -0
- package/dist/transport/connectionManager.js.map +1 -0
- package/dist/transport/credentialLifecycle.d.ts +178 -0
- package/dist/transport/credentialLifecycle.d.ts.map +1 -0
- package/dist/transport/credentialLifecycle.js +324 -0
- package/dist/transport/credentialLifecycle.js.map +1 -0
- package/dist/transport/heartbeat.d.ts +66 -0
- package/dist/transport/heartbeat.d.ts.map +1 -0
- package/dist/transport/heartbeat.js +94 -0
- package/dist/transport/heartbeat.js.map +1 -0
- package/dist/transport/httpClient.d.ts +143 -0
- package/dist/transport/httpClient.d.ts.map +1 -0
- package/dist/transport/httpClient.js +150 -0
- package/dist/transport/httpClient.js.map +1 -0
- package/dist/transport/httpFeed.d.ts +4 -0
- package/dist/transport/httpFeed.d.ts.map +1 -0
- package/dist/transport/httpFeed.js +94 -0
- package/dist/transport/httpFeed.js.map +1 -0
- package/dist/transport/httpOptions.d.ts +34 -0
- package/dist/transport/httpOptions.d.ts.map +1 -0
- package/dist/transport/httpOptions.js +13 -0
- package/dist/transport/httpOptions.js.map +1 -0
- package/dist/transport/httpTransport.d.ts +68 -0
- package/dist/transport/httpTransport.d.ts.map +1 -0
- package/dist/transport/httpTransport.js +1433 -0
- package/dist/transport/httpTransport.js.map +1 -0
- package/dist/transport/networkProbe.d.ts +85 -0
- package/dist/transport/networkProbe.d.ts.map +1 -0
- package/dist/transport/networkProbe.js +208 -0
- package/dist/transport/networkProbe.js.map +1 -0
- package/dist/transport/wsFrameHandlers.d.ts +129 -0
- package/dist/transport/wsFrameHandlers.d.ts.map +1 -0
- package/dist/transport/wsFrameHandlers.js +429 -0
- package/dist/transport/wsFrameHandlers.js.map +1 -0
- package/dist/transport/wsTransport.d.ts +575 -0
- package/dist/transport/wsTransport.d.ts.map +1 -0
- package/dist/transport/wsTransport.js +1024 -0
- package/dist/transport/wsTransport.js.map +1 -0
- package/dist/types/assertExact.d.ts +18 -0
- package/dist/types/assertExact.d.ts.map +1 -0
- package/dist/types/assertExact.js +2 -0
- package/dist/types/assertExact.js.map +1 -0
- package/dist/types/global.d.ts +108 -0
- package/dist/types/global.d.ts.map +1 -0
- package/dist/types/global.js +41 -0
- package/dist/types/global.js.map +1 -0
- package/dist/types/index.d.ts +206 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +57 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/modelData.d.ts +11 -0
- package/dist/types/modelData.d.ts.map +1 -0
- package/dist/types/modelData.js +10 -0
- package/dist/types/modelData.js.map +1 -0
- package/dist/types/participant.d.ts +21 -0
- package/dist/types/participant.d.ts.map +1 -0
- package/dist/types/participant.js +11 -0
- package/dist/types/participant.js.map +1 -0
- package/dist/types/streams.d.ts +545 -0
- package/dist/types/streams.d.ts.map +1 -0
- package/dist/types/streams.js +12 -0
- package/dist/types/streams.js.map +1 -0
- package/dist/utils/asyncIterator.d.ts +35 -0
- package/dist/utils/asyncIterator.d.ts.map +1 -0
- package/dist/utils/asyncIterator.js +136 -0
- package/dist/utils/asyncIterator.js.map +1 -0
- package/dist/utils/duration.d.ts +51 -0
- package/dist/utils/duration.d.ts.map +1 -0
- package/dist/utils/duration.js +78 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/json.d.ts +58 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +277 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/webhooks/events.d.ts +44 -0
- package/dist/webhooks/events.d.ts.map +1 -0
- package/dist/webhooks/events.js +43 -0
- package/dist/webhooks/events.js.map +1 -0
- package/dist/webhooks/index.d.ts +9 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +9 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/wire/accountResponses.d.ts +463 -0
- package/dist/wire/accountResponses.d.ts.map +1 -0
- package/dist/wire/accountResponses.js +294 -0
- package/dist/wire/accountResponses.js.map +1 -0
- package/dist/wire/auth.d.ts +57 -0
- package/dist/wire/auth.d.ts.map +1 -0
- package/dist/wire/auth.js +71 -0
- package/dist/wire/auth.js.map +1 -0
- package/dist/wire/bootstrapReason.d.ts +10 -0
- package/dist/wire/bootstrapReason.d.ts.map +1 -0
- package/dist/wire/bootstrapReason.js +9 -0
- package/dist/wire/bootstrapReason.js.map +1 -0
- package/dist/wire/claimEvent.d.ts +70 -0
- package/dist/wire/claimEvent.d.ts.map +1 -0
- package/dist/wire/claimEvent.js +74 -0
- package/dist/wire/claimEvent.js.map +1 -0
- package/dist/wire/claims.d.ts +475 -0
- package/dist/wire/claims.d.ts.map +1 -0
- package/dist/wire/claims.js +326 -0
- package/dist/wire/claims.js.map +1 -0
- package/dist/wire/commit.d.ts +604 -0
- package/dist/wire/commit.d.ts.map +1 -0
- package/dist/wire/commit.js +322 -0
- package/dist/wire/commit.js.map +1 -0
- package/dist/wire/delta.d.ts +251 -0
- package/dist/wire/delta.d.ts.map +1 -0
- package/dist/wire/delta.js +148 -0
- package/dist/wire/delta.js.map +1 -0
- package/dist/wire/errorEnvelope.d.ts +73 -0
- package/dist/wire/errorEnvelope.d.ts.map +1 -0
- package/dist/wire/errorEnvelope.js +124 -0
- package/dist/wire/errorEnvelope.js.map +1 -0
- package/dist/wire/feedCursor.d.ts +61 -0
- package/dist/wire/feedCursor.d.ts.map +1 -0
- package/dist/wire/feedCursor.js +83 -0
- package/dist/wire/feedCursor.js.map +1 -0
- package/dist/wire/feedEvent.d.ts +264 -0
- package/dist/wire/feedEvent.d.ts.map +1 -0
- package/dist/wire/feedEvent.js +66 -0
- package/dist/wire/feedEvent.js.map +1 -0
- package/dist/wire/frames.d.ts +195 -0
- package/dist/wire/frames.d.ts.map +1 -0
- package/dist/wire/frames.js +51 -0
- package/dist/wire/frames.js.map +1 -0
- package/dist/wire/inboundFrames.d.ts +490 -0
- package/dist/wire/inboundFrames.d.ts.map +1 -0
- package/dist/wire/inboundFrames.js +117 -0
- package/dist/wire/inboundFrames.js.map +1 -0
- package/dist/wire/index.d.ts +55 -0
- package/dist/wire/index.d.ts.map +1 -0
- package/dist/wire/index.js +84 -0
- package/dist/wire/index.js.map +1 -0
- package/dist/wire/listEnvelope.d.ts +38 -0
- package/dist/wire/listEnvelope.d.ts.map +1 -0
- package/dist/wire/listEnvelope.js +43 -0
- package/dist/wire/listEnvelope.js.map +1 -0
- package/dist/wire/modelMutations.d.ts +32 -0
- package/dist/wire/modelMutations.d.ts.map +1 -0
- package/dist/wire/modelMutations.js +53 -0
- package/dist/wire/modelMutations.js.map +1 -0
- package/dist/wire/modelResponses.d.ts +79 -0
- package/dist/wire/modelResponses.d.ts.map +1 -0
- package/dist/wire/modelResponses.js +44 -0
- package/dist/wire/modelResponses.js.map +1 -0
- package/dist/wire/modelShape.d.ts +79 -0
- package/dist/wire/modelShape.d.ts.map +1 -0
- package/dist/wire/modelShape.js +75 -0
- package/dist/wire/modelShape.js.map +1 -0
- package/dist/wire/protocol.d.ts +39 -0
- package/dist/wire/protocol.d.ts.map +1 -0
- package/dist/wire/protocol.js +39 -0
- package/dist/wire/protocol.js.map +1 -0
- package/dist/wire/protocolVersion.d.ts +74 -0
- package/dist/wire/protocolVersion.d.ts.map +1 -0
- package/dist/wire/protocolVersion.js +84 -0
- package/dist/wire/protocolVersion.js.map +1 -0
- package/package.json +187 -0
- package/src/ablo.ts +139 -0
- package/src/ai-sdk/coordinatedTool.ts +214 -0
- package/src/ai-sdk/index.ts +7 -0
- package/src/auth/apiKey.ts +540 -0
- package/src/auth/bootstrapScope.ts +15 -0
- package/src/auth/browserCredentialSafety.ts +48 -0
- package/src/auth/capability.ts +326 -0
- package/src/auth/capabilityLifecycle.ts +174 -0
- package/src/auth/credentialEndpoint.ts +79 -0
- package/src/auth/credentialEndpointProtocol.ts +51 -0
- package/src/auth/credentialKind.ts +20 -0
- package/src/auth/credentialPolicy.ts +244 -0
- package/src/auth/credentialResult.ts +23 -0
- package/src/auth/credentialSource.ts +99 -0
- package/src/auth/hostedEndpoints.ts +24 -0
- package/src/auth/identity.ts +330 -0
- package/src/auth/index.ts +592 -0
- package/src/auth/schemas.ts +94 -0
- package/src/auth/sessionMint.ts +126 -0
- package/src/auth/token.ts +4 -0
- package/src/batching/index.ts +200 -0
- package/src/coordination/awaitClaimGrant.ts +243 -0
- package/src/coordination/claimHeartbeatLoop.ts +165 -0
- package/src/coordination/claimMeta.ts +56 -0
- package/src/coordination/events.ts +86 -0
- package/src/coordination/index.ts +181 -0
- package/src/coordination/locator.ts +200 -0
- package/src/coordination/schema.ts +1346 -0
- package/src/coordination/targetConflict.ts +85 -0
- package/src/coordination/trace.ts +173 -0
- package/src/docs/catalog.ts +274 -0
- package/src/docs/index.ts +18 -0
- package/src/durableWrites.ts +134 -0
- package/src/environment.ts +132 -0
- package/src/errorCodes.ts +1591 -0
- package/src/errors.ts +918 -0
- package/src/footprint.ts +0 -0
- package/src/headlessClient.ts +161 -0
- package/src/index.ts +52 -0
- package/src/keys/index.ts +254 -0
- package/src/log/syncDeltaRow.ts +119 -0
- package/src/logger.ts +22 -0
- package/src/observability.ts +85 -0
- package/src/policy/types.ts +292 -0
- package/src/resources/functionalUpdate.ts +151 -0
- package/src/resources/httpResources.ts +520 -0
- package/src/resources/modelOperations.ts +444 -0
- package/src/resources/mutationOptions.ts +66 -0
- package/src/resources/where.ts +160 -0
- package/src/resources/writeOptionsSchema.ts +91 -0
- package/src/schema/coordination.ts +161 -0
- package/src/schema/ddl.ts +593 -0
- package/src/schema/ddlLock.ts +53 -0
- package/src/schema/diff.ts +489 -0
- package/src/schema/field.ts +321 -0
- package/src/schema/fieldRef.ts +88 -0
- package/src/schema/generate.ts +95 -0
- package/src/schema/index.ts +278 -0
- package/src/schema/loadStrategy.ts +52 -0
- package/src/schema/model.ts +476 -0
- package/src/schema/openapi.ts +658 -0
- package/src/schema/queries.ts +273 -0
- package/src/schema/relation.ts +291 -0
- package/src/schema/residency.ts +30 -0
- package/src/schema/roles.ts +325 -0
- package/src/schema/schema.ts +825 -0
- package/src/schema/select.ts +115 -0
- package/src/schema/serialize.ts +373 -0
- package/src/schema/sugar.ts +194 -0
- package/src/schema/tenancy.ts +221 -0
- package/src/server/adapter.ts +203 -0
- package/src/server/commit.ts +109 -0
- package/src/server/index.ts +26 -0
- package/src/server/readConfig.ts +82 -0
- package/src/server/storageMode.ts +20 -0
- package/src/source/adapter.ts +85 -0
- package/src/source/adapters/drizzle.ts +291 -0
- package/src/source/adapters/kysely.ts +346 -0
- package/src/source/adapters/kyselyMutationCore.ts +220 -0
- package/src/source/adapters/memory.ts +154 -0
- package/src/source/adapters/prisma.ts +282 -0
- package/src/source/conformance.ts +287 -0
- package/src/source/connector.ts +394 -0
- package/src/source/connectorProtocol.ts +189 -0
- package/src/source/contract.ts +221 -0
- package/src/source/drizzle.ts +1 -0
- package/src/source/factory.ts +444 -0
- package/src/source/idempotency.ts +189 -0
- package/src/source/index.ts +182 -0
- package/src/source/kysely.ts +2 -0
- package/src/source/migrations.ts +109 -0
- package/src/source/next.ts +38 -0
- package/src/source/pushQueue.ts +368 -0
- package/src/source/signing.ts +279 -0
- package/src/source/types.ts +502 -0
- package/src/syncLog/contract.ts +32 -0
- package/src/syncLog/index.ts +1 -0
- package/src/testing/fixtures/httpResponses.ts +155 -0
- package/src/transactionLayer.ts +122 -0
- package/src/transactions/settlement/commitEnvelope.ts +192 -0
- package/src/transactions/settlement/httpCommitEnvelope.ts +250 -0
- package/src/transactions/settlement/idempotencyKey.ts +11 -0
- package/src/transactions/settlement/pendingWrite.ts +24 -0
- package/src/transport/commitFrames.ts +225 -0
- package/src/transport/connectionManager.ts +856 -0
- package/src/transport/credentialLifecycle.ts +389 -0
- package/src/transport/heartbeat.ts +118 -0
- package/src/transport/httpClient.ts +354 -0
- package/src/transport/httpFeed.ts +111 -0
- package/src/transport/httpOptions.ts +41 -0
- package/src/transport/httpTransport.ts +1976 -0
- package/src/transport/networkProbe.ts +249 -0
- package/src/transport/wsFrameHandlers.ts +619 -0
- package/src/transport/wsTransport.ts +1491 -0
- package/src/types/assertExact.ts +17 -0
- package/src/types/global.ts +123 -0
- package/src/types/index.ts +270 -0
- package/src/types/modelData.ts +11 -0
- package/src/types/participant.ts +22 -0
- package/src/types/streams.ts +702 -0
- package/src/utils/asyncIterator.ts +141 -0
- package/src/utils/duration.ts +88 -0
- package/src/utils/json.ts +281 -0
- package/src/webhooks/events.ts +96 -0
- package/src/webhooks/index.ts +12 -0
- package/src/wire/accountResponses.ts +328 -0
- package/src/wire/auth.ts +86 -0
- package/src/wire/bootstrapReason.ts +10 -0
- package/src/wire/claimEvent.ts +85 -0
- package/src/wire/claims.ts +370 -0
- package/src/wire/commit.ts +379 -0
- package/src/wire/delta.ts +173 -0
- package/src/wire/errorEnvelope.ts +133 -0
- package/src/wire/feedCursor.ts +91 -0
- package/src/wire/feedEvent.ts +74 -0
- package/src/wire/frames.ts +77 -0
- package/src/wire/inboundFrames.ts +182 -0
- package/src/wire/index.ts +328 -0
- package/src/wire/listEnvelope.ts +51 -0
- package/src/wire/modelMutations.ts +55 -0
- package/src/wire/modelResponses.ts +48 -0
- package/src/wire/modelShape.ts +83 -0
- package/src/wire/protocol.ts +39 -0
- package/src/wire/protocolVersion.ts +97 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ClaimTargetDetails } from './locator.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether two claims on the same entity collide — the single most consequential
|
|
5
|
+
* predicate in the claim protocol, and the one rule that decides whether a
|
|
6
|
+
* second writer is granted a lease or made to wait.
|
|
7
|
+
*
|
|
8
|
+
* It lived in two files for as long as there were two claim authorities: the
|
|
9
|
+
* Redis lease store, which is authoritative wherever Redis is wired, and the
|
|
10
|
+
* in-process presence store, which answers when it is not. Both spelled the
|
|
11
|
+
* rule out in full, byte for byte, so a change to the granularity semantics had
|
|
12
|
+
* two places to land and no way to notice when it landed in one. It is one
|
|
13
|
+
* definition here, and both authorities import it.
|
|
14
|
+
*
|
|
15
|
+
* It lives in the settlement core rather than the server because it is the rule
|
|
16
|
+
* itself, not a deployment of it: a claim authority running against a
|
|
17
|
+
* developer's own database has to answer this question exactly the same way,
|
|
18
|
+
* and a client that wants to predict a refusal before paying for the round trip
|
|
19
|
+
* reads the same predicate. Nothing about it needs a socket, a store, or a
|
|
20
|
+
* screen.
|
|
21
|
+
*
|
|
22
|
+
* Entity identity is NOT part of this comparison. Callers reach this predicate
|
|
23
|
+
* having already narrowed to a single `(organization, environment, entityType,
|
|
24
|
+
* entityId)` bucket — the lease store through its key, the presence store
|
|
25
|
+
* through its per-entity scan — so what remains to decide is only whether the
|
|
26
|
+
* two sub-targets within that entity overlap.
|
|
27
|
+
*
|
|
28
|
+
* **The bias is deliberate: when in doubt, conflict.** A false conflict costs a
|
|
29
|
+
* writer a wait. A missed conflict hands two writers the same target and loses
|
|
30
|
+
* one of their updates with no error anywhere, which is the failure this
|
|
31
|
+
* predicate exists to prevent.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The named parts a claim covers, as one set.
|
|
36
|
+
*
|
|
37
|
+
* `field` and `fields` are the same idea at two cardinalities, so the rule
|
|
38
|
+
* reads both through here and never has to ask which one a caller used. Names
|
|
39
|
+
* are lowercased for the same reason the single-field comparison always
|
|
40
|
+
* lowercased them.
|
|
41
|
+
*/
|
|
42
|
+
function fieldSet(target: ClaimTargetDetails | undefined): Set<string> {
|
|
43
|
+
const named = [
|
|
44
|
+
...(target?.field !== undefined ? [target.field] : []),
|
|
45
|
+
...(target?.fields ?? []),
|
|
46
|
+
];
|
|
47
|
+
return new Set(named.map((n) => n.toLowerCase()));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Whether a claim narrows below the whole entity at all. */
|
|
51
|
+
function hasSubtarget(target: ClaimTargetDetails | undefined): boolean {
|
|
52
|
+
return Boolean(
|
|
53
|
+
target?.field || (target?.fields && target.fields.length > 0),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function targetsConflict(
|
|
58
|
+
held: ClaimTargetDetails,
|
|
59
|
+
incoming: ClaimTargetDetails | undefined,
|
|
60
|
+
): boolean {
|
|
61
|
+
// Whole-entity claims are conservative: they conflict with any narrower
|
|
62
|
+
// field claim under the same entity.
|
|
63
|
+
if (!hasSubtarget(held) || !hasSubtarget(incoming)) return true;
|
|
64
|
+
|
|
65
|
+
// Field is the floor. A claim is only as fine as the smallest thing the write
|
|
66
|
+
// path can address, and today that is a whole field: nothing writes part of a
|
|
67
|
+
// value. Sub-field targeting — a text range, a path into a document — would
|
|
68
|
+
// let two writers hold disjoint parts of the SAME field at once, which is
|
|
69
|
+
// only safe once concurrent edits to one field can be reconciled (operational
|
|
70
|
+
// transformation). We have not solved that yet, so we do not offer the finer
|
|
71
|
+
// grain: two claims on the same field conflict, full stop. When same-field
|
|
72
|
+
// concurrency is solved, sub-field targets return with real disjointness.
|
|
73
|
+
// See docs/plans/claim-granularity-field-floor.md.
|
|
74
|
+
//
|
|
75
|
+
// A claim that names no field covers every field, so it conflicts with any
|
|
76
|
+
// claim under the same entity. Two that both name fields conflict only where
|
|
77
|
+
// their sets intersect.
|
|
78
|
+
const heldFields = fieldSet(held);
|
|
79
|
+
const incomingFields = fieldSet(incoming);
|
|
80
|
+
return (
|
|
81
|
+
heldFields.size === 0 ||
|
|
82
|
+
incomingFields.size === 0 ||
|
|
83
|
+
[...heldFields].some((name) => incomingFields.has(name))
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A claim log — the simplest way to watch agents collide. The engine reports
|
|
3
|
+
* the claim lifecycle (`acquired → queued → granted → lost / rejected /
|
|
4
|
+
* expired`) and the notify-instead-of-abort stale write through two channels:
|
|
5
|
+
* human-readable `logger` lines (shown with `new Ablo({ debug: true })`) and
|
|
6
|
+
* structured `observability.captureClaim` / `captureConflict` calls.
|
|
7
|
+
*
|
|
8
|
+
* This is a third channel, shaped for tests and evals. Pass a {@link ClaimLog}
|
|
9
|
+
* as `Ablo({ observability })`, run your scenario, then read back an ordered
|
|
10
|
+
* list — print it to eyeball what happened, or call `collisions()` to assert on it.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
ClaimEvent,
|
|
15
|
+
ConflictEvent,
|
|
16
|
+
CoordinationObserver,
|
|
17
|
+
} from './events.js';
|
|
18
|
+
|
|
19
|
+
// ─────────────────────────────────────────────
|
|
20
|
+
// Formatters — one readable line per event. Shared by the debug logger and
|
|
21
|
+
// this log so console output and log output never drift.
|
|
22
|
+
// ─────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/** A claim state change as one quiet, greppable line. */
|
|
25
|
+
export function formatClaim(e: ClaimEvent): string {
|
|
26
|
+
const target = e.model && e.id ? `${e.model}/${e.id}` : e.claimId ?? 'unknown target';
|
|
27
|
+
const scope = e.field ? `#${e.field}` : '';
|
|
28
|
+
const pos = e.position !== undefined ? ` [pos ${e.position}]` : '';
|
|
29
|
+
// The kind belongs to the counterparty, which is the only participant an
|
|
30
|
+
// event names: on an acquisition the participant is us.
|
|
31
|
+
const kind = e.heldBy?.participantKind;
|
|
32
|
+
const actor = e.actor ? `${e.actor}${kind ? ` (${kind})` : ''}` : '';
|
|
33
|
+
// `rejected`/`lost` name the blocking holder; the rest name us (or no one).
|
|
34
|
+
const by = actor
|
|
35
|
+
? e.phase === 'rejected' || e.phase === 'lost'
|
|
36
|
+
? ` — held by ${actor}`
|
|
37
|
+
: ` — by ${actor}`
|
|
38
|
+
: '';
|
|
39
|
+
// The cause when there is one, in the policy's own words when a policy
|
|
40
|
+
// decided; otherwise what the holder said they were doing. A line never
|
|
41
|
+
// shows both, because a claim that ended has a cause and a claim that is
|
|
42
|
+
// simply alive has only its description.
|
|
43
|
+
const why = e.reason
|
|
44
|
+
? `: ${e.policyReason ?? e.reason}`
|
|
45
|
+
: e.description
|
|
46
|
+
? `: ${e.description}`
|
|
47
|
+
: '';
|
|
48
|
+
return `claim ${e.phase}: ${target}${scope}${pos}${by}${why}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** A notify-instead-of-abort stale write as one readable line. */
|
|
52
|
+
export function formatConflict(e: ConflictEvent): string {
|
|
53
|
+
const rows = e.rows.map((r) => `${r.model}/${r.id}(${r.fields.join(',')})`).join(', ');
|
|
54
|
+
return `conflict: tx ${e.clientTxId} — ${e.rows.length} row(s) changed underneath${rows ? `: ${rows}` : ''}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ─────────────────────────────────────────────
|
|
58
|
+
// Log — collect → inspect / assert
|
|
59
|
+
// ─────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
/** One ordered entry in a {@link ClaimLog}. */
|
|
62
|
+
export interface ClaimLogEntry {
|
|
63
|
+
/** Monotonic order index — deterministic, clock-free, eval-friendly. */
|
|
64
|
+
readonly seq: number;
|
|
65
|
+
/** The same one-line text the console and breadcrumb channels emit. */
|
|
66
|
+
readonly line: string;
|
|
67
|
+
/** A collision worth flagging: a rejected/lost claim or a stale write. */
|
|
68
|
+
readonly collision: boolean;
|
|
69
|
+
readonly claim?: ClaimEvent;
|
|
70
|
+
readonly conflict?: ConflictEvent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Collects the claim lifecycle + stale-write collisions into an ordered list.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const log = new ClaimLog();
|
|
79
|
+
* const ablo = new Ablo({ schema, apiKey, observability: log });
|
|
80
|
+
* // …run the agents…
|
|
81
|
+
* console.log(`${log}`); // pretty timeline for eyeballing
|
|
82
|
+
* expect(log.collisions()).toHaveLength(0); // assert no one stepped on anyone
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* Implements the transaction layer's narrow {@link CoordinationObserver}.
|
|
86
|
+
* The sync engine re-serves a compatibility subclass that fills its broader
|
|
87
|
+
* lifecycle-observability contract, so the public `Ablo({ observability })`
|
|
88
|
+
* usage remains unchanged without teaching this core class about bootstrap,
|
|
89
|
+
* IndexedDB, or WebSockets.
|
|
90
|
+
*/
|
|
91
|
+
export class ClaimLog implements CoordinationObserver {
|
|
92
|
+
// Immutable list: a new array reference on every change. This is what lets
|
|
93
|
+
// `useSyncExternalStore(log.onChange, () => log.entries)` detect updates —
|
|
94
|
+
// it compares snapshots by reference, so an in-place push would never render.
|
|
95
|
+
private rows: readonly ClaimLogEntry[] = [];
|
|
96
|
+
private seq = 0;
|
|
97
|
+
private readonly listeners = new Set<() => void>();
|
|
98
|
+
|
|
99
|
+
/** Cap the buffer so a long-running session can't grow unbounded. */
|
|
100
|
+
constructor(private readonly max = 1_000) {}
|
|
101
|
+
|
|
102
|
+
// —— the two channels we record ——
|
|
103
|
+
|
|
104
|
+
captureClaim(claim: ClaimEvent): void {
|
|
105
|
+
this.add({
|
|
106
|
+
line: formatClaim(claim),
|
|
107
|
+
collision: claim.phase === 'rejected' || claim.phase === 'lost',
|
|
108
|
+
claim,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
captureConflict(conflict: ConflictEvent): void {
|
|
113
|
+
this.add({ line: formatConflict(conflict), collision: true, conflict });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// —— reactivity ——
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Fire `listener` every time an event lands. Returns an unsubscribe fn. Same
|
|
120
|
+
* contract as `ablo.claims.onChange` — drop it into `useSyncExternalStore` in
|
|
121
|
+
* React or `autorun` in MobX to render a live activity feed.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```tsx
|
|
125
|
+
* const log = useMemo(() => new ClaimLog(), []);
|
|
126
|
+
* const entries = useSyncExternalStore(log.onChange, () => log.entries);
|
|
127
|
+
* return <ul>{entries.map((e) => <li key={e.seq}>{e.line}</li>)}</ul>;
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
readonly onChange = (listener: () => void): (() => void) => {
|
|
131
|
+
this.listeners.add(listener);
|
|
132
|
+
return () => this.listeners.delete(listener);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// —— inspection ——
|
|
136
|
+
|
|
137
|
+
/** The full ordered list. Stable reference until the next event lands. */
|
|
138
|
+
get entries(): readonly ClaimLogEntry[] {
|
|
139
|
+
return this.rows;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Only the collisions: rejected/lost claims + stale writes. */
|
|
143
|
+
collisions(): readonly ClaimLogEntry[] {
|
|
144
|
+
return this.rows.filter((e) => e.collision);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Drop everything — useful between scenarios in one process. */
|
|
148
|
+
clear(): void {
|
|
149
|
+
this.rows = [];
|
|
150
|
+
this.seq = 0;
|
|
151
|
+
this.notify();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Printable: one event per line, collisions marked. */
|
|
155
|
+
toString(): string {
|
|
156
|
+
if (this.rows.length === 0) return 'claim log: (empty)';
|
|
157
|
+
const w = String(this.rows.length).length;
|
|
158
|
+
return this.rows
|
|
159
|
+
.map((e) => `${String(e.seq).padStart(w)} ${e.collision ? '⚠ ' : ' '}${e.line}`)
|
|
160
|
+
.join('\n');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private add(entry: Omit<ClaimLogEntry, 'seq'>): void {
|
|
164
|
+
const next = [...this.rows, { seq: this.seq++, ...entry }];
|
|
165
|
+
this.rows = next.length > this.max ? next.slice(next.length - this.max) : next;
|
|
166
|
+
this.notify();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private notify(): void {
|
|
170
|
+
for (const listener of this.listeners) listener();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The catalog of documentation this package ships.
|
|
3
|
+
*
|
|
4
|
+
* One definition of *which docs exist*, read from the files themselves. Every
|
|
5
|
+
* reader — `ablo docs`, the public `/api/docs/*` routes, the MCP docs tools —
|
|
6
|
+
* resolves through here rather than keeping its own list, because a
|
|
7
|
+
* hand-maintained index of a directory is a copy that drifts the moment a page
|
|
8
|
+
* is added and nothing fails when it does. Before this module the public web
|
|
9
|
+
* allowlist had fallen 21 pages behind the corpus, including `coordination`.
|
|
10
|
+
*
|
|
11
|
+
* Title and description are DERIVED from each file's own convention: an H1,
|
|
12
|
+
* then a one-paragraph blockquote stating what the page is for. That blockquote
|
|
13
|
+
* is the description everywhere it is needed — the site frontmatter lifts the
|
|
14
|
+
* same line — so a page states its own promise exactly once, in the source that
|
|
15
|
+
* ships in the npm tarball and still reads correctly as plain markdown.
|
|
16
|
+
*
|
|
17
|
+
* The published set mirrors the tarball's `files` globs (`docs/*.md`,
|
|
18
|
+
* `docs/examples/*.md`, plus the three root files). Anything else under `docs/`
|
|
19
|
+
* — `docs/internal/**` above all — is neither shipped nor catalogued, and that
|
|
20
|
+
* exclusion is the only thing keeping internal notes off the public routes now
|
|
21
|
+
* that they read from here.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
25
|
+
import { basename, join } from 'node:path';
|
|
26
|
+
|
|
27
|
+
/** Where a page sits in the corpus, and how a reader should group it. */
|
|
28
|
+
export type DocKind = 'guide' | 'example' | 'package';
|
|
29
|
+
|
|
30
|
+
/** One documentation page, as shipped. */
|
|
31
|
+
export interface DocEntry {
|
|
32
|
+
/** Stable reference: `quickstart`, `examples/nextjs`, `agents`. */
|
|
33
|
+
readonly slug: string;
|
|
34
|
+
/** Human-readable title — the file's H1, or curated for the root files. */
|
|
35
|
+
readonly title: string;
|
|
36
|
+
/** One line stating what the page is for — the file's promise blockquote. */
|
|
37
|
+
readonly description: string;
|
|
38
|
+
readonly kind: DocKind;
|
|
39
|
+
/** Absolute path on disk. */
|
|
40
|
+
readonly path: string;
|
|
41
|
+
readonly mime: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const MARKDOWN_MIME = 'text/markdown; charset=utf-8';
|
|
45
|
+
const TEXT_MIME = 'text/plain; charset=utf-8';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The three files that document the package itself rather than a topic. They
|
|
49
|
+
* live at the package root, not under `docs/`, and none follows the H1 +
|
|
50
|
+
* blockquote convention — `llms.txt` opens with a prose paragraph and
|
|
51
|
+
* `README.md` with a banner — so their titles and descriptions are curated
|
|
52
|
+
* here, the one place that knows they are a different kind of artifact.
|
|
53
|
+
*
|
|
54
|
+
* Their slug is their filename, because the filename IS how these are referred
|
|
55
|
+
* to everywhere (`AGENTS.md` is an ecosystem convention, not a topic name) and
|
|
56
|
+
* because a bare word would collide: `docs/agents.md` is a published guide that
|
|
57
|
+
* the docs index cross-links as `agents`, and whichever of the two won that
|
|
58
|
+
* name would silently shadow the other. Friendlier spellings are aliases below.
|
|
59
|
+
*/
|
|
60
|
+
const PACKAGE_FILES: readonly {
|
|
61
|
+
readonly filename: string;
|
|
62
|
+
readonly title: string;
|
|
63
|
+
readonly description: string;
|
|
64
|
+
readonly mime: string;
|
|
65
|
+
}[] = [
|
|
66
|
+
{
|
|
67
|
+
filename: 'AGENTS.md',
|
|
68
|
+
title: 'AGENTS.md',
|
|
69
|
+
description:
|
|
70
|
+
'The playbook a coding agent follows to install and drive Ablo without hanging on a prompt.',
|
|
71
|
+
mime: MARKDOWN_MIME,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
filename: 'README.md',
|
|
75
|
+
title: 'README',
|
|
76
|
+
description: 'Package overview — what Ablo is and the shape of the API.',
|
|
77
|
+
mime: MARKDOWN_MIME,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
filename: 'llms.txt',
|
|
81
|
+
title: 'llms.txt',
|
|
82
|
+
description: 'The curated single-file index of the whole API, for machine readers.',
|
|
83
|
+
mime: TEXT_MIME,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Curated redirects for references that are not a slug: the friendly spellings
|
|
89
|
+
* of the root files, plus the renames the public URLs carried before this
|
|
90
|
+
* module existed, kept so old links and any agent working from a cached page
|
|
91
|
+
* still resolve. Identity mappings are NOT listed — a slug resolves to itself
|
|
92
|
+
* by derivation, and restating the other 30 here would rebuild the
|
|
93
|
+
* hand-maintained list this module exists to delete.
|
|
94
|
+
*/
|
|
95
|
+
const SLUG_ALIASES: Readonly<Record<string, string>> = {
|
|
96
|
+
readme: 'README.md',
|
|
97
|
+
overview: 'README.md',
|
|
98
|
+
llms: 'llms.txt',
|
|
99
|
+
storage: 'data-sources',
|
|
100
|
+
'docs/storage.md': 'data-sources',
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Read the catalog from a package root — the directory holding `docs/` and the
|
|
105
|
+
* three root files.
|
|
106
|
+
*
|
|
107
|
+
* The root is a parameter rather than resolved here because each reader knows
|
|
108
|
+
* it differently and they are genuinely different facts: the CLI resolves it
|
|
109
|
+
* against its own bundle inside `node_modules`, while the web app resolves it
|
|
110
|
+
* against the monorepo checkout. Nothing is cached; callers that serve many
|
|
111
|
+
* requests should memoize the returned array.
|
|
112
|
+
*/
|
|
113
|
+
export async function readDocsCatalog(packageRoot: string): Promise<DocEntry[]> {
|
|
114
|
+
const docsDir = join(packageRoot, 'docs');
|
|
115
|
+
const entries: DocEntry[] = [];
|
|
116
|
+
|
|
117
|
+
entries.push(...(await readDocsDirectory(docsDir, 'guide')));
|
|
118
|
+
entries.push(...(await readDocsDirectory(join(docsDir, 'examples'), 'example')));
|
|
119
|
+
|
|
120
|
+
for (const file of PACKAGE_FILES) {
|
|
121
|
+
const path = join(packageRoot, file.filename);
|
|
122
|
+
const body = await readFileOrNull(path);
|
|
123
|
+
if (body === null) continue;
|
|
124
|
+
entries.push({
|
|
125
|
+
slug: file.filename,
|
|
126
|
+
title: file.title,
|
|
127
|
+
description: file.description,
|
|
128
|
+
kind: 'package',
|
|
129
|
+
path,
|
|
130
|
+
mime: file.mime,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return entries.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Read one flat directory of markdown. Deliberately non-recursive: the shipped
|
|
139
|
+
* set is `docs/*.md` plus `docs/examples/*.md`, so descending would catalogue
|
|
140
|
+
* `docs/internal/**` — notes that are not in the tarball and must not reach a
|
|
141
|
+
* public route.
|
|
142
|
+
*/
|
|
143
|
+
async function readDocsDirectory(dir: string, kind: DocKind): Promise<DocEntry[]> {
|
|
144
|
+
let names: string[];
|
|
145
|
+
try {
|
|
146
|
+
const found = await readdir(dir, { withFileTypes: true });
|
|
147
|
+
names = found.filter((e) => e.isFile() && e.name.endsWith('.md')).map((e) => e.name);
|
|
148
|
+
} catch {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const entries: DocEntry[] = [];
|
|
153
|
+
for (const name of names) {
|
|
154
|
+
const path = join(dir, name);
|
|
155
|
+
const body = await readFileOrNull(path);
|
|
156
|
+
if (body === null) continue;
|
|
157
|
+
const stem = basename(name, '.md');
|
|
158
|
+
const { title, description } = parseDocHeader(body);
|
|
159
|
+
entries.push({
|
|
160
|
+
slug: kind === 'example' ? `examples/${stem}` : stem,
|
|
161
|
+
title: title ?? stem,
|
|
162
|
+
description,
|
|
163
|
+
kind,
|
|
164
|
+
path,
|
|
165
|
+
mime: MARKDOWN_MIME,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return entries;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** The H1 a page opens with, and the blockquote paragraph that follows it. */
|
|
172
|
+
const H1_LINE = /^#[ \t]+(.+?)[ \t]*$/m;
|
|
173
|
+
const PROMISE_BLOCKQUOTE = /^\s*\n((?:>.*\n)+)/;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Pull a page's title and promise line out of its markdown.
|
|
177
|
+
*
|
|
178
|
+
* The convention every page follows: an H1, then a blockquote paragraph saying
|
|
179
|
+
* what the page is for. A page missing either simply reports what it has — the
|
|
180
|
+
* catalog never invents prose.
|
|
181
|
+
*/
|
|
182
|
+
export function parseDocHeader(body: string): {
|
|
183
|
+
readonly title: string | null;
|
|
184
|
+
readonly description: string;
|
|
185
|
+
} {
|
|
186
|
+
const heading = H1_LINE.exec(body);
|
|
187
|
+
const title = heading?.[1] ?? null;
|
|
188
|
+
|
|
189
|
+
const afterHeading = heading === null ? body : body.slice(heading.index + heading[0].length);
|
|
190
|
+
const promise = PROMISE_BLOCKQUOTE.exec(afterHeading);
|
|
191
|
+
const description =
|
|
192
|
+
promise?.[1]
|
|
193
|
+
?.split('\n')
|
|
194
|
+
.filter(Boolean)
|
|
195
|
+
.map((line) => line.replace(/^>\s?/, ''))
|
|
196
|
+
.join(' ')
|
|
197
|
+
.trim() ?? '';
|
|
198
|
+
|
|
199
|
+
return { title, description };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Resolve a reference to a page. Accepts the slug (`coordination`), a curated
|
|
204
|
+
* alias (`storage`), or a repo-relative path (`docs/coordination.md`,
|
|
205
|
+
* `AGENTS.md`) — the three forms readers actually arrive with. Returns null
|
|
206
|
+
* rather than throwing so a caller can render its own not-found.
|
|
207
|
+
*/
|
|
208
|
+
export function findDoc(catalog: readonly DocEntry[], reference: string): DocEntry | null {
|
|
209
|
+
const trimmed = reference.trim();
|
|
210
|
+
if (trimmed === '') return null;
|
|
211
|
+
|
|
212
|
+
const direct = matchSlug(catalog, trimmed);
|
|
213
|
+
if (direct) return direct;
|
|
214
|
+
|
|
215
|
+
const aliased = SLUG_ALIASES[trimmed.toLowerCase()];
|
|
216
|
+
if (aliased) {
|
|
217
|
+
const target = matchSlug(catalog, aliased);
|
|
218
|
+
if (target) return target;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Path form: `docs/coordination.md`, `docs/examples/nextjs.md`, `llms.txt`.
|
|
222
|
+
const asSlug = trimmed
|
|
223
|
+
.replace(/^\.?\//, '')
|
|
224
|
+
.replace(/^docs\//, '')
|
|
225
|
+
.replace(/\.(md|txt)$/i, '');
|
|
226
|
+
return matchSlug(catalog, asSlug);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function matchSlug(catalog: readonly DocEntry[], slug: string): DocEntry | null {
|
|
230
|
+
const needle = slug.toLowerCase();
|
|
231
|
+
return catalog.find((entry) => entry.slug.toLowerCase() === needle) ?? null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Slugs closest to a miss, for a "did you mean" line. Ranks by shared prefix,
|
|
236
|
+
* then substring containment — enough to catch a typo or a half-remembered
|
|
237
|
+
* name without pulling in a distance library.
|
|
238
|
+
*/
|
|
239
|
+
export function suggestSlugs(
|
|
240
|
+
catalog: readonly DocEntry[],
|
|
241
|
+
reference: string,
|
|
242
|
+
limit = 3
|
|
243
|
+
): string[] {
|
|
244
|
+
const needle = reference.trim().toLowerCase();
|
|
245
|
+
if (needle === '') return [];
|
|
246
|
+
|
|
247
|
+
return catalog
|
|
248
|
+
.map((entry) => {
|
|
249
|
+
const slug = entry.slug.toLowerCase();
|
|
250
|
+
let score = 0;
|
|
251
|
+
if (slug.includes(needle) || needle.includes(slug)) score += 10;
|
|
252
|
+
score += sharedPrefixLength(slug, needle);
|
|
253
|
+
return { slug: entry.slug, score };
|
|
254
|
+
})
|
|
255
|
+
.filter(({ score }) => score > 2)
|
|
256
|
+
.sort((a, b) => b.score - a.score)
|
|
257
|
+
.slice(0, limit)
|
|
258
|
+
.map(({ slug }) => slug);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function sharedPrefixLength(a: string, b: string): number {
|
|
262
|
+
const max = Math.min(a.length, b.length);
|
|
263
|
+
let i = 0;
|
|
264
|
+
while (i < max && a[i] === b[i]) i += 1;
|
|
265
|
+
return i;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function readFileOrNull(path: string): Promise<string | null> {
|
|
269
|
+
try {
|
|
270
|
+
return await readFile(path, 'utf8');
|
|
271
|
+
} catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic access to the documentation this package ships.
|
|
3
|
+
*
|
|
4
|
+
* The docs travel in the npm tarball beside the code they describe, so a reader
|
|
5
|
+
* that resolves them through here is reading the pages for the version actually
|
|
6
|
+
* installed — not whatever the website is serving today. That is the whole
|
|
7
|
+
* point of the subpath: a published version is frozen, its docs are frozen with
|
|
8
|
+
* it, and the canonical `get` contract cannot drift behind a pinned dependency.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
readDocsCatalog,
|
|
13
|
+
findDoc,
|
|
14
|
+
parseDocHeader,
|
|
15
|
+
suggestSlugs,
|
|
16
|
+
type DocEntry,
|
|
17
|
+
type DocKind,
|
|
18
|
+
} from './catalog.js';
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The durable-write port and the option that installs it.
|
|
3
|
+
*
|
|
4
|
+
* Owns the persistence contract behind `Ablo({ durableWrites })` — a behavior
|
|
5
|
+
* contract of methods, not a serialized shape, which is why it lives here
|
|
6
|
+
* rather than in `transactions/settlement/`. The records that cross this port
|
|
7
|
+
* are owned by `pendingWriteSchema` there; this module never redescribes them.
|
|
8
|
+
*
|
|
9
|
+
* The engine consumes the port through `commitOutboxStore`, and the HTTP client
|
|
10
|
+
* accepts the same option through `transport/httpOptions`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { AbloValidationError } from './errors.js';
|
|
15
|
+
import type { CommitOutboxScope } from './transactions/settlement/commitEnvelope.js';
|
|
16
|
+
import type { PendingWrite } from './transactions/settlement/pendingWrite.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Persistence port used by `Ablo({ durableWrites })`.
|
|
20
|
+
*
|
|
21
|
+
* `seal` is the durability boundary: it must atomically persist the exact write
|
|
22
|
+
* and consume the staged records that write supersedes. Resolving this promise
|
|
23
|
+
* authorizes Ablo to dispatch the request, so adapters must never report success
|
|
24
|
+
* before the data is durable.
|
|
25
|
+
*/
|
|
26
|
+
export interface DurableWriteStore {
|
|
27
|
+
/**
|
|
28
|
+
* Atomically reserve a pending write and consume the staged records it owns.
|
|
29
|
+
* The same id + same request is idempotent; the same id + a different request
|
|
30
|
+
* must be rejected. For a source-accepted envelope, a re-seal may add the
|
|
31
|
+
* monotonic `acceptedAt`/`correlationId` evidence and the store must preserve
|
|
32
|
+
* that upgrade atomically rather than ignoring it.
|
|
33
|
+
*/
|
|
34
|
+
seal(
|
|
35
|
+
write: PendingWrite,
|
|
36
|
+
consumedRecordIds: readonly string[],
|
|
37
|
+
): Promise<void>;
|
|
38
|
+
/** Load all unacknowledged writes. Stored data is treated as untrusted. */
|
|
39
|
+
list(): Promise<readonly unknown[]>;
|
|
40
|
+
/** Remove one write only after its outcome is definitive. */
|
|
41
|
+
remove(writeId: string): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Runtime validation for injected adapters, including JavaScript consumers. */
|
|
45
|
+
export const durableWriteStoreSchema = z.custom<DurableWriteStore>(
|
|
46
|
+
(value) => {
|
|
47
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
48
|
+
const candidate = value as Record<string, unknown>;
|
|
49
|
+
return (
|
|
50
|
+
typeof candidate.seal === 'function' &&
|
|
51
|
+
typeof candidate.list === 'function' &&
|
|
52
|
+
typeof candidate.remove === 'function'
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
{ message: 'store must implement seal(), list(), and remove()' },
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/** Options for crash-durable `create`, `update`, and `delete` calls. */
|
|
59
|
+
export const durableWritesConfigSchema = z.strictObject({
|
|
60
|
+
store: durableWriteStoreSchema,
|
|
61
|
+
/** Separates deployments or workflow lanes that share an authenticated actor. */
|
|
62
|
+
namespace: z.string().trim().min(1).optional(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export type DurableWritesConfig = z.infer<typeof durableWritesConfigSchema>;
|
|
66
|
+
|
|
67
|
+
interface DurableWriteOptionInput {
|
|
68
|
+
readonly durableWrites?: DurableWritesConfig;
|
|
69
|
+
/** Compatibility input for pre-`durableWrites` clients. */
|
|
70
|
+
readonly commitOutbox?: DurableWriteStore;
|
|
71
|
+
/** Compatibility input and internal child-client identity seam. */
|
|
72
|
+
readonly commitOutboxScope?: CommitOutboxScope;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ResolvedDurableWrites {
|
|
76
|
+
readonly store?: DurableWriteStore;
|
|
77
|
+
readonly namespace?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function invalidDurableWrites(message: string): AbloValidationError {
|
|
81
|
+
return new AbloValidationError(`Ablo: invalid \`durableWrites\` option — ${message}.`, {
|
|
82
|
+
code: 'invalid_options',
|
|
83
|
+
param: 'durableWrites',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolves one canonical store configuration for both HTTP and WebSocket
|
|
89
|
+
* clients. Mixed old/new configuration fails loudly so Ablo never persists to
|
|
90
|
+
* one adapter while the caller believes another adapter is authoritative.
|
|
91
|
+
*/
|
|
92
|
+
export function resolveDurableWrites(
|
|
93
|
+
options: DurableWriteOptionInput,
|
|
94
|
+
): ResolvedDurableWrites {
|
|
95
|
+
if (options.durableWrites !== undefined && options.commitOutbox !== undefined) {
|
|
96
|
+
throw invalidDurableWrites(
|
|
97
|
+
'pass `durableWrites` or the deprecated `commitOutbox`, not both',
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (options.durableWrites !== undefined) {
|
|
102
|
+
const parsed = durableWritesConfigSchema.safeParse(options.durableWrites);
|
|
103
|
+
if (!parsed.success) {
|
|
104
|
+
throw invalidDurableWrites(
|
|
105
|
+
parsed.error.issues.map((issue) => issue.message).join('; '),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
store: parsed.data.store,
|
|
110
|
+
...(parsed.data.namespace !== undefined
|
|
111
|
+
? { namespace: parsed.data.namespace }
|
|
112
|
+
: options.commitOutboxScope?.namespace !== undefined
|
|
113
|
+
? { namespace: options.commitOutboxScope.namespace }
|
|
114
|
+
: {}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (options.commitOutbox !== undefined) {
|
|
119
|
+
const parsed = durableWriteStoreSchema.safeParse(options.commitOutbox);
|
|
120
|
+
if (!parsed.success) {
|
|
121
|
+
throw invalidDurableWrites(
|
|
122
|
+
parsed.error.issues.map((issue) => issue.message).join('; '),
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
store: parsed.data,
|
|
127
|
+
...(options.commitOutboxScope?.namespace !== undefined
|
|
128
|
+
? { namespace: options.commitOutboxScope.namespace }
|
|
129
|
+
: {}),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {};
|
|
134
|
+
}
|