@abloatai/transaction 0.47.0 → 0.49.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 +7 -7
- package/README.md +1 -1
- package/dist/ai-sdk/modelTools.d.ts +1 -1
- package/dist/ai-sdk/modelTools.js +1 -1
- package/dist/ai-sdk/updateTool.d.ts +2 -2
- package/dist/ai-sdk/updateTool.d.ts.map +1 -1
- package/dist/auth/bootstrapScope.d.ts +1 -1
- package/dist/auth/capability.d.ts +32 -10
- package/dist/auth/capability.d.ts.map +1 -1
- package/dist/auth/capability.js +9 -3
- package/dist/auth/capability.js.map +1 -1
- package/dist/auth/capabilityLifecycle.d.ts +2 -2
- package/dist/auth/capabilityLifecycle.d.ts.map +1 -1
- package/dist/auth/capabilityLifecycle.js +3 -2
- package/dist/auth/capabilityLifecycle.js.map +1 -1
- package/dist/auth/identity.d.ts +3 -0
- package/dist/auth/identity.d.ts.map +1 -1
- package/dist/auth/identity.js +13 -1
- package/dist/auth/identity.js.map +1 -1
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/schemas.d.ts +18 -1
- package/dist/auth/schemas.d.ts.map +1 -1
- package/dist/auth/schemas.js +3 -1
- package/dist/auth/schemas.js.map +1 -1
- package/dist/auth/sessionMint.d.ts.map +1 -1
- package/dist/auth/sessionMint.js +0 -1
- package/dist/auth/sessionMint.js.map +1 -1
- package/dist/branches.d.ts +61 -12
- package/dist/branches.d.ts.map +1 -1
- package/dist/branches.js +25 -3
- package/dist/branches.js.map +1 -1
- package/dist/commitRecordRuntime.d.ts +30 -0
- package/dist/commitRecordRuntime.d.ts.map +1 -0
- package/dist/commitRecordRuntime.js +188 -0
- package/dist/commitRecordRuntime.js.map +1 -0
- package/dist/coordination/index.d.ts +3 -3
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +2 -2
- package/dist/coordination/index.js.map +1 -1
- package/dist/coordination/locator.d.ts +5 -0
- package/dist/coordination/locator.d.ts.map +1 -1
- package/dist/coordination/locator.js +12 -0
- package/dist/coordination/locator.js.map +1 -1
- package/dist/coordination/schema.d.ts +205 -15
- package/dist/coordination/schema.d.ts.map +1 -1
- package/dist/coordination/schema.js +88 -47
- package/dist/coordination/schema.js.map +1 -1
- package/dist/coordination/targetConflict.js +1 -1
- package/dist/durableWrites.d.ts +3 -3
- package/dist/durableWrites.d.ts.map +1 -1
- package/dist/durableWrites.js +1 -1
- package/dist/errorCodes.d.ts +35 -2
- package/dist/errorCodes.d.ts.map +1 -1
- package/dist/errorCodes.js +67 -19
- package/dist/errorCodes.js.map +1 -1
- package/dist/errorObservation.d.ts +82 -0
- package/dist/errorObservation.d.ts.map +1 -0
- package/dist/errorObservation.js +101 -0
- package/dist/errorObservation.js.map +1 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -1
- package/dist/errors.js.map +1 -1
- package/dist/footprint.d.ts +10 -22
- package/dist/footprint.d.ts.map +1 -1
- package/dist/footprint.js +12 -24
- package/dist/footprint.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/read-set.d.ts +8 -0
- package/dist/internal/read-set.d.ts.map +1 -0
- package/dist/internal/read-set.js +7 -0
- package/dist/internal/read-set.js.map +1 -0
- package/dist/logger.d.ts +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +1 -1
- package/dist/readSetContext.d.ts +54 -0
- package/dist/readSetContext.d.ts.map +1 -0
- package/dist/readSetContext.js +98 -0
- package/dist/readSetContext.js.map +1 -0
- package/dist/resources/functionalUpdate.d.ts +13 -3
- package/dist/resources/functionalUpdate.d.ts.map +1 -1
- package/dist/resources/functionalUpdate.js.map +1 -1
- package/dist/resources/httpResources.d.ts +23 -7
- package/dist/resources/httpResources.d.ts.map +1 -1
- package/dist/resources/modelOperations.d.ts +2 -2
- package/dist/resources/modelOperations.js +1 -1
- package/dist/resources/mutationOptions.d.ts +1 -1
- package/dist/resources/mutationOptions.js +1 -1
- package/dist/resources/where.d.ts +1 -1
- package/dist/resources/where.js +1 -1
- package/dist/resources/writeOptionsSchema.d.ts +39 -4
- package/dist/resources/writeOptionsSchema.d.ts.map +1 -1
- package/dist/resources/writeOptionsSchema.js +12 -6
- package/dist/resources/writeOptionsSchema.js.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/openapi.d.ts.map +1 -1
- package/dist/schema/openapi.js +45 -11
- package/dist/schema/openapi.js.map +1 -1
- package/dist/server/commit.d.ts +7 -1
- package/dist/server/commit.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/source/adapters/kysely.d.ts.map +1 -1
- package/dist/source/adapters/kysely.js +11 -4
- package/dist/source/adapters/kysely.js.map +1 -1
- package/dist/source/adapters/kyselyMutationCore.d.ts.map +1 -1
- package/dist/source/adapters/kyselyMutationCore.js +14 -2
- package/dist/source/adapters/kyselyMutationCore.js.map +1 -1
- package/dist/source/contract.d.ts +2 -0
- package/dist/source/contract.d.ts.map +1 -1
- package/dist/source/index.d.ts +1 -1
- package/dist/source/index.d.ts.map +1 -1
- package/dist/source/types.d.ts +1 -1
- package/dist/testing/fixtures/httpResponses.d.ts +30 -1
- package/dist/testing/fixtures/httpResponses.d.ts.map +1 -1
- package/dist/testing/fixtures/httpResponses.js +48 -1
- package/dist/testing/fixtures/httpResponses.js.map +1 -1
- package/dist/transactionLayer.d.ts +1 -1
- package/dist/transactions/{settlement → confirmation}/commitEnvelope.d.ts +4 -2
- package/dist/transactions/confirmation/commitEnvelope.d.ts.map +1 -0
- package/dist/transactions/{settlement → confirmation}/commitEnvelope.js +8 -3
- package/dist/transactions/confirmation/commitEnvelope.js.map +1 -0
- package/dist/transactions/confirmation/httpCommitEnvelope.d.ts.map +1 -0
- package/dist/transactions/confirmation/httpCommitEnvelope.js.map +1 -0
- package/dist/transactions/confirmation/idempotencyKey.d.ts.map +1 -0
- package/dist/transactions/confirmation/idempotencyKey.js.map +1 -0
- package/dist/transactions/{settlement → confirmation}/pendingWrite.d.ts +3 -2
- package/dist/transactions/confirmation/pendingWrite.d.ts.map +1 -0
- package/dist/transactions/confirmation/pendingWrite.js.map +1 -0
- package/dist/transport/commitFrames.d.ts +1 -0
- package/dist/transport/commitFrames.d.ts.map +1 -1
- package/dist/transport/commitFrames.js +8 -7
- package/dist/transport/commitFrames.js.map +1 -1
- package/dist/transport/connectionManager.d.ts +1 -1
- package/dist/transport/connectionManager.js +1 -1
- package/dist/transport/httpClient.d.ts +23 -9
- package/dist/transport/httpClient.d.ts.map +1 -1
- package/dist/transport/httpClient.js +134 -15
- package/dist/transport/httpClient.js.map +1 -1
- package/dist/transport/httpOptions.d.ts +9 -1
- package/dist/transport/httpOptions.d.ts.map +1 -1
- package/dist/transport/httpTransport.d.ts +3 -0
- package/dist/transport/httpTransport.d.ts.map +1 -1
- package/dist/transport/httpTransport.js +109 -22
- package/dist/transport/httpTransport.js.map +1 -1
- package/dist/transport/wsFrameHandlers.d.ts +3 -1
- package/dist/transport/wsFrameHandlers.d.ts.map +1 -1
- package/dist/transport/wsFrameHandlers.js +38 -17
- package/dist/transport/wsFrameHandlers.js.map +1 -1
- package/dist/transport/wsTransport.d.ts +3 -0
- package/dist/transport/wsTransport.d.ts.map +1 -1
- package/dist/transport/wsTransport.js +32 -1
- package/dist/transport/wsTransport.js.map +1 -1
- package/dist/utils/json.d.ts +1 -1
- package/dist/utils/json.js +1 -1
- package/dist/wire/accountResponses.d.ts +1 -1
- package/dist/wire/auth.d.ts +2 -2
- package/dist/wire/commit.d.ts +1652 -213
- package/dist/wire/commit.d.ts.map +1 -1
- package/dist/wire/commit.js +196 -132
- package/dist/wire/commit.js.map +1 -1
- package/dist/wire/delta.d.ts +1 -1
- package/dist/wire/errorEnvelope.d.ts +1 -0
- package/dist/wire/errorEnvelope.d.ts.map +1 -1
- package/dist/wire/errorEnvelope.js +1 -0
- package/dist/wire/errorEnvelope.js.map +1 -1
- package/dist/wire/feedCursor.d.ts +1 -1
- package/dist/wire/feedCursor.js +1 -1
- package/dist/wire/feedEvent.d.ts +3 -3
- package/dist/wire/frames.d.ts +8 -4
- package/dist/wire/frames.d.ts.map +1 -1
- package/dist/wire/frames.js +6 -3
- package/dist/wire/frames.js.map +1 -1
- package/dist/wire/inboundFrames.d.ts +44 -4
- package/dist/wire/inboundFrames.d.ts.map +1 -1
- package/dist/wire/index.d.ts +6 -4
- package/dist/wire/index.d.ts.map +1 -1
- package/dist/wire/index.js +6 -5
- package/dist/wire/index.js.map +1 -1
- package/dist/wire/modelMutations.d.ts +35 -0
- package/dist/wire/modelMutations.d.ts.map +1 -1
- package/dist/wire/modelMutations.js +9 -2
- package/dist/wire/modelMutations.js.map +1 -1
- package/dist/wire/modelResponses.d.ts +12 -1
- package/dist/wire/modelResponses.d.ts.map +1 -1
- package/dist/wire/modelResponses.js +12 -1
- package/dist/wire/modelResponses.js.map +1 -1
- package/package.json +12 -2
- package/src/ai-sdk/modelTools.ts +1 -1
- package/src/ai-sdk/updateTool.ts +2 -2
- package/src/auth/bootstrapScope.ts +1 -1
- package/src/auth/capability.ts +13 -4
- package/src/auth/capabilityLifecycle.ts +3 -2
- package/src/auth/identity.ts +16 -1
- package/src/auth/index.ts +2 -0
- package/src/auth/schemas.ts +3 -0
- package/src/auth/sessionMint.ts +0 -1
- package/src/branches.ts +27 -3
- package/src/commitRecordRuntime.ts +245 -0
- package/src/coordination/index.ts +24 -1
- package/src/coordination/locator.ts +17 -0
- package/src/coordination/schema.ts +114 -49
- package/src/coordination/targetConflict.ts +1 -1
- package/src/durableWrites.ts +3 -3
- package/src/errorCodes.ts +205 -25
- package/src/errorObservation.ts +121 -0
- package/src/errors.ts +5 -1
- package/src/footprint.ts +16 -27
- package/src/index.ts +8 -1
- package/src/internal/read-set.ts +18 -0
- package/src/logger.ts +1 -1
- package/src/observability.ts +1 -1
- package/src/readSetContext.ts +164 -0
- package/src/resources/functionalUpdate.ts +16 -4
- package/src/resources/httpResources.ts +27 -8
- package/src/resources/modelOperations.ts +2 -2
- package/src/resources/mutationOptions.ts +1 -1
- package/src/resources/where.ts +1 -1
- package/src/resources/writeOptionsSchema.ts +30 -12
- package/src/schema/index.ts +1 -1
- package/src/schema/openapi.ts +52 -11
- package/src/server/commit.ts +7 -1
- package/src/server/index.ts +5 -1
- package/src/source/adapters/kysely.ts +12 -4
- package/src/source/adapters/kyselyMutationCore.ts +14 -2
- package/src/source/index.ts +1 -1
- package/src/source/types.ts +1 -1
- package/src/testing/fixtures/httpResponses.ts +60 -1
- package/src/transactionLayer.ts +1 -1
- package/src/transactions/{settlement → confirmation}/commitEnvelope.ts +13 -3
- package/src/transport/commitFrames.ts +7 -5
- package/src/transport/connectionManager.ts +1 -1
- package/src/transport/httpClient.ts +256 -29
- package/src/transport/httpOptions.ts +9 -1
- package/src/transport/httpTransport.ts +139 -27
- package/src/transport/wsFrameHandlers.ts +46 -8
- package/src/transport/wsTransport.ts +42 -1
- package/src/utils/json.ts +1 -1
- package/src/wire/commit.ts +248 -147
- package/src/wire/errorEnvelope.ts +1 -0
- package/src/wire/feedCursor.ts +1 -1
- package/src/wire/frames.ts +9 -4
- package/src/wire/index.ts +38 -5
- package/src/wire/modelMutations.ts +16 -2
- package/src/wire/modelResponses.ts +14 -1
- package/dist/transactions/settlement/commitEnvelope.d.ts.map +0 -1
- package/dist/transactions/settlement/commitEnvelope.js.map +0 -1
- package/dist/transactions/settlement/httpCommitEnvelope.d.ts.map +0 -1
- package/dist/transactions/settlement/httpCommitEnvelope.js.map +0 -1
- package/dist/transactions/settlement/idempotencyKey.d.ts.map +0 -1
- package/dist/transactions/settlement/idempotencyKey.js.map +0 -1
- package/dist/transactions/settlement/pendingWrite.d.ts.map +0 -1
- package/dist/transactions/settlement/pendingWrite.js.map +0 -1
- /package/dist/transactions/{settlement → confirmation}/httpCommitEnvelope.d.ts +0 -0
- /package/dist/transactions/{settlement → confirmation}/httpCommitEnvelope.js +0 -0
- /package/dist/transactions/{settlement → confirmation}/idempotencyKey.d.ts +0 -0
- /package/dist/transactions/{settlement → confirmation}/idempotencyKey.js +0 -0
- /package/dist/transactions/{settlement → confirmation}/pendingWrite.js +0 -0
- /package/src/transactions/{settlement → confirmation}/httpCommitEnvelope.ts +0 -0
- /package/src/transactions/{settlement → confirmation}/idempotencyKey.ts +0 -0
- /package/src/transactions/{settlement → confirmation}/pendingWrite.ts +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
hasWireCode,
|
|
5
5
|
translateHttpError,
|
|
6
6
|
} from '../errors.js';
|
|
7
|
-
import {
|
|
7
|
+
import { effectiveAuthoritySchema } from './capability.js';
|
|
8
8
|
import type {
|
|
9
9
|
RotateSessionParams,
|
|
10
10
|
SessionRevocation,
|
|
@@ -27,7 +27,8 @@ export const capabilityRotationResponseSchema = z.object({
|
|
|
27
27
|
token: z.string().trim().min(1),
|
|
28
28
|
expiresAt: z.iso.datetime().nullable(),
|
|
29
29
|
organizationId: z.string().min(1),
|
|
30
|
-
|
|
30
|
+
branchRoot: z.boolean().default(false),
|
|
31
|
+
scope: effectiveAuthoritySchema,
|
|
31
32
|
rotatedFrom: z.object({
|
|
32
33
|
capabilityId: z.string().min(1),
|
|
33
34
|
expiresAt: z.iso.datetime(),
|
package/src/auth/identity.ts
CHANGED
|
@@ -34,6 +34,7 @@ import type { AuthCredentialSource } from '../auth/credentialSource.js';
|
|
|
34
34
|
import type { CredentialProvider } from './credentialResult.js';
|
|
35
35
|
import { resolveApiKeyValue, resolveBootstrapBaseUrl } from './apiKey.js';
|
|
36
36
|
import type { DeliveryPartitionRoute } from './deliveryPartition.js';
|
|
37
|
+
import type { EffectiveAuthority } from './capability.js';
|
|
37
38
|
|
|
38
39
|
export interface IdentityResolveInput {
|
|
39
40
|
readonly options: {
|
|
@@ -71,6 +72,8 @@ export interface ResolvedIdentity {
|
|
|
71
72
|
readonly syncGroups: readonly string[] | undefined;
|
|
72
73
|
readonly participantKind: ParticipantKind;
|
|
73
74
|
readonly deliveryPartition: DeliveryPartitionRoute | null;
|
|
75
|
+
/** Effective authority confirmed by the server (or explicit self-hosted configuration). */
|
|
76
|
+
readonly authority: EffectiveAuthority;
|
|
74
77
|
/** Set only on the hosted-cloud path; the caller keeps it to stop refreshes on shutdown. */
|
|
75
78
|
readonly refreshScheduler: RefreshScheduler | null;
|
|
76
79
|
}
|
|
@@ -195,6 +198,16 @@ export async function resolveParticipantIdentity(
|
|
|
195
198
|
syncGroups: options.syncGroups,
|
|
196
199
|
participantKind: kind,
|
|
197
200
|
deliveryPartition: null,
|
|
201
|
+
authority: {
|
|
202
|
+
organizationId: accountScope,
|
|
203
|
+
projectId: accountScope,
|
|
204
|
+
branchId: internalOptions.branchId ?? null,
|
|
205
|
+
participantKind: kind,
|
|
206
|
+
participantId: userId,
|
|
207
|
+
operations: [],
|
|
208
|
+
syncGroups: options.syncGroups ?? [],
|
|
209
|
+
deliveryPartition: null,
|
|
210
|
+
},
|
|
198
211
|
refreshScheduler: null,
|
|
199
212
|
};
|
|
200
213
|
}
|
|
@@ -246,6 +259,7 @@ async function resolveViaIdentity(
|
|
|
246
259
|
syncGroups: mergedSyncGroups,
|
|
247
260
|
participantKind: identity.participantKind,
|
|
248
261
|
deliveryPartition: identity.deliveryPartition,
|
|
262
|
+
authority: identity.authority,
|
|
249
263
|
refreshScheduler: null,
|
|
250
264
|
};
|
|
251
265
|
}
|
|
@@ -322,7 +336,7 @@ async function resolveHosted(input: HostedInput): Promise<ResolvedIdentity> {
|
|
|
322
336
|
accountScope: exchange.scope.organizationId,
|
|
323
337
|
projectId: exchange.scope.projectId ?? exchange.scope.organizationId,
|
|
324
338
|
branchId: exchange.scope.branchId,
|
|
325
|
-
branchRoot: exchange.
|
|
339
|
+
branchRoot: exchange.branchRoot,
|
|
326
340
|
// teamIds isn't needed because the server already encoded
|
|
327
341
|
// team-level access into scope.syncGroups.
|
|
328
342
|
teamIds: undefined,
|
|
@@ -330,6 +344,7 @@ async function resolveHosted(input: HostedInput): Promise<ResolvedIdentity> {
|
|
|
330
344
|
syncGroups: exchange.scope.syncGroups,
|
|
331
345
|
participantKind: input.kind,
|
|
332
346
|
deliveryPartition: exchange.scope.deliveryPartition,
|
|
347
|
+
authority: exchange.scope,
|
|
333
348
|
refreshScheduler,
|
|
334
349
|
};
|
|
335
350
|
}
|
package/src/auth/index.ts
CHANGED
|
@@ -74,6 +74,7 @@ export {
|
|
|
74
74
|
capabilityOperationSchema,
|
|
75
75
|
capabilityCanSchema,
|
|
76
76
|
capabilityCanSchemaFor,
|
|
77
|
+
effectiveAuthoritySchema,
|
|
77
78
|
capabilityScopeSchema,
|
|
78
79
|
capabilityRequestSchema,
|
|
79
80
|
capabilityMintResponseSchema,
|
|
@@ -88,6 +89,7 @@ export type {
|
|
|
88
89
|
CapabilityOperation,
|
|
89
90
|
CapabilityCan,
|
|
90
91
|
CapabilityGrant,
|
|
92
|
+
EffectiveAuthority,
|
|
91
93
|
CapabilityScope,
|
|
92
94
|
CapabilityMintResponse,
|
|
93
95
|
CapabilityRequest,
|
package/src/auth/schemas.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { participantKindSchema } from '../coordination/schema.js';
|
|
3
3
|
import {
|
|
4
4
|
capabilityMintResponseSchema,
|
|
5
|
+
effectiveAuthoritySchema,
|
|
5
6
|
grantedOperationSchema,
|
|
6
7
|
type CapabilityMintResponse,
|
|
7
8
|
} from './capability.js';
|
|
@@ -26,6 +27,8 @@ export const IdentityResolveResponseSchema = z.object({
|
|
|
26
27
|
branchRoot: z.boolean().default(false),
|
|
27
28
|
syncGroups: z.array(z.string()),
|
|
28
29
|
deliveryPartition: deliveryPartitionRouteSchema.nullable().default(null),
|
|
30
|
+
/** Canonical server-confirmed authority of the authenticated credential. */
|
|
31
|
+
authority: effectiveAuthoritySchema,
|
|
29
32
|
userMeta: z.record(z.string(), z.unknown()),
|
|
30
33
|
});
|
|
31
34
|
|
package/src/auth/sessionMint.ts
CHANGED
|
@@ -93,7 +93,6 @@ export async function mintSession<S extends SchemaRecord>(
|
|
|
93
93
|
organizationId: res.organizationId,
|
|
94
94
|
projectId: res.projectId,
|
|
95
95
|
branchId: res.branchId,
|
|
96
|
-
branchRoot: res.branchRoot,
|
|
97
96
|
syncGroups: res.syncGroups,
|
|
98
97
|
operations: res.operations,
|
|
99
98
|
participantKind: 'user',
|
package/src/branches.ts
CHANGED
|
@@ -87,6 +87,28 @@ export const branchParentCompatibilitySchema = z.enum([
|
|
|
87
87
|
]);
|
|
88
88
|
export type BranchParentCompatibility = z.infer<typeof branchParentCompatibilitySchema>;
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* The one ownership/storage vocabulary for durable branch data.
|
|
92
|
+
* Missing configuration is explicit (`unbound`), never inferred as hosted.
|
|
93
|
+
*/
|
|
94
|
+
export const branchStorageSchema = z.discriminatedUnion('kind', [
|
|
95
|
+
z.object({ kind: z.literal('unbound') }).strict(),
|
|
96
|
+
z.object({
|
|
97
|
+
kind: z.literal('customer'),
|
|
98
|
+
transport: z.enum(['direct', 'endpoint']),
|
|
99
|
+
status: z.enum(['unverified', 'active', 'rejected']),
|
|
100
|
+
}).strict(),
|
|
101
|
+
z.object({
|
|
102
|
+
kind: z.literal('internal'),
|
|
103
|
+
implementation: z.enum(['log', 'tables']),
|
|
104
|
+
}).strict(),
|
|
105
|
+
z.object({
|
|
106
|
+
kind: z.literal('blocked'),
|
|
107
|
+
reason: z.literal('orphaned_external_marker'),
|
|
108
|
+
}).strict(),
|
|
109
|
+
]);
|
|
110
|
+
export type BranchStorage = z.infer<typeof branchStorageSchema>;
|
|
111
|
+
|
|
90
112
|
export const branchStatusSchemaSummarySchema = z
|
|
91
113
|
.object({
|
|
92
114
|
active: z.boolean(),
|
|
@@ -101,8 +123,8 @@ export const branchStatusSchemaSummarySchema = z
|
|
|
101
123
|
|
|
102
124
|
export const branchStatusDataSourceSchema = z
|
|
103
125
|
.object({
|
|
104
|
-
|
|
105
|
-
status: z.enum(['unverified', 'active', 'rejected'])
|
|
126
|
+
connection: z.enum(['direct', 'endpoint']),
|
|
127
|
+
status: z.enum(['unverified', 'active', 'rejected']),
|
|
106
128
|
host: z.string().nullable(),
|
|
107
129
|
database: z.string().nullable(),
|
|
108
130
|
cursor: z.string().nullable(),
|
|
@@ -111,7 +133,8 @@ export const branchStatusDataSourceSchema = z
|
|
|
111
133
|
last_success_at: z.string().nullable(),
|
|
112
134
|
last_error: z.string().nullable(),
|
|
113
135
|
})
|
|
114
|
-
.strict()
|
|
136
|
+
.strict()
|
|
137
|
+
.nullable();
|
|
115
138
|
|
|
116
139
|
export const branchStatusBlockerSchema = z
|
|
117
140
|
.object({
|
|
@@ -127,6 +150,7 @@ export const branchStatusResponseSchema = z
|
|
|
127
150
|
branch: branchResponseSchema,
|
|
128
151
|
ready: z.boolean(),
|
|
129
152
|
schema: branchStatusSchemaSummarySchema,
|
|
153
|
+
storage: branchStorageSchema,
|
|
130
154
|
data_source: branchStatusDataSourceSchema,
|
|
131
155
|
blockers: z.array(branchStatusBlockerSchema).readonly(),
|
|
132
156
|
})
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_TRACK_ON_STALE,
|
|
3
|
+
type CommitReadSetEntry,
|
|
4
|
+
type ReadDependency,
|
|
5
|
+
type ReadSetEntry,
|
|
6
|
+
type TrackDependency,
|
|
7
|
+
} from './coordination/schema.js';
|
|
8
|
+
import {
|
|
9
|
+
commitRecordIdentity,
|
|
10
|
+
publishCommitRecord,
|
|
11
|
+
type ReadSetContext,
|
|
12
|
+
} from './readSetContext.js';
|
|
13
|
+
import {
|
|
14
|
+
commitRecordSchema,
|
|
15
|
+
type CommitOperationBody,
|
|
16
|
+
type CommitReceiptWire,
|
|
17
|
+
} from './wire/commit.js';
|
|
18
|
+
|
|
19
|
+
interface HttpCommitObservation {
|
|
20
|
+
readonly receipt: CommitReceiptWire;
|
|
21
|
+
readonly method: string;
|
|
22
|
+
readonly path: string;
|
|
23
|
+
readonly body: unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface WebSocketCommitObservation {
|
|
27
|
+
readonly receipt: CommitReceiptWire;
|
|
28
|
+
readonly operations: readonly {
|
|
29
|
+
readonly type: string;
|
|
30
|
+
readonly model: string;
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly input?: Record<string, unknown>;
|
|
33
|
+
readonly claimId?: string | null;
|
|
34
|
+
readonly readAt?: number | null;
|
|
35
|
+
readonly onStale?: CommitOperationBody['onStale'] | null;
|
|
36
|
+
readonly fenceToken?: number | null;
|
|
37
|
+
}[];
|
|
38
|
+
readonly reads?: readonly ReadDependency[] | null;
|
|
39
|
+
readonly track?: readonly TrackDependency[] | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function commitEntry(dependency: ReadDependency): CommitReadSetEntry {
|
|
43
|
+
return {
|
|
44
|
+
target: 'group' in dependency
|
|
45
|
+
? { scope: 'group', group: dependency.group }
|
|
46
|
+
: {
|
|
47
|
+
scope: 'row',
|
|
48
|
+
model: dependency.model,
|
|
49
|
+
id: dependency.id,
|
|
50
|
+
...(dependency.fields ? { fields: dependency.fields } : {}),
|
|
51
|
+
},
|
|
52
|
+
watermark: dependency.readAt,
|
|
53
|
+
lifetime: 'commit',
|
|
54
|
+
onStale: dependency.onStale ?? 'reject',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function persistedEntry(
|
|
59
|
+
dependency: TrackDependency,
|
|
60
|
+
defaultWatermark: number,
|
|
61
|
+
): ReadSetEntry {
|
|
62
|
+
return {
|
|
63
|
+
target: 'group' in dependency
|
|
64
|
+
? { scope: 'group', group: dependency.group }
|
|
65
|
+
: { scope: 'row', model: dependency.model, id: dependency.id },
|
|
66
|
+
watermark: dependency.readAt ?? defaultWatermark,
|
|
67
|
+
lifetime: 'persisted',
|
|
68
|
+
onStale: dependency.onStale ?? DEFAULT_TRACK_ON_STALE,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function bodyRecord(value: unknown): Record<string, unknown> {
|
|
73
|
+
return typeof value === 'object' && value !== null
|
|
74
|
+
? value as Record<string, unknown>
|
|
75
|
+
: {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function retainedOperations(operations: readonly CommitOperationBody[]) {
|
|
79
|
+
return operations.map(({ data: _data, ...operation }) => ({
|
|
80
|
+
...operation,
|
|
81
|
+
data: { retention: 'redacted' as const },
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function commitEvidence(
|
|
86
|
+
receipt: CommitReceiptWire,
|
|
87
|
+
operations: readonly CommitOperationBody[],
|
|
88
|
+
transport: 'http' | 'websocket',
|
|
89
|
+
) {
|
|
90
|
+
return {
|
|
91
|
+
attempts: [{
|
|
92
|
+
id: receipt.clientTxId,
|
|
93
|
+
observedAt: receipt.createdAt,
|
|
94
|
+
transport,
|
|
95
|
+
kind: 'execution' as const,
|
|
96
|
+
}],
|
|
97
|
+
actor: {
|
|
98
|
+
kind: receipt.authority.participantKind,
|
|
99
|
+
id: receipt.authority.participantId,
|
|
100
|
+
},
|
|
101
|
+
// A receipt does not prove which live claim grant the server matched.
|
|
102
|
+
// Durable server records populate this from the claim gate instead.
|
|
103
|
+
claims: [],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function operationFromModelRequest(
|
|
108
|
+
observation: HttpCommitObservation,
|
|
109
|
+
body: Record<string, unknown>,
|
|
110
|
+
): CommitOperationBody[] {
|
|
111
|
+
const segments = observation.path.split('/').filter(Boolean);
|
|
112
|
+
const modelIndex = segments.indexOf('models');
|
|
113
|
+
if (modelIndex < 0) return [];
|
|
114
|
+
const model = decodeURIComponent(segments[modelIndex + 1] ?? '');
|
|
115
|
+
const pathId = segments[modelIndex + 2];
|
|
116
|
+
const action = observation.method === 'POST'
|
|
117
|
+
? 'create'
|
|
118
|
+
: observation.method === 'DELETE'
|
|
119
|
+
? 'delete'
|
|
120
|
+
: 'update';
|
|
121
|
+
return [{
|
|
122
|
+
action,
|
|
123
|
+
model,
|
|
124
|
+
...(pathId ? { id: decodeURIComponent(pathId) } : typeof body.id === 'string' ? { id: body.id } : {}),
|
|
125
|
+
...(body.data && typeof body.data === 'object'
|
|
126
|
+
? { data: body.data as Record<string, unknown> }
|
|
127
|
+
: {}),
|
|
128
|
+
...(typeof body.readAt === 'number' ? { readAt: body.readAt } : {}),
|
|
129
|
+
...(typeof body.onStale === 'string'
|
|
130
|
+
? { onStale: body.onStale as CommitOperationBody['onStale'] }
|
|
131
|
+
: {}),
|
|
132
|
+
...(typeof body.fenceToken === 'number' ? { fenceToken: body.fenceToken } : {}),
|
|
133
|
+
...(typeof body.claim === 'string' ? { claimId: body.claim } : {}),
|
|
134
|
+
}];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** @internal Joins exact HTTP request and receipt projections. */
|
|
138
|
+
export function recordHttpCommitReceipt(
|
|
139
|
+
context: ReadSetContext | undefined,
|
|
140
|
+
observation: HttpCommitObservation,
|
|
141
|
+
): void {
|
|
142
|
+
if (!context?.getStore()) return;
|
|
143
|
+
const body = bodyRecord(observation.body);
|
|
144
|
+
const operations = Array.isArray(body.operations)
|
|
145
|
+
? body.operations as CommitOperationBody[]
|
|
146
|
+
: operationFromModelRequest(observation, body);
|
|
147
|
+
const reads = Array.isArray(body.reads) ? body.reads as ReadDependency[] : [];
|
|
148
|
+
const track = Array.isArray(body.track) ? body.track as TrackDependency[] : [];
|
|
149
|
+
const readSet: ReadSetEntry[] = reads.map(commitEntry);
|
|
150
|
+
for (const operation of operations) {
|
|
151
|
+
if (typeof operation.readAt !== 'number' || !operation.id) continue;
|
|
152
|
+
readSet.push(commitEntry({
|
|
153
|
+
model: operation.model,
|
|
154
|
+
id: operation.id,
|
|
155
|
+
readAt: operation.readAt,
|
|
156
|
+
onStale: operation.onStale ?? 'reject',
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
readSet.push(...track.map((entry) => persistedEntry(entry, observation.receipt.lastSyncId)));
|
|
160
|
+
|
|
161
|
+
const record = commitRecordSchema.parse({
|
|
162
|
+
id: commitRecordIdentity(context, observation.receipt.clientTxId).id,
|
|
163
|
+
createdAt: observation.receipt.createdAt,
|
|
164
|
+
status: observation.receipt.status,
|
|
165
|
+
statusAt: observation.receipt.statusAt,
|
|
166
|
+
lastSyncId: observation.receipt.lastSyncId,
|
|
167
|
+
...(observation.receipt.correlationId
|
|
168
|
+
? { correlationId: observation.receipt.correlationId }
|
|
169
|
+
: {}),
|
|
170
|
+
readSet,
|
|
171
|
+
operations: retainedOperations(operations),
|
|
172
|
+
...commitEvidence(observation.receipt, operations, 'http'),
|
|
173
|
+
authority: observation.receipt.authority,
|
|
174
|
+
receipt: {
|
|
175
|
+
clientTxId: observation.receipt.clientTxId,
|
|
176
|
+
serverTxId: observation.receipt.serverTxId,
|
|
177
|
+
ops: observation.receipt.ops,
|
|
178
|
+
...(observation.receipt.notifications
|
|
179
|
+
? { notifications: observation.receipt.notifications }
|
|
180
|
+
: {}),
|
|
181
|
+
...(observation.receipt.missingIds
|
|
182
|
+
? { missingIds: observation.receipt.missingIds }
|
|
183
|
+
: {}),
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
publishCommitRecord(context, record);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** @internal Joins an exact commit frame and its authoritative WS receipt. */
|
|
190
|
+
export function recordWebSocketCommitReceipt(
|
|
191
|
+
context: ReadSetContext | undefined,
|
|
192
|
+
observation: WebSocketCommitObservation,
|
|
193
|
+
): void {
|
|
194
|
+
if (!context?.getStore()) return;
|
|
195
|
+
const operations: CommitOperationBody[] = observation.operations.map((operation) => ({
|
|
196
|
+
action: operation.type.toLowerCase() as CommitOperationBody['action'],
|
|
197
|
+
model: operation.model,
|
|
198
|
+
id: operation.id,
|
|
199
|
+
...(operation.input ? { data: operation.input } : {}),
|
|
200
|
+
...(operation.claimId ? { claimId: operation.claimId } : {}),
|
|
201
|
+
...(typeof operation.readAt === 'number' ? { readAt: operation.readAt } : {}),
|
|
202
|
+
...(operation.onStale ? { onStale: operation.onStale } : {}),
|
|
203
|
+
...(typeof operation.fenceToken === 'number'
|
|
204
|
+
? { fenceToken: operation.fenceToken }
|
|
205
|
+
: {}),
|
|
206
|
+
}));
|
|
207
|
+
const readSet: ReadSetEntry[] = (observation.reads ?? []).map(commitEntry);
|
|
208
|
+
for (const operation of operations) {
|
|
209
|
+
if (typeof operation.readAt !== 'number' || !operation.id) continue;
|
|
210
|
+
readSet.push(commitEntry({
|
|
211
|
+
model: operation.model,
|
|
212
|
+
id: operation.id,
|
|
213
|
+
readAt: operation.readAt,
|
|
214
|
+
onStale: operation.onStale ?? 'reject',
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
readSet.push(...(observation.track ?? []).map((entry) =>
|
|
218
|
+
persistedEntry(entry, observation.receipt.lastSyncId)));
|
|
219
|
+
const record = commitRecordSchema.parse({
|
|
220
|
+
id: commitRecordIdentity(context, observation.receipt.clientTxId).id,
|
|
221
|
+
createdAt: observation.receipt.createdAt,
|
|
222
|
+
status: observation.receipt.status,
|
|
223
|
+
statusAt: observation.receipt.statusAt,
|
|
224
|
+
lastSyncId: observation.receipt.lastSyncId,
|
|
225
|
+
...(observation.receipt.correlationId
|
|
226
|
+
? { correlationId: observation.receipt.correlationId }
|
|
227
|
+
: {}),
|
|
228
|
+
readSet,
|
|
229
|
+
operations: retainedOperations(operations),
|
|
230
|
+
...commitEvidence(observation.receipt, operations, 'websocket'),
|
|
231
|
+
authority: observation.receipt.authority,
|
|
232
|
+
receipt: {
|
|
233
|
+
clientTxId: observation.receipt.clientTxId,
|
|
234
|
+
serverTxId: observation.receipt.serverTxId,
|
|
235
|
+
ops: observation.receipt.ops,
|
|
236
|
+
...(observation.receipt.notifications
|
|
237
|
+
? { notifications: observation.receipt.notifications }
|
|
238
|
+
: {}),
|
|
239
|
+
...(observation.receipt.missingIds
|
|
240
|
+
? { missingIds: observation.receipt.missingIds }
|
|
241
|
+
: {}),
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
publishCommitRecord(context, record);
|
|
245
|
+
}
|
|
@@ -22,6 +22,17 @@ export {
|
|
|
22
22
|
targetRefSchema,
|
|
23
23
|
// Layer 3 — optimistic stale-context
|
|
24
24
|
onStaleModeSchema,
|
|
25
|
+
MAX_READ_SET_ENTRIES,
|
|
26
|
+
readSetWatermarkSchema,
|
|
27
|
+
readSetRowTargetSchema,
|
|
28
|
+
readSetGroupTargetSchema,
|
|
29
|
+
commitReadSetTargetSchema,
|
|
30
|
+
persistedReadSetRowTargetSchema,
|
|
31
|
+
persistedReadSetTargetSchema,
|
|
32
|
+
commitReadSetEntrySchema,
|
|
33
|
+
persistedReadSetEntrySchema,
|
|
34
|
+
readSetEntrySchema,
|
|
35
|
+
readSetSchema,
|
|
25
36
|
writeGuardSchema,
|
|
26
37
|
staleNotificationSchema,
|
|
27
38
|
rowStaleNotificationSchema,
|
|
@@ -29,7 +40,10 @@ export {
|
|
|
29
40
|
stalePropagationSchema,
|
|
30
41
|
|
|
31
42
|
readDependencySchema,
|
|
43
|
+
readDependencyListSchema,
|
|
44
|
+
readSetProjectionEntryCount,
|
|
32
45
|
trackDependencySchema,
|
|
46
|
+
trackDependencyListSchema,
|
|
33
47
|
// Layer 2 — pessimistic claim / claim-lease
|
|
34
48
|
claimStatusSchema,
|
|
35
49
|
wireClaimStatusSchema,
|
|
@@ -103,6 +117,15 @@ export type {
|
|
|
103
117
|
TargetRef,
|
|
104
118
|
// Layer 3 — optimistic stale-context
|
|
105
119
|
OnStaleMode,
|
|
120
|
+
ReadSetWatermark,
|
|
121
|
+
ReadSetRowTarget,
|
|
122
|
+
ReadSetGroupTarget,
|
|
123
|
+
CommitReadSetTarget,
|
|
124
|
+
PersistedReadSetTarget,
|
|
125
|
+
CommitReadSetEntry,
|
|
126
|
+
PersistedReadSetEntry,
|
|
127
|
+
ReadSetEntry,
|
|
128
|
+
ReadSet,
|
|
106
129
|
WriteGuard,
|
|
107
130
|
StaleNotification,
|
|
108
131
|
RowStaleNotification,
|
|
@@ -179,6 +202,7 @@ export type {
|
|
|
179
202
|
} from './locator.js';
|
|
180
203
|
export {
|
|
181
204
|
batchFence,
|
|
205
|
+
claimIdFor,
|
|
182
206
|
fenceTokenFor,
|
|
183
207
|
isTargetTuple,
|
|
184
208
|
subTarget,
|
|
@@ -186,4 +210,3 @@ export {
|
|
|
186
210
|
modelTarget,
|
|
187
211
|
streamTarget,
|
|
188
212
|
} from './locator.js';
|
|
189
|
-
|
|
@@ -198,3 +198,20 @@ export function fenceTokenFor(
|
|
|
198
198
|
? fence.token
|
|
199
199
|
: null;
|
|
200
200
|
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The claim identity an operation carries when it writes the row named by a
|
|
204
|
+
* held claim. Like the fence token, a claim id cannot travel to another row.
|
|
205
|
+
*/
|
|
206
|
+
export function claimIdFor(
|
|
207
|
+
source: EntityLocator | null | undefined,
|
|
208
|
+
claimId: string | null | undefined,
|
|
209
|
+
model: string,
|
|
210
|
+
id: string | null,
|
|
211
|
+
): string | null {
|
|
212
|
+
if (source == null || claimId == null || id === null) return null;
|
|
213
|
+
const target = modelTarget(source);
|
|
214
|
+
return model.toLowerCase() === target.model.toLowerCase() && id === target.id
|
|
215
|
+
? claimId
|
|
216
|
+
: null;
|
|
217
|
+
}
|