@abloatai/transaction 0.46.0 → 0.47.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 (79) hide show
  1. package/dist/ai-sdk/modelTools.d.ts.map +1 -1
  2. package/dist/ai-sdk/modelTools.js +1 -2
  3. package/dist/ai-sdk/modelTools.js.map +1 -1
  4. package/dist/ai-sdk/updateTool.d.ts.map +1 -1
  5. package/dist/ai-sdk/updateTool.js +0 -1
  6. package/dist/ai-sdk/updateTool.js.map +1 -1
  7. package/dist/auth/capability.d.ts +8 -0
  8. package/dist/auth/capability.d.ts.map +1 -1
  9. package/dist/auth/capability.js +2 -0
  10. package/dist/auth/capability.js.map +1 -1
  11. package/dist/auth/capabilityLifecycle.d.ts +4 -0
  12. package/dist/auth/capabilityLifecycle.d.ts.map +1 -1
  13. package/dist/auth/deliveryPartition.d.ts +14 -0
  14. package/dist/auth/deliveryPartition.d.ts.map +1 -0
  15. package/dist/auth/deliveryPartition.js +16 -0
  16. package/dist/auth/deliveryPartition.js.map +1 -0
  17. package/dist/auth/identity.d.ts +2 -0
  18. package/dist/auth/identity.d.ts.map +1 -1
  19. package/dist/auth/identity.js +3 -0
  20. package/dist/auth/identity.js.map +1 -1
  21. package/dist/auth/schemas.d.ts +8 -0
  22. package/dist/auth/schemas.d.ts.map +1 -1
  23. package/dist/auth/schemas.js +3 -0
  24. package/dist/auth/schemas.js.map +1 -1
  25. package/dist/auth/sessionMint.d.ts.map +1 -1
  26. package/dist/auth/sessionMint.js +1 -0
  27. package/dist/auth/sessionMint.js.map +1 -1
  28. package/dist/errorCodes.d.ts +3 -1
  29. package/dist/errorCodes.d.ts.map +1 -1
  30. package/dist/errorCodes.js +3 -1
  31. package/dist/errorCodes.js.map +1 -1
  32. package/dist/footprint.d.ts.map +1 -1
  33. package/dist/footprint.js +3 -1
  34. package/dist/footprint.js.map +1 -1
  35. package/dist/pricing.d.ts +21 -2
  36. package/dist/pricing.d.ts.map +1 -1
  37. package/dist/pricing.js +32 -8
  38. package/dist/pricing.js.map +1 -1
  39. package/dist/resources/httpResources.d.ts +0 -1
  40. package/dist/resources/httpResources.d.ts.map +1 -1
  41. package/dist/resources/modelOperations.d.ts +13 -3
  42. package/dist/resources/modelOperations.d.ts.map +1 -1
  43. package/dist/source/migrations.d.ts +1 -1
  44. package/dist/source/migrations.d.ts.map +1 -1
  45. package/dist/source/migrations.js +18 -7
  46. package/dist/source/migrations.js.map +1 -1
  47. package/dist/transport/httpTransport.d.ts.map +1 -1
  48. package/dist/transport/httpTransport.js +5 -10
  49. package/dist/transport/httpTransport.js.map +1 -1
  50. package/dist/transport/wsTransport.d.ts +8 -0
  51. package/dist/transport/wsTransport.d.ts.map +1 -1
  52. package/dist/transport/wsTransport.js +8 -0
  53. package/dist/transport/wsTransport.js.map +1 -1
  54. package/dist/wire/dataSourceResponses.d.ts +17 -1
  55. package/dist/wire/dataSourceResponses.d.ts.map +1 -1
  56. package/dist/wire/dataSourceResponses.js +18 -0
  57. package/dist/wire/dataSourceResponses.js.map +1 -1
  58. package/dist/wire/index.d.ts +2 -2
  59. package/dist/wire/index.d.ts.map +1 -1
  60. package/dist/wire/index.js +1 -1
  61. package/dist/wire/index.js.map +1 -1
  62. package/package.json +1 -1
  63. package/src/ai-sdk/modelTools.ts +1 -2
  64. package/src/ai-sdk/updateTool.ts +0 -1
  65. package/src/auth/capability.ts +2 -0
  66. package/src/auth/deliveryPartition.ts +18 -0
  67. package/src/auth/identity.ts +5 -0
  68. package/src/auth/schemas.ts +3 -0
  69. package/src/auth/sessionMint.ts +1 -0
  70. package/src/errorCodes.ts +13 -1
  71. package/src/footprint.ts +3 -1
  72. package/src/pricing.ts +36 -8
  73. package/src/resources/httpResources.ts +0 -1
  74. package/src/resources/modelOperations.ts +14 -3
  75. package/src/source/migrations.ts +21 -7
  76. package/src/transport/httpTransport.ts +5 -10
  77. package/src/transport/wsTransport.ts +18 -0
  78. package/src/wire/dataSourceResponses.ts +20 -0
  79. package/src/wire/index.ts +2 -0
@@ -78,7 +78,7 @@ export { projectResponseSchema, projectListResponseSchema, provisionedKeySchema,
78
78
  // The datasource routes' responses — the `ablo connect` surface: register,
79
79
  // validate, locate, list, deregister. What the server, the CLI, and the
80
80
  // dashboard agree on.
81
- export { READINESS_ITEMS, READINESS_ADVISORY_ITEMS, isReadinessItem, readinessFailureSchema, readinessAdvisorySchema, datasourceSummarySchema, datasourceListResponseSchema, datasourceValidationResponseSchema, datasourceLocationResponseSchema, datasourceDisconnectedResponseSchema, } from './dataSourceResponses.js';
81
+ export { READINESS_ITEMS, READINESS_ADVISORY_ITEMS, isReadinessItem, readinessFailureSchema, readinessAdvisorySchema, datasourceSummarySchema, datasourceListResponseSchema, datasourceValidationResponseSchema, datasourceLocationResponseSchema, datasourceResnapshotResponseSchema, datasourceDisconnectedResponseSchema, } from './dataSourceResponses.js';
82
82
  // The inbound socket surface: every frame the server can send, and how each
83
83
  // one's payload is validated.
84
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":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,6BAA6B,GAC9B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGrE,8EAA8E;AAC9E,8BAA8B;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,cAAc;AACd,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,2EAA2E;AAC3E,8EAA8E;AAC9E,gFAAgF;AAChF,OAAO,EACL,gBAAgB,EAChB,8BAA8B,EAC9B,wBAAwB,EACxB,2BAA2B,EAC3B,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAY9B,6EAA6E;AAC7E,8EAA8E;AAC9E,gDAAgD;AAChD,OAAO,EACL,gCAAgC,EAChC,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,2BAA2B,EAC3B,2BAA2B,EAC3B,2BAA2B,EAC3B,eAAe,EACf,0BAA0B;AAC1B,8EAA8E;AAC9E,oEAAoE;AACpE,2BAA2B,EAC3B,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAiBrB,kFAAkF;AAClF,0EAA0E;AAC1E,kFAAkF;AAClF,wDAAwD;AACxD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,GACZ,MAAM,YAAY,CAAC;AAapB,6EAA6E;AAC7E,OAAO,EACL,SAAS,EACT,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,sBAAsB;AACtB,4EAA4E;AAC5E,4EAA4E;AAC5E,0CAA0C;AAC1C,aAAa,GACd,MAAM,cAAc,CAAC;AAGtB,8EAA8E;AAC9E,4EAA4E;AAC5E,4EAA4E;AAC5E,wDAAwD;AACxD,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,4BAA4B,EAC5B,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,+EAA+E;AAC/E,+EAA+E;AAC/E,6EAA6E;AAC7E,6DAA6D;AAC7D,OAAO;AACL,qEAAqE;AACrE,0EAA0E;AAC1E,yEAAyE;AACzE,oBAAoB,EACpB,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,2BAA2B,EAC3B,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,2BAA2B,EAC3B,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,8BAA8B,EAC9B,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAmBrB,yEAAyE;AACzE,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAG7B,gFAAgF;AAChF,wEAAwE;AACxE,OAAO,EACL,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAQzB,6EAA6E;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAGjE,4EAA4E;AAC5E,qEAAqE;AACrE,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,EACzB,wBAAwB,EACxB,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAqB/B,2EAA2E;AAC3E,wEAAwE;AACxE,sBAAsB;AACtB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,4BAA4B,EAC5B,kCAAkC,EAClC,gCAAgC,EAChC,oCAAoC,GACrC,MAAM,0BAA0B,CAAC;AAalC,4EAA4E;AAC5E,8BAA8B;AAC9B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAS5B,+EAA+E;AAC/E,qDAAqD;AACrD,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wire/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/transaction",
3
- "version": "0.46.0",
3
+ "version": "0.47.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",
@@ -100,7 +100,6 @@ export function createTool<TInput, T, CreateInput>(
100
100
  const row = await model.create({
101
101
  data: options.data(input),
102
102
  ...(id !== undefined ? { id } : {}),
103
- wait: 'confirmed',
104
103
  });
105
104
  return { status: 'created', row };
106
105
  },
@@ -156,7 +155,7 @@ export function deleteTool<TInput, T, Fields = T>(
156
155
  };
157
156
  }
158
157
  try {
159
- await model.delete({ id, claim, wait: 'confirmed' });
158
+ await model.delete({ id, claim });
160
159
  return { status: 'deleted', id };
161
160
  } finally {
162
161
  await claim.release();
@@ -184,7 +184,6 @@ export function updateTool<
184
184
  id,
185
185
  data: options.apply(current, input),
186
186
  claim,
187
- wait: 'confirmed',
188
187
  });
189
188
  return { status: 'written', row };
190
189
  } finally {
@@ -27,6 +27,7 @@ import { z } from 'zod';
27
27
  import { participantKindSchema } from '../coordination/schema.js';
28
28
  import { syncGroupInputSchema } from '../schema/roles.js';
29
29
  import { authTokenSchema } from './token.js';
30
+ import { deliveryPartitionRouteSchema } from './deliveryPartition.js';
30
31
 
31
32
  /**
32
33
  * The verbs a grant can name — the whole vocabulary, in one place. Every other
@@ -253,6 +254,7 @@ export const capabilityScopeSchema = z.object({
253
254
  operations: z.array(grantedOperationSchema),
254
255
  participantKind: participantKindSchema,
255
256
  participantId: z.string().min(1),
257
+ deliveryPartition: deliveryPartitionRouteSchema.nullable().default(null),
256
258
  });
257
259
  export type CapabilityScope = z.infer<typeof capabilityScopeSchema>;
258
260
 
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Opaque gateway-routing coordinate resolved by the server.
5
+ *
6
+ * Clients echo this on the WebSocket upgrade; gateways still authenticate the
7
+ * credential and recompute ownership, so it is routing metadata rather than an
8
+ * authorization claim.
9
+ */
10
+ export const deliveryPartitionRouteSchema = z.object({
11
+ index: z.number().int().nonnegative(),
12
+ count: z.number().int().min(2),
13
+ }).refine((route) => route.index < route.count, {
14
+ message: 'delivery partition index must be less than count',
15
+ path: ['index'],
16
+ });
17
+
18
+ export type DeliveryPartitionRoute = z.infer<typeof deliveryPartitionRouteSchema>;
@@ -33,6 +33,7 @@ import type { Logger } from '../logger.js';
33
33
  import type { AuthCredentialSource } from '../auth/credentialSource.js';
34
34
  import type { CredentialProvider } from './credentialResult.js';
35
35
  import { resolveApiKeyValue, resolveBootstrapBaseUrl } from './apiKey.js';
36
+ import type { DeliveryPartitionRoute } from './deliveryPartition.js';
36
37
 
37
38
  export interface IdentityResolveInput {
38
39
  readonly options: {
@@ -69,6 +70,7 @@ export interface ResolvedIdentity {
69
70
  readonly capabilityToken: string | undefined;
70
71
  readonly syncGroups: readonly string[] | undefined;
71
72
  readonly participantKind: ParticipantKind;
73
+ readonly deliveryPartition: DeliveryPartitionRoute | null;
72
74
  /** Set only on the hosted-cloud path; the caller keeps it to stop refreshes on shutdown. */
73
75
  readonly refreshScheduler: RefreshScheduler | null;
74
76
  }
@@ -192,6 +194,7 @@ export async function resolveParticipantIdentity(
192
194
  capabilityToken: cred.getBearer,
193
195
  syncGroups: options.syncGroups,
194
196
  participantKind: kind,
197
+ deliveryPartition: null,
195
198
  refreshScheduler: null,
196
199
  };
197
200
  }
@@ -242,6 +245,7 @@ async function resolveViaIdentity(
242
245
  capabilityToken: bearer,
243
246
  syncGroups: mergedSyncGroups,
244
247
  participantKind: identity.participantKind,
248
+ deliveryPartition: identity.deliveryPartition,
245
249
  refreshScheduler: null,
246
250
  };
247
251
  }
@@ -325,6 +329,7 @@ async function resolveHosted(input: HostedInput): Promise<ResolvedIdentity> {
325
329
  capabilityToken: exchange.token,
326
330
  syncGroups: exchange.scope.syncGroups,
327
331
  participantKind: input.kind,
332
+ deliveryPartition: exchange.scope.deliveryPartition,
328
333
  refreshScheduler,
329
334
  };
330
335
  }
@@ -7,6 +7,7 @@ import {
7
7
  } from './capability.js';
8
8
  import { AbloAuthenticationError } from '../errors.js';
9
9
  import { authTokenSchema } from './token.js';
10
+ import { deliveryPartitionRouteSchema } from './deliveryPartition.js';
10
11
 
11
12
  // Not a second enum. The auth responses carry the same participant vocabulary
12
13
  // the coordination plane parses, so they validate against the same schema — a
@@ -24,6 +25,7 @@ export const IdentityResolveResponseSchema = z.object({
24
25
  branchId: z.string().min(1).nullable().default(null),
25
26
  branchRoot: z.boolean().default(false),
26
27
  syncGroups: z.array(z.string()),
28
+ deliveryPartition: deliveryPartitionRouteSchema.nullable().default(null),
27
29
  userMeta: z.record(z.string(), z.unknown()),
28
30
  });
29
31
 
@@ -46,6 +48,7 @@ export const EphemeralKeyResponseSchema = z.object({
46
48
  branchId: z.string().min(1).nullable().default(null),
47
49
  branchRoot: z.boolean().default(false),
48
50
  syncGroups: z.array(z.string()),
51
+ deliveryPartition: deliveryPartitionRouteSchema.nullable().default(null),
49
52
  /** Effective operation grant stored on the credential. Empty ONLY for a
50
53
  * control-plane-only session, which grants no data operations by design. */
51
54
  operations: z.array(grantedOperationSchema),
@@ -98,6 +98,7 @@ export async function mintSession<S extends SchemaRecord>(
98
98
  operations: res.operations,
99
99
  participantKind: 'user',
100
100
  participantId: res.participantId,
101
+ deliveryPartition: res.deliveryPartition,
101
102
  },
102
103
  userMeta: params.userMeta ?? { id: res.participantId },
103
104
  };
package/src/errorCodes.ts CHANGED
@@ -39,7 +39,7 @@ import { z } from 'zod';
39
39
  * error documentation and returned on the `Ablo-Version` response header, so a
40
40
  * consumer can detect when its expected contract has drifted from the server's.
41
41
  */
42
- export const ERROR_CONTRACT_VERSION = '2026-07-23';
42
+ export const ERROR_CONTRACT_VERSION = '2026-07-30';
43
43
 
44
44
  /** A coarse grouping of error codes, used to organize metrics and documentation. */
45
45
  export type ErrorCategory =
@@ -1046,6 +1046,12 @@ export const ERROR_CODES = {
1046
1046
  true,
1047
1047
  'The server is at connection capacity. Retry shortly — transient and not specific to your credentials.'
1048
1048
  ),
1049
+ delivery_partition_mismatch: wire(
1050
+ 'transport',
1051
+ 503,
1052
+ true,
1053
+ 'The connection reached a gateway that does not own its delivery partition. Retry through the cell router.'
1054
+ ),
1049
1055
  fetch_unavailable: client(
1050
1056
  'transport',
1051
1057
  'This environment provides no `fetch` implementation, so HTTP requests cannot be made. Run on a platform with `fetch` (Node 18+, modern browsers) or supply a polyfill.'
@@ -1240,6 +1246,12 @@ export const ERROR_CODES = {
1240
1246
  false,
1241
1247
  "The request targeted a project the caller's key is not scoped to."
1242
1248
  ),
1249
+ branch_scope_denied: wire(
1250
+ 'permission',
1251
+ 403,
1252
+ false,
1253
+ "The request targeted a branch the caller's key is not scoped to."
1254
+ ),
1243
1255
  project_slug_taken: wire(
1244
1256
  'validation',
1245
1257
  409,
package/src/footprint.ts CHANGED
@@ -127,7 +127,9 @@ function planeDigest(plane: FootprintPlane): string {
127
127
  // The organization-default project may be omitted or repeated as the
128
128
  // organization id; both spell the same branch coordinates.
129
129
  const project = plane.projectId === plane.organizationId ? '' : (plane.projectId ?? '');
130
- const key = [plane.organizationId, project, plane.branchId].join('');
130
+ // Delimit the coordinates. Concatenation alone makes structurally different
131
+ // planes such as ("ab", "c") and ("a", "bc") hash the same input.
132
+ const key = [plane.organizationId, project, plane.branchId].join('\0');
131
133
 
132
134
  const round = (seed: number): string => {
133
135
  let hash = seed;
package/src/pricing.ts CHANGED
@@ -23,7 +23,7 @@
23
23
  * rather than billed.
24
24
  *
25
25
  * The allowance a tier advertises is DERIVED, never stored: "the floor covers
26
- * 49.5M operations" is {@link opsForUsd} applied to the floor. Storing it
26
+ * 10M operations" is {@link opsForUsd} applied to the floor. Storing it
27
27
  * alongside the floor is how a published price silently stops matching the
28
28
  * invoice, because raising one number does not fail anything that pins the
29
29
  * other.
@@ -47,7 +47,7 @@ export type { MeterEvent, PlanTier, RateBracket };
47
47
  * could observe the difference. It is emitted into the generated pricing
48
48
  * documentation so a stale copy is identifiable on sight.
49
49
  */
50
- export const PRICING_VERSION = '2026-07-27';
50
+ export const PRICING_VERSION = '2026-07-31';
51
51
 
52
52
  /**
53
53
  * Resolve a stored plan string (`stripe_subscription.plan`) to a tier.
@@ -82,12 +82,40 @@ export const METER_EVENT_AXIS: Record<MeterEvent, BillableAxis | null> = {
82
82
 
83
83
  /** How each meter reads on an invoice line and in the pricing table. */
84
84
  export const METER_EVENT_LABEL: Record<MeterEvent, string> = {
85
- 'api.commit_ops': 'commit operations',
85
+ 'api.commit_ops': 'writes',
86
86
  'api.model_reads': 'model reads',
87
87
  'api.claim_creates': 'claim creates',
88
88
  'api.bootstraps': 'bootstraps',
89
89
  };
90
90
 
91
+ /**
92
+ * What each meter counts, in the words a customer is quoted. It lives beside
93
+ * the label because a meter's name and its definition are one fact: a page that
94
+ * renamed the line without restating what it counts would be describing a
95
+ * different meter.
96
+ *
97
+ * These say **write**, never *commit*. A commit is the protocol's atomic batch
98
+ * and it belongs in the protocol reference; the surface a customer buys against
99
+ * is `create` / `update` / `delete`, which the front door calls writing. Pricing
100
+ * copy is read by people who have never opened the protocol reference, and a
101
+ * word they have not met cannot clarify what they are paying for.
102
+ *
103
+ * All three read as "someone did something", because they are one price and a
104
+ * reader who has to hold three different shapes in mind will assume there are
105
+ * three different charges. Each line then answers the question that particular
106
+ * meter provokes: whether batching is cheaper, whether cached reads count, and
107
+ * whether holding a claim costs more than taking one.
108
+ */
109
+ export const METER_EVENT_COUNTS: Record<MeterEvent, string> = {
110
+ 'api.commit_ops':
111
+ 'One every time someone changes something. Adding, editing, and removing all count the same, and changing 500 things is 500 operations however they are sent.',
112
+ 'api.model_reads':
113
+ 'One every time someone reads something the engine answers. Reads a client already has locally never reach us and never count.',
114
+ 'api.claim_creates':
115
+ 'One every time someone takes ownership of a row so others wait their turn. Holding it and releasing it are free.',
116
+ 'api.bootstraps': 'Recorded, never charged. Connecting a client is free.',
117
+ };
118
+
91
119
  /** The meters a customer is charged for, in declaration order. */
92
120
  export const BILLABLE_METER_EVENTS: readonly MeterEvent[] = (
93
121
  meterEventSchema.options as readonly MeterEvent[]
@@ -185,8 +213,8 @@ export const planDefinitionSchema = z.object({
185
213
  hardCapOps: z.number().int().positive().nullable(),
186
214
  /**
187
215
  * A hard daily stop, which is a burst guard rather than an allowance. A month
188
- * of operations is a comfortable month of building and about ten minutes of
189
- * one agent at full rate, so a monthly cap alone lets a runaway loop erase the
216
+ * of operations is a comfortable month of building and about a minute of one
217
+ * agent at full rate, so a monthly cap alone lets a runaway loop erase the
190
218
  * whole month before anyone notices. The daily figure is what turns that into
191
219
  * a floor on how fast the month can be spent. `null` on metered tiers, which
192
220
  * are billed rather than stopped.
@@ -214,8 +242,8 @@ export const PLANS = z
214
242
  label: 'Free',
215
243
  summary: 'Build against the real engine without a card.',
216
244
  monthlyMinimumUsd: 0,
217
- hardCapOps: 1_000_000,
218
- hardCapOpsPerDay: 100_000,
245
+ hardCapOps: 100_000,
246
+ hardCapOpsPerDay: 10_000,
219
247
  storageGib: 1,
220
248
  maxConcurrentConnections: 25,
221
249
  contractPriced: false,
@@ -225,7 +253,7 @@ export const PLANS = z
225
253
  tier: 'scale',
226
254
  label: 'Scale',
227
255
  summary: 'Production traffic, metered above a monthly floor.',
228
- monthlyMinimumUsd: 99,
256
+ monthlyMinimumUsd: 20,
229
257
  hardCapOps: null,
230
258
  hardCapOpsPerDay: null,
231
259
  storageGib: 50,
@@ -276,7 +276,6 @@ export interface ModelMutationOptions extends ClaimedOptions {
276
276
  readonly idempotencyKey?: string | null;
277
277
  readonly readAt?: number | null;
278
278
  readonly onStale?: OnStaleMode | null;
279
- readonly wait?: CommitWait;
280
279
  readonly claim?: Claim | ClaimOptions | null;
281
280
  /** Fencing token (Option B) from the claim; server-validated at commit. */
282
281
  readonly fenceToken?: number | null;
@@ -558,15 +558,26 @@ export interface ModelRetrieveParams extends ServerRetrieveOptions {
558
558
  readonly id: string;
559
559
  }
560
560
 
561
+ /**
562
+ * Options shared by schema model writes.
563
+ *
564
+ * Reactive clients apply the row change optimistically before returning from
565
+ * the call. The returned promise has one stable settlement contract across
566
+ * reactive and stateless clients: it resolves only after authoritative
567
+ * confirmation. Callers that need an earlier queued receipt use the lower-level
568
+ * `commits.create` resource instead.
569
+ */
570
+ export type ModelWriteOptions = Omit<MutationOptions, 'wait'>;
571
+
561
572
  export interface ModelCreateParams<T, CreateInput>
562
- extends MutationOptions {
573
+ extends ModelWriteOptions {
563
574
  readonly data: CreateInput;
564
575
  readonly id?: string | null;
565
576
  readonly claim?: Claim<T> | ClaimTargetOptions<CreateInput> | null;
566
577
  }
567
578
 
568
579
  export interface ModelUpdateParams<T, Fields = T>
569
- extends MutationOptions {
580
+ extends ModelWriteOptions {
570
581
  readonly id: string;
571
582
  /**
572
583
  * Patch only fields declared by the model's Zod input shape. Hydrated rows
@@ -578,7 +589,7 @@ export interface ModelUpdateParams<T, Fields = T>
578
589
  }
579
590
 
580
591
  export interface ModelDeleteParams<T, Fields = T>
581
- extends MutationOptions {
592
+ extends ModelWriteOptions {
582
593
  readonly id: string;
583
594
  readonly claim?: Claim<T> | ClaimTargetOptions<Fields> | null;
584
595
  }
@@ -22,15 +22,28 @@ import type { Migration } from './contract.js';
22
22
  * block resolves the ledger through the search path and runs the `ALTER` only
23
23
  * when the column is absent — a true no-op on a table that already has it.
24
24
  */
25
- function addColumnIfAbsent(column: string, definition: string): string {
25
+ function quoteIdent(value: string): string {
26
+ return `"${value.replace(/"/g, '""')}"`;
27
+ }
28
+
29
+ function quoteLiteral(value: string): string {
30
+ return `'${value.replace(/'/g, "''")}'`;
31
+ }
32
+
33
+ function qualified(schema: string, relation: string): string {
34
+ return `${quoteIdent(schema)}.${quoteIdent(relation)}`;
35
+ }
36
+
37
+ function addColumnIfAbsent(schema: string, column: string, definition: string): string {
38
+ const ledger = qualified(schema, 'ablo_idempotency');
26
39
  return `DO $$
27
- DECLARE ledger regclass := to_regclass('ablo_idempotency');
40
+ DECLARE ledger regclass := to_regclass(${quoteLiteral(ledger)});
28
41
  BEGIN
29
42
  IF ledger IS NOT NULL AND NOT EXISTS (
30
43
  SELECT 1 FROM pg_attribute
31
44
  WHERE attrelid = ledger AND attname = '${column}' AND attnum > 0 AND NOT attisdropped
32
45
  ) THEN
33
- ALTER TABLE ablo_idempotency ADD COLUMN ${column} ${definition};
46
+ ALTER TABLE ${ledger} ADD COLUMN ${quoteIdent(column)} ${definition};
34
47
  END IF;
35
48
  END $$;`;
36
49
  }
@@ -39,11 +52,12 @@ END $$;`;
39
52
  * rows carry a bounded `expires_at` (set by the adapter at write time) so the
40
53
  * customer can prune them; the `infinity` column default is only a fallback for
41
54
  * a row inserted without one. */
42
- export function idempotencyLedgerMigrations(): readonly Migration[] {
55
+ export function idempotencyLedgerMigrations(schema = 'public'): readonly Migration[] {
56
+ const ledger = qualified(schema, 'ablo_idempotency');
43
57
  return [
44
58
  {
45
59
  name: 'ablo_idempotency',
46
- up: `CREATE TABLE IF NOT EXISTS ablo_idempotency (
60
+ up: `CREATE TABLE IF NOT EXISTS ${ledger} (
47
61
  client_tx_id TEXT PRIMARY KEY,
48
62
  response JSONB NOT NULL,
49
63
  request_hash TEXT,
@@ -64,11 +78,11 @@ export function idempotencyLedgerMigrations(): readonly Migration[] {
64
78
  // setup — owned by another role — the no-op still errors "must be owner".
65
79
  // Guard on the catalog (readable regardless of ownership) so the ALTER
66
80
  // runs only when the column is genuinely absent, keeping re-runs safe.
67
- up: addColumnIfAbsent('request_hash', 'TEXT'),
81
+ up: addColumnIfAbsent(schema, 'request_hash', 'TEXT'),
68
82
  },
69
83
  {
70
84
  name: 'ablo_idempotency_permanent_retention',
71
- up: addColumnIfAbsent('expires_at', `TIMESTAMPTZ NOT NULL DEFAULT 'infinity'`),
85
+ up: addColumnIfAbsent(schema, 'expires_at', `TIMESTAMPTZ NOT NULL DEFAULT 'infinity'`),
72
86
  },
73
87
  ];
74
88
  }
@@ -1433,7 +1433,6 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1433
1433
  idempotencyKey: options.idempotencyKey,
1434
1434
  readAt: options.readAt,
1435
1435
  onStale: options.onStale,
1436
- wait: options.wait,
1437
1436
  claim: options.claim,
1438
1437
  },
1439
1438
  `${modelName} ${action}`
@@ -1476,7 +1475,10 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1476
1475
  method,
1477
1476
  idempotencyKey: clientTxId,
1478
1477
  body: requestBody,
1479
- wait: options?.wait ?? 'confirmed',
1478
+ // Model methods have one promise contract: authoritative
1479
+ // confirmation. Early queued receipts remain available through the
1480
+ // lower-level `commits.create` lifecycle surface.
1481
+ wait: 'confirmed',
1480
1482
  },
1481
1483
  beforeSettlement
1482
1484
  );
@@ -1837,7 +1839,6 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1837
1839
  mutateModel('update', name, id, patch, {
1838
1840
  readAt,
1839
1841
  onStale: 'reject',
1840
- wait: 'confirmed',
1841
1842
  }),
1842
1843
  });
1843
1844
  }
@@ -1879,13 +1880,7 @@ export function createHttpTransport(options: HttpTransportOptions): HttpTranspor
1879
1880
  name,
1880
1881
  id,
1881
1882
  params.data,
1882
- {
1883
- ...options,
1884
- // This method returns the authoritative row, not a receipt. A
1885
- // queued source acceptance cannot satisfy that return contract,
1886
- // even when the caller supplied `wait: 'queued'`.
1887
- wait: 'confirmed',
1888
- },
1883
+ options,
1889
1884
  async () => {
1890
1885
  const read = await retrieveModel<T>(name, { id });
1891
1886
  if (read.data === undefined) {
@@ -70,6 +70,7 @@ import {
70
70
  noopSocketObservability,
71
71
  type SocketObservability,
72
72
  } from '../observability.js';
73
+ import type { DeliveryPartitionRoute } from '../auth/deliveryPartition.js';
73
74
 
74
75
  /**
75
76
  * Ceiling for the exponential reconnect backoff (`reconnectDelay * 2^n`,
@@ -95,6 +96,11 @@ export interface WsTransportOptions {
95
96
  */
96
97
  userId?: string;
97
98
  organizationId?: string;
99
+ /**
100
+ * Opaque server-resolved delivery route. The transport echoes it on every
101
+ * WebSocket upgrade; the receiving gateway authenticates and verifies it.
102
+ */
103
+ deliveryPartition?: DeliveryPartitionRoute | null;
98
104
  lastSyncId?: number;
99
105
  syncGroups?: string[];
100
106
  capabilities?: SyncCapabilities;
@@ -450,6 +456,7 @@ export class WsTransport<
450
456
  lastSyncId: 0,
451
457
  userId: '',
452
458
  organizationId: '',
459
+ deliveryPartition: null,
453
460
  capabilities: {
454
461
  partialBootstrap: true,
455
462
  compressedDeltas: true,
@@ -672,6 +679,12 @@ export class WsTransport<
672
679
  this.options.syncGroups.forEach((group) => {
673
680
  params.append('syncGroups', group);
674
681
  });
682
+ if (this.options.deliveryPartition) {
683
+ params.set(
684
+ 'deliveryPartition',
685
+ `${this.options.deliveryPartition.index}-${this.options.deliveryPartition.count}`,
686
+ );
687
+ }
675
688
 
676
689
  const wsUrl = `${this.options.url}?${params.toString()}`;
677
690
 
@@ -1488,4 +1501,9 @@ export class WsTransport<
1488
1501
  setSyncGroups(syncGroups: readonly string[]): void {
1489
1502
  this.options.syncGroups = [...syncGroups];
1490
1503
  }
1504
+
1505
+ /** Seeds the server-resolved route before the held first connection opens. */
1506
+ setDeliveryPartition(deliveryPartition: DeliveryPartitionRoute | null): void {
1507
+ this.options.deliveryPartition = deliveryPartition;
1508
+ }
1491
1509
  }
@@ -42,8 +42,10 @@ export const READINESS_ITEMS = [
42
42
  'wal_level',
43
43
  'publication',
44
44
  'replication_role',
45
+ 'replication_slot_capacity',
45
46
  'replica_identity',
46
47
  'table_select',
48
+ 'snapshot_row_security',
47
49
  'write_role',
48
50
  'row_security',
49
51
  'database_privileges',
@@ -153,6 +155,22 @@ export const datasourceValidationResponseSchema = z.object({
153
155
  });
154
156
  export type DatasourceValidationResponse = z.infer<typeof datasourceValidationResponseSchema>;
155
157
 
158
+ /** `POST /v1/datasources/resnapshot` — accepted reset of the direct source's
159
+ * initial load. The replacement snapshot completes asynchronously. */
160
+ export const datasourceResnapshotResponseSchema = z.object({
161
+ object: z.literal('datasource_resnapshot'),
162
+ initial_snapshot: z.object({ status: z.literal('loading') }),
163
+ replication_slot: z
164
+ .object({
165
+ slot: z.string(),
166
+ released: z.boolean(),
167
+ detail: z.string().optional(),
168
+ remove_with: z.string().optional(),
169
+ })
170
+ .optional(),
171
+ });
172
+ export type DatasourceResnapshotResponse = z.infer<typeof datasourceResnapshotResponseSchema>;
173
+
156
174
  /**
157
175
  * `POST /v1/datasources/locate` — which plane already holds a database.
158
176
  * A targeted lookup, not an enumeration: the caller must hold the connection
@@ -161,6 +179,8 @@ export type DatasourceValidationResponse = z.infer<typeof datasourceValidationRe
161
179
  */
162
180
  export const datasourceLocationResponseSchema = z.object({
163
181
  object: z.literal('datasource_location').optional(),
182
+ /** False with held=null means another organization owns the binding. */
183
+ available: z.boolean().optional(),
164
184
  held: z
165
185
  .object({
166
186
  project: z.string().nullable(),
package/src/wire/index.ts CHANGED
@@ -315,6 +315,7 @@ export {
315
315
  datasourceListResponseSchema,
316
316
  datasourceValidationResponseSchema,
317
317
  datasourceLocationResponseSchema,
318
+ datasourceResnapshotResponseSchema,
318
319
  datasourceDisconnectedResponseSchema,
319
320
  } from './dataSourceResponses.js';
320
321
  export type {
@@ -326,6 +327,7 @@ export type {
326
327
  DatasourceListResponse,
327
328
  DatasourceValidationResponse,
328
329
  DatasourceLocationResponse,
330
+ DatasourceResnapshotResponse,
329
331
  DatasourceDisconnectedResponse,
330
332
  } from './dataSourceResponses.js';
331
333