@abloatai/transaction 0.46.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-sdk/modelTools.d.ts.map +1 -1
- package/dist/ai-sdk/modelTools.js +1 -2
- package/dist/ai-sdk/modelTools.js.map +1 -1
- package/dist/ai-sdk/updateTool.d.ts.map +1 -1
- package/dist/ai-sdk/updateTool.js +0 -1
- package/dist/ai-sdk/updateTool.js.map +1 -1
- package/dist/auth/capability.d.ts +8 -0
- package/dist/auth/capability.d.ts.map +1 -1
- package/dist/auth/capability.js +2 -0
- package/dist/auth/capability.js.map +1 -1
- package/dist/auth/capabilityLifecycle.d.ts +4 -0
- package/dist/auth/capabilityLifecycle.d.ts.map +1 -1
- package/dist/auth/deliveryPartition.d.ts +14 -0
- package/dist/auth/deliveryPartition.d.ts.map +1 -0
- package/dist/auth/deliveryPartition.js +16 -0
- package/dist/auth/deliveryPartition.js.map +1 -0
- package/dist/auth/identity.d.ts +2 -0
- package/dist/auth/identity.d.ts.map +1 -1
- package/dist/auth/identity.js +3 -0
- package/dist/auth/identity.js.map +1 -1
- package/dist/auth/schemas.d.ts +8 -0
- package/dist/auth/schemas.d.ts.map +1 -1
- package/dist/auth/schemas.js +3 -0
- package/dist/auth/schemas.js.map +1 -1
- package/dist/auth/sessionMint.d.ts.map +1 -1
- package/dist/auth/sessionMint.js +1 -0
- package/dist/auth/sessionMint.js.map +1 -1
- package/dist/branches.d.ts +61 -12
- package/dist/branches.d.ts.map +1 -1
- package/dist/branches.js +25 -3
- package/dist/branches.js.map +1 -1
- package/dist/errorCodes.d.ts +18 -2
- package/dist/errorCodes.d.ts.map +1 -1
- package/dist/errorCodes.js +28 -12
- package/dist/errorCodes.js.map +1 -1
- package/dist/footprint.d.ts +10 -22
- package/dist/footprint.d.ts.map +1 -1
- package/dist/footprint.js +14 -24
- package/dist/footprint.js.map +1 -1
- package/dist/pricing.d.ts +21 -2
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +32 -8
- package/dist/pricing.js.map +1 -1
- package/dist/resources/httpResources.d.ts +0 -1
- package/dist/resources/httpResources.d.ts.map +1 -1
- package/dist/resources/modelOperations.d.ts +13 -3
- package/dist/resources/modelOperations.d.ts.map +1 -1
- package/dist/schema/openapi.js +4 -4
- package/dist/schema/openapi.js.map +1 -1
- package/dist/source/index.d.ts +1 -1
- package/dist/source/index.d.ts.map +1 -1
- package/dist/source/migrations.d.ts +1 -1
- package/dist/source/migrations.d.ts.map +1 -1
- package/dist/source/migrations.js +18 -7
- package/dist/source/migrations.js.map +1 -1
- package/dist/transport/httpTransport.d.ts.map +1 -1
- package/dist/transport/httpTransport.js +5 -10
- package/dist/transport/httpTransport.js.map +1 -1
- package/dist/transport/wsTransport.d.ts +8 -0
- package/dist/transport/wsTransport.d.ts.map +1 -1
- package/dist/transport/wsTransport.js +8 -0
- package/dist/transport/wsTransport.js.map +1 -1
- package/dist/wire/dataSourceResponses.d.ts +17 -1
- package/dist/wire/dataSourceResponses.d.ts.map +1 -1
- package/dist/wire/dataSourceResponses.js +18 -0
- package/dist/wire/dataSourceResponses.js.map +1 -1
- package/dist/wire/index.d.ts +2 -2
- package/dist/wire/index.d.ts.map +1 -1
- package/dist/wire/index.js +1 -1
- package/dist/wire/index.js.map +1 -1
- package/package.json +1 -1
- package/src/ai-sdk/modelTools.ts +1 -2
- package/src/ai-sdk/updateTool.ts +0 -1
- package/src/auth/capability.ts +2 -0
- package/src/auth/deliveryPartition.ts +18 -0
- package/src/auth/identity.ts +5 -0
- package/src/auth/schemas.ts +3 -0
- package/src/auth/sessionMint.ts +1 -0
- package/src/branches.ts +27 -3
- package/src/errorCodes.ts +113 -17
- package/src/footprint.ts +18 -27
- package/src/pricing.ts +36 -8
- package/src/resources/httpResources.ts +0 -1
- package/src/resources/modelOperations.ts +14 -3
- package/src/schema/openapi.ts +4 -4
- package/src/source/index.ts +1 -1
- package/src/source/migrations.ts +21 -7
- package/src/transport/httpTransport.ts +5 -10
- package/src/transport/wsTransport.ts +18 -0
- package/src/wire/dataSourceResponses.ts +20 -0
- package/src/wire/index.ts +2 -0
|
@@ -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
|
|
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
|
|
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
|
|
592
|
+
extends ModelWriteOptions {
|
|
582
593
|
readonly id: string;
|
|
583
594
|
readonly claim?: Claim<T> | ClaimTargetOptions<Fields> | null;
|
|
584
595
|
}
|
package/src/schema/openapi.ts
CHANGED
|
@@ -644,7 +644,7 @@ export function abloOpenApi(options: SchemaToOpenApiOptions = {}): Json {
|
|
|
644
644
|
'/v1/branches/{id}/status': {
|
|
645
645
|
get: {
|
|
646
646
|
tags: ['branches'],
|
|
647
|
-
summary: 'Diagnose one branch
|
|
647
|
+
summary: 'Diagnose one branch',
|
|
648
648
|
description:
|
|
649
649
|
'Returns branch lifecycle, active schema, compatibility with the parent schema, safe datasource coordinates, and readiness blockers.',
|
|
650
650
|
parameters: [idParam()],
|
|
@@ -699,7 +699,7 @@ export function abloOpenApi(options: SchemaToOpenApiOptions = {}): Json {
|
|
|
699
699
|
description:
|
|
700
700
|
'One round trip per cadence for a worker holding many rows, instead of ' +
|
|
701
701
|
'one per row. Takes only `ttl`; the leases are whichever ones your ' +
|
|
702
|
-
'credential holds on this
|
|
702
|
+
'credential holds on this branch.',
|
|
703
703
|
requestBody: optionalJsonBody(derive(claimHeartbeatRequestSchema, 'input')),
|
|
704
704
|
responses: {
|
|
705
705
|
'200': namedResp(
|
|
@@ -812,7 +812,7 @@ export function abloOpenApi(options: SchemaToOpenApiOptions = {}): Json {
|
|
|
812
812
|
tags: ['schema'],
|
|
813
813
|
summary: 'What the models look like',
|
|
814
814
|
description:
|
|
815
|
-
"The schema deployed on your credential's
|
|
815
|
+
"The schema deployed on your credential's branch: every model with its " +
|
|
816
816
|
'fields, their types, and its relations. Read this when you have no ' +
|
|
817
817
|
'local schema declaration to read types from — it is what makes a ' +
|
|
818
818
|
'field typo a local check rather than a rejected write. Each model ' +
|
|
@@ -835,7 +835,7 @@ export function abloOpenApi(options: SchemaToOpenApiOptions = {}): Json {
|
|
|
835
835
|
'How a caller without a socket learns what its peers did. Omit ' +
|
|
836
836
|
'`after` for the most recent entries, then copy each page\'s ' +
|
|
837
837
|
'`next_cursor` back as `after` to walk forward. Scope is taken from ' +
|
|
838
|
-
'your key — organization,
|
|
838
|
+
'your key — organization, branch and sync groups — so a caller cannot ' +
|
|
839
839
|
'widen what it sees by asking.',
|
|
840
840
|
parameters: queryParams(logQuerySchema),
|
|
841
841
|
responses: {
|
package/src/source/index.ts
CHANGED
package/src/source/migrations.ts
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|