@abloatai/transaction 0.39.0 → 0.41.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 (110) hide show
  1. package/dist/auth/index.d.ts +12 -3
  2. package/dist/auth/index.d.ts.map +1 -1
  3. package/dist/auth/index.js +14 -6
  4. package/dist/auth/index.js.map +1 -1
  5. package/dist/auth/schemas.d.ts +1 -0
  6. package/dist/auth/schemas.d.ts.map +1 -1
  7. package/dist/auth/schemas.js +10 -2
  8. package/dist/auth/schemas.js.map +1 -1
  9. package/dist/coordination/events.d.ts +9 -0
  10. package/dist/coordination/events.d.ts.map +1 -1
  11. package/dist/coordination/index.d.ts +2 -2
  12. package/dist/coordination/index.d.ts.map +1 -1
  13. package/dist/coordination/index.js +1 -1
  14. package/dist/coordination/index.js.map +1 -1
  15. package/dist/coordination/schema.d.ts +226 -34
  16. package/dist/coordination/schema.d.ts.map +1 -1
  17. package/dist/coordination/schema.js +180 -48
  18. package/dist/coordination/schema.js.map +1 -1
  19. package/dist/coordination/trace.d.ts.map +1 -1
  20. package/dist/coordination/trace.js +9 -1
  21. package/dist/coordination/trace.js.map +1 -1
  22. package/dist/errorCodes.d.ts +5 -0
  23. package/dist/errorCodes.d.ts.map +1 -1
  24. package/dist/errorCodes.js +10 -1
  25. package/dist/errorCodes.js.map +1 -1
  26. package/dist/errors.d.ts.map +1 -1
  27. package/dist/errors.js +9 -2
  28. package/dist/errors.js.map +1 -1
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +3 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/policy/types.d.ts +10 -2
  34. package/dist/policy/types.d.ts.map +1 -1
  35. package/dist/policy/types.js.map +1 -1
  36. package/dist/pricing.d.ts +194 -0
  37. package/dist/pricing.d.ts.map +1 -0
  38. package/dist/pricing.js +330 -0
  39. package/dist/pricing.js.map +1 -0
  40. package/dist/resources/functionalUpdate.d.ts.map +1 -1
  41. package/dist/resources/functionalUpdate.js +8 -8
  42. package/dist/resources/functionalUpdate.js.map +1 -1
  43. package/dist/schema/index.d.ts +1 -1
  44. package/dist/schema/index.d.ts.map +1 -1
  45. package/dist/schema/index.js +1 -1
  46. package/dist/schema/index.js.map +1 -1
  47. package/dist/schema/roles.d.ts +19 -0
  48. package/dist/schema/roles.d.ts.map +1 -1
  49. package/dist/schema/roles.js +23 -3
  50. package/dist/schema/roles.js.map +1 -1
  51. package/dist/schema/schema.d.ts +1 -1
  52. package/dist/schema/schema.d.ts.map +1 -1
  53. package/dist/schema/schema.js +1 -1
  54. package/dist/schema/schema.js.map +1 -1
  55. package/dist/schema/tenancy.d.ts +1 -1
  56. package/dist/transactions/settlement/commitEnvelope.d.ts +10 -2
  57. package/dist/transactions/settlement/commitEnvelope.d.ts.map +1 -1
  58. package/dist/transactions/settlement/pendingWrite.d.ts +10 -2
  59. package/dist/transactions/settlement/pendingWrite.d.ts.map +1 -1
  60. package/dist/transport/wsFrameHandlers.d.ts.map +1 -1
  61. package/dist/transport/wsFrameHandlers.js +9 -3
  62. package/dist/transport/wsFrameHandlers.js.map +1 -1
  63. package/dist/wire/accountResponses.d.ts +100 -0
  64. package/dist/wire/accountResponses.d.ts.map +1 -1
  65. package/dist/wire/accountResponses.js +70 -0
  66. package/dist/wire/accountResponses.js.map +1 -1
  67. package/dist/wire/auth.d.ts +1 -0
  68. package/dist/wire/auth.d.ts.map +1 -1
  69. package/dist/wire/auth.js +16 -4
  70. package/dist/wire/auth.js.map +1 -1
  71. package/dist/wire/commit.d.ts +708 -100
  72. package/dist/wire/commit.d.ts.map +1 -1
  73. package/dist/wire/dataSourceResponses.d.ts +171 -0
  74. package/dist/wire/dataSourceResponses.d.ts.map +1 -0
  75. package/dist/wire/dataSourceResponses.js +168 -0
  76. package/dist/wire/dataSourceResponses.js.map +1 -0
  77. package/dist/wire/frames.d.ts +20 -4
  78. package/dist/wire/frames.d.ts.map +1 -1
  79. package/dist/wire/inboundFrames.d.ts +102 -14
  80. package/dist/wire/inboundFrames.d.ts.map +1 -1
  81. package/dist/wire/index.d.ts +4 -2
  82. package/dist/wire/index.d.ts.map +1 -1
  83. package/dist/wire/index.js +5 -1
  84. package/dist/wire/index.js.map +1 -1
  85. package/dist/wire/pricing.d.ts +43 -0
  86. package/dist/wire/pricing.d.ts.map +1 -0
  87. package/dist/wire/pricing.js +36 -0
  88. package/dist/wire/pricing.js.map +1 -0
  89. package/package.json +6 -1
  90. package/src/auth/index.ts +26 -9
  91. package/src/auth/schemas.ts +14 -3
  92. package/src/coordination/events.ts +9 -0
  93. package/src/coordination/index.ts +8 -0
  94. package/src/coordination/schema.ts +200 -51
  95. package/src/coordination/trace.ts +9 -1
  96. package/src/errorCodes.ts +30 -1
  97. package/src/errors.ts +9 -2
  98. package/src/index.ts +4 -0
  99. package/src/policy/types.ts +10 -2
  100. package/src/pricing.ts +350 -0
  101. package/src/resources/functionalUpdate.ts +11 -11
  102. package/src/schema/index.ts +2 -0
  103. package/src/schema/roles.ts +26 -3
  104. package/src/schema/schema.ts +2 -0
  105. package/src/transport/wsFrameHandlers.ts +9 -3
  106. package/src/wire/accountResponses.ts +76 -0
  107. package/src/wire/auth.ts +19 -4
  108. package/src/wire/dataSourceResponses.ts +188 -0
  109. package/src/wire/index.ts +33 -0
  110. package/src/wire/pricing.ts +41 -0
@@ -74,7 +74,11 @@ export { fieldTypeSchema, fieldMetaSchema, relationTypeSchema, relationMetaSchem
74
74
  export { modelMutationRequestSchema } from './modelMutations.js';
75
75
  // The account routes' responses — projects, the deployed schema, the commit
76
76
  // log, usage. What the server, the CLI, and the MCP server agree on.
77
- export { projectResponseSchema, projectListResponseSchema, provisionedKeySchema, provisionKeyResponseSchema, conflictAxisWireSchema, schemaModelResponseSchema, schemaReadResponseSchema, logOpSchema, LOG_OP_BY_ACTION, logEventSchema, usageBucketSchema, usageReportResponseSchema, controlKeySchema, controlKeyListResponseSchema, keyMintedResponseSchema, keyRevokedResponseSchema, } from './accountResponses.js';
77
+ export { projectResponseSchema, projectListResponseSchema, provisionedKeySchema, provisionKeyResponseSchema, conflictAxisWireSchema, schemaModelResponseSchema, schemaReadResponseSchema, logOpSchema, LOG_OP_BY_ACTION, logEventSchema, usageBucketSchema, usageReportResponseSchema, meterUsageSchema, billingSummarySchema, usageSummaryResponseSchema, controlKeySchema, controlKeyListResponseSchema, keyMintedResponseSchema, keyRevokedResponseSchema, } from './accountResponses.js';
78
+ // The datasource routes' responses — the `ablo connect` surface: register,
79
+ // validate, locate, list, deregister. What the server, the CLI, and the
80
+ // dashboard agree on.
81
+ export { READINESS_ITEMS, READINESS_ADVISORY_ITEMS, isReadinessItem, readinessFailureSchema, readinessAdvisorySchema, datasourceSummarySchema, datasourceListResponseSchema, datasourceValidationResponseSchema, datasourceLocationResponseSchema, datasourceDisconnectedResponseSchema, } from './dataSourceResponses.js';
78
82
  // The inbound socket surface: every frame the server can send, and how each
79
83
  // one's payload is validated.
80
84
  export { WS_INBOUND_FRAMES, wsInboundEnvelopeSchema, isKnownInboundFrame, isSchemaValidatedFrame, } from './inboundFrames.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wire/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wire/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * The pricing vocabulary that crosses the wire: the tier names, the meter
3
+ * names, and the shape of one rate-card step. Account responses carry these,
4
+ * so they live in the dependency-free wire layer; the pricing contract
5
+ * (`../pricing.ts`) derives the rate card, the plans, and the bill arithmetic
6
+ * from them and re-exports them for its consumers.
7
+ */
8
+ import { z } from 'zod';
9
+ export declare const planTierSchema: z.ZodEnum<{
10
+ free: "free";
11
+ scale: "scale";
12
+ enterprise: "enterprise";
13
+ }>;
14
+ export type PlanTier = z.infer<typeof planTierSchema>;
15
+ /**
16
+ * Every meter the engine records, over any transport. This is the closed set
17
+ * behind the loose `eventName` strings that `UsageRecorder` and the quota gate
18
+ * pass around.
19
+ *
20
+ * Recording and pricing are separate questions. A meter exists so usage can be
21
+ * gated and attributed; whether it reaches an invoice is `METER_EVENT_AXIS`.
22
+ * Bootstraps are recorded and quota-gated but deliberately unpriced: a bootstrap
23
+ * is what a client does once to become useful, and charging for it would price
24
+ * the act of connecting.
25
+ */
26
+ export declare const meterEventSchema: z.ZodEnum<{
27
+ "api.commit_ops": "api.commit_ops";
28
+ "api.model_reads": "api.model_reads";
29
+ "api.claim_creates": "api.claim_creates";
30
+ "api.bootstraps": "api.bootstraps";
31
+ }>;
32
+ export type MeterEvent = z.infer<typeof meterEventSchema>;
33
+ /**
34
+ * One step of the rate card. `throughOps` is the cumulative ceiling the rate
35
+ * applies up to, and `null` marks the final, unbounded step. Rates are marginal:
36
+ * crossing a ceiling reprices the operations above it, never the ones below.
37
+ */
38
+ export declare const rateBracketSchema: z.ZodObject<{
39
+ throughOps: z.ZodNullable<z.ZodNumber>;
40
+ usdPerMillionOps: z.ZodNumber;
41
+ }, z.core.$strip>;
42
+ export type RateBracket = z.infer<typeof rateBracketSchema>;
43
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/wire/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;EAA0C,CAAC;AACtE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB;;;;;EAK3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;iBAG5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The pricing vocabulary that crosses the wire: the tier names, the meter
3
+ * names, and the shape of one rate-card step. Account responses carry these,
4
+ * so they live in the dependency-free wire layer; the pricing contract
5
+ * (`../pricing.ts`) derives the rate card, the plans, and the bill arithmetic
6
+ * from them and re-exports them for its consumers.
7
+ */
8
+ import { z } from 'zod';
9
+ export const planTierSchema = z.enum(['free', 'scale', 'enterprise']);
10
+ /**
11
+ * Every meter the engine records, over any transport. This is the closed set
12
+ * behind the loose `eventName` strings that `UsageRecorder` and the quota gate
13
+ * pass around.
14
+ *
15
+ * Recording and pricing are separate questions. A meter exists so usage can be
16
+ * gated and attributed; whether it reaches an invoice is `METER_EVENT_AXIS`.
17
+ * Bootstraps are recorded and quota-gated but deliberately unpriced: a bootstrap
18
+ * is what a client does once to become useful, and charging for it would price
19
+ * the act of connecting.
20
+ */
21
+ export const meterEventSchema = z.enum([
22
+ 'api.commit_ops',
23
+ 'api.model_reads',
24
+ 'api.claim_creates',
25
+ 'api.bootstraps',
26
+ ]);
27
+ /**
28
+ * One step of the rate card. `throughOps` is the cumulative ceiling the rate
29
+ * applies up to, and `null` marks the final, unbounded step. Rates are marginal:
30
+ * crossing a ceiling reprices the operations above it, never the ones below.
31
+ */
32
+ export const rateBracketSchema = z.object({
33
+ throughOps: z.number().int().positive().nullable(),
34
+ usdPerMillionOps: z.number().nonnegative(),
35
+ });
36
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/wire/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AAGtE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC;IACrC,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;IACnB,gBAAgB;CACjB,CAAC,CAAC;AAGH;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAClD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;CAC3C,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/transaction",
3
- "version": "0.39.0",
3
+ "version": "0.41.0",
4
4
  "description": "The headless Ablo transaction client and canonical contracts for reads, commits, settlement, claims, and durable observation.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -17,6 +17,11 @@
17
17
  "import": "./dist/errorCodes.js",
18
18
  "default": "./dist/errorCodes.js"
19
19
  },
20
+ "./pricing": {
21
+ "types": "./dist/pricing.d.ts",
22
+ "import": "./dist/pricing.js",
23
+ "default": "./dist/pricing.js"
24
+ },
20
25
  "./environment": {
21
26
  "types": "./dist/environment.d.ts",
22
27
  "import": "./dist/environment.js",
package/src/auth/index.ts CHANGED
@@ -241,16 +241,25 @@ interface MintUserSessionBase {
241
241
  * for organizations whose schemas it does not own has no way to name their
242
242
  * models, and a grant is checked against the session's schema at mint time. The
243
243
  * server expands the verbs across that schema and stores the same enumerated
244
- * `model.verb` allowlist either way.
244
+ * `model.verb` allowlist either way. The third form grants no data operations
245
+ * at all, for a session that only proves identity to control-plane surfaces —
246
+ * it involves no schema, so it mints even for an organization that has not
247
+ * pushed one yet.
245
248
  */
246
249
  export type MintUserSessionRequest = MintUserSessionBase & {
247
- /** The allowlist, named model by model. Provide this or the field below. */
250
+ /** The allowlist, named model by model. Provide exactly one grant form. */
248
251
  readonly operations?: readonly GrantedOperation[];
249
252
  /**
250
253
  * The allowlist as verbs alone, expanded by the server across the models in
251
- * the session's active schema. Provide this or the field above.
254
+ * the session's active schema. Provide exactly one grant form.
252
255
  */
253
256
  readonly activeSchemaOperations?: readonly CapabilityOperation[];
257
+ /**
258
+ * No data operations: the session proves who the user is to control-plane
259
+ * surfaces (the dashboard, credential provisioning) and can touch no
260
+ * application data. Provide exactly one grant form.
261
+ */
262
+ readonly controlPlaneOnly?: true;
254
263
  };
255
264
 
256
265
  /**
@@ -278,13 +287,19 @@ export async function mintUserSessionKey(
278
287
  { code: 'base_url_missing' },
279
288
  );
280
289
  }
281
- // Exactly one grant form. Both would be two answers to one question; neither
290
+ // Exactly one grant form. Several would be two answers to one question; none
282
291
  // would send an empty allowlist, and an empty allowlist is read as
283
292
  // unrestricted rather than as nothing. The server refuses either way; this
284
293
  // says so before the round trip, where the caller can see which call did it.
285
- if ((options.operations === undefined) === (options.activeSchemaOperations === undefined)) {
294
+ const grantForms = [
295
+ options.operations,
296
+ options.activeSchemaOperations,
297
+ options.controlPlaneOnly,
298
+ ].filter((form) => form !== undefined).length;
299
+ if (grantForms !== 1) {
286
300
  throw new AbloAuthenticationError(
287
- 'Provide either operations or activeSchemaOperations for a user-session mint, not both.',
301
+ 'Provide exactly one of operations, activeSchemaOperations, or controlPlaneOnly ' +
302
+ 'for a user-session mint.',
288
303
  { code: 'invalid_body' },
289
304
  );
290
305
  }
@@ -316,9 +331,11 @@ export async function mintUserSessionKey(
316
331
  }
317
332
  : {}),
318
333
  ...(options.syncGroups ? { syncGroups: options.syncGroups } : {}),
319
- ...(options.operations
320
- ? { operations: options.operations }
321
- : { activeSchemaOperations: options.activeSchemaOperations }),
334
+ ...(options.controlPlaneOnly
335
+ ? { controlPlaneOnly: true }
336
+ : options.operations
337
+ ? { operations: options.operations }
338
+ : { activeSchemaOperations: options.activeSchemaOperations }),
322
339
  ttlSeconds: options.ttlSeconds,
323
340
  ...(options.label ? { label: options.label } : {}),
324
341
  }),
@@ -46,9 +46,20 @@ export const EphemeralKeyResponseSchema = z.object({
46
46
  branchId: z.string().min(1).nullable().default(null),
47
47
  branchRoot: z.boolean().default(false),
48
48
  syncGroups: z.array(z.string()),
49
- /** Effective operation grant stored on the credential. */
50
- operations: z.array(grantedOperationSchema).min(1),
51
- });
49
+ /** Effective operation grant stored on the credential. Empty ONLY for a
50
+ * control-plane-only session, which grants no data operations by design. */
51
+ operations: z.array(grantedOperationSchema),
52
+ /** Echoed for a session minted with the control-plane-only grant form: the
53
+ * credential proves identity to control-plane surfaces and can touch no
54
+ * application data. */
55
+ controlPlaneOnly: z.literal(true).optional(),
56
+ }).refine(
57
+ (response) => response.controlPlaneOnly === true || response.operations.length > 0,
58
+ {
59
+ message: 'a data session must carry at least one granted operation',
60
+ path: ['operations'],
61
+ },
62
+ );
52
63
 
53
64
  export type EphemeralKeyResponse = z.infer<typeof EphemeralKeyResponseSchema>;
54
65
 
@@ -76,6 +76,15 @@ export interface ConflictEvent {
76
76
  id: string;
77
77
  fields: readonly string[];
78
78
  writtenBy?: ParticipantKind;
79
+ /**
80
+ * The group premise this row breached, when the conflict was found at group
81
+ * grain. `model`/`id` stay the row that actually moved, so a log line can
82
+ * say which row moved AND which premise it broke — the two used to be the
83
+ * same field, and a group conflict logged its group key as the row.
84
+ */
85
+ group?: string;
86
+ /** How the row reached `group` — `self`, `parent`, or `transitive`. */
87
+ via?: string;
79
88
  }[];
80
89
  }
81
90
 
@@ -24,6 +24,10 @@ export {
24
24
  onStaleModeSchema,
25
25
  writeGuardSchema,
26
26
  staleNotificationSchema,
27
+ rowStaleNotificationSchema,
28
+ groupStaleNotificationSchema,
29
+ stalePropagationSchema,
30
+
27
31
  readDependencySchema,
28
32
  trackDependencySchema,
29
33
  // Layer 2 — pessimistic claim / claim-lease
@@ -101,6 +105,9 @@ export type {
101
105
  OnStaleMode,
102
106
  WriteGuard,
103
107
  StaleNotification,
108
+ RowStaleNotification,
109
+ GroupStaleNotification,
110
+ StalePropagation,
104
111
  ReadDependency,
105
112
  TrackDependency,
106
113
  // Layer 2 — pessimistic claim / claim-lease
@@ -179,3 +186,4 @@ export {
179
186
  modelTarget,
180
187
  streamTarget,
181
188
  } from './locator.js';
189
+
@@ -1,5 +1,9 @@
1
1
  import { z } from 'zod';
2
- import { syncGroupInputSchema } from '../schema/roles.js';
2
+ import {
3
+ syncGroupInputSchema,
4
+ syncGroupRefSchema,
5
+ syncGroupSchema,
6
+ } from '../schema/roles.js';
3
7
  export { syncGroupInputSchema } from '../schema/roles.js';
4
8
  import { isFieldRef, type FieldRef } from '../schema/fieldRef.js';
5
9
  import type { ParticipantKind } from '../types/participant.js';
@@ -213,6 +217,28 @@ export const targetRefSchema = z.object({
213
217
  });
214
218
  export type TargetRef = z.infer<typeof targetRefSchema>;
215
219
 
220
+ /**
221
+ * What a {@link ModelClaim} points at — the target locator as SDK callers see
222
+ * it, keyed by `model` and `id` rather than the wire schema's `entityType` and
223
+ * `entityId`. This is the public `ModelTarget` shape.
224
+ *
225
+ * Declared beside {@link targetRefSchema} because the two are the same shape in
226
+ * two spellings, and a member added to one belongs in the other. Both are read
227
+ * by {@link staleNotificationSchema} and the claim family below, so this has to
228
+ * precede them.
229
+ */
230
+ export const modelTargetSchema = z
231
+ .object({
232
+ model: z.string(),
233
+ id: z.string(),
234
+ field: z.string().optional(),
235
+ /** Several named parts at once — see {@link targetRefSchema}. */
236
+ fields: z.array(z.string()).readonly().optional(),
237
+ meta: z.record(z.string(), z.unknown()).optional(),
238
+ })
239
+ .readonly();
240
+ export type ModelTarget = z.infer<typeof modelTargetSchema>;
241
+
216
242
  /**
217
243
  * The same locator in the spelling the wait line and the claim handle use —
218
244
  * `{ type, id }` for the entity, the sub-entity half unchanged. It is a
@@ -270,45 +296,153 @@ export type WriteGuard = z.infer<typeof writeGuardSchema>;
270
296
  * re-commits. `reject` throws instead, and `overwrite` proceeds silently —
271
297
  * neither notifies.
272
298
  */
273
- export const staleNotificationSchema = z.object({
299
+ /**
300
+ * A log position, as the server reports one.
301
+ *
302
+ * Server-PRODUCED watermarks are constrained here; the caller-supplied
303
+ * {@link writeGuardSchema} `readAt` deliberately is not. The asymmetry is the
304
+ * trust direction, not an oversight: the server controls what it stamps, so
305
+ * stating the domain costs nothing, while tightening an inbound field would
306
+ * reject payloads the wire accepts today.
307
+ */
308
+ const syncIdSchema = z.number().int().nonnegative();
309
+
310
+ /**
311
+ * How a change reached the premise that fired — the three ways a record joins a
312
+ * sync group, which is the vocabulary `RecordGroupSpec` already routes by
313
+ * (`selfKind` / `parents` / `transitive`) rather than a fourth name for it.
314
+ *
315
+ * Without this a group notification can only say "something in the group you
316
+ * read moved", and the cheapest correct response to that is to re-read the
317
+ * whole group. `via` plus the notification's `target` narrows it to the row
318
+ * that actually moved and how it got there, which is usually a one-row re-read.
319
+ *
320
+ * • `self` — the row that moved IS the group's scope root.
321
+ * • `parent` — it sits one declared containment edge below the root.
322
+ * • `transitive` — the root is ≥2 hops up (`comment → task → project`).
323
+ */
324
+ export const stalePropagationSchema = z
325
+ .object({
326
+ via: z.enum(['self', 'parent', 'transitive']),
327
+ /**
328
+ * The intermediate models walked from the moved row up to the scope root,
329
+ * nearest hop first — the part of the route a reader cannot see from the
330
+ * two endpoints. Empty on `self` and `parent`, which have no intermediate.
331
+ *
332
+ * Model names, not rows: naming the intermediate ROWS would cost a join per
333
+ * notification, and the route is what explains the reach. `target` already
334
+ * identifies the row that moved and `group` the premise it broke.
335
+ */
336
+ through: z.array(z.string()).readonly(),
337
+ })
338
+ .readonly();
339
+ export type StalePropagation = z.infer<typeof stalePropagationSchema>;
340
+
341
+ /**
342
+ * What both notification scopes carry. The arms below derive from it rather
343
+ * than restate it, the same way {@link claimStateSchema} projects the claim
344
+ * record.
345
+ */
346
+ const staleNotificationBaseSchema = z.object({
274
347
  /** Names this object's type; every returned object carries such a tag. */
275
- object: z.literal('stale_notification').optional(),
276
- /** Model name of the conflicting row. */
277
- model: z.string(),
278
- /** Row id. */
279
- id: z.string(),
280
- /** The watermark the committer reasoned against (its `readAt`). */
281
- readAt: z.number(),
282
- /**
283
- * Newest delta id on the row — the committer's new watermark. Re-capture
284
- * context at/after this id to reconcile.
285
- */
286
- observedSyncId: z.number(),
348
+ object: z.literal('stale_notification'),
287
349
  /**
288
- * Fields whose concurrent change collided with this write (intersection of
289
- * the committer's written columns and a newer delta's `changed_fields`).
290
- * Empty ⇒ a whole-entity change (CREATE/DELETE/legacy delta).
350
+ * The row that moved, and which part of it — `fields` holds the columns whose
351
+ * concurrent change collided (empty a whole-entity CREATE/DELETE).
352
+ *
353
+ * The same shape a claim names its subject with, so one reader handles "who
354
+ * holds this row" and "this row moved under you" without learning two
355
+ * vocabularies. In BOTH scopes this is the row that actually changed: a group
356
+ * notification names the moved row here and the fired premise in `group`.
291
357
  */
292
- conflictingFields: z.array(z.string()),
358
+ target: modelTargetSchema,
359
+ /** The watermark the committer reasoned against (its `readAt`). */
360
+ readAt: syncIdSchema,
293
361
  /**
294
- * The live values of `conflictingFields` after the conflict — the piece a
295
- * plain stale error omits. It lets the actor reconcile without a follow-up read.
362
+ * Newest delta id on the premise — the committer's new watermark. Re-capture
363
+ * context at/after this id to reconcile.
296
364
  */
297
- currentValues: z.record(z.string(), z.unknown()),
365
+ observedSyncId: syncIdSchema,
298
366
  /** Who wrote the conflicting delta. */
299
367
  writtenBy: z.object({
300
368
  kind: participantKindSchema,
301
369
  id: z.string(),
302
370
  }),
371
+ });
372
+
373
+ /** A premise on one row: that row moved. */
374
+ export const rowStaleNotificationSchema = staleNotificationBaseSchema.extend({
375
+ scope: z.literal('row'),
376
+ /**
377
+ * The live values of `target.fields` after the conflict — the piece a plain
378
+ * stale error omits. It lets the actor reconcile without a follow-up read.
379
+ *
380
+ * Row scope only. Reading live values is cheap for one known row and is what
381
+ * a group breach cannot promise, so the group arm omits the field rather than
382
+ * carrying an empty one that reads as "nothing changed".
383
+ */
384
+ currentValues: z.record(z.string(), z.unknown()),
385
+ });
386
+ export type RowStaleNotification = z.infer<typeof rowStaleNotificationSchema>;
387
+
388
+ /** A premise on a whole sync group: something in it moved. */
389
+ export const groupStaleNotificationSchema = staleNotificationBaseSchema.extend({
390
+ scope: z.literal('group'),
391
+ /**
392
+ * The group premise that fired (`report:abc`, `section:s1`).
393
+ *
394
+ * Same format schema the premise declares, so the value a caller writes into
395
+ * `reads[].group` and the value it gets back name a group identically. The
396
+ * BRANDED view is for values Ablo mints; a notification only echoes the
397
+ * premise it was handed, and re-parsing it to acquire a brand would be a
398
+ * second validation of data the commit boundary already checked.
399
+ */
400
+ group: syncGroupRefSchema,
401
+ /**
402
+ * How `target` reached `group`. Absent when the schema's record-group spec is
403
+ * unavailable to the commit path, which is the only case where the server
404
+ * knows a group moved without knowing the route.
405
+ */
406
+ propagation: stalePropagationSchema.optional(),
303
407
  /**
304
- * Set when this notification is for a GROUP premise (e.g. `report:abc`,
305
- * `section:s1`) rather than a single row "something in the group you read
306
- * changed." For a group notification `conflictingFields`/`currentValues` are
307
- * empty (the change could span many rows); re-read the group at
308
- * `observedSyncId` to reconcile. Absent a row-scoped notification.
408
+ * How much of the group moved the decision "re-read these rows" versus
409
+ * "give up and take the whole group" needs a size, and a premise that only
410
+ * says *something* changed forces the expensive branch every time.
411
+ *
412
+ * Counts DISTINCT ROWS, not deltas: two writes to one row is one row's worth
413
+ * of re-reading. `sample` names the most recently changed of them and is
414
+ * capped, so `truncated` says whether it tells the whole story.
415
+ *
416
+ * Absent when the commit path did not measure it (a durable `track` fires per
417
+ * commit and does not pay for the extra statement).
309
418
  */
310
- group: z.string().optional(),
419
+ changed: z
420
+ .object({
421
+ count: z.number().int().nonnegative(),
422
+ sample: z.array(modelTargetSchema).readonly(),
423
+ truncated: z.boolean(),
424
+ })
425
+ .optional(),
311
426
  });
427
+ export type GroupStaleNotification = z.infer<
428
+ typeof groupStaleNotificationSchema
429
+ >;
430
+
431
+ /**
432
+ * One advisory, two scopes, told apart by `scope`.
433
+ *
434
+ * A real discriminated union rather than a flat object with an optional
435
+ * `group`, which is what {@link readDependencySchema} already does for the
436
+ * premise side. While it was flat, the two scopes disagreed about what their
437
+ * fields meant — `model`/`id` held a row in one and the group key in the other,
438
+ * and `conflictingFields`/`currentValues` were empty by construction in the
439
+ * group case — so every consumer had to re-derive the scope from `group`'s
440
+ * presence and read the prose to know which fields were load-bearing.
441
+ */
442
+ export const staleNotificationSchema = z.discriminatedUnion('scope', [
443
+ rowStaleNotificationSchema,
444
+ groupStaleNotificationSchema,
445
+ ]);
312
446
  export type StaleNotification = z.infer<typeof staleNotificationSchema>;
313
447
 
314
448
  /**
@@ -338,7 +472,13 @@ const readRowDependencySchema = z.object({
338
472
  });
339
473
 
340
474
  const readGroupDependencySchema = z.object({
341
- group: z.string(),
475
+ /**
476
+ * The caller-facing view of the format: `reads: [{ group: 'report:abc' }]`
477
+ * type-checks inline, `'nonsense'` does not. The
478
+ * {@link groupStaleNotificationSchema} this premise fires uses the branded
479
+ * view, because there Ablo is the author.
480
+ */
481
+ group: syncGroupRefSchema,
342
482
  readAt: z.number(),
343
483
  onStale: onStaleModeSchema.optional(),
344
484
  });
@@ -361,7 +501,12 @@ export type ReadDependency = z.infer<typeof readDependencySchema>;
361
501
  * same reference: a track names its target exactly as a read does, and the
362
502
  * three ways it differs are stated here as omissions the compiler holds.
363
503
  *
364
- * • no `onStale` a track always notifies; that is what tracking is;
504
+ * • `onStale` NARROWED, not dropped `notify` (the default) reports the
505
+ * change on the tracker's next receipt and lets the commit through;
506
+ * `reject` refuses that commit while the belief is stale, so an agent
507
+ * cannot write on something it has been shown to be out of date about.
508
+ * `overwrite` is excluded because it means "apply my write anyway" and a
509
+ * track guards no write of its own to apply;
365
510
  * • no `fields` — a track fires at row grain, because the server keeps one
366
511
  * row per tracked target and reports that the target moved, not which
367
512
  * column did (`track_dependencies` has no field axis to store one in);
@@ -373,15 +518,36 @@ export type ReadDependency = z.infer<typeof readDependencySchema>;
373
518
  * genuinely cannot carry has to be omitted here on purpose, in one line, rather
374
519
  * than by being quietly left out of a copy.
375
520
  */
376
- const trackReadAtSchema = { readAt: z.number().optional() } as const;
521
+ /**
522
+ * A track's disposition — the premise enum with `overwrite` subtracted, derived
523
+ * from it rather than spelled again, so a mode added to the convention reaches
524
+ * a track unless it is deliberately excluded here.
525
+ */
526
+ export const trackOnStaleSchema = onStaleModeSchema.exclude(['overwrite']);
527
+ export type TrackOnStale = z.infer<typeof trackOnStaleSchema>;
528
+
529
+ /**
530
+ * What a track does when the caller says nothing — reporting, the behavior every
531
+ * track had before the disposition existed, so an existing registration is
532
+ * unchanged.
533
+ *
534
+ * Declared here because the value has to agree in three places that cannot
535
+ * import each other: this schema, the column DEFAULT, and the server's insert.
536
+ * The two SQL copies are pinned to this one by a test
537
+ * (`trackOnStaleDomain.test.ts`) rather than by anyone remembering.
538
+ */
539
+ export const DEFAULT_TRACK_ON_STALE: TrackOnStale = 'notify';
540
+
541
+ const trackBaseSchema = {
542
+ readAt: z.number().optional(),
543
+ onStale: trackOnStaleSchema.optional(),
544
+ } as const;
377
545
 
378
546
  export const trackDependencySchema = z.union([
379
547
  readRowDependencySchema
380
548
  .omit({ onStale: true, fields: true, readAt: true })
381
- .extend(trackReadAtSchema),
382
- readGroupDependencySchema
383
- .omit({ onStale: true, readAt: true })
384
- .extend(trackReadAtSchema),
549
+ .extend(trackBaseSchema),
550
+ readGroupDependencySchema.omit({ onStale: true, readAt: true }).extend(trackBaseSchema),
385
551
  ]);
386
552
  export type TrackDependency = z.infer<typeof trackDependencySchema>;
387
553
 
@@ -725,23 +891,6 @@ export const claimExpiredSchema = z.object({
725
891
  export type ClaimExpired = z.infer<typeof claimExpiredSchema>;
726
892
 
727
893
 
728
- /**
729
- * What a {@link ModelClaim} points at — the target locator as SDK callers see
730
- * it, keyed by `model` and `id` rather than the wire schema's `entityType` and
731
- * `entityId`. This is the public `ModelTarget` shape.
732
- */
733
- export const modelTargetSchema = z
734
- .object({
735
- model: z.string(),
736
- id: z.string(),
737
- field: z.string().optional(),
738
- /** Several named parts at once — see {@link targetRefSchema}. */
739
- fields: z.array(z.string()).readonly().optional(),
740
- meta: z.record(z.string(), z.unknown()).optional(),
741
- })
742
- .readonly();
743
- export type ModelTarget = z.infer<typeof modelTargetSchema>;
744
-
745
894
  /**
746
895
  * The two states a claim can be observed in while it still exists.
747
896
  *
@@ -50,7 +50,15 @@ export function formatClaim(e: ClaimEvent): string {
50
50
 
51
51
  /** A notify-instead-of-abort stale write as one readable line. */
52
52
  export function formatConflict(e: ConflictEvent): string {
53
- const rows = e.rows.map((r) => `${r.model}/${r.id}(${r.fields.join(',')})`).join(', ');
53
+ const rows = e.rows
54
+ .map((r) => {
55
+ // A group conflict reads as "which row moved, and which premise it broke",
56
+ // because those are two different things and the reader needs both to know
57
+ // whether to re-read one row or the whole group.
58
+ const premise = r.group ? ` ${r.via ? `${r.via} → ` : '→ '}${r.group}` : '';
59
+ return `${r.model}/${r.id}(${r.fields.join(',')})${premise}`;
60
+ })
61
+ .join(', ');
54
62
  return `conflict: tx ${e.clientTxId} — ${e.rows.length} row(s) changed underneath${rows ? `: ${rows}` : ''}`;
55
63
  }
56
64