@abloatai/transaction 0.43.0 → 0.45.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/dist/ai-sdk/modelTools.d.ts +2 -4
- package/dist/ai-sdk/modelTools.d.ts.map +1 -1
- package/dist/ai-sdk/modelTools.js.map +1 -1
- package/dist/ai-sdk/updateTool.d.ts +2 -4
- package/dist/ai-sdk/updateTool.d.ts.map +1 -1
- package/dist/ai-sdk/updateTool.js.map +1 -1
- package/dist/branches.d.ts +4 -4
- package/dist/coordination/awaitClaimGrant.d.ts +10 -0
- package/dist/coordination/awaitClaimGrant.d.ts.map +1 -1
- package/dist/coordination/awaitClaimGrant.js +58 -45
- package/dist/coordination/awaitClaimGrant.js.map +1 -1
- package/dist/errors.d.ts +7 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +14 -6
- package/dist/errors.js.map +1 -1
- package/dist/resources/httpResources.d.ts +4 -4
- package/dist/resources/httpResources.d.ts.map +1 -1
- package/dist/resources/modelOperations.d.ts +113 -21
- package/dist/resources/modelOperations.d.ts.map +1 -1
- package/dist/resources/modelOperations.js +43 -1
- package/dist/resources/modelOperations.js.map +1 -1
- package/dist/transport/httpTransport.d.ts.map +1 -1
- package/dist/transport/httpTransport.js +49 -15
- package/dist/transport/httpTransport.js.map +1 -1
- package/dist/transport/wsFrameHandlers.d.ts.map +1 -1
- package/dist/transport/wsFrameHandlers.js +12 -0
- package/dist/transport/wsFrameHandlers.js.map +1 -1
- package/dist/wire/commit.d.ts +6 -0
- package/dist/wire/commit.d.ts.map +1 -1
- package/dist/wire/commit.js +2 -0
- package/dist/wire/commit.js.map +1 -1
- package/package.json +1 -1
- package/src/ai-sdk/modelTools.ts +2 -1
- package/src/ai-sdk/updateTool.ts +2 -1
- package/src/coordination/awaitClaimGrant.ts +86 -74
- package/src/errors.ts +17 -5
- package/src/resources/httpResources.ts +5 -1
- package/src/resources/modelOperations.ts +169 -19
- package/src/transport/httpTransport.ts +73 -19
- package/src/transport/wsFrameHandlers.ts +14 -0
- package/src/wire/commit.ts +2 -0
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
AbloClaimedError,
|
|
11
|
+
AbloError,
|
|
11
12
|
AbloAuthenticationError,
|
|
12
13
|
AbloConnectionError,
|
|
13
14
|
AbloIdempotencyError,
|
|
@@ -113,10 +114,19 @@ import type {
|
|
|
113
114
|
ClaimLookupParams,
|
|
114
115
|
ClaimOptions,
|
|
115
116
|
ClaimParams,
|
|
117
|
+
ClaimSkipParams,
|
|
116
118
|
ClaimReorderParams,
|
|
117
119
|
ModelTrackParams,
|
|
118
120
|
ModelTrackResult,
|
|
119
121
|
ServerReadOptions,
|
|
122
|
+
ResolvedClaimContentionOptions,
|
|
123
|
+
ClaimQueueView,
|
|
124
|
+
} from '../resources/modelOperations.js';
|
|
125
|
+
import {
|
|
126
|
+
claimAttemptFailure,
|
|
127
|
+
claimQueueView,
|
|
128
|
+
emitClaimStatus,
|
|
129
|
+
resolveClaimContentionOptions,
|
|
120
130
|
} from '../resources/modelOperations.js';
|
|
121
131
|
import type { Duration } from '../utils/duration.js';
|
|
122
132
|
import type { TrackDependency } from '../coordination/schema.js';
|
|
@@ -1148,7 +1158,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1148
1158
|
async function awaitGrantOverHttp(
|
|
1149
1159
|
targetLabel: string,
|
|
1150
1160
|
queued: ClaimQueuedResponse,
|
|
1151
|
-
options:
|
|
1161
|
+
options: ResolvedClaimContentionOptions,
|
|
1152
1162
|
): Promise<{ id: string; fenceToken?: number }> {
|
|
1153
1163
|
// The queued reply is a claim resource in its waiting state, so the
|
|
1154
1164
|
// handle is its `id` — same rule as the 201 and the poll.
|
|
@@ -1161,17 +1171,24 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1161
1171
|
throw error;
|
|
1162
1172
|
};
|
|
1163
1173
|
|
|
1164
|
-
|
|
1174
|
+
emitClaimStatus(options.onStatus, {
|
|
1175
|
+
type: 'queued',
|
|
1176
|
+
claimId,
|
|
1177
|
+
position: queued.position,
|
|
1178
|
+
ahead: queued.position + 1,
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
if (options.maxDepth !== undefined && queued.position >= options.maxDepth) {
|
|
1165
1182
|
return rejectAndLeave(
|
|
1166
1183
|
new AbloClaimedError(
|
|
1167
|
-
`Claim queue for ${targetLabel} is ${queued.position} deep (max ${options.
|
|
1184
|
+
`Claim queue for ${targetLabel} is ${queued.position} deep (max ${options.maxDepth}).`,
|
|
1168
1185
|
{ code: 'queue_too_deep' }
|
|
1169
1186
|
)
|
|
1170
1187
|
);
|
|
1171
1188
|
}
|
|
1172
1189
|
|
|
1173
1190
|
const deadline =
|
|
1174
|
-
options.
|
|
1191
|
+
options.timeoutMs !== undefined ? Date.now() + options.timeoutMs : undefined;
|
|
1175
1192
|
let delay = GRANT_POLL_FIRST_MS;
|
|
1176
1193
|
for (;;) {
|
|
1177
1194
|
if (signal?.aborted) {
|
|
@@ -1185,7 +1202,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1185
1202
|
if (deadline !== undefined && Date.now() >= deadline) {
|
|
1186
1203
|
return rejectAndLeave(
|
|
1187
1204
|
new AbloClaimedError(
|
|
1188
|
-
`Timed out after ${options.
|
|
1205
|
+
`Timed out after ${options.timeoutMs}ms waiting for the queue grant on ${targetLabel}.`,
|
|
1189
1206
|
{ code: 'grant_timeout' }
|
|
1190
1207
|
)
|
|
1191
1208
|
);
|
|
@@ -1218,6 +1235,11 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1218
1235
|
})
|
|
1219
1236
|
);
|
|
1220
1237
|
}
|
|
1238
|
+
emitClaimStatus(options.onStatus, {
|
|
1239
|
+
type: 'granted',
|
|
1240
|
+
claimId,
|
|
1241
|
+
waited: true,
|
|
1242
|
+
});
|
|
1221
1243
|
return state.fenceToken !== undefined
|
|
1222
1244
|
? { id: claimId, fenceToken: state.fenceToken }
|
|
1223
1245
|
: { id: claimId };
|
|
@@ -1492,6 +1514,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1492
1514
|
const acquireClaim = async (
|
|
1493
1515
|
params: ClaimParams<Fields>
|
|
1494
1516
|
): Promise<{ id: string; fenceToken?: number }> => {
|
|
1517
|
+
const contention = resolveClaimContentionOptions(params);
|
|
1495
1518
|
// The row is named by the URL, so `target` carries only the narrowing a
|
|
1496
1519
|
// claim adds below it. Sending it is what makes a field-scoped claim
|
|
1497
1520
|
// actually field-scoped: the server's conflict rule reads `path`,
|
|
@@ -1512,13 +1535,25 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1512
1535
|
...(Object.keys(narrowing).length > 0 ? { target: narrowing } : {}),
|
|
1513
1536
|
// `queue` (default true) → queue behind the holder; false → fail-fast
|
|
1514
1537
|
// with AbloClaimedError (work-distribution dedup).
|
|
1515
|
-
queue:
|
|
1538
|
+
queue: contention.wait,
|
|
1516
1539
|
};
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1540
|
+
let body: z.infer<typeof claimAcquireResponseSchema>;
|
|
1541
|
+
try {
|
|
1542
|
+
body = await requestJson(
|
|
1543
|
+
claimPath(params.id),
|
|
1544
|
+
{ method: 'POST', body: JSON.stringify(request) },
|
|
1545
|
+
claimAcquireResponseSchema
|
|
1546
|
+
);
|
|
1547
|
+
} catch (error) {
|
|
1548
|
+
const normalized = error instanceof AbloError
|
|
1549
|
+
? error
|
|
1550
|
+
: new AbloConnectionError(String(error));
|
|
1551
|
+
emitClaimStatus(
|
|
1552
|
+
contention.onStatus,
|
|
1553
|
+
claimAttemptFailure(contention.wait, normalized),
|
|
1554
|
+
);
|
|
1555
|
+
throw error;
|
|
1556
|
+
}
|
|
1522
1557
|
// One resource, two states, discriminated by `status`. The queued arm
|
|
1523
1558
|
// WAITS, exactly as the socket client does: `claim({ id })` means
|
|
1524
1559
|
// "serialize me behind the holder" on every transport, and the grant
|
|
@@ -1527,8 +1562,28 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1527
1562
|
// why it no longer surfaces as one here. The `claims` namespace remains
|
|
1528
1563
|
// the manual ticket surface.)
|
|
1529
1564
|
if (body.status === 'queued') {
|
|
1530
|
-
|
|
1565
|
+
try {
|
|
1566
|
+
return await awaitGrantOverHttp(
|
|
1567
|
+
`${name}/${params.id}`,
|
|
1568
|
+
body,
|
|
1569
|
+
contention,
|
|
1570
|
+
);
|
|
1571
|
+
} catch (error) {
|
|
1572
|
+
const normalized = error instanceof AbloError
|
|
1573
|
+
? error
|
|
1574
|
+
: new AbloConnectionError(String(error));
|
|
1575
|
+
emitClaimStatus(
|
|
1576
|
+
contention.onStatus,
|
|
1577
|
+
claimAttemptFailure(contention.wait, normalized),
|
|
1578
|
+
);
|
|
1579
|
+
throw error;
|
|
1580
|
+
}
|
|
1531
1581
|
}
|
|
1582
|
+
emitClaimStatus(contention.onStatus, {
|
|
1583
|
+
type: 'granted',
|
|
1584
|
+
claimId: body.id,
|
|
1585
|
+
waited: false,
|
|
1586
|
+
});
|
|
1532
1587
|
// The lease's own fields are mirrored at the top level, the same place
|
|
1533
1588
|
// the poll puts them — one reader for both answers.
|
|
1534
1589
|
return body.fenceToken !== undefined
|
|
@@ -1566,7 +1621,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1566
1621
|
};
|
|
1567
1622
|
|
|
1568
1623
|
function claimImpl(
|
|
1569
|
-
params:
|
|
1624
|
+
params: ClaimSkipParams<Fields>
|
|
1570
1625
|
): Promise<HeldClaim<T> | null>;
|
|
1571
1626
|
function claimImpl(params: ClaimParams<Fields>): Promise<HeldClaim<T>>;
|
|
1572
1627
|
async function claimImpl(
|
|
@@ -1582,7 +1637,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1582
1637
|
// and the write-site claim path calls `acquireClaim` directly, so a
|
|
1583
1638
|
// write that could not claim still fails loudly.
|
|
1584
1639
|
if (
|
|
1585
|
-
params.
|
|
1640
|
+
!resolveClaimContentionOptions(params).wait &&
|
|
1586
1641
|
error instanceof AbloClaimedError &&
|
|
1587
1642
|
(error.code === 'entity_claimed' || error.code === 'claim_conflict')
|
|
1588
1643
|
) {
|
|
@@ -1687,14 +1742,13 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
|
|
|
1687
1742
|
},
|
|
1688
1743
|
queue: async (
|
|
1689
1744
|
params: ClaimLookupParams<T>
|
|
1690
|
-
): Promise<
|
|
1745
|
+
): Promise<ClaimQueueView> => {
|
|
1691
1746
|
const res = await claimsForEntity(params);
|
|
1692
|
-
return
|
|
1693
|
-
|
|
1694
|
-
data: res.data
|
|
1747
|
+
return claimQueueView(
|
|
1748
|
+
res.data
|
|
1695
1749
|
.filter((row) => row.status === 'queued')
|
|
1696
1750
|
.map(claimFromModelClaim),
|
|
1697
|
-
|
|
1751
|
+
);
|
|
1698
1752
|
},
|
|
1699
1753
|
reorder: async (params: ClaimReorderParams<T>): Promise<void> => {
|
|
1700
1754
|
await requestRaw(`${claimPath(params.id)}/reorder`, {
|
|
@@ -223,14 +223,18 @@ const handleMutationResult: WsFrameHandler = (session, message) => {
|
|
|
223
223
|
// such as validation issues, survive being wrapped in an Error.
|
|
224
224
|
let errorMessage: string;
|
|
225
225
|
let errorCode: string | undefined;
|
|
226
|
+
let requestId: string | undefined;
|
|
226
227
|
let requiredCapability: RequiredCapability | undefined;
|
|
228
|
+
let details: Readonly<Record<string, unknown>> | undefined;
|
|
227
229
|
if (typeof error === 'string') {
|
|
228
230
|
errorMessage = error;
|
|
229
231
|
} else if (error != null && typeof error === 'object') {
|
|
230
232
|
const obj = error as {
|
|
231
233
|
code?: unknown;
|
|
232
234
|
message?: unknown;
|
|
235
|
+
request_id?: unknown;
|
|
233
236
|
requiredCapability?: unknown;
|
|
237
|
+
details?: unknown;
|
|
234
238
|
};
|
|
235
239
|
if (typeof obj.code === 'string') errorCode = obj.code;
|
|
236
240
|
if (typeof obj.message === 'string') {
|
|
@@ -249,6 +253,14 @@ const handleMutationResult: WsFrameHandler = (session, message) => {
|
|
|
249
253
|
) {
|
|
250
254
|
requiredCapability = obj.requiredCapability as RequiredCapability;
|
|
251
255
|
}
|
|
256
|
+
requestId =
|
|
257
|
+
typeof obj.request_id === 'string' ? obj.request_id : undefined;
|
|
258
|
+
details =
|
|
259
|
+
obj.details != null &&
|
|
260
|
+
typeof obj.details === 'object' &&
|
|
261
|
+
!Array.isArray(obj.details)
|
|
262
|
+
? (obj.details as Readonly<Record<string, unknown>>)
|
|
263
|
+
: undefined;
|
|
252
264
|
} else {
|
|
253
265
|
errorMessage = 'mutation failed on server';
|
|
254
266
|
}
|
|
@@ -298,7 +310,9 @@ const handleMutationResult: WsFrameHandler = (session, message) => {
|
|
|
298
310
|
pending.reject(
|
|
299
311
|
errorFromWire(errorMessage, {
|
|
300
312
|
code: errorCode,
|
|
313
|
+
requestId,
|
|
301
314
|
requiredCapability,
|
|
315
|
+
details,
|
|
302
316
|
}),
|
|
303
317
|
);
|
|
304
318
|
}
|
package/src/wire/commit.ts
CHANGED
|
@@ -157,7 +157,9 @@ export const rejectedCommitReceiptSchema = z.object({
|
|
|
157
157
|
code: errorCodeSchema,
|
|
158
158
|
message: z.string(),
|
|
159
159
|
field: z.string().optional(),
|
|
160
|
+
request_id: z.string().optional(),
|
|
160
161
|
requiredCapability: requiredCapabilityWireSchema.optional(),
|
|
162
|
+
details: z.record(z.string(), z.unknown()).optional(),
|
|
161
163
|
}),
|
|
162
164
|
});
|
|
163
165
|
export type RejectedCommitReceiptWire = z.infer<typeof rejectedCommitReceiptSchema>;
|