@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
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
import { createHttpTransport, } from './httpTransport.js';
|
|
21
21
|
import { modelWireNames } from '../auth/capability.js';
|
|
22
22
|
import { omittedModelError } from '../schema/select.js';
|
|
23
|
+
import { reconcileFunctionalUpdate, } from '../resources/functionalUpdate.js';
|
|
23
24
|
import { AbloConnectionError, AbloValidationError } from '../errors.js';
|
|
25
|
+
import { abortReadSetCommit, capturePointRead, createReadSetContext, consumeReadSet, prepareReadSet, } from '../readSetContext.js';
|
|
26
|
+
import { recordHttpCommitReceipt } from '../commitRecordRuntime.js';
|
|
24
27
|
/**
|
|
25
28
|
* Private transport members that pass straight through the facade. Everything
|
|
26
29
|
* else must be a declared schema model; there is no dynamic fallback namespace.
|
|
@@ -32,6 +35,7 @@ const PROTOCOL_MEMBERS = new Set([
|
|
|
32
35
|
'commits',
|
|
33
36
|
'claims',
|
|
34
37
|
'logs',
|
|
38
|
+
'identity',
|
|
35
39
|
'getAuthToken',
|
|
36
40
|
'sessions',
|
|
37
41
|
]);
|
|
@@ -45,9 +49,10 @@ function isProtocolMember(prop) {
|
|
|
45
49
|
* receipts because functional updates need them. This is the single boundary
|
|
46
50
|
* that unwraps those transport details for application code.
|
|
47
51
|
*/
|
|
48
|
-
function createHttpModelClient(protocol) {
|
|
52
|
+
function createHttpModelClient(protocol, modelName, clientIdentity, readSetContext) {
|
|
49
53
|
async function readRow(id) {
|
|
50
54
|
const read = await protocol.get({ id });
|
|
55
|
+
capturePointRead(readSetContext, clientIdentity, modelName, id, read.data, read.stamp);
|
|
51
56
|
return read.data;
|
|
52
57
|
}
|
|
53
58
|
async function requireUpdatedRow(id) {
|
|
@@ -68,40 +73,148 @@ function createHttpModelClient(protocol) {
|
|
|
68
73
|
...(claim !== undefined ? { claim } : {}),
|
|
69
74
|
};
|
|
70
75
|
}
|
|
76
|
+
function preparedMutation(params) {
|
|
77
|
+
const prepared = prepareReadSet(readSetContext, clientIdentity, params.readAt, params.onStale, params.idempotencyKey, params.reads);
|
|
78
|
+
return {
|
|
79
|
+
options: {
|
|
80
|
+
...mutationOptions(params),
|
|
81
|
+
...(prepared.readAt !== undefined ? { readAt: prepared.readAt } : {}),
|
|
82
|
+
...(prepared.onStale !== undefined ? { onStale: prepared.onStale } : {}),
|
|
83
|
+
...(prepared.reads !== undefined ? { reads: prepared.reads } : {}),
|
|
84
|
+
...(prepared.idempotencyKey !== undefined
|
|
85
|
+
? { idempotencyKey: prepared.idempotencyKey }
|
|
86
|
+
: {}),
|
|
87
|
+
},
|
|
88
|
+
consumed: prepared.consumed,
|
|
89
|
+
automaticCommit: prepared.automaticCommit,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
71
92
|
async function update(arg, updater, options) {
|
|
72
93
|
if (typeof arg === 'string') {
|
|
73
94
|
if (!updater) {
|
|
74
95
|
throw new AbloValidationError('Functional update requires an updater function.', { code: 'write_options_invalid' });
|
|
75
96
|
}
|
|
76
|
-
const receipt = await
|
|
97
|
+
const receipt = await reconcileFunctionalUpdate(updater, options, {
|
|
98
|
+
model: modelName,
|
|
99
|
+
id: arg,
|
|
100
|
+
readFresh: async () => {
|
|
101
|
+
const read = await protocol.get({ id: arg });
|
|
102
|
+
capturePointRead(readSetContext, clientIdentity, modelName, arg, read.data, read.stamp);
|
|
103
|
+
return { data: read.data, stamp: read.stamp };
|
|
104
|
+
},
|
|
105
|
+
writeNext: async (patch, readAt) => {
|
|
106
|
+
const prepared = preparedMutation({
|
|
107
|
+
readAt,
|
|
108
|
+
onStale: 'reject',
|
|
109
|
+
reads: options?.reads,
|
|
110
|
+
});
|
|
111
|
+
try {
|
|
112
|
+
const result = await protocol.update({
|
|
113
|
+
...prepared.options,
|
|
114
|
+
id: arg,
|
|
115
|
+
data: patch,
|
|
116
|
+
});
|
|
117
|
+
consumeReadSet(readSetContext, clientIdentity, prepared.consumed, prepared.automaticCommit);
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
abortReadSetCommit(readSetContext, prepared.automaticCommit);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
});
|
|
77
126
|
return receipt === undefined ? undefined : requireUpdatedRow(arg);
|
|
78
127
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
128
|
+
const prepared = preparedMutation(arg);
|
|
129
|
+
try {
|
|
130
|
+
await protocol.update({
|
|
131
|
+
...prepared.options,
|
|
132
|
+
id: arg.id,
|
|
133
|
+
data: arg.data,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
abortReadSetCommit(readSetContext, prepared.automaticCommit);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
consumeReadSet(readSetContext, clientIdentity, prepared.consumed, prepared.automaticCommit);
|
|
83
141
|
return requireUpdatedRow(arg.id);
|
|
84
142
|
}
|
|
85
143
|
const get = async (params) => {
|
|
86
144
|
const read = await protocol.get(params);
|
|
145
|
+
capturePointRead(readSetContext, clientIdentity, modelName, params.id, read.data, read.stamp);
|
|
87
146
|
return read.data;
|
|
88
147
|
};
|
|
148
|
+
const list = async (options) => {
|
|
149
|
+
const snapshot = await protocol.list(options);
|
|
150
|
+
const registry = readSetContext?.getStore();
|
|
151
|
+
if (!registry)
|
|
152
|
+
return [...snapshot.data];
|
|
153
|
+
if (!snapshot.evidence) {
|
|
154
|
+
throw new AbloConnectionError(`${modelName}.list did not return row evidence. Upgrade the Ablo server or use get({ id }).`, { code: 'commit_no_result' });
|
|
155
|
+
}
|
|
156
|
+
const byId = new Map(snapshot.evidence.map((entry) => [entry.id, entry.stamp]));
|
|
157
|
+
for (const row of snapshot.data) {
|
|
158
|
+
const id = typeof row === 'object' && row !== null
|
|
159
|
+
? Reflect.get(row, 'id')
|
|
160
|
+
: undefined;
|
|
161
|
+
const stamp = typeof id === 'string' ? byId.get(id) : undefined;
|
|
162
|
+
if (typeof id !== 'string' || stamp === undefined) {
|
|
163
|
+
throw new AbloConnectionError(`${modelName}.list returned a row without matching evidence.`, { code: 'commit_no_result' });
|
|
164
|
+
}
|
|
165
|
+
capturePointRead(readSetContext, clientIdentity, modelName, id, row, stamp);
|
|
166
|
+
}
|
|
167
|
+
return [...snapshot.data];
|
|
168
|
+
};
|
|
169
|
+
// Claim acquisition performs its authoritative read only after the grant.
|
|
170
|
+
// Preserve that exact post-grant watermark while retaining the callable
|
|
171
|
+
// namespace and all of its state/queue/release members through the proxy.
|
|
172
|
+
const claim = new Proxy(protocol.claim, {
|
|
173
|
+
apply(target, thisArg, argArray) {
|
|
174
|
+
const result = Reflect.apply(target, thisArg, argArray);
|
|
175
|
+
return result.then((held) => {
|
|
176
|
+
if (held && held.readAt !== undefined) {
|
|
177
|
+
capturePointRead(readSetContext, clientIdentity, modelName, held.target.id, held.data, held.readAt);
|
|
178
|
+
}
|
|
179
|
+
return held;
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
});
|
|
89
183
|
return {
|
|
90
184
|
get,
|
|
91
185
|
retrieve: get,
|
|
92
|
-
list
|
|
186
|
+
list,
|
|
93
187
|
async create(params) {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
188
|
+
const id = params.id ?? '';
|
|
189
|
+
const prepared = preparedMutation(params);
|
|
190
|
+
let row;
|
|
191
|
+
try {
|
|
192
|
+
row = await protocol.create({
|
|
193
|
+
...prepared.options,
|
|
194
|
+
...(params.id !== undefined ? { id: params.id } : {}),
|
|
195
|
+
data: params.data,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
abortReadSetCommit(readSetContext, prepared.automaticCommit);
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
consumeReadSet(readSetContext, clientIdentity, prepared.consumed, prepared.automaticCommit);
|
|
98
203
|
return row;
|
|
99
204
|
},
|
|
100
205
|
update,
|
|
101
206
|
async delete(params) {
|
|
102
|
-
|
|
207
|
+
const prepared = preparedMutation(params);
|
|
208
|
+
try {
|
|
209
|
+
await protocol.delete({ ...prepared.options, id: params.id });
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
abortReadSetCommit(readSetContext, prepared.automaticCommit);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
consumeReadSet(readSetContext, clientIdentity, prepared.consumed, prepared.automaticCommit);
|
|
103
216
|
},
|
|
104
|
-
claim
|
|
217
|
+
claim,
|
|
105
218
|
track: (params) => protocol.track(params),
|
|
106
219
|
};
|
|
107
220
|
}
|
|
@@ -113,21 +226,27 @@ function createHttpModelClient(protocol) {
|
|
|
113
226
|
*/
|
|
114
227
|
/** @internal Constructed only through the public `Ablo({ transport: 'http' })` factory. */
|
|
115
228
|
export function createAbloHttpClient(options) {
|
|
116
|
-
const { schema, ...rest } = options;
|
|
229
|
+
const { schema, onCommitReceipt, ...rest } = options;
|
|
230
|
+
const readSetContext = createReadSetContext();
|
|
117
231
|
const transport = createHttpTransport({
|
|
118
232
|
...rest,
|
|
119
233
|
// Derived from the schema this client is bound to, never assembled by hand
|
|
120
234
|
// — see `auth/capability.ts`.
|
|
121
235
|
modelTypenames: modelWireNames(schema.models),
|
|
236
|
+
onCommitReceipt: (observation) => {
|
|
237
|
+
recordHttpCommitReceipt(readSetContext, observation);
|
|
238
|
+
onCommitReceipt?.(observation);
|
|
239
|
+
},
|
|
122
240
|
});
|
|
123
241
|
const schemaModels = new Set(Object.keys(schema.models));
|
|
242
|
+
const clientIdentity = {};
|
|
124
243
|
const omittedModels = new Set(schema.omittedModels ?? []);
|
|
125
244
|
const models = new Map();
|
|
126
245
|
const model = (name) => {
|
|
127
246
|
const cached = models.get(name);
|
|
128
247
|
if (cached)
|
|
129
248
|
return cached;
|
|
130
|
-
const created = createHttpModelClient(transport.model(name));
|
|
249
|
+
const created = createHttpModelClient(transport.model(name), name, clientIdentity, readSetContext);
|
|
131
250
|
models.set(name, created);
|
|
132
251
|
return created;
|
|
133
252
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpClient.js","sourceRoot":"","sources":["../../src/transport/httpClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,mBAAmB,GAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"httpClient.js","sourceRoot":"","sources":["../../src/transport/httpClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
import type { Schema, SchemaRecord } from '../schema/schema.js';
|
|
13
13
|
import type { AuthClientOptions } from '../auth/apiKey.js';
|
|
14
14
|
import type { CoordinationObservability } from '../observability.js';
|
|
15
|
-
import type { CommitOutboxScope } from '../transactions/
|
|
15
|
+
import type { CommitOutboxScope } from '../transactions/confirmation/commitEnvelope.js';
|
|
16
|
+
import type { CommitReceiptWire } from '../wire/commit.js';
|
|
16
17
|
import type { DurableWriteStore, DurableWritesConfig } from '../durableWrites.js';
|
|
17
18
|
export interface HttpClientConfig<S extends SchemaRecord = SchemaRecord> extends AuthClientOptions {
|
|
18
19
|
schema: Schema<S>;
|
|
@@ -30,5 +31,12 @@ export interface HttpClientConfig<S extends SchemaRecord = SchemaRecord> extends
|
|
|
30
31
|
commitOutboxScope?: CommitOutboxScope;
|
|
31
32
|
/** Which transport carries this client's traffic. */
|
|
32
33
|
transport?: 'websocket' | 'http' | undefined;
|
|
34
|
+
/** @internal Exact receipt phases observed while dispatching one HTTP commit. */
|
|
35
|
+
onCommitReceipt?: (observation: {
|
|
36
|
+
readonly receipt: CommitReceiptWire;
|
|
37
|
+
readonly method: string;
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly body: unknown;
|
|
40
|
+
}) => void;
|
|
33
41
|
}
|
|
34
42
|
//# sourceMappingURL=httpOptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpOptions.d.ts","sourceRoot":"","sources":["../../src/transport/httpOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"httpOptions.d.ts","sourceRoot":"","sources":["../../src/transport/httpOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AACxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,CAGrE,SAAQ,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IAC9D,aAAa,CAAC,EAAE,yBAAyB,CAAC;IAC1C,iFAAiF;IACjF,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,qDAAqD;IACrD,SAAS,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;IAC7C,iFAAiF;IACjF,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE;QAC9B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;QACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;KACxB,KAAK,IAAI,CAAC;CACZ"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { HttpClientConfig } from './httpOptions.js';
|
|
9
9
|
import type { CommitResource, HttpClaimsResource, HttpTransportModel, HttpLogsResource, SessionResource } from '../resources/httpResources.js';
|
|
10
|
+
import type { EffectiveAuthority } from '../auth/capability.js';
|
|
10
11
|
import type { SchemaRecord } from '../schema/schema.js';
|
|
11
12
|
import type { CoordinationObservability } from '../observability.js';
|
|
12
13
|
/** @internal Private options for the schema-agnostic HTTP protocol transport. */
|
|
@@ -47,6 +48,8 @@ export interface HttpTransport {
|
|
|
47
48
|
*/
|
|
48
49
|
readonly claims: HttpClaimsResource;
|
|
49
50
|
readonly logs: HttpLogsResource;
|
|
51
|
+
/** Server-confirmed authority of the active bearer, populated by `ready()`. */
|
|
52
|
+
readonly identity: EffectiveAuthority | null;
|
|
50
53
|
model<T = Record<string, unknown>, Fields = T>(name: string): HttpTransportModel<T, Fields>;
|
|
51
54
|
/**
|
|
52
55
|
* Resolve the active bearer credential this client authenticates with — the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"httpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/httpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"httpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/httpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAKV,cAAc,EAGd,kBAAkB,EAClB,kBAAkB,EAKlB,gBAAgB,EAIhB,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAOvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAqBhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAgCxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAcrE,iFAAiF;AACjF,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAAG;IACpE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,iFAAiF;IACjF,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACvE;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,yBAAyB,CAAC;IACnD;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAYjD,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,EAC3C,IAAI,EAAE,MAAM,GACX,kBAAkB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACjC;;;;;;OAMG;IACH,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;CAClD;AA4CD,2DAA2D;AAC3D,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAizDhF"}
|
|
@@ -10,7 +10,7 @@ import { v5 as uuidv5 } from 'uuid';
|
|
|
10
10
|
import { reconcileFunctionalUpdate, } from '../resources/functionalUpdate.js';
|
|
11
11
|
import { assertBrowserSafety, readProcessEnv, resolveApiKey, resolveApiKeyValue, resolveAuthToken, resolveBaseURL, resolveBootstrapBaseUrl, rejectRemovedDatabaseUrlOption, warnIfCliKeyMismatch, } from '../auth/apiKey.js';
|
|
12
12
|
import { PROTOCOL_VERSION, PROTOCOL_VERSION_HEADER } from '../wire/protocolVersion.js';
|
|
13
|
-
import { commitReceiptSchema } from '../wire/commit.js';
|
|
13
|
+
import { commitReceiptSchema, commitRecordSchema, commitRecordListSchema, commitRecordListOptionsSchema, commitRecordWhereSchema, } from '../wire/commit.js';
|
|
14
14
|
import { logListResponseSchema } from '../wire/feedEvent.js';
|
|
15
15
|
import { claimAcquireResponseSchema, claimHeartbeatBatchReplySchema, claimHeartbeatReplySchema, claimListResponseSchema, claimStateSchema, } from '../wire/claims.js';
|
|
16
16
|
import { modelListResponseSchema, modelReadResponseSchema, } from '../wire/modelResponses.js';
|
|
@@ -37,10 +37,10 @@ function heldHeartbeatReply(reply, label) {
|
|
|
37
37
|
}
|
|
38
38
|
import { claimAttemptFailure, claimQueueView, emitClaimStatus, resolveClaimContentionOptions, } from '../resources/modelOperations.js';
|
|
39
39
|
import { claimDescription } from '../coordination/schema.js';
|
|
40
|
-
import { subTarget, streamTarget, batchFence, fenceTokenFor, } from '../coordination/locator.js';
|
|
40
|
+
import { subTarget, streamTarget, batchFence, claimIdFor, fenceTokenFor, } from '../coordination/locator.js';
|
|
41
41
|
import { declaredMeta, wireMeta } from '../coordination/claimMeta.js';
|
|
42
42
|
import { assertWriteOptions } from '../resources/writeOptionsSchema.js';
|
|
43
|
-
import { createDurableHttpCommitEnvelope, canonicalHttpCommitBody, durableHttpCommitEnvelopeSchema, httpCommitEnvelopeRecordId, isHttpCommitReplayExpired, } from '../transactions/
|
|
43
|
+
import { createDurableHttpCommitEnvelope, canonicalHttpCommitBody, durableHttpCommitEnvelopeSchema, httpCommitEnvelopeRecordId, isHttpCommitReplayExpired, } from '../transactions/confirmation/httpCommitEnvelope.js';
|
|
44
44
|
import { resolveDurableWrites } from '../durableWrites.js';
|
|
45
45
|
/** @internal Default per-request deadline for the private HTTP transport. */
|
|
46
46
|
export const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
@@ -155,6 +155,7 @@ export function createHttpTransport(options) {
|
|
|
155
155
|
});
|
|
156
156
|
let httpOutboxScopeNamespace = null;
|
|
157
157
|
let readyPromise = null;
|
|
158
|
+
let effectiveAuthority = null;
|
|
158
159
|
let httpCommitLane = Promise.resolve();
|
|
159
160
|
function runInHttpCommitLane(work) {
|
|
160
161
|
const result = httpCommitLane.then(work);
|
|
@@ -187,7 +188,7 @@ export function createHttpTransport(options) {
|
|
|
187
188
|
});
|
|
188
189
|
return httpOutboxScopeNamespace;
|
|
189
190
|
}
|
|
190
|
-
async function
|
|
191
|
+
async function prepare() {
|
|
191
192
|
if (readyPromise)
|
|
192
193
|
return readyPromise;
|
|
193
194
|
readyPromise = (async () => {
|
|
@@ -202,6 +203,13 @@ export function createHttpTransport(options) {
|
|
|
202
203
|
throw error;
|
|
203
204
|
}
|
|
204
205
|
}
|
|
206
|
+
async function ready() {
|
|
207
|
+
await prepare();
|
|
208
|
+
if (!effectiveAuthority) {
|
|
209
|
+
const rawIdentity = await requestRaw('/auth/identity', { method: 'GET' }, true);
|
|
210
|
+
effectiveAuthority = parseIdentityResolveResponse(rawIdentity).authority;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
205
213
|
async function authHeaders(sealedProtocolVersion) {
|
|
206
214
|
const apiKey = await resolveApiKeyValue(configuredApiKey);
|
|
207
215
|
const token = apiKey ?? configuredAuthToken;
|
|
@@ -250,7 +258,7 @@ export function createHttpTransport(options) {
|
|
|
250
258
|
*/
|
|
251
259
|
async function requestRaw(path, init, skipReady = false) {
|
|
252
260
|
if (!skipReady)
|
|
253
|
-
await
|
|
261
|
+
await prepare();
|
|
254
262
|
const { idempotencyKey, sealedProtocolVersion, ...requestInit } = init;
|
|
255
263
|
const headers = await authHeaders(sealedProtocolVersion);
|
|
256
264
|
if (idempotencyKey)
|
|
@@ -356,7 +364,7 @@ export function createHttpTransport(options) {
|
|
|
356
364
|
await commitOutbox.remove(recordId);
|
|
357
365
|
}
|
|
358
366
|
catch (cause) {
|
|
359
|
-
// Do not report the remote outcome until local
|
|
367
|
+
// Do not report the remote outcome until local confirmation is durable.
|
|
360
368
|
// The retained record can still be replayed inside the safe window.
|
|
361
369
|
throw new AbloConnectionError('The server settled the commit, but its local outbox record could not be cleared.', { code: 'db_not_opened', cause });
|
|
362
370
|
}
|
|
@@ -392,6 +400,32 @@ export function createHttpTransport(options) {
|
|
|
392
400
|
}
|
|
393
401
|
return accepted;
|
|
394
402
|
}
|
|
403
|
+
function observeCommitReceipt(request, receipt) {
|
|
404
|
+
// A successful receipt carries the same server-authored authority as the
|
|
405
|
+
// identity exchange. Reuse it so startup replay does not add a redundant
|
|
406
|
+
// auth request before callers can inspect `identity`.
|
|
407
|
+
effectiveAuthority = receipt.authority;
|
|
408
|
+
if (!options.onCommitReceipt)
|
|
409
|
+
return;
|
|
410
|
+
let body = request.body;
|
|
411
|
+
try {
|
|
412
|
+
body = JSON.parse(request.body);
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
// Preserve the exact opaque body for observability if it is not JSON.
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
options.onCommitReceipt({
|
|
419
|
+
receipt,
|
|
420
|
+
method: request.method,
|
|
421
|
+
path: request.path,
|
|
422
|
+
body,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
// Receipt observation must never change the commit outcome.
|
|
427
|
+
}
|
|
428
|
+
}
|
|
395
429
|
function replicationLagTimeout(request, response) {
|
|
396
430
|
return new AbloConnectionError(`The source accepted commit ${request.idempotencyKey}, but its replication echo did not arrive within ${requestTimeoutMs}ms.`, {
|
|
397
431
|
code: 'replication_lag_timeout',
|
|
@@ -436,6 +470,7 @@ export function createHttpTransport(options) {
|
|
|
436
470
|
signal: confirmationController.signal,
|
|
437
471
|
}, true);
|
|
438
472
|
const next = parseSuccessfulCommitResponse(raw, request.idempotencyKey);
|
|
473
|
+
observeCommitReceipt(request, next);
|
|
439
474
|
if (next.correlationId !== correlationId) {
|
|
440
475
|
throw new AbloIdempotencyError('The same HTTP commit replay returned different source correlation evidence.', { code: 'idempotency_conflict' });
|
|
441
476
|
}
|
|
@@ -501,6 +536,13 @@ export function createHttpTransport(options) {
|
|
|
501
536
|
body: envelope.request.body,
|
|
502
537
|
}, true);
|
|
503
538
|
const response = parseSuccessfulCommitResponse(raw, envelope.idempotencyKey);
|
|
539
|
+
observeCommitReceipt({
|
|
540
|
+
idempotencyKey: envelope.idempotencyKey,
|
|
541
|
+
method: envelope.request.method,
|
|
542
|
+
path: envelope.request.path,
|
|
543
|
+
body: envelope.request.body,
|
|
544
|
+
sealedProtocolVersion: envelope.protocolVersion,
|
|
545
|
+
}, response);
|
|
504
546
|
if (envelope.correlationId !== undefined &&
|
|
505
547
|
response.correlationId !== envelope.correlationId) {
|
|
506
548
|
throw new AbloIdempotencyError('The saved HTTP commit replay returned different source correlation evidence.', { code: 'idempotency_conflict' });
|
|
@@ -602,10 +644,10 @@ export function createHttpTransport(options) {
|
|
|
602
644
|
await commitOutbox.seal(envelope, []);
|
|
603
645
|
return envelope;
|
|
604
646
|
}
|
|
605
|
-
async function dispatchHttpCommit(input,
|
|
647
|
+
async function dispatchHttpCommit(input, beforeConfirmation) {
|
|
606
648
|
return runInHttpCommitLane(async () => {
|
|
607
|
-
await
|
|
608
|
-
//
|
|
649
|
+
await prepare();
|
|
650
|
+
// Startup preparation covers replay. Re-draining here makes every later write wait
|
|
609
651
|
// behind an ambiguous predecessor from this same process.
|
|
610
652
|
const replayed = await replayHttpCommitOutbox();
|
|
611
653
|
const prior = replayed.get(input.idempotencyKey);
|
|
@@ -635,7 +677,7 @@ export function createHttpTransport(options) {
|
|
|
635
677
|
}
|
|
636
678
|
}
|
|
637
679
|
if (priorResponse.status === 'confirmed') {
|
|
638
|
-
await
|
|
680
|
+
await beforeConfirmation?.(priorResponse);
|
|
639
681
|
await settleHttpEnvelope(prior.envelope.id);
|
|
640
682
|
}
|
|
641
683
|
return priorResponse;
|
|
@@ -660,6 +702,7 @@ export function createHttpTransport(options) {
|
|
|
660
702
|
body: exactRequest.body,
|
|
661
703
|
}, true);
|
|
662
704
|
response = parseSuccessfulCommitResponse(raw, input.idempotencyKey);
|
|
705
|
+
observeCommitReceipt(exactRequest, response);
|
|
663
706
|
if (durableEnvelope && response.status === 'queued') {
|
|
664
707
|
await persistHttpAcceptance(durableEnvelope, response);
|
|
665
708
|
}
|
|
@@ -673,12 +716,12 @@ export function createHttpTransport(options) {
|
|
|
673
716
|
}
|
|
674
717
|
throw error;
|
|
675
718
|
}
|
|
676
|
-
// A model-create readback can participate in
|
|
719
|
+
// A model-create readback can participate in confirmation: if it fails,
|
|
677
720
|
// retain the exact write so a same-key retry recovers the generated id.
|
|
678
721
|
// A queued source receipt cannot be read back from the log yet and stays
|
|
679
722
|
// durable until a later confirmed replay.
|
|
680
723
|
if (response.status === 'confirmed') {
|
|
681
|
-
await
|
|
724
|
+
await beforeConfirmation?.(response);
|
|
682
725
|
if (durableEnvelope)
|
|
683
726
|
await settleHttpEnvelope(durableEnvelope.id);
|
|
684
727
|
}
|
|
@@ -700,13 +743,14 @@ export function createHttpTransport(options) {
|
|
|
700
743
|
? crypto.randomUUID()
|
|
701
744
|
: `id_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
702
745
|
}
|
|
703
|
-
function normalizeCommitOperation(op, defaults, fence) {
|
|
746
|
+
function normalizeCommitOperation(op, defaults, fence, claim) {
|
|
704
747
|
return {
|
|
705
748
|
action: op.action,
|
|
706
749
|
model: op.model,
|
|
707
750
|
id: op.id ?? null,
|
|
708
751
|
data: op.data ?? null,
|
|
709
752
|
transactionId: op.transactionId ?? null,
|
|
753
|
+
claimId: op.claimId ?? claimIdFor(claim?.target, claim?.id, op.model, op.id ?? null),
|
|
710
754
|
readAt: op.readAt ?? defaults.readAt ?? null,
|
|
711
755
|
onStale: op.onStale ?? defaults.onStale ?? null,
|
|
712
756
|
fenceToken: op.fenceToken ?? fenceTokenFor(fence, op.model, op.id ?? null),
|
|
@@ -718,7 +762,7 @@ export function createHttpTransport(options) {
|
|
|
718
762
|
code: 'commit_operation_required',
|
|
719
763
|
});
|
|
720
764
|
}
|
|
721
|
-
return commitOptions.operations.map((op) => normalizeCommitOperation(op, commitOptions, fence));
|
|
765
|
+
return commitOptions.operations.map((op) => normalizeCommitOperation(op, commitOptions, fence, commitOptions.claim ?? null));
|
|
722
766
|
}
|
|
723
767
|
async function listClaimState(target) {
|
|
724
768
|
const params = new URLSearchParams();
|
|
@@ -860,6 +904,8 @@ export function createHttpTransport(options) {
|
|
|
860
904
|
onStale: commitOptions.onStale,
|
|
861
905
|
wait: commitOptions.wait,
|
|
862
906
|
claim: commitOptions.claim,
|
|
907
|
+
reads: commitOptions.reads,
|
|
908
|
+
track: commitOptions.track,
|
|
863
909
|
}, 'commits.create');
|
|
864
910
|
const clientTxId = createClientTxId(commitOptions.idempotencyKey);
|
|
865
911
|
// Same claim vocabulary as the WS client's `commits.create`: a handle
|
|
@@ -899,7 +945,7 @@ export function createHttpTransport(options) {
|
|
|
899
945
|
// `requestJson` throws via `translateHttpError` on any non-2xx, so
|
|
900
946
|
// reaching here implies success and `body` is already the success-only
|
|
901
947
|
// receipt union — a rejection is a separate type that never arrives here.
|
|
902
|
-
// The
|
|
948
|
+
// The confirmation status therefore passes through verbatim: no branch may
|
|
903
949
|
// collapse a state the server reported into a different one.
|
|
904
950
|
return {
|
|
905
951
|
id: body.id ?? body.clientTxId,
|
|
@@ -911,6 +957,30 @@ export function createHttpTransport(options) {
|
|
|
911
957
|
...(body.missingIds && body.missingIds.length > 0 ? { missingIds: body.missingIds } : {}),
|
|
912
958
|
};
|
|
913
959
|
},
|
|
960
|
+
get({ id }) {
|
|
961
|
+
if (!id) {
|
|
962
|
+
throw new AbloValidationError('commits.get requires a non-empty id.', {
|
|
963
|
+
code: 'write_options_invalid',
|
|
964
|
+
param: 'id',
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
return requestJson(`/v1/commits/${encodeURIComponent(id)}`, { method: 'GET' }, commitRecordSchema.nullable());
|
|
968
|
+
},
|
|
969
|
+
list(options = {}) {
|
|
970
|
+
const parsed = commitRecordListOptionsSchema.parse(options);
|
|
971
|
+
const where = commitRecordWhereSchema.parse(parsed.where ?? {});
|
|
972
|
+
const params = new URLSearchParams();
|
|
973
|
+
if (where.actorId)
|
|
974
|
+
params.set('actorId', where.actorId);
|
|
975
|
+
if (where.status)
|
|
976
|
+
params.set('status', where.status);
|
|
977
|
+
if (parsed.cursor)
|
|
978
|
+
params.set('cursor', parsed.cursor);
|
|
979
|
+
if (parsed.limit !== undefined)
|
|
980
|
+
params.set('limit', String(parsed.limit));
|
|
981
|
+
const query = params.size > 0 ? `?${params.toString()}` : '';
|
|
982
|
+
return requestJson(`/v1/commits${query}`, { method: 'GET' }, commitRecordListSchema);
|
|
983
|
+
},
|
|
914
984
|
};
|
|
915
985
|
const logs = {
|
|
916
986
|
list(logOptions = {}) {
|
|
@@ -959,7 +1029,10 @@ export function createHttpTransport(options) {
|
|
|
959
1029
|
// transport is schema-agnostic — it moves rows for whatever schema the
|
|
960
1030
|
// caller declared, and `T` is that declaration. Row validation belongs to
|
|
961
1031
|
// the typed facade above, which holds the model's schema.
|
|
962
|
-
return
|
|
1032
|
+
return {
|
|
1033
|
+
data: res.data,
|
|
1034
|
+
...(res.evidence ? { evidence: res.evidence } : {}),
|
|
1035
|
+
};
|
|
963
1036
|
}
|
|
964
1037
|
async function retrieveModel(modelName, params) {
|
|
965
1038
|
await applyClaimedPolicy({ model: modelName, id: params.id }, params);
|
|
@@ -987,12 +1060,16 @@ export function createHttpTransport(options) {
|
|
|
987
1060
|
* multi-operation envelopes; this helper handles the one-operation,
|
|
988
1061
|
* one-record case.
|
|
989
1062
|
*/
|
|
990
|
-
async function mutateModel(action, modelName, id, data, options,
|
|
1063
|
+
async function mutateModel(action, modelName, id, data, options, beforeConfirmation) {
|
|
991
1064
|
assertWriteOptions(options && {
|
|
992
1065
|
idempotencyKey: options.idempotencyKey,
|
|
993
1066
|
readAt: options.readAt,
|
|
994
1067
|
onStale: options.onStale,
|
|
995
1068
|
claim: options.claim,
|
|
1069
|
+
claimRef: options.claimRef,
|
|
1070
|
+
fenceToken: options.fenceToken,
|
|
1071
|
+
reads: options.reads,
|
|
1072
|
+
track: options.track,
|
|
996
1073
|
}, `${modelName} ${action}`);
|
|
997
1074
|
const clientTxId = createClientTxId(options?.idempotencyKey);
|
|
998
1075
|
const encModel = encodeURIComponent(modelName);
|
|
@@ -1014,6 +1091,8 @@ export function createHttpTransport(options) {
|
|
|
1014
1091
|
claim: normalizeClaimId(options?.claimRef) ?? claimHandle?.id,
|
|
1015
1092
|
onStale: options?.onStale ?? (claimHandle?.readAt !== undefined ? 'reject' : undefined),
|
|
1016
1093
|
readAt,
|
|
1094
|
+
reads: options?.reads,
|
|
1095
|
+
track: options?.track,
|
|
1017
1096
|
// The claim's fencing token (Option B), so the per-model HTTP write door
|
|
1018
1097
|
// fences the same as the WS proxy and `commits.create`.
|
|
1019
1098
|
fenceToken: options?.fenceToken ?? claimHandle?.fenceToken,
|
|
@@ -1033,7 +1112,7 @@ export function createHttpTransport(options) {
|
|
|
1033
1112
|
// confirmation. Early queued receipts remain available through the
|
|
1034
1113
|
// lower-level `commits.create` lifecycle surface.
|
|
1035
1114
|
wait: 'confirmed',
|
|
1036
|
-
},
|
|
1115
|
+
}, beforeConfirmation);
|
|
1037
1116
|
}
|
|
1038
1117
|
catch (error) {
|
|
1039
1118
|
// The per-model write door (`ablo.<model>.update/create/delete`). Capture
|
|
@@ -1042,7 +1121,7 @@ export function createHttpTransport(options) {
|
|
|
1042
1121
|
throw error;
|
|
1043
1122
|
}
|
|
1044
1123
|
// Same contract as `commits.create` above: a non-2xx already threw, so
|
|
1045
|
-
// `body` is the success-only receipt union and its
|
|
1124
|
+
// `body` is the success-only receipt union and its confirmation status passes
|
|
1046
1125
|
// through verbatim rather than through a catch-all branch.
|
|
1047
1126
|
return {
|
|
1048
1127
|
id: body.serverTxId,
|
|
@@ -1258,7 +1337,14 @@ export function createHttpTransport(options) {
|
|
|
1258
1337
|
if (!claimInput)
|
|
1259
1338
|
return run(input);
|
|
1260
1339
|
if (isClaimHandle(claimInput)) {
|
|
1261
|
-
return run({
|
|
1340
|
+
return run({
|
|
1341
|
+
...input,
|
|
1342
|
+
claimRef: { id: claimInput.id },
|
|
1343
|
+
...(claimInput.fenceToken !== undefined
|
|
1344
|
+
? { fenceToken: claimInput.fenceToken }
|
|
1345
|
+
: {}),
|
|
1346
|
+
claim: undefined,
|
|
1347
|
+
});
|
|
1262
1348
|
}
|
|
1263
1349
|
// `isClaimHandle` ruled out the handle form above; the generic mismatch
|
|
1264
1350
|
// (the union carries `Claim`, the guard narrows `Claim<T>`) keeps the
|
|
@@ -1338,7 +1424,7 @@ export function createHttpTransport(options) {
|
|
|
1338
1424
|
created = read.data;
|
|
1339
1425
|
});
|
|
1340
1426
|
if (created === undefined) {
|
|
1341
|
-
throw new AbloConnectionError('Create
|
|
1427
|
+
throw new AbloConnectionError('Create confirmation did not return its row.', {
|
|
1342
1428
|
code: 'commit_no_result',
|
|
1343
1429
|
});
|
|
1344
1430
|
}
|
|
@@ -1379,8 +1465,9 @@ export function createHttpTransport(options) {
|
|
|
1379
1465
|
}
|
|
1380
1466
|
return {
|
|
1381
1467
|
ready,
|
|
1468
|
+
get identity() { return effectiveAuthority; },
|
|
1382
1469
|
waitForFlush: () => runInHttpCommitLane(async () => {
|
|
1383
|
-
await
|
|
1470
|
+
await prepare();
|
|
1384
1471
|
const replayed = await replayHttpCommitOutbox();
|
|
1385
1472
|
await confirmReplayedHttpCommits(replayed);
|
|
1386
1473
|
}),
|