@abloatai/transaction 0.51.0 → 0.53.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.
Files changed (216) hide show
  1. package/dist/ablo.d.ts +1 -1
  2. package/dist/ablo.js +1 -1
  3. package/dist/ai-sdk/updateTool.d.ts +1 -1
  4. package/dist/ai-sdk/updateTool.js +1 -1
  5. package/dist/auth/apiKey.d.ts +0 -6
  6. package/dist/auth/apiKey.d.ts.map +1 -1
  7. package/dist/auth/apiKey.js +13 -60
  8. package/dist/auth/apiKey.js.map +1 -1
  9. package/dist/auth/baseUrl.d.ts +38 -0
  10. package/dist/auth/baseUrl.d.ts.map +1 -0
  11. package/dist/auth/baseUrl.js +126 -0
  12. package/dist/auth/baseUrl.js.map +1 -0
  13. package/dist/auth/capability.d.ts +2 -2
  14. package/dist/auth/capability.js +1 -1
  15. package/dist/auth/index.d.ts +15 -2
  16. package/dist/auth/index.d.ts.map +1 -1
  17. package/dist/auth/index.js +35 -21
  18. package/dist/auth/index.js.map +1 -1
  19. package/dist/auth/schemas.d.ts +24 -1
  20. package/dist/auth/schemas.d.ts.map +1 -1
  21. package/dist/auth/schemas.js +8 -2
  22. package/dist/auth/schemas.js.map +1 -1
  23. package/dist/auth/sessionIssuanceProtocol.d.ts +41 -0
  24. package/dist/auth/sessionIssuanceProtocol.d.ts.map +1 -0
  25. package/dist/auth/sessionIssuanceProtocol.js +48 -0
  26. package/dist/auth/sessionIssuanceProtocol.js.map +1 -0
  27. package/dist/auth/sessionMint.js +2 -2
  28. package/dist/branches.d.ts +34 -33
  29. package/dist/branches.d.ts.map +1 -1
  30. package/dist/branches.js +2 -4
  31. package/dist/branches.js.map +1 -1
  32. package/dist/coordination/schema.d.ts +3 -2
  33. package/dist/coordination/schema.d.ts.map +1 -1
  34. package/dist/coordination/schema.js +7 -2
  35. package/dist/coordination/schema.js.map +1 -1
  36. package/dist/errorCodes.d.ts +7 -3
  37. package/dist/errorCodes.d.ts.map +1 -1
  38. package/dist/errorCodes.js +8 -4
  39. package/dist/errorCodes.js.map +1 -1
  40. package/dist/errors.d.ts +1 -1
  41. package/dist/errors.js +1 -1
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/resources/httpResources.d.ts +35 -2
  46. package/dist/resources/httpResources.d.ts.map +1 -1
  47. package/dist/resources/httpResources.js +10 -1
  48. package/dist/resources/httpResources.js.map +1 -1
  49. package/dist/resources/modelOperations.d.ts +18 -6
  50. package/dist/resources/modelOperations.d.ts.map +1 -1
  51. package/dist/resources/modelOperations.js.map +1 -1
  52. package/dist/resources/where.d.ts +67 -2
  53. package/dist/resources/where.d.ts.map +1 -1
  54. package/dist/resources/where.js +73 -0
  55. package/dist/resources/where.js.map +1 -1
  56. package/dist/schema/ddl.d.ts.map +1 -1
  57. package/dist/schema/ddl.js +9 -12
  58. package/dist/schema/ddl.js.map +1 -1
  59. package/dist/schema/field.d.ts +3 -3
  60. package/dist/schema/field.js +2 -2
  61. package/dist/schema/fieldRef.d.ts +1 -1
  62. package/dist/schema/generate.d.ts +2 -3
  63. package/dist/schema/generate.d.ts.map +1 -1
  64. package/dist/schema/generate.js +2 -8
  65. package/dist/schema/generate.js.map +1 -1
  66. package/dist/schema/index.d.ts +2 -2
  67. package/dist/schema/index.js +3 -3
  68. package/dist/schema/model.d.ts +7 -7
  69. package/dist/schema/model.js +2 -2
  70. package/dist/schema/openapi.d.ts.map +1 -1
  71. package/dist/schema/openapi.js +63 -21
  72. package/dist/schema/openapi.js.map +1 -1
  73. package/dist/schema/queries.d.ts +1 -1
  74. package/dist/schema/queries.js +1 -1
  75. package/dist/schema/relation.d.ts +8 -8
  76. package/dist/schema/relation.js +5 -5
  77. package/dist/schema/schema.d.ts +24 -37
  78. package/dist/schema/schema.d.ts.map +1 -1
  79. package/dist/schema/schema.js +15 -28
  80. package/dist/schema/schema.js.map +1 -1
  81. package/dist/schema/sugar.d.ts +7 -7
  82. package/dist/schema/sugar.js +5 -5
  83. package/dist/server/adapter.d.ts +2 -0
  84. package/dist/server/adapter.d.ts.map +1 -1
  85. package/dist/server/commit.d.ts +5 -1
  86. package/dist/server/commit.d.ts.map +1 -1
  87. package/dist/server/index.d.ts +3 -2
  88. package/dist/server/index.d.ts.map +1 -1
  89. package/dist/server/index.js.map +1 -1
  90. package/dist/server/readConfig.d.ts +109 -57
  91. package/dist/server/readConfig.d.ts.map +1 -1
  92. package/dist/server/readConfig.js +19 -5
  93. package/dist/server/readConfig.js.map +1 -1
  94. package/dist/source/adapters/drizzle.d.ts.map +1 -1
  95. package/dist/source/adapters/drizzle.js +5 -0
  96. package/dist/source/adapters/drizzle.js.map +1 -1
  97. package/dist/source/adapters/kysely.d.ts.map +1 -1
  98. package/dist/source/adapters/kysely.js +33 -8
  99. package/dist/source/adapters/kysely.js.map +1 -1
  100. package/dist/source/adapters/kyselyMutationCore.d.ts +1 -1
  101. package/dist/source/adapters/kyselyMutationCore.d.ts.map +1 -1
  102. package/dist/source/adapters/kyselyMutationCore.js +58 -20
  103. package/dist/source/adapters/kyselyMutationCore.js.map +1 -1
  104. package/dist/source/adapters/memory.d.ts.map +1 -1
  105. package/dist/source/adapters/memory.js +5 -0
  106. package/dist/source/adapters/memory.js.map +1 -1
  107. package/dist/source/adapters/prisma.d.ts.map +1 -1
  108. package/dist/source/adapters/prisma.js +6 -1
  109. package/dist/source/adapters/prisma.js.map +1 -1
  110. package/dist/source/conformance.js +21 -21
  111. package/dist/source/contract.d.ts +17 -0
  112. package/dist/source/contract.d.ts.map +1 -1
  113. package/dist/source/contract.js +31 -0
  114. package/dist/source/contract.js.map +1 -1
  115. package/dist/source/index.d.ts +1 -1
  116. package/dist/source/index.d.ts.map +1 -1
  117. package/dist/source/index.js +1 -1
  118. package/dist/source/index.js.map +1 -1
  119. package/dist/source/types.d.ts +1 -0
  120. package/dist/source/types.d.ts.map +1 -1
  121. package/dist/source/types.js.map +1 -1
  122. package/dist/transactionLayer.d.ts +3 -3
  123. package/dist/transactionLayer.js +3 -3
  124. package/dist/transport/httpClient.d.ts +13 -4
  125. package/dist/transport/httpClient.d.ts.map +1 -1
  126. package/dist/transport/httpClient.js +4 -2
  127. package/dist/transport/httpClient.js.map +1 -1
  128. package/dist/transport/httpTransport.d.ts +1 -0
  129. package/dist/transport/httpTransport.d.ts.map +1 -1
  130. package/dist/transport/httpTransport.js +79 -11
  131. package/dist/transport/httpTransport.js.map +1 -1
  132. package/dist/transport/wsFrameHandlers.d.ts.map +1 -1
  133. package/dist/transport/wsFrameHandlers.js +3 -0
  134. package/dist/transport/wsFrameHandlers.js.map +1 -1
  135. package/dist/types/streams.d.ts +2 -2
  136. package/dist/wire/accountResponses.d.ts +18 -13
  137. package/dist/wire/accountResponses.d.ts.map +1 -1
  138. package/dist/wire/accountResponses.js +5 -11
  139. package/dist/wire/accountResponses.js.map +1 -1
  140. package/dist/wire/claims.d.ts +1 -0
  141. package/dist/wire/claims.d.ts.map +1 -1
  142. package/dist/wire/claims.js +7 -1
  143. package/dist/wire/claims.js.map +1 -1
  144. package/dist/wire/commit.d.ts +144 -0
  145. package/dist/wire/commit.d.ts.map +1 -1
  146. package/dist/wire/commit.js +22 -1
  147. package/dist/wire/commit.js.map +1 -1
  148. package/dist/wire/frames.d.ts +4 -0
  149. package/dist/wire/frames.d.ts.map +1 -1
  150. package/dist/wire/inboundFrames.d.ts +22 -0
  151. package/dist/wire/inboundFrames.d.ts.map +1 -1
  152. package/dist/wire/index.d.ts +3 -3
  153. package/dist/wire/index.d.ts.map +1 -1
  154. package/dist/wire/index.js +2 -2
  155. package/dist/wire/index.js.map +1 -1
  156. package/dist/wire/listEnvelope.d.ts +20 -0
  157. package/dist/wire/listEnvelope.d.ts.map +1 -1
  158. package/dist/wire/listEnvelope.js +20 -0
  159. package/dist/wire/listEnvelope.js.map +1 -1
  160. package/dist/wire/protocol.d.ts +1 -1
  161. package/dist/wire/protocol.js +1 -1
  162. package/package.json +1 -1
  163. package/src/ablo.ts +1 -1
  164. package/src/ai-sdk/updateTool.ts +1 -1
  165. package/src/auth/apiKey.ts +13 -61
  166. package/src/auth/baseUrl.ts +144 -0
  167. package/src/auth/capability.ts +3 -3
  168. package/src/auth/index.ts +62 -21
  169. package/src/auth/schemas.ts +16 -2
  170. package/src/auth/sessionIssuanceProtocol.ts +57 -0
  171. package/src/auth/sessionMint.ts +2 -2
  172. package/src/branches.ts +2 -4
  173. package/src/coordination/schema.ts +7 -2
  174. package/src/errorCodes.ts +29 -5
  175. package/src/errors.ts +1 -1
  176. package/src/index.ts +2 -0
  177. package/src/resources/httpResources.ts +45 -2
  178. package/src/resources/modelOperations.ts +18 -6
  179. package/src/resources/where.ts +70 -4
  180. package/src/schema/ddl.ts +9 -13
  181. package/src/schema/field.ts +3 -3
  182. package/src/schema/fieldRef.ts +1 -1
  183. package/src/schema/generate.ts +2 -8
  184. package/src/schema/index.ts +3 -3
  185. package/src/schema/model.ts +7 -7
  186. package/src/schema/openapi.ts +64 -21
  187. package/src/schema/queries.ts +1 -1
  188. package/src/schema/relation.ts +8 -8
  189. package/src/schema/residency.ts +0 -1
  190. package/src/schema/schema.ts +33 -58
  191. package/src/schema/sugar.ts +7 -7
  192. package/src/server/adapter.ts +2 -0
  193. package/src/server/commit.ts +5 -1
  194. package/src/server/index.ts +8 -2
  195. package/src/server/readConfig.ts +111 -57
  196. package/src/source/adapters/drizzle.ts +5 -0
  197. package/src/source/adapters/kysely.ts +48 -10
  198. package/src/source/adapters/kyselyMutationCore.ts +69 -22
  199. package/src/source/adapters/memory.ts +5 -0
  200. package/src/source/adapters/prisma.ts +6 -1
  201. package/src/source/conformance.ts +21 -21
  202. package/src/source/contract.ts +34 -0
  203. package/src/source/index.ts +2 -0
  204. package/src/source/types.ts +1 -0
  205. package/src/transactionLayer.ts +3 -3
  206. package/src/transport/httpClient.ts +23 -6
  207. package/src/transport/httpTransport.ts +88 -11
  208. package/src/transport/wsFrameHandlers.ts +3 -0
  209. package/src/types/global.ts +1 -1
  210. package/src/types/streams.ts +2 -2
  211. package/src/wire/accountResponses.ts +5 -11
  212. package/src/wire/claims.ts +7 -1
  213. package/src/wire/commit.ts +31 -1
  214. package/src/wire/index.ts +10 -1
  215. package/src/wire/listEnvelope.ts +23 -0
  216. package/src/wire/protocol.ts +1 -1
@@ -84,6 +84,7 @@ import type {
84
84
  ModelMutationOptions,
85
85
  ModelReadOptions,
86
86
  HttpTransportRead,
87
+ HttpTransportList,
87
88
  HttpLogsResource,
88
89
  ModelTarget,
89
90
  CreateSessionParams,
@@ -151,6 +152,7 @@ import { declaredMeta, wireMeta } from '../coordination/claimMeta.js';
151
152
  import type { Claim, ClaimHeartbeat, ClaimHeartbeatOptions, HeldClaim } from '../types/streams.js';
152
153
  import type { CoordinationObservability } from '../observability.js';
153
154
  import { assertWriteOptions } from '../resources/writeOptionsSchema.js';
155
+ import { normalizeWhere } from '../resources/where.js';
154
156
  import {
155
157
  createDurableHttpCommitEnvelope,
156
158
  canonicalHttpCommitBody,
@@ -203,6 +205,7 @@ const DEFAULT_CLAIM_TTL_MS = 60_000;
203
205
  export interface HttpTransport {
204
206
  ready(): Promise<void>;
205
207
  waitForFlush(): Promise<void>;
208
+ /** Drains scheduled commits and active requests. */
206
209
  dispose(): Promise<void>;
207
210
  purge(): Promise<void>;
208
211
  readonly commits: CommitResource;
@@ -361,6 +364,26 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
361
364
  let readyPromise: Promise<void> | null = null;
362
365
  let effectiveAuthority: EffectiveAuthority | null = null;
363
366
  let httpCommitLane: Promise<void> = Promise.resolve();
367
+ let activeRequests = 0;
368
+ let requestIdleWaiters: Array<() => void> = [];
369
+ let disposePromise: Promise<void> | null = null;
370
+
371
+ function requestStarted(): void {
372
+ activeRequests += 1;
373
+ }
374
+
375
+ function requestFinished(): void {
376
+ activeRequests -= 1;
377
+ if (activeRequests !== 0) return;
378
+ const waiters = requestIdleWaiters;
379
+ requestIdleWaiters = [];
380
+ for (const resolve of waiters) resolve();
381
+ }
382
+
383
+ function waitForRequestIdle(): Promise<void> {
384
+ if (activeRequests === 0) return Promise.resolve();
385
+ return new Promise((resolve) => requestIdleWaiters.push(resolve));
386
+ }
364
387
 
365
388
  function runInHttpCommitLane<T>(work: () => Promise<T>): Promise<T> {
366
389
  const result = httpCommitLane.then(work);
@@ -475,7 +498,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
475
498
  * the commit paths do with their receipt schema. Everywhere else, go through
476
499
  * {@link requestJson}, which will not let a response past unvalidated.
477
500
  */
478
- async function requestRaw(
501
+ async function performRequest(
479
502
  path: string,
480
503
  init: RequestInit & {
481
504
  readonly idempotencyKey?: string | null;
@@ -557,6 +580,22 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
557
580
  return body;
558
581
  }
559
582
 
583
+ async function requestRaw(
584
+ path: string,
585
+ init: RequestInit & {
586
+ readonly idempotencyKey?: string | null;
587
+ readonly sealedProtocolVersion?: number;
588
+ },
589
+ skipReady = false
590
+ ): Promise<unknown> {
591
+ requestStarted();
592
+ try {
593
+ return await performRequest(path, init, skipReady);
594
+ } finally {
595
+ requestFinished();
596
+ }
597
+ }
598
+
560
599
  /**
561
600
  * Issues one request and validates its body against the route's schema.
562
601
  *
@@ -729,6 +768,11 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
729
768
  initial: CommitResponse
730
769
  ): Promise<CommitResponse> {
731
770
  let current = initial;
771
+ const operationResults = initial.operationResults;
772
+ const withOperationResults = (receipt: CommitResponse): CommitResponse =>
773
+ operationResults?.length
774
+ ? { ...receipt, operationResults }
775
+ : receipt;
732
776
  const correlationId = initial.correlationId;
733
777
  const deadlineAt = requestTimeoutMs > 0 ? Date.now() + requestTimeoutMs : null;
734
778
 
@@ -780,7 +824,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
780
824
  if (confirmationDeadline) clearTimeout(confirmationDeadline);
781
825
  }
782
826
 
783
- if (current.status === 'confirmed') return current;
827
+ if (current.status === 'confirmed') return withOperationResults(current);
784
828
  const delayMs =
785
829
  deadlineAt === null
786
830
  ? HTTP_CONFIRMATION_POLL_INTERVAL_MS
@@ -791,7 +835,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
791
835
  });
792
836
  }
793
837
  }
794
- return current;
838
+ return withOperationResults(current);
795
839
  }
796
840
 
797
841
  async function replayHttpCommitOutbox(): Promise<Map<string, ReplayedHttpCommit>> {
@@ -1111,6 +1155,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1111
1155
  model: op.model,
1112
1156
  id: op.id ?? null,
1113
1157
  data: op.data ?? null,
1158
+ where: op.where ?? null,
1114
1159
  transactionId: op.transactionId ?? null,
1115
1160
  claimId:
1116
1161
  op.claimId ?? claimIdFor(claim?.target, claim?.id, op.model, op.id ?? null),
@@ -1392,6 +1437,9 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1392
1437
  ? { notifications: body.notifications }
1393
1438
  : {}),
1394
1439
  ...(body.missingIds && body.missingIds.length > 0 ? { missingIds: body.missingIds } : {}),
1440
+ ...(body.operationResults && body.operationResults.length > 0
1441
+ ? { operationResults: body.operationResults }
1442
+ : {}),
1395
1443
  };
1396
1444
  },
1397
1445
  get({ id }) {
@@ -1447,9 +1495,12 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1447
1495
  async function listModel<T>(
1448
1496
  modelName: string,
1449
1497
  options?: ServerReadOptions<T>,
1450
- ): Promise<{ readonly data: readonly T[]; readonly evidence?: readonly { id: string; stamp: number }[] }> {
1498
+ ): Promise<HttpTransportList<T>> {
1451
1499
  const params = new URLSearchParams();
1452
1500
  if (options?.limit !== undefined) params.set('limit', String(options.limit));
1501
+ if (options?.cursor !== undefined) {
1502
+ params.set('cursor', options.cursor);
1503
+ }
1453
1504
  if (options?.orderBy) {
1454
1505
  const [col, dir] = Object.entries(options.orderBy)[0] ?? [];
1455
1506
  if (col) {
@@ -1457,12 +1508,27 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1457
1508
  if (dir === 'desc') params.set('order', 'desc');
1458
1509
  }
1459
1510
  }
1460
- // The collection route turns any non-reserved query param into an equality
1461
- // filter (`?status=todo`). The wire is AND-only equality matches what a
1462
- // stateless reactor needs; richer predicates stay on the stateful path.
1463
- if (options?.where && typeof options.where === 'object') {
1464
- for (const [k, v] of Object.entries(options.where as Record<string, unknown>)) {
1465
- if (v !== undefined && v !== null && typeof v !== 'object') params.set(k, String(v));
1511
+ // The whole filter travels as the canonical clause list, so every operator
1512
+ // the grammar declares survives the trip. The previous encoding walked the
1513
+ // object's own entries and skipped any value that was an object, which
1514
+ // silently discarded `IN` filters and every tuple-form clause: the request
1515
+ // went out unfiltered and the caller read the result as a filtered one.
1516
+ const clauses = normalizeWhere(options?.where);
1517
+ if (clauses.length > 0) {
1518
+ params.set('where', JSON.stringify(clauses));
1519
+ // Plain equality also goes out in the older `?column=value` shorthand.
1520
+ // A server that predates the `where` parameter does not reserve the name
1521
+ // and does not declare it as a column, so it skips it — and a dropped
1522
+ // filter is not an error there, it is a wider answer than the caller
1523
+ // asked for. Sending both means a version skew loses only the operator
1524
+ // filters, which that server could not have honoured anyway. A current
1525
+ // server ignores a shorthand key the clause list already carries.
1526
+ for (const clause of clauses) {
1527
+ const [column] = clause;
1528
+ const value = clause.length === 2 ? clause[1] : clause[2];
1529
+ if (clause.length === 3 && clause[1] !== '=') continue;
1530
+ if (value === null || typeof value === 'object') continue;
1531
+ params.set(column, String(value));
1466
1532
  }
1467
1533
  }
1468
1534
  const qs = params.toString();
@@ -1477,6 +1543,8 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1477
1543
  // the typed facade above, which holds the model's schema.
1478
1544
  return {
1479
1545
  data: res.data as T[],
1546
+ hasMore: res.has_more,
1547
+ nextCursor: res.next_cursor,
1480
1548
  ...(res.evidence ? { evidence: res.evidence } : {}),
1481
1549
  };
1482
1550
  }
@@ -2053,7 +2121,16 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
2053
2121
  const replayed = await replayHttpCommitOutbox();
2054
2122
  await confirmReplayedHttpCommits(replayed);
2055
2123
  }),
2056
- async dispose() {},
2124
+ dispose() {
2125
+ if (!disposePromise) {
2126
+ const scheduledCommits = httpCommitLane;
2127
+ disposePromise = (async () => {
2128
+ await scheduledCommits;
2129
+ await waitForRequestIdle();
2130
+ })();
2131
+ }
2132
+ return disposePromise;
2133
+ },
2057
2134
  async purge() {},
2058
2135
  commits,
2059
2136
  claims,
@@ -222,6 +222,9 @@ const handleMutationResult: WsFrameHandler = (session, message) => {
222
222
  ...(receipt.missingIds && receipt.missingIds.length > 0
223
223
  ? { missingIds: receipt.missingIds }
224
224
  : {}),
225
+ ...(receipt.operationResults && receipt.operationResults.length > 0
226
+ ? { operationResults: receipt.operationResults }
227
+ : {}),
225
228
  }),
226
229
  );
227
230
  } else {
@@ -51,7 +51,7 @@ export interface DefaultSyncShape {
51
51
  // `models` is a `SchemaRecord` (not `Record<string, unknown>`) so that
52
52
  // `ResolveSchema['models']` still satisfies the `R extends SchemaRecord`
53
53
  // bound on the SDK hooks when no `Register` is present — e.g. a shared
54
- // package (`@ablo/documents`, `@ablo/teams`) typechecked standalone, with no
54
+ // package (`feature packages`) typechecked standalone, with no
55
55
  // app registration in scope. Without this the fallback wouldn't type-check
56
56
  // against `useAblo<R>()`/`AbloProvider<R>` and every such package would need
57
57
  // its own ambient registration.
@@ -629,12 +629,12 @@ export interface Claim<T = Record<string, unknown>, M = ResolveClaimMeta> {
629
629
  revoke?: () => void;
630
630
  /**
631
631
  * Extend the lease past the liveness window — the "still working" signal
632
- * for long-running tasks. Resolving means the lease is still yours, now
632
+ * for long-running items. Resolving means the lease is still yours, now
633
633
  * good until the returned `expiresAt`; a lease that lapsed (and may have
634
634
  * been granted to the next in line) rejects with an
635
635
  * {@link ../errors.js AbloClaimedError} carrying code `claim_lost`, so the
636
636
  * failed beat doubles as the loss notification. Each beat's extension is
637
- * clamped server-side — hold a long task by beating on a cadence (pass
637
+ * clamped server-side — hold a long item by beating on a cadence (pass
638
638
  * `heartbeat` when claiming to have the SDK do this for you), not by
639
639
  * asking once for a huge window. Present only on a claim you hold.
640
640
  */
@@ -14,6 +14,7 @@
14
14
  */
15
15
 
16
16
  import { z } from 'zod';
17
+ import { listEnvelopeSchema } from './listEnvelope.js';
17
18
  // Composed, never restated: these are the artifact's own shapes, and a
18
19
  // hand-written mirror here would be a second copy of the exact record this
19
20
  // response exists to stop withholding.
@@ -45,16 +46,9 @@ export type ProjectResponse = z.infer<typeof projectResponseSchema>;
45
46
  /**
46
47
  * `GET /v1/projects`.
47
48
  *
48
- * Note what this is NOT: the canonical {@link ListEnvelope}. An org's projects
49
- * are returned whole, so the route emits `data` with no `has_more`/`next_cursor`
50
- * beside it. That divergence is real and this schema states it rather than
51
- * describing a pagination the endpoint does not implement — adding the two
52
- * fields is an API change, not a documentation fix.
49
+ * Uses the canonical paginated list envelope shared by every collection.
53
50
  */
54
- export const projectListResponseSchema = z.object({
55
- object: z.literal('list'),
56
- data: z.array(projectResponseSchema).readonly(),
57
- });
51
+ export const projectListResponseSchema = listEnvelopeSchema(projectResponseSchema);
58
52
  export type ProjectListResponse = z.infer<typeof projectListResponseSchema>;
59
53
 
60
54
  /** One minted key, returned exactly once — the plaintext is never readable again. */
@@ -101,7 +95,7 @@ export const conflictAxisWireSchema = z.object({
101
95
 
102
96
  /** One model in the deployed schema, as the schema read reports it. */
103
97
  export const schemaModelResponseSchema = z.object({
104
- /** The key local code addresses (`ablo.documents`). */
98
+ /** The key local code addresses (`ablo.records`). */
105
99
  key: z.string(),
106
100
  /** The wire typename the engine routes and gates on. */
107
101
  typename: z.string(),
@@ -122,7 +116,7 @@ export const schemaModelResponseSchema = z.object({
122
116
  *
123
117
  * The schema artifact has always carried these and this response dropped
124
118
  * them, so a caller with no local schema declaration — which is every caller
125
- * that is not TypeScript — had no way to learn that `task.title` is a
119
+ * that is not TypeScript — had no way to learn that `item.title` is a
126
120
  * required string. It found out from a 400 at the end of a round trip.
127
121
  *
128
122
  * For an agent that is not merely slow, it is a reasoning detour: a typo
@@ -121,7 +121,13 @@ export const listQuerySchema = z.object({
121
121
  limit: z.string().optional(),
122
122
  order_by: z.string().optional(),
123
123
  order: z.enum(['asc', 'desc']).optional(),
124
- /** Keyset cursor: the id of the last row from the previous page. */
124
+ /**
125
+ * Keyset cursor: the opaque `next_cursor` the previous page returned. It
126
+ * encodes the sort position it was issued for, so it is not a row id and is
127
+ * refused against a different `order_by`/`order`.
128
+ */
129
+ cursor: z.string().optional(),
130
+ /** @deprecated The pre-0.53.0 spelling of `cursor`. Send `cursor`. */
125
131
  starting_after: z.string().optional(),
126
132
  });
127
133
  export type ListQuery = z.infer<typeof listQuerySchema>;
@@ -102,6 +102,31 @@ export type CommitWait = z.infer<typeof commitWaitSchema>;
102
102
  const missingIdsSchema = z.array(z.string().min(1));
103
103
  const notificationsSchema = z.array(staleNotificationSchema);
104
104
 
105
+ export const commitOperationOutcomeSchema = z.enum([
106
+ 'created',
107
+ 'updated',
108
+ 'deleted',
109
+ 'archived',
110
+ 'unarchived',
111
+ ]);
112
+
113
+ export const commitOperationResultSchema = z.strictObject({
114
+ transactionId: z.string().min(1),
115
+ outcome: commitOperationOutcomeSchema,
116
+ row: z.record(z.string(), z.unknown()),
117
+ });
118
+ export type CommitOperationResult<
119
+ Row extends Record<string, unknown> = Record<string, unknown>,
120
+ > = Omit<z.infer<typeof commitOperationResultSchema>, 'row'> & { readonly row: Row };
121
+
122
+ const operationResultsSchema = z
123
+ .array(commitOperationResultSchema)
124
+ .min(1)
125
+ .refine(
126
+ (results) => new Set(results.map((result) => result.transactionId)).size === results.length,
127
+ 'operation result transactionIds must be unique',
128
+ );
129
+
105
130
  export const commitActorSchema = z.strictObject({
106
131
  kind: participantKindSchema,
107
132
  id: z.string().min(1),
@@ -155,6 +180,8 @@ const successfulReceiptCommonShape = {
155
180
  authority: effectiveAuthoritySchema,
156
181
  notifications: notificationsSchema.optional(),
157
182
  missingIds: missingIdsSchema.optional(),
183
+ /** Exact rows returned by the writing transaction; absent on durable replay. */
184
+ operationResults: operationResultsSchema.optional(),
158
185
  } as const;
159
186
 
160
187
  const queuedCommitReceiptSchema = queuedCommitStatusSchema.safeExtend(
@@ -316,6 +343,7 @@ export type CommitExecutionResult = z.infer<typeof commitExecutionResultSchema>;
316
343
  const ackCommonShape = {
317
344
  notifications: notificationsSchema.optional(),
318
345
  missingIds: missingIdsSchema.optional(),
346
+ operationResults: operationResultsSchema.optional(),
319
347
  } as const;
320
348
 
321
349
  /** Normalized acknowledgement handed from a mutation transport to the queue. */
@@ -350,6 +378,7 @@ export const clientCommitReceiptSchema = z.strictObject({
350
378
  lastSyncId: readSetWatermarkSchema.optional(),
351
379
  notifications: notificationsSchema.optional(),
352
380
  missingIds: missingIdsSchema.optional(),
381
+ operationResults: operationResultsSchema.optional(),
353
382
  });
354
383
  export type ClientCommitReceipt = z.infer<typeof clientCommitReceiptSchema>;
355
384
 
@@ -382,13 +411,14 @@ export const commitOperationBodySchema = z.object({
382
411
  action: z.string(),
383
412
  model: z.string(),
384
413
  data: z.record(z.string(), z.unknown()).nullish(),
414
+ where: z.record(z.string().min(1), z.unknown()).nullish(),
385
415
  });
386
416
  export type CommitOperationBody = z.infer<typeof commitOperationBodySchema>;
387
417
 
388
418
  /** Commit records retain intent metadata but never copy customer mutation data. */
389
419
  export const COMMIT_OPERATION_DATA_RETENTION = 'redacted' as const;
390
420
  export const commitRecordOperationSchema = commitOperationBodySchema
391
- .omit({ data: true })
421
+ .omit({ data: true, where: true })
392
422
  .safeExtend({ data: z.strictObject({ retention: z.literal(COMMIT_OPERATION_DATA_RETENTION) }) });
393
423
  export type CommitRecordOperation = z.infer<typeof commitRecordOperationSchema>;
394
424
 
package/src/wire/index.ts CHANGED
@@ -22,7 +22,13 @@ export {
22
22
  INTERNAL_ERROR_PUBLIC_MESSAGE,
23
23
  } from './errorEnvelope.js';
24
24
  export type { ErrorEnvelope } from './errorEnvelope.js';
25
- export { listEnvelopeSchema, listEnvelope } from './listEnvelope.js';
25
+ export {
26
+ listEnvelopeSchema,
27
+ listEnvelope,
28
+ CURSOR_PARAM,
29
+ CURSOR_PARAM_ALIAS,
30
+ CURSOR_PARAM_NAMES,
31
+ } from './listEnvelope.js';
26
32
  export type { ListEnvelope } from './listEnvelope.js';
27
33
 
28
34
  // The `GET /v1/logs` feed — the two arms, their envelope, and the cursor that
@@ -99,6 +105,8 @@ export {
99
105
  commitStatusSchema,
100
106
  commitWaitSchema,
101
107
  commitReceiptSchema,
108
+ commitOperationOutcomeSchema,
109
+ commitOperationResultSchema,
102
110
  rejectedCommitReceiptSchema,
103
111
  mutationResultPayloadSchema,
104
112
  mutationResultMessageSchema,
@@ -121,6 +129,7 @@ export {
121
129
  } from './commit.js';
122
130
  export type {
123
131
  CommitOperationBody,
132
+ CommitOperationResult,
124
133
  CommitActor,
125
134
  CommitAttempt,
126
135
  CommitClaimReference,
@@ -10,6 +10,29 @@
10
10
  */
11
11
  import { z } from 'zod';
12
12
 
13
+ /**
14
+ * The query parameter a caller resumes a collection with, and the single alias
15
+ * retained for it.
16
+ *
17
+ * Declared beside the envelope that issues `next_cursor`, because the parameter
18
+ * and the field it consumes are one contract and both planes read them: the
19
+ * server to know which names are taken, the spec generator to document them,
20
+ * the client to send one. When the name lived in each of those separately, this
21
+ * spec described `starting_after` for a model list and `cursor` for a commit
22
+ * record list — the same concept under two names, in one document.
23
+ *
24
+ * `starting_after` is the spelling used through 0.52.0. It borrowed a name whose
25
+ * established meaning elsewhere is a row id, while this value has always been an
26
+ * opaque token bound to the sort it was issued for.
27
+ */
28
+ export const CURSOR_PARAM = 'cursor';
29
+
30
+ /** @deprecated The pre-0.53.0 spelling of {@link CURSOR_PARAM}. */
31
+ export const CURSOR_PARAM_ALIAS = 'starting_after';
32
+
33
+ /** Both names a cursor may arrive under, for reserving them in a query string. */
34
+ export const CURSOR_PARAM_NAMES: readonly string[] = [CURSOR_PARAM, CURSOR_PARAM_ALIAS];
35
+
13
36
  /**
14
37
  * Builds the authoritative list-envelope schema for a row schema. Keeping the
15
38
  * item validator generic lets every endpoint share the same envelope contract
@@ -16,7 +16,7 @@
16
16
  * The lease is three ping intervals long and is renewed on every ping, so a
17
17
  * live holder always has at least two intervals of runway and a silent one
18
18
  * lapses about two missed pings after it stops renewing. The window measures
19
- * liveness, not how long a task may run: widening the lease without also
19
+ * liveness, not how long a item may run: widening the lease without also
20
20
  * widening the ping makes holders flap, and neither value should be redefined
21
21
  * anywhere else.
22
22
  */