@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.
Files changed (270) hide show
  1. package/CONVENTIONS.md +7 -7
  2. package/README.md +1 -1
  3. package/dist/ai-sdk/modelTools.d.ts +1 -1
  4. package/dist/ai-sdk/modelTools.js +1 -1
  5. package/dist/ai-sdk/updateTool.d.ts +2 -2
  6. package/dist/ai-sdk/updateTool.d.ts.map +1 -1
  7. package/dist/auth/bootstrapScope.d.ts +1 -1
  8. package/dist/auth/capability.d.ts +32 -10
  9. package/dist/auth/capability.d.ts.map +1 -1
  10. package/dist/auth/capability.js +9 -3
  11. package/dist/auth/capability.js.map +1 -1
  12. package/dist/auth/capabilityLifecycle.d.ts +2 -2
  13. package/dist/auth/capabilityLifecycle.d.ts.map +1 -1
  14. package/dist/auth/capabilityLifecycle.js +3 -2
  15. package/dist/auth/capabilityLifecycle.js.map +1 -1
  16. package/dist/auth/identity.d.ts +3 -0
  17. package/dist/auth/identity.d.ts.map +1 -1
  18. package/dist/auth/identity.js +13 -1
  19. package/dist/auth/identity.js.map +1 -1
  20. package/dist/auth/index.d.ts +2 -2
  21. package/dist/auth/index.d.ts.map +1 -1
  22. package/dist/auth/index.js +1 -1
  23. package/dist/auth/index.js.map +1 -1
  24. package/dist/auth/schemas.d.ts +18 -1
  25. package/dist/auth/schemas.d.ts.map +1 -1
  26. package/dist/auth/schemas.js +3 -1
  27. package/dist/auth/schemas.js.map +1 -1
  28. package/dist/auth/sessionMint.d.ts.map +1 -1
  29. package/dist/auth/sessionMint.js +0 -1
  30. package/dist/auth/sessionMint.js.map +1 -1
  31. package/dist/branches.d.ts +61 -12
  32. package/dist/branches.d.ts.map +1 -1
  33. package/dist/branches.js +25 -3
  34. package/dist/branches.js.map +1 -1
  35. package/dist/commitRecordRuntime.d.ts +30 -0
  36. package/dist/commitRecordRuntime.d.ts.map +1 -0
  37. package/dist/commitRecordRuntime.js +188 -0
  38. package/dist/commitRecordRuntime.js.map +1 -0
  39. package/dist/coordination/index.d.ts +3 -3
  40. package/dist/coordination/index.d.ts.map +1 -1
  41. package/dist/coordination/index.js +2 -2
  42. package/dist/coordination/index.js.map +1 -1
  43. package/dist/coordination/locator.d.ts +5 -0
  44. package/dist/coordination/locator.d.ts.map +1 -1
  45. package/dist/coordination/locator.js +12 -0
  46. package/dist/coordination/locator.js.map +1 -1
  47. package/dist/coordination/schema.d.ts +205 -15
  48. package/dist/coordination/schema.d.ts.map +1 -1
  49. package/dist/coordination/schema.js +88 -47
  50. package/dist/coordination/schema.js.map +1 -1
  51. package/dist/coordination/targetConflict.js +1 -1
  52. package/dist/durableWrites.d.ts +3 -3
  53. package/dist/durableWrites.d.ts.map +1 -1
  54. package/dist/durableWrites.js +1 -1
  55. package/dist/errorCodes.d.ts +35 -2
  56. package/dist/errorCodes.d.ts.map +1 -1
  57. package/dist/errorCodes.js +67 -19
  58. package/dist/errorCodes.js.map +1 -1
  59. package/dist/errorObservation.d.ts +82 -0
  60. package/dist/errorObservation.d.ts.map +1 -0
  61. package/dist/errorObservation.js +101 -0
  62. package/dist/errorObservation.js.map +1 -0
  63. package/dist/errors.d.ts +2 -0
  64. package/dist/errors.d.ts.map +1 -1
  65. package/dist/errors.js +6 -1
  66. package/dist/errors.js.map +1 -1
  67. package/dist/footprint.d.ts +10 -22
  68. package/dist/footprint.d.ts.map +1 -1
  69. package/dist/footprint.js +12 -24
  70. package/dist/footprint.js.map +1 -1
  71. package/dist/index.d.ts +5 -2
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +1 -1
  74. package/dist/index.js.map +1 -1
  75. package/dist/internal/read-set.d.ts +8 -0
  76. package/dist/internal/read-set.d.ts.map +1 -0
  77. package/dist/internal/read-set.js +7 -0
  78. package/dist/internal/read-set.js.map +1 -0
  79. package/dist/logger.d.ts +1 -1
  80. package/dist/observability.d.ts +1 -1
  81. package/dist/observability.js +1 -1
  82. package/dist/readSetContext.d.ts +54 -0
  83. package/dist/readSetContext.d.ts.map +1 -0
  84. package/dist/readSetContext.js +98 -0
  85. package/dist/readSetContext.js.map +1 -0
  86. package/dist/resources/functionalUpdate.d.ts +13 -3
  87. package/dist/resources/functionalUpdate.d.ts.map +1 -1
  88. package/dist/resources/functionalUpdate.js.map +1 -1
  89. package/dist/resources/httpResources.d.ts +23 -7
  90. package/dist/resources/httpResources.d.ts.map +1 -1
  91. package/dist/resources/modelOperations.d.ts +2 -2
  92. package/dist/resources/modelOperations.js +1 -1
  93. package/dist/resources/mutationOptions.d.ts +1 -1
  94. package/dist/resources/mutationOptions.js +1 -1
  95. package/dist/resources/where.d.ts +1 -1
  96. package/dist/resources/where.js +1 -1
  97. package/dist/resources/writeOptionsSchema.d.ts +39 -4
  98. package/dist/resources/writeOptionsSchema.d.ts.map +1 -1
  99. package/dist/resources/writeOptionsSchema.js +12 -6
  100. package/dist/resources/writeOptionsSchema.js.map +1 -1
  101. package/dist/schema/index.js +1 -1
  102. package/dist/schema/index.js.map +1 -1
  103. package/dist/schema/openapi.d.ts.map +1 -1
  104. package/dist/schema/openapi.js +45 -11
  105. package/dist/schema/openapi.js.map +1 -1
  106. package/dist/server/commit.d.ts +7 -1
  107. package/dist/server/commit.d.ts.map +1 -1
  108. package/dist/server/index.d.ts +1 -1
  109. package/dist/server/index.d.ts.map +1 -1
  110. package/dist/server/index.js +1 -1
  111. package/dist/server/index.js.map +1 -1
  112. package/dist/source/adapters/kysely.d.ts.map +1 -1
  113. package/dist/source/adapters/kysely.js +11 -4
  114. package/dist/source/adapters/kysely.js.map +1 -1
  115. package/dist/source/adapters/kyselyMutationCore.d.ts.map +1 -1
  116. package/dist/source/adapters/kyselyMutationCore.js +14 -2
  117. package/dist/source/adapters/kyselyMutationCore.js.map +1 -1
  118. package/dist/source/contract.d.ts +2 -0
  119. package/dist/source/contract.d.ts.map +1 -1
  120. package/dist/source/index.d.ts +1 -1
  121. package/dist/source/index.d.ts.map +1 -1
  122. package/dist/source/types.d.ts +1 -1
  123. package/dist/testing/fixtures/httpResponses.d.ts +30 -1
  124. package/dist/testing/fixtures/httpResponses.d.ts.map +1 -1
  125. package/dist/testing/fixtures/httpResponses.js +48 -1
  126. package/dist/testing/fixtures/httpResponses.js.map +1 -1
  127. package/dist/transactionLayer.d.ts +1 -1
  128. package/dist/transactions/{settlement → confirmation}/commitEnvelope.d.ts +4 -2
  129. package/dist/transactions/confirmation/commitEnvelope.d.ts.map +1 -0
  130. package/dist/transactions/{settlement → confirmation}/commitEnvelope.js +8 -3
  131. package/dist/transactions/confirmation/commitEnvelope.js.map +1 -0
  132. package/dist/transactions/confirmation/httpCommitEnvelope.d.ts.map +1 -0
  133. package/dist/transactions/confirmation/httpCommitEnvelope.js.map +1 -0
  134. package/dist/transactions/confirmation/idempotencyKey.d.ts.map +1 -0
  135. package/dist/transactions/confirmation/idempotencyKey.js.map +1 -0
  136. package/dist/transactions/{settlement → confirmation}/pendingWrite.d.ts +3 -2
  137. package/dist/transactions/confirmation/pendingWrite.d.ts.map +1 -0
  138. package/dist/transactions/confirmation/pendingWrite.js.map +1 -0
  139. package/dist/transport/commitFrames.d.ts +1 -0
  140. package/dist/transport/commitFrames.d.ts.map +1 -1
  141. package/dist/transport/commitFrames.js +8 -7
  142. package/dist/transport/commitFrames.js.map +1 -1
  143. package/dist/transport/connectionManager.d.ts +1 -1
  144. package/dist/transport/connectionManager.js +1 -1
  145. package/dist/transport/httpClient.d.ts +23 -9
  146. package/dist/transport/httpClient.d.ts.map +1 -1
  147. package/dist/transport/httpClient.js +134 -15
  148. package/dist/transport/httpClient.js.map +1 -1
  149. package/dist/transport/httpOptions.d.ts +9 -1
  150. package/dist/transport/httpOptions.d.ts.map +1 -1
  151. package/dist/transport/httpTransport.d.ts +3 -0
  152. package/dist/transport/httpTransport.d.ts.map +1 -1
  153. package/dist/transport/httpTransport.js +109 -22
  154. package/dist/transport/httpTransport.js.map +1 -1
  155. package/dist/transport/wsFrameHandlers.d.ts +3 -1
  156. package/dist/transport/wsFrameHandlers.d.ts.map +1 -1
  157. package/dist/transport/wsFrameHandlers.js +38 -17
  158. package/dist/transport/wsFrameHandlers.js.map +1 -1
  159. package/dist/transport/wsTransport.d.ts +3 -0
  160. package/dist/transport/wsTransport.d.ts.map +1 -1
  161. package/dist/transport/wsTransport.js +32 -1
  162. package/dist/transport/wsTransport.js.map +1 -1
  163. package/dist/utils/json.d.ts +1 -1
  164. package/dist/utils/json.js +1 -1
  165. package/dist/wire/accountResponses.d.ts +1 -1
  166. package/dist/wire/auth.d.ts +2 -2
  167. package/dist/wire/commit.d.ts +1652 -213
  168. package/dist/wire/commit.d.ts.map +1 -1
  169. package/dist/wire/commit.js +196 -132
  170. package/dist/wire/commit.js.map +1 -1
  171. package/dist/wire/delta.d.ts +1 -1
  172. package/dist/wire/errorEnvelope.d.ts +1 -0
  173. package/dist/wire/errorEnvelope.d.ts.map +1 -1
  174. package/dist/wire/errorEnvelope.js +1 -0
  175. package/dist/wire/errorEnvelope.js.map +1 -1
  176. package/dist/wire/feedCursor.d.ts +1 -1
  177. package/dist/wire/feedCursor.js +1 -1
  178. package/dist/wire/feedEvent.d.ts +3 -3
  179. package/dist/wire/frames.d.ts +8 -4
  180. package/dist/wire/frames.d.ts.map +1 -1
  181. package/dist/wire/frames.js +6 -3
  182. package/dist/wire/frames.js.map +1 -1
  183. package/dist/wire/inboundFrames.d.ts +44 -4
  184. package/dist/wire/inboundFrames.d.ts.map +1 -1
  185. package/dist/wire/index.d.ts +6 -4
  186. package/dist/wire/index.d.ts.map +1 -1
  187. package/dist/wire/index.js +6 -5
  188. package/dist/wire/index.js.map +1 -1
  189. package/dist/wire/modelMutations.d.ts +35 -0
  190. package/dist/wire/modelMutations.d.ts.map +1 -1
  191. package/dist/wire/modelMutations.js +9 -2
  192. package/dist/wire/modelMutations.js.map +1 -1
  193. package/dist/wire/modelResponses.d.ts +12 -1
  194. package/dist/wire/modelResponses.d.ts.map +1 -1
  195. package/dist/wire/modelResponses.js +12 -1
  196. package/dist/wire/modelResponses.js.map +1 -1
  197. package/package.json +12 -2
  198. package/src/ai-sdk/modelTools.ts +1 -1
  199. package/src/ai-sdk/updateTool.ts +2 -2
  200. package/src/auth/bootstrapScope.ts +1 -1
  201. package/src/auth/capability.ts +13 -4
  202. package/src/auth/capabilityLifecycle.ts +3 -2
  203. package/src/auth/identity.ts +16 -1
  204. package/src/auth/index.ts +2 -0
  205. package/src/auth/schemas.ts +3 -0
  206. package/src/auth/sessionMint.ts +0 -1
  207. package/src/branches.ts +27 -3
  208. package/src/commitRecordRuntime.ts +245 -0
  209. package/src/coordination/index.ts +24 -1
  210. package/src/coordination/locator.ts +17 -0
  211. package/src/coordination/schema.ts +114 -49
  212. package/src/coordination/targetConflict.ts +1 -1
  213. package/src/durableWrites.ts +3 -3
  214. package/src/errorCodes.ts +205 -25
  215. package/src/errorObservation.ts +121 -0
  216. package/src/errors.ts +5 -1
  217. package/src/footprint.ts +16 -27
  218. package/src/index.ts +8 -1
  219. package/src/internal/read-set.ts +18 -0
  220. package/src/logger.ts +1 -1
  221. package/src/observability.ts +1 -1
  222. package/src/readSetContext.ts +164 -0
  223. package/src/resources/functionalUpdate.ts +16 -4
  224. package/src/resources/httpResources.ts +27 -8
  225. package/src/resources/modelOperations.ts +2 -2
  226. package/src/resources/mutationOptions.ts +1 -1
  227. package/src/resources/where.ts +1 -1
  228. package/src/resources/writeOptionsSchema.ts +30 -12
  229. package/src/schema/index.ts +1 -1
  230. package/src/schema/openapi.ts +52 -11
  231. package/src/server/commit.ts +7 -1
  232. package/src/server/index.ts +5 -1
  233. package/src/source/adapters/kysely.ts +12 -4
  234. package/src/source/adapters/kyselyMutationCore.ts +14 -2
  235. package/src/source/index.ts +1 -1
  236. package/src/source/types.ts +1 -1
  237. package/src/testing/fixtures/httpResponses.ts +60 -1
  238. package/src/transactionLayer.ts +1 -1
  239. package/src/transactions/{settlement → confirmation}/commitEnvelope.ts +13 -3
  240. package/src/transport/commitFrames.ts +7 -5
  241. package/src/transport/connectionManager.ts +1 -1
  242. package/src/transport/httpClient.ts +256 -29
  243. package/src/transport/httpOptions.ts +9 -1
  244. package/src/transport/httpTransport.ts +139 -27
  245. package/src/transport/wsFrameHandlers.ts +46 -8
  246. package/src/transport/wsTransport.ts +42 -1
  247. package/src/utils/json.ts +1 -1
  248. package/src/wire/commit.ts +248 -147
  249. package/src/wire/errorEnvelope.ts +1 -0
  250. package/src/wire/feedCursor.ts +1 -1
  251. package/src/wire/frames.ts +9 -4
  252. package/src/wire/index.ts +38 -5
  253. package/src/wire/modelMutations.ts +16 -2
  254. package/src/wire/modelResponses.ts +14 -1
  255. package/dist/transactions/settlement/commitEnvelope.d.ts.map +0 -1
  256. package/dist/transactions/settlement/commitEnvelope.js.map +0 -1
  257. package/dist/transactions/settlement/httpCommitEnvelope.d.ts.map +0 -1
  258. package/dist/transactions/settlement/httpCommitEnvelope.js.map +0 -1
  259. package/dist/transactions/settlement/idempotencyKey.d.ts.map +0 -1
  260. package/dist/transactions/settlement/idempotencyKey.js.map +0 -1
  261. package/dist/transactions/settlement/pendingWrite.d.ts.map +0 -1
  262. package/dist/transactions/settlement/pendingWrite.js.map +0 -1
  263. /package/dist/transactions/{settlement → confirmation}/httpCommitEnvelope.d.ts +0 -0
  264. /package/dist/transactions/{settlement → confirmation}/httpCommitEnvelope.js +0 -0
  265. /package/dist/transactions/{settlement → confirmation}/idempotencyKey.d.ts +0 -0
  266. /package/dist/transactions/{settlement → confirmation}/idempotencyKey.js +0 -0
  267. /package/dist/transactions/{settlement → confirmation}/pendingWrite.js +0 -0
  268. /package/src/transactions/{settlement → confirmation}/httpCommitEnvelope.ts +0 -0
  269. /package/src/transactions/{settlement → confirmation}/idempotencyKey.ts +0 -0
  270. /package/src/transactions/{settlement → confirmation}/pendingWrite.ts +0 -0
@@ -0,0 +1,121 @@
1
+ import { z } from 'zod';
2
+
3
+ export const errorObservationSeveritySchema = z.enum([
4
+ 'debug', 'info', 'warning', 'error', 'fatal',
5
+ ]);
6
+
7
+ export const errorObservationChannelSchema = z.enum([
8
+ 'http', 'websocket', 'connector', 'background', 'process', 'cli', 'browser',
9
+ ]);
10
+
11
+ const TRUNCATION_MARKER = '…[truncated]';
12
+
13
+ /**
14
+ * Keep an observation field inside its wire bound without dropping the event.
15
+ * This lives beside the schema so producers cannot accidentally enforce a
16
+ * different limit. Redaction still happens before parsing at each boundary.
17
+ */
18
+ export function boundObservationString(value: string, maxLength: number): string {
19
+ if (value.length <= maxLength) return value;
20
+ return `${value.slice(0, maxLength - TRUNCATION_MARKER.length)}${TRUNCATION_MARKER}`;
21
+ }
22
+
23
+ const boundedString = (maxLength: number) =>
24
+ z.preprocess(
25
+ (value) => typeof value === 'string' ? boundObservationString(value, maxLength) : value,
26
+ z.string().max(maxLength),
27
+ );
28
+
29
+ const boundedCauseSchema = z.object({
30
+ type: boundedString(200),
31
+ message: boundedString(2_000),
32
+ });
33
+
34
+ /** Runtime-neutral private event vocabulary shared by every error boundary. */
35
+ export const errorObservationSchema = z.object({
36
+ eventId: boundedString(200).pipe(z.string().min(1)),
37
+ occurredAt: z.iso.datetime(),
38
+ service: boundedString(100).pipe(z.string().min(1)),
39
+ stage: boundedString(100).pipe(z.string().min(1)),
40
+ release: boundedString(200).optional(),
41
+ severity: errorObservationSeveritySchema,
42
+ channel: errorObservationChannelSchema,
43
+ scope: boundedString(200).pipe(z.string().min(1)),
44
+ operation: boundedString(300).pipe(z.string().min(1)),
45
+ errorCode: boundedString(200).pipe(z.string().min(1)),
46
+ errorType: boundedString(200).pipe(z.string().min(1)),
47
+ category: boundedString(100).pipe(z.string().min(1)),
48
+ retryable: z.boolean(),
49
+ /** Whether application code converted the failure into an expected outcome. */
50
+ handled: z.boolean(),
51
+ publicMessage: boundedString(2_000),
52
+ internalMessage: boundedString(4_000).optional(),
53
+ stack: boundedString(20_000).optional(),
54
+ httpStatus: z.number().int().min(100).max(599).optional(),
55
+ requestId: boundedString(200).optional(),
56
+ traceId: boundedString(200).optional(),
57
+ spanId: boundedString(200).optional(),
58
+ organizationId: boundedString(200).optional(),
59
+ projectId: boundedString(200).optional(),
60
+ branchId: boundedString(200).optional(),
61
+ keyKind: boundedString(100).optional(),
62
+ storageKind: boundedString(100).optional(),
63
+ storageTransport: boundedString(100).optional(),
64
+ dataSourceId: boundedString(200).optional(),
65
+ connectorState: boundedString(100).optional(),
66
+ model: boundedString(200).optional(),
67
+ cause: z.array(boundedCauseSchema).max(5).optional(),
68
+ diagnosticContext: z.record(z.string(), z.unknown()).optional(),
69
+ });
70
+
71
+ export type ErrorObservation = Readonly<z.infer<typeof errorObservationSchema>>;
72
+ export type ErrorObservationChannel = z.infer<typeof errorObservationChannelSchema>;
73
+ export type ErrorObservationSeverity = z.infer<typeof errorObservationSeveritySchema>;
74
+
75
+ const SENSITIVE_KEYS = [
76
+ 'password', 'secret', 'token', 'apikey', 'authorization', 'cookie',
77
+ 'databaseurl', 'connectionstring', 'ek', 'sk', 'rk', 'body', 'payload', 'sql', 'query',
78
+ ];
79
+ const MASK = '[redacted]';
80
+ const SECRET_PATTERNS = [
81
+ /postgres(?:ql)?:\/\/[^\s"']+/gi,
82
+ /\b[a-z]{2,4}_[A-Za-z0-9]{12,}\b/g,
83
+ ];
84
+
85
+ export function redactObservationString(value: string): string {
86
+ return SECRET_PATTERNS.reduce((current, pattern) => current.replace(pattern, MASK), value);
87
+ }
88
+
89
+ function isSensitiveObservationKey(key: string): boolean {
90
+ const normalized = key.toLowerCase().replace(/[^a-z]/g, '');
91
+ return SENSITIVE_KEYS.some(
92
+ (sensitive) => normalized === sensitive || (sensitive.length > 3 && normalized.includes(sensitive)),
93
+ );
94
+ }
95
+
96
+ /** Runtime-neutral, circular-safe sanitizer used before any observation sink. */
97
+ export function sanitizeObservationValue(
98
+ value: unknown,
99
+ depth = 0,
100
+ seen = new WeakSet(),
101
+ ): unknown {
102
+ if (depth > 6) return '[truncated]';
103
+ if (typeof value === 'string') return redactObservationString(value);
104
+ if (value && typeof value === 'object') {
105
+ if (seen.has(value)) return '[circular]';
106
+ seen.add(value);
107
+ }
108
+ if (Array.isArray(value)) {
109
+ return value.map((item) => sanitizeObservationValue(item, depth + 1, seen));
110
+ }
111
+ if (value && typeof value === 'object') {
112
+ const sanitized: Record<string, unknown> = {};
113
+ for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
114
+ sanitized[key] = isSensitiveObservationKey(key)
115
+ ? MASK
116
+ : sanitizeObservationValue(item, depth + 1, seen);
117
+ }
118
+ return sanitized;
119
+ }
120
+ return value;
121
+ }
package/src/errors.ts CHANGED
@@ -64,6 +64,8 @@ export class AbloError extends Error {
64
64
  * `x-request-id` header or a live commit's rejection frame. Include it in
65
65
  * support requests. */
66
66
  readonly requestId?: string;
67
+ /** Opaque id of the exact private observation associated with this error. */
68
+ readonly eventId?: string;
67
69
  /** The specific input that caused the error, as a model or field path such as
68
70
  * `'dataroomMember.grants.subject'`, so tooling can point at the exact
69
71
  * offending value. */
@@ -96,6 +98,7 @@ export class AbloError extends Error {
96
98
  if (options?.requestId !== undefined) this.requestId = options.requestId;
97
99
  if (options?.param !== undefined) this.param = options.param;
98
100
  if (options?.details !== undefined) this.details = options.details;
101
+ if (typeof options?.details?.event_id === 'string') this.eventId = options.details.event_id;
99
102
  const docUrl = options?.docUrl ?? (options?.code ? docUrlForCode(options.code) : undefined);
100
103
  if (docUrl !== undefined) this.docUrl = docUrl;
101
104
  if (options?.cause !== undefined) {
@@ -142,7 +145,8 @@ export class AbloError extends Error {
142
145
  const code = this.code ? ` [${this.code}]` : '';
143
146
  const docs = this.docUrl ? ` (see ${this.docUrl})` : '';
144
147
  const req = this.requestId ? ` [request_id: ${this.requestId}]` : '';
145
- return `${this.name}${code}: ${this.message}${docs}${req}`;
148
+ const event = this.eventId ? ` [event_id: ${this.eventId}]` : '';
149
+ return `${this.name}${code}: ${this.message}${docs}${req}${event}`;
146
150
  }
147
151
  }
148
152
 
package/src/footprint.ts CHANGED
@@ -51,25 +51,14 @@ export interface FootprintArtifact {
51
51
 
52
52
  // ── The names, for the code that creates and reads these objects ────────────
53
53
 
54
- /**
55
- * The publication Ablo's replication reads from. Constant by design: a
56
- * publication declares what streams, and several readers are meant to share one
57
- * (`publication_names` is a per-stream option, not slot state).
58
- */
54
+ /** Prefix used to derive a branch-scoped publication name. The exact unsuffixed
55
+ * name is retained only so `ablo connect scan` can identify an old installation. */
59
56
  export const ABLO_PUBLICATION = 'ablo_publication';
60
- /**
61
- * The replication slot that holds Ablo's position in the write-ahead log.
62
- *
63
- * Constant, and it should not be — a slot stores ONE position, so two
64
- * connections sharing this name compete for the same marker. It is why a
65
- * database can be connected to one plane at a time. ADR 0020 derives it per
66
- * connection; {@link isValidReplicationSlotName} is the check a derived name
67
- * has to pass.
68
- */
57
+ /** Prefix used to derive the branch-scoped replication slot. */
69
58
  export const ABLO_REPLICATION_SLOT = 'ablo_slot';
70
- /** The least-privilege login Ablo reads with. Per-connection under ADR 0020. */
59
+ /** Prefix used to derive the branch-scoped least-privilege replication login. */
71
60
  export const ABLO_REPLICATION_ROLE = 'ablo_replicator';
72
- /** The separate least-privilege login used only for row writes. */
61
+ /** Prefix used to derive the branch-scoped login used only for row writes. */
73
62
  export const ABLO_WRITE_ROLE = 'ablo_writer';
74
63
  /** The bookkeeping table that makes a retried write land once. */
75
64
  export const ABLO_IDEMPOTENCY_TABLE = 'ablo_idempotency';
@@ -90,15 +79,15 @@ export function isValidReplicationSlotName(name: string): boolean {
90
79
 
91
80
  // ── Per-connection names (ADR 0020) ─────────────────────────────────────────
92
81
 
93
- /** The immutable branch coordinates a connection is identified by. */
94
- export interface FootprintPlane {
82
+ /** The immutable branch coordinates that identify one customer Data Source. */
83
+ export interface DataSourceIdentity {
95
84
  readonly organizationId: string;
96
85
  readonly branchId: string;
97
86
  /** Omitted for the organization-default project. */
98
87
  readonly projectId?: string;
99
88
  }
100
89
 
101
- /** The names one connection owns. Nothing here is shared with another plane. */
90
+ /** The names one connection owns. Nothing here is shared with another Data Source. */
102
91
  export interface FootprintNames {
103
92
  readonly slot: string;
104
93
  readonly publication: string;
@@ -114,7 +103,7 @@ export interface FootprintNames {
114
103
  const SUFFIX_LENGTH = 16;
115
104
 
116
105
  /**
117
- * FNV-1a over the plane, in hex.
106
+ * FNV-1a over the Data Source identity, in hex.
118
107
  *
119
108
  * Deliberately not a cryptographic hash: this module is imported by the CLI,
120
109
  * which runs in environments without `node:crypto` guaranteed, and the property
@@ -123,13 +112,14 @@ const SUFFIX_LENGTH = 16;
123
112
  * over different seeds give the sixteen hex characters, which is ample for the
124
113
  * handful of planes any one database is ever connected to.
125
114
  */
126
- function planeDigest(plane: FootprintPlane): string {
115
+ function dataSourceDigest(identity: DataSourceIdentity): string {
127
116
  // The organization-default project may be omitted or repeated as the
128
117
  // organization id; both spell the same branch coordinates.
129
- const project = plane.projectId === plane.organizationId ? '' : (plane.projectId ?? '');
118
+ const project =
119
+ identity.projectId === identity.organizationId ? '' : (identity.projectId ?? '');
130
120
  // Delimit the coordinates. Concatenation alone makes structurally different
131
121
  // planes such as ("ab", "c") and ("a", "bc") hash the same input.
132
- const key = [plane.organizationId, project, plane.branchId].join('\0');
122
+ const key = [identity.organizationId, project, identity.branchId].join('\0');
133
123
 
134
124
  const round = (seed: number): string => {
135
125
  let hash = seed;
@@ -148,16 +138,15 @@ function planeDigest(plane: FootprintPlane): string {
148
138
  * The objects this connection owns, named so no other connection can claim them.
149
139
  *
150
140
  * A slot stores ONE position, so two connections sharing a name compete for the
151
- * same marker and Postgres reports nothing which is why the constants these
152
- * replace made a database connectable to one plane at a time. The publication
141
+ * same marker and Postgres reports nothing. The publication
153
142
  * and roles are derived from the same digest so a database's footprint reads as
154
143
  * one set per connection rather than a mix of shared and private objects.
155
144
  *
156
145
  * Stable: the same plane always derives the same names, so re-running setup is a
157
146
  * no-op rather than a second installation.
158
147
  */
159
- export function footprintNamesFor(plane: FootprintPlane): FootprintNames {
160
- const suffix = planeDigest(plane);
148
+ export function footprintNamesFor(identity: DataSourceIdentity): FootprintNames {
149
+ const suffix = dataSourceDigest(identity);
161
150
  const names: FootprintNames = {
162
151
  slot: `${ABLO_REPLICATION_SLOT}_${suffix}`,
163
152
  publication: `${ABLO_PUBLICATION}_${suffix}`,
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The Ablo settlement core (ADR 0013).
2
+ * The Ablo confirmation core (ADR 0013).
3
3
  *
4
4
  * The transaction layer that the reactive client is a consumer of, not the
5
5
  * other way round. The root barrel is deliberate: it exports the seam —
@@ -31,8 +31,15 @@ export { Ablo } from './ablo.js';
31
31
  export type {
32
32
  AbloHttpClient,
33
33
  AbloHttpClientOptions,
34
+ CapturedRow,
34
35
  HttpModelClient,
36
+ HttpModelMutationParams,
35
37
  } from './transport/httpClient.js';
38
+ export type {
39
+ FunctionalUpdateOptions,
40
+ /** @deprecated Use `FunctionalUpdateOptions`. */
41
+ ContentionOptions,
42
+ } from './resources/functionalUpdate.js';
36
43
 
37
44
  // The types the seam's signatures reference.
38
45
  export type {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Package-private ReadSet integration seam used by the reactive materialiser.
3
+ * Application code declares dependencies through `reads: [returnedRow]`.
4
+ */
5
+ export {
6
+ abortReadSetCommit,
7
+ capturePointRead,
8
+ createReadSetContext,
9
+ commitRecordIdentity,
10
+ consumeReadSet,
11
+ prepareReadSet,
12
+ publishCommitRecord,
13
+ } from '../readSetContext.js';
14
+ export { recordWebSocketCommitReceipt } from '../commitRecordRuntime.js';
15
+ export type {
16
+ PreparedReadSet,
17
+ ReadSetContext,
18
+ } from '../readSetContext.js';
package/src/logger.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * A contract with no framework and no local state: credential exchange, commit,
5
5
  * and claim all need to log with no UI and no offline store present, so the port
6
- * belongs to the settlement core (ADR 0016). The consumer supplies the
6
+ * belongs to the confirmation core (ADR 0016). The consumer supplies the
7
7
  * implementation; the SDK ships a no-op default.
8
8
  */
9
9
  export interface Logger {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The observability the settlement core reports on its own behalf.
2
+ * The observability the confirmation core reports on its own behalf.
3
3
  *
4
4
  * Coordination outcomes — a claim changing state, a stale-write collision that
5
5
  * notified instead of aborting — happen with no UI and no local store anywhere,
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Client-local opaque evidence for rows returned by authoritative reads.
3
+ *
4
+ * The name is retained internally to avoid churn across the two transports,
5
+ * but this is not an execution context: it has no async carrier and no ambient
6
+ * scope. Evidence is keyed only by the exact object returned to the caller.
7
+ */
8
+ import {
9
+ readDependencySchema,
10
+ type CommitReadSetEntry,
11
+ type OnStaleMode,
12
+ type ReadDependency,
13
+ } from './coordination/schema.js';
14
+ import { AbloValidationError } from './errors.js';
15
+ import type { CommitRecord } from './wire/commit.js';
16
+
17
+ type ClientIdentity = object;
18
+
19
+ /** @internal One exact returned-row assertion. */
20
+ export interface CapturedReadEvidence {
21
+ readonly client: ClientIdentity;
22
+ readonly entry: CommitReadSetEntry;
23
+ readonly row: object;
24
+ }
25
+
26
+ /** @internal Per-client registry. Weak keys do not retain application rows. */
27
+ export interface ReadRegistry {
28
+ readonly byRow: WeakMap<object, CapturedReadEvidence>;
29
+ readonly commitRecords: Map<string, CommitRecord>;
30
+ onCommitRecord?: (record: CommitRecord) => void | Promise<void>;
31
+ }
32
+
33
+ /** @internal Client-local evidence registry handle. */
34
+ export interface ReadSetContext {
35
+ getStore(): ReadRegistry;
36
+ }
37
+
38
+ export interface PreparedReadSet {
39
+ readonly readAt?: number;
40
+ readonly onStale?: OnStaleMode;
41
+ readonly reads?: readonly ReadDependency[] | null;
42
+ readonly consumed: readonly CapturedReadEvidence[];
43
+ readonly automaticCommit: false;
44
+ readonly idempotencyKey?: string;
45
+ }
46
+
47
+ /** @internal Creates one isolated evidence registry for one Ablo client. */
48
+ export function createReadSetContext(options?: {
49
+ readonly onCommitRecord?: (record: CommitRecord) => void | Promise<void>;
50
+ }): ReadSetContext {
51
+ const registry: ReadRegistry = {
52
+ byRow: new WeakMap(),
53
+ commitRecords: new Map(),
54
+ ...(options?.onCommitRecord ? { onCommitRecord: options.onCommitRecord } : {}),
55
+ };
56
+ return { getStore: () => registry };
57
+ }
58
+
59
+ /** @internal Retains and reports one immutable logical commit snapshot. */
60
+ export function publishCommitRecord(
61
+ context: ReadSetContext | undefined,
62
+ record: CommitRecord,
63
+ ): void {
64
+ const registry = context?.getStore();
65
+ if (!registry) return;
66
+ registry.commitRecords.set(record.id, record);
67
+ try {
68
+ const observed = registry.onCommitRecord?.(record);
69
+ if (observed) void Promise.resolve(observed).catch(() => undefined);
70
+ } catch {
71
+ // Observability must never change a commit's outcome.
72
+ }
73
+ }
74
+
75
+ /** @internal Associates evidence with the exact row object returned to a caller. */
76
+ export function capturePointRead(
77
+ context: ReadSetContext | undefined,
78
+ client: ClientIdentity,
79
+ model: string,
80
+ id: string,
81
+ row: unknown,
82
+ readAt: number,
83
+ ): void {
84
+ if (!context || typeof row !== 'object' || row === null) return;
85
+ const rowObject = row as object;
86
+ context.getStore().byRow.set(rowObject, {
87
+ client,
88
+ row: rowObject,
89
+ entry: {
90
+ target: { scope: 'row', model, id },
91
+ watermark: readAt,
92
+ lifetime: 'commit',
93
+ onStale: 'reject',
94
+ },
95
+ });
96
+ }
97
+
98
+ /** @internal Resolves only dependencies explicitly supplied through `reads`. */
99
+ export function prepareReadSet(
100
+ context: ReadSetContext | undefined,
101
+ client: ClientIdentity,
102
+ explicitReadAt: number | null | undefined,
103
+ explicitOnStale: OnStaleMode | null | undefined,
104
+ explicitIdempotencyKey: string | null | undefined,
105
+ reads: readonly unknown[] | null | undefined,
106
+ ): PreparedReadSet {
107
+ const registry = context?.getStore();
108
+ const consumed: CapturedReadEvidence[] = [];
109
+ const resolvedReads: ReadDependency[] = [];
110
+
111
+ for (const entry of reads ?? []) {
112
+ const captured =
113
+ registry && typeof entry === 'object' && entry !== null
114
+ ? registry.byRow.get(entry)
115
+ : undefined;
116
+ if (captured?.client === client) {
117
+ const target = captured.entry.target;
118
+ if (target.scope !== 'row') {
119
+ throw new AbloValidationError('Captured read evidence must name a row.', {
120
+ code: 'write_options_invalid', param: 'reads',
121
+ });
122
+ }
123
+ resolvedReads.push({
124
+ model: target.model,
125
+ id: target.id,
126
+ readAt: captured.entry.watermark,
127
+ });
128
+ consumed.push(captured);
129
+ continue;
130
+ }
131
+ const canonical = readDependencySchema.safeParse(entry);
132
+ if (canonical.success) {
133
+ resolvedReads.push(canonical.data);
134
+ continue;
135
+ }
136
+ throw new AbloValidationError(
137
+ 'A row passed through `reads` was not the exact object returned by this Ablo client. Re-read it and pass that object directly.',
138
+ { code: 'write_options_invalid', param: 'reads' },
139
+ );
140
+ }
141
+
142
+ return {
143
+ ...(explicitReadAt != null ? { readAt: explicitReadAt } : {}),
144
+ ...(explicitOnStale != null ? { onStale: explicitOnStale } : {}),
145
+ ...(reads !== undefined ? { reads: reads === null ? null : resolvedReads } : {}),
146
+ consumed,
147
+ automaticCommit: false,
148
+ ...(explicitIdempotencyKey != null ? { idempotencyKey: explicitIdempotencyKey } : {}),
149
+ };
150
+ }
151
+
152
+ /** @internal Commit identity is the explicit request idempotency identity. */
153
+ export function commitRecordIdentity(
154
+ _context: ReadSetContext | undefined,
155
+ attemptId: string,
156
+ ): { readonly id: string } {
157
+ return { id: attemptId };
158
+ }
159
+
160
+ /** @internal Explicit row evidence is reusable; successful writes do not consume it. */
161
+ export function consumeReadSet(..._args: readonly unknown[]): void {}
162
+
163
+ /** @internal There is no ambient automatic-commit reservation to release. */
164
+ export function abortReadSetCommit(..._args: readonly unknown[]): void {}
@@ -28,6 +28,7 @@ import {
28
28
  AbloClaimedError,
29
29
  AbloContentionError,
30
30
  } from '../errors.js';
31
+ import type { ReadDependency } from '../coordination/schema.js';
31
32
 
32
33
  /**
33
34
  * The functional form of an update: given the freshly-read row, return the
@@ -38,8 +39,8 @@ export type ModelUpdater<T> = (
38
39
  current: T,
39
40
  ) => Partial<T> | null | undefined | Promise<Partial<T> | null | undefined>;
40
41
 
41
- /** Tuning for the functional update's internal reconcile loop. */
42
- export interface ContentionOptions {
42
+ /** Options for the functional `update(id, reducer, options)` form. */
43
+ export interface FunctionalUpdateOptions<Dependency = ReadDependency> {
43
44
  /**
44
45
  * Max reconcile rounds under contention before throwing
45
46
  * {@link AbloContentionError}. Each round re-reads the latest row and re-runs
@@ -48,8 +49,19 @@ export interface ContentionOptions {
48
49
  readonly retries?: number;
49
50
  /** Abort the reconcile loop (e.g. the request was cancelled). */
50
51
  readonly signal?: AbortSignal;
52
+ /**
53
+ * Cross-target state this reducer decision depends on. Captured point rows
54
+ * are resolved by the public client; canonical dependencies remain the
55
+ * low-level escape hatch. Dependencies survive reconcilable CAS failures and
56
+ * are consumed only with the successful attempt.
57
+ */
58
+ readonly reads?: readonly Dependency[] | null;
51
59
  }
52
60
 
61
+ /** @deprecated Use {@link FunctionalUpdateOptions}. */
62
+ export type ContentionOptions<Dependency = ReadDependency> =
63
+ FunctionalUpdateOptions<Dependency>;
64
+
53
65
  /** Reconcile rounds before a hot row is declared permanently contended. */
54
66
  export const DEFAULT_CONTENTION_RETRIES = 16;
55
67
 
@@ -104,9 +116,9 @@ export interface ReconcileTransport<T, R> {
104
116
  * both transports so the guarantee is provably identical. Returns the write's
105
117
  * result, or `undefined` when the updater opted out of writing.
106
118
  */
107
- export async function reconcileFunctionalUpdate<T, R>(
119
+ export async function reconcileFunctionalUpdate<T, R, Read = ReadDependency>(
108
120
  updater: ModelUpdater<T>,
109
- options: ContentionOptions | undefined,
121
+ options: FunctionalUpdateOptions<Read> | undefined,
110
122
  transport: ReconcileTransport<T, R>,
111
123
  ): Promise<R | undefined> {
112
124
  const retries = options?.retries ?? DEFAULT_CONTENTION_RETRIES;
@@ -15,14 +15,19 @@ import type { ClaimHeartbeatReply, ClaimState } from '../wire/claims.js';
15
15
  import type {
16
16
  ClientCommitReceipt,
17
17
  CommitWait,
18
+ CommitRecord,
19
+ CommitRecordList,
20
+ CommitRecordListOptions,
21
+ CommitRecordWhere,
18
22
  } from '../wire/commit.js';
19
23
  import type { LogListResponse, LogQuery } from '../wire/feedEvent.js';
20
- // Re-exported, not redeclared. `wire/commit.ts` owns the settlement vocabulary
24
+ import type { ModelListEvidence } from '../wire/modelResponses.js';
25
+ // Re-exported, not redeclared. `wire/commit.ts` owns the commit-status vocabulary
21
26
  // and derives the waitable subset from it; this module serves that name to SDK
22
27
  // consumers. Restating the subset here as its own union produced a type that
23
28
  // matched the canonical one only by both happening to list the same two
24
29
  // strings — and would have silently disagreed with the runtime `wait`
25
- // validator the moment a third settlement state existed.
30
+ // validator the moment a third commit status existed.
26
31
  export type { CommitWait };
27
32
  // `ModelTarget` (the `model` and `id` locator) and `ModelClaim` (the resolved
28
33
  // claim view) are defined in `../coordination/schema`, derived from a single
@@ -39,7 +44,7 @@ import type { SyncGroupInput } from '../schema/roles.js';
39
44
  import type {
40
45
  CapabilityCan,
41
46
  CapabilityOperation,
42
- CapabilityScope,
47
+ EffectiveAuthority,
43
48
  } from '../auth/capability.js';
44
49
  import type {
45
50
  Claim,
@@ -48,7 +53,7 @@ import type {
48
53
  Duration,
49
54
  HeldClaim,
50
55
  } from '../types/streams.js';
51
- import type { ModelUpdater, ContentionOptions } from './functionalUpdate.js';
56
+ import type { ModelUpdater, FunctionalUpdateOptions } from './functionalUpdate.js';
52
57
  import type {
53
58
  ClaimOptions,
54
59
  ClaimAttemptEvent,
@@ -93,6 +98,12 @@ export interface HttpTransportRead<T = Record<string, unknown>> {
93
98
  readonly claims: readonly ModelClaim[];
94
99
  }
95
100
 
101
+ /** @internal Exact collection envelope retained until the typed facade captures evidence. */
102
+ export interface HttpTransportList<T = Record<string, unknown>> {
103
+ readonly data: readonly T[];
104
+ readonly evidence?: readonly ModelListEvidence[];
105
+ }
106
+
96
107
  export type IfClaimedPolicy = 'return' | 'fail';
97
108
 
98
109
  export interface ClaimedOptions {
@@ -160,6 +171,8 @@ export interface CommitOperationInput {
160
171
  readonly id?: string | null;
161
172
  readonly data?: Record<string, unknown> | null;
162
173
  readonly transactionId?: string | null;
174
+ /** Claim identity derived from a held claim; not an application id. */
175
+ readonly claimId?: string | null;
163
176
  readonly readAt?: number | null;
164
177
  readonly onStale?: OnStaleMode | null;
165
178
  /** Fencing token (Option B) from the batch's claim handle; server-validated. */
@@ -207,6 +220,8 @@ export type CommitReceipt = ClientCommitReceipt;
207
220
 
208
221
  export interface CommitResource {
209
222
  create(options: CommitCreateOptions): Promise<CommitReceipt>;
223
+ get(options: { readonly id: string }): Promise<CommitRecord | null>;
224
+ list(options?: CommitRecordListOptions): Promise<CommitRecordList>;
210
225
  }
211
226
 
212
227
  export interface HttpLogListOptions
@@ -276,6 +291,10 @@ export interface ModelMutationOptions extends ClaimedOptions {
276
291
  readonly idempotencyKey?: string | null;
277
292
  readonly readAt?: number | null;
278
293
  readonly onStale?: OnStaleMode | null;
294
+ /** Commit-lifetime read dependencies checked before this mutation lands. */
295
+ readonly reads?: readonly ReadDependency[] | null;
296
+ /** Persisted read dependencies registered by this mutation. */
297
+ readonly track?: readonly TrackDependency[] | null;
279
298
  readonly claim?: Claim | ClaimOptions | null;
280
299
  /** Fencing token (Option B) from the claim; server-validated at commit. */
281
300
  readonly fenceToken?: number | null;
@@ -332,7 +351,7 @@ export interface HttpTransportModel<
332
351
  * and `limit`. The typed public client always exposes `ablo.<model>.list`;
333
352
  * this protocol shape is private transport machinery.
334
353
  */
335
- list(options?: ServerReadOptions<T>): Promise<T[]>;
354
+ list(options?: ServerReadOptions<T>): Promise<HttpTransportList<T>>;
336
355
  /**
337
356
  * Creates a row and returns the confirmed server row, including framework
338
357
  * defaults such as `createdAt` and `createdBy`. Matches the stateful client's
@@ -354,7 +373,7 @@ export interface HttpTransportModel<
354
373
  update(
355
374
  id: string,
356
375
  updater: ModelUpdater<T>,
357
- options?: ContentionOptions,
376
+ options?: FunctionalUpdateOptions,
358
377
  ): Promise<CommitReceipt | undefined>;
359
378
  delete(params: ModelMutationOptions & { readonly id: string }): Promise<CommitReceipt>;
360
379
  /**
@@ -475,7 +494,7 @@ export interface AbloSession {
475
494
  organizationId: string;
476
495
  /** The grant this token carries, on both axes — the same shape the key row
477
496
  * stores and the gates enforce. */
478
- scope: CapabilityScope;
497
+ scope: EffectiveAuthority;
479
498
  userMeta: Record<string, unknown>;
480
499
  }
481
500
 
@@ -492,7 +511,7 @@ export interface SessionRotation {
492
511
  token: string;
493
512
  expiresAt: string | null;
494
513
  organizationId: string;
495
- scope: CapabilityScope;
514
+ scope: EffectiveAuthority;
496
515
  rotatedFrom: {
497
516
  id: string;
498
517
  expiresAt: string;
@@ -3,7 +3,7 @@
3
3
  * caller passes to a read, a write, or a claim.
4
4
  *
5
5
  * These types describe the *change or the query being requested*, never a local
6
- * copy of the rows it touches, so they sit in the settlement core and are shared
6
+ * copy of the rows it touches, so they sit in the commit core and are shared
7
7
  * by every transport and every caller (ADR 0013 §4, ADR 0016). The factory that
8
8
  * binds them to reactive model instances — `createModelProxy` — stays with the
9
9
  * reactive consumer, along with `ModelOperations` and `ModelCollaboration`,
@@ -562,7 +562,7 @@ export interface ModelRetrieveParams extends ServerRetrieveOptions {
562
562
  * Options shared by schema model writes.
563
563
  *
564
564
  * Reactive clients apply the row change optimistically before returning from
565
- * the call. The returned promise has one stable settlement contract across
565
+ * the call. The returned promise has one stable confirmation contract across
566
566
  * reactive and stateless clients: it resolves only after authoritative
567
567
  * confirmation. Callers that need an earlier queued receipt use the lower-level
568
568
  * `commits.create` resource instead.
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Every field here defines, orders, settles, or authorises *the change itself*
5
5
  * — request identity, commit disposition, fencing, and the premise it rests on.
6
- * None of it touches a local copy of rows, so it belongs with the settlement
6
+ * None of it touches a local copy of rows, so it belongs with the commit
7
7
  * core rather than the reactive consumer (ADR 0013 §4, ADR 0016).
8
8
  */
9
9
 
@@ -10,7 +10,7 @@
10
10
  * key — for example, fetching every block whose `sectionId` falls in a set of ids.
11
11
  *
12
12
  * These types describe the *request*, not any local copy of the rows it returns,
13
- * so they live with the settlement core rather than the reactive consumer.
13
+ * so they live with the commit core rather than the reactive consumer.
14
14
  */
15
15
 
16
16
  import { z } from 'zod';