@byok-sdk/cloud-dataplane 0.11.0 → 0.12.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/index.js +343 -98
- package/dist/index.js.map +1 -1
- package/dist/runtime.js +338 -98
- package/dist/runtime.js.map +1 -1
- package/dist/sql/0016_mailbox_delivery_watermark.sql +20 -0
- package/dist/sql/0017_agent_message_admission.sql +23 -0
- package/dist/stores/core/mailbox.d.ts +5 -4
- package/dist/stores/devices.d.ts +10 -1
- package/dist/stores/nonces.d.ts +1 -2
- package/dist/stores/pairing-codes.d.ts +15 -8
- package/dist/stores/task-attempts.d.ts +20 -1
- package/dist/tenant-erasure.d.ts +2 -2
- package/package.json +4 -4
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- 0016_mailbox_delivery_watermark.sql — server-owned mailbox delivery bound.
|
|
2
|
+
--
|
|
3
|
+
-- Client acknowledgement is allowed only through the highest cursor the
|
|
4
|
+
-- server has returned to that exact tenant/device. Enqueue allocation is not
|
|
5
|
+
-- delivery authority: next_seq may be far ahead while no response has exposed
|
|
6
|
+
-- those rows. Existing acknowledged rows are the one safe backfill fact — an
|
|
7
|
+
-- acknowledgement already persisted before this migration necessarily came
|
|
8
|
+
-- from the historical delivery path.
|
|
9
|
+
|
|
10
|
+
ALTER TABLE device_stream
|
|
11
|
+
ADD COLUMN delivered_seq bigint NOT NULL DEFAULT 0;
|
|
12
|
+
|
|
13
|
+
UPDATE device_stream
|
|
14
|
+
SET delivered_seq = acked_seq;
|
|
15
|
+
|
|
16
|
+
ALTER TABLE device_stream
|
|
17
|
+
ADD CONSTRAINT device_stream_delivery_nonnegative
|
|
18
|
+
CHECK (delivered_seq >= 0),
|
|
19
|
+
ADD CONSTRAINT device_stream_ack_within_delivery
|
|
20
|
+
CHECK (acked_seq <= delivered_seq);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
-- Durable first-message admission serialized with task cancellation.
|
|
2
|
+
--
|
|
3
|
+
-- This one row records both the admission and the immutable final disposition:
|
|
4
|
+
-- exactly one new agent.message.publish may cross from a live task into the
|
|
5
|
+
-- product consumer. A pending row is deliberately fail-closed: elapsed time
|
|
6
|
+
-- cannot prove that an external consumer stopped, so retries never invoke it
|
|
7
|
+
-- again or synthesize a terminal result. The task row is locked by the
|
|
8
|
+
-- application transaction before inserting here, so cancellation and first
|
|
9
|
+
-- message admission have one durable winner.
|
|
10
|
+
|
|
11
|
+
CREATE TABLE agent_message_admission (
|
|
12
|
+
tenant_id text NOT NULL,
|
|
13
|
+
device_id text NOT NULL,
|
|
14
|
+
task_id text NOT NULL,
|
|
15
|
+
message_id text NOT NULL,
|
|
16
|
+
payload_body text NOT NULL,
|
|
17
|
+
terminal_body text,
|
|
18
|
+
PRIMARY KEY (tenant_id, device_id, task_id),
|
|
19
|
+
UNIQUE (tenant_id, device_id, message_id),
|
|
20
|
+
FOREIGN KEY (tenant_id, task_id)
|
|
21
|
+
REFERENCES task (tenant_id, task_id)
|
|
22
|
+
ON DELETE CASCADE
|
|
23
|
+
);
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* The load-bearing rule, and the one a composition can break silently:
|
|
5
5
|
* **reading is not acknowledging.** `readAfter` is a `SELECT` and nothing else.
|
|
6
6
|
* The only ack is `advanceCursor`, which the daemon calls after it has durably
|
|
7
|
-
* journaled the envelope
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* journaled the envelope. It is monotonic and bounded by `recordDelivery`:
|
|
8
|
+
* regression and future cursors are refused with the cursor state they lost
|
|
9
|
+
* to rather than re-delivering or silently skipping work.
|
|
10
10
|
*
|
|
11
11
|
* `collectRetired` deletes acked rows and **marks** unacked ones `expired`. It
|
|
12
12
|
* never deletes an unacked row. §12.7.5 requires an envelope that aged out
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* the SQL expression of §12.6.2 layer 3: there is no bare device index to
|
|
20
20
|
* accidentally query.
|
|
21
21
|
*/
|
|
22
|
-
import { type Clock, type MailboxAdvanceCursorInput, type MailboxAppendInput, type MailboxCursorState, type MailboxMessage, type MailboxPage, type MailboxReadQuery, type MailboxRetentionInput, type MailboxRetentionResult, type MailboxStore, type TenantId } from '@byok-sdk/core';
|
|
22
|
+
import { type Clock, type MailboxAdvanceCursorInput, type MailboxAppendInput, type MailboxCursorState, type MailboxMessage, type MailboxPage, type MailboxReadQuery, type MailboxRecordDeliveryInput, type MailboxRetentionInput, type MailboxRetentionResult, type MailboxStore, type TenantId } from '@byok-sdk/core';
|
|
23
23
|
import type { Pool } from 'pg';
|
|
24
24
|
export declare const OUTBOX_COLUMNS = "tenant_id, device_id, seq, message_id, body, body_hash, byte_size, state, appended_at";
|
|
25
25
|
export interface OutboxRow {
|
|
@@ -40,6 +40,7 @@ export declare class PostgresMailboxStore implements MailboxStore {
|
|
|
40
40
|
append(tenant: TenantId, input: MailboxAppendInput): Promise<MailboxMessage>;
|
|
41
41
|
readAfter(tenant: TenantId, query: MailboxReadQuery): Promise<MailboxPage>;
|
|
42
42
|
advanceCursor(tenant: TenantId, input: MailboxAdvanceCursorInput): Promise<MailboxCursorState>;
|
|
43
|
+
recordDelivery(tenant: TenantId, input: MailboxRecordDeliveryInput): Promise<MailboxCursorState>;
|
|
43
44
|
readCursor(tenant: TenantId, deviceId: string): Promise<MailboxCursorState>;
|
|
44
45
|
collectRetired(tenant: TenantId, input: MailboxRetentionInput): Promise<MailboxRetentionResult>;
|
|
45
46
|
}
|
package/dist/stores/devices.d.ts
CHANGED
|
@@ -19,7 +19,16 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { type Clock, type PresenceStore, type TenantId, type TenantReadiness } from '@byok-sdk/core';
|
|
21
21
|
import type { DeviceDirectory, DeviceRecord, DeviceRegistration } from '@byok-sdk/cloud';
|
|
22
|
-
import type { Pool } from 'pg';
|
|
22
|
+
import type { Pool, PoolClient } from 'pg';
|
|
23
|
+
/**
|
|
24
|
+
* The client-scoped registration mutation shared by standalone device
|
|
25
|
+
* registration and pairing enrollment. Its caller owns the transaction so the
|
|
26
|
+
* guarded pairing-code update, machine supersession cleanup, and insert can
|
|
27
|
+
* commit or roll back together.
|
|
28
|
+
*/
|
|
29
|
+
export declare function registerDeviceOnClient(client: PoolClient, tenant: TenantId, input: DeviceRegistration): Promise<DeviceRecord>;
|
|
30
|
+
/** Read one active device while a caller-owned transaction still holds its authority lock. */
|
|
31
|
+
export declare function getDeviceOnClient(client: PoolClient, tenant: TenantId, deviceId: string): Promise<DeviceRecord | undefined>;
|
|
23
32
|
export declare class PostgresDeviceDirectory implements DeviceDirectory {
|
|
24
33
|
#private;
|
|
25
34
|
constructor(pool: Pool, clock?: Clock);
|
package/dist/stores/nonces.d.ts
CHANGED
|
@@ -21,6 +21,5 @@ export declare class PostgresNonceStore implements NonceStore {
|
|
|
21
21
|
#private;
|
|
22
22
|
constructor(pool: Pool, clock: Clock, crypto: CloudCrypto, ttlMs?: number);
|
|
23
23
|
issue(tenant: TenantId, deviceId: string): Promise<string>;
|
|
24
|
-
|
|
25
|
-
markUsed(tenant: TenantId, nonce: string): Promise<void>;
|
|
24
|
+
consumeIfValid(tenant: TenantId, deviceId: string, nonce: string): Promise<boolean>;
|
|
26
25
|
}
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Postgres {@link PairingCodeStore}: single-use codes bound to the tenant and
|
|
3
3
|
* product they were minted for.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* exclusive.
|
|
5
|
+
* Enrollment is one transaction. `UPDATE ... WHERE redeemed_at IS NULL AND
|
|
6
|
+
* expires_at >= $now RETURNING ...` claims the code only inside the same client
|
|
7
|
+
* transaction that applies machine supersession/state cleanup and inserts the
|
|
8
|
+
* device. A read-then-write would let two callers observe an unused code; an
|
|
9
|
+
* autocommitted redemption would strand a code when registration fails.
|
|
11
10
|
*
|
|
12
11
|
* Unknown, expired, and already-used all answer `undefined`. The reference
|
|
13
12
|
* server distinguishes them in its 401 text; a hosted multi-tenant surface
|
|
@@ -16,11 +15,19 @@
|
|
|
16
15
|
* difference an attacker enumerating codes would pay for.
|
|
17
16
|
*/
|
|
18
17
|
import type { Clock, TenantId } from '@byok-sdk/core';
|
|
19
|
-
import type {
|
|
18
|
+
import type { DeviceRecord, PairingCodeInfo, PairingCodeIssueInput, PairingCodeStore } from '@byok-sdk/cloud';
|
|
20
19
|
import type { Pool } from 'pg';
|
|
21
20
|
export declare class PostgresPairingCodeStore implements PairingCodeStore {
|
|
22
21
|
#private;
|
|
23
22
|
constructor(pool: Pool, clock: Clock);
|
|
24
23
|
issue(tenant: TenantId, input: PairingCodeIssueInput): Promise<PairingCodeInfo>;
|
|
25
|
-
|
|
24
|
+
redeemAndRegister(input: {
|
|
25
|
+
readonly pairingCode: string;
|
|
26
|
+
readonly deviceId: string;
|
|
27
|
+
readonly deviceName: string;
|
|
28
|
+
readonly devicePublicKey: string;
|
|
29
|
+
readonly proofKeyId: string;
|
|
30
|
+
readonly proofKeyEpoch: number;
|
|
31
|
+
readonly machineId?: string;
|
|
32
|
+
}): Promise<DeviceRecord | undefined>;
|
|
26
33
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* `claim` and `recordStatus` on a task this tenant never offered write nothing
|
|
15
15
|
* and return `undefined`.
|
|
16
16
|
*/
|
|
17
|
-
import type
|
|
17
|
+
import { type AgentMessageAdmission, type AgentRef, type TaskAttempt, type TaskAttemptStatus, type TaskAttemptStore } from '@byok-sdk/cloud';
|
|
18
18
|
import type { Clock, TenantId } from '@byok-sdk/core';
|
|
19
19
|
import type { Pool } from 'pg';
|
|
20
20
|
export interface TaskRow {
|
|
@@ -49,6 +49,25 @@ export declare class PostgresTaskAttemptStore implements TaskAttemptStore {
|
|
|
49
49
|
readonly attempt: TaskAttempt;
|
|
50
50
|
readonly created: boolean;
|
|
51
51
|
}>;
|
|
52
|
+
reserveAgentMessage(tenant: TenantId, input: {
|
|
53
|
+
readonly taskId: string;
|
|
54
|
+
readonly deviceId: string;
|
|
55
|
+
readonly messageId: string;
|
|
56
|
+
readonly payloadBody: string;
|
|
57
|
+
}): Promise<'reserved' | 'pending' | 'rejected'>;
|
|
58
|
+
readAgentMessage(tenant: TenantId, input: {
|
|
59
|
+
readonly taskId: string;
|
|
60
|
+
readonly deviceId: string;
|
|
61
|
+
readonly messageId: string;
|
|
62
|
+
readonly payloadBody: string;
|
|
63
|
+
}): Promise<AgentMessageAdmission | undefined>;
|
|
64
|
+
finalizeAgentMessage(tenant: TenantId, input: {
|
|
65
|
+
readonly taskId: string;
|
|
66
|
+
readonly deviceId: string;
|
|
67
|
+
readonly messageId: string;
|
|
68
|
+
readonly payloadBody: string;
|
|
69
|
+
readonly terminalBody: string;
|
|
70
|
+
}): Promise<AgentMessageAdmission | undefined>;
|
|
52
71
|
get(tenant: TenantId, taskId: string): Promise<TaskAttempt | undefined>;
|
|
53
72
|
getMany(tenant: TenantId, taskIds: readonly string[]): Promise<readonly TaskAttempt[]>;
|
|
54
73
|
claim(tenant: TenantId, input: {
|
package/dist/tenant-erasure.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Clock, type TenantId } from '@byok-sdk/core';
|
|
2
2
|
import type { Pool } from 'pg';
|
|
3
3
|
import { type R2BlobStoreOptions, type R2ObjectMaintenance } from './stores/r2-blobs';
|
|
4
|
-
/** Every tenant-owned table as of
|
|
5
|
-
export declare const TENANT_ERASURE_TABLES: readonly ['object_reference', 'object_manifest', 'storage_reservation', 'storage_usage', 'storage_entitlement', 'gc_cursor', 'cleanup_job', 'tenant_retention_policy', 'skill_pack_file', 'skill_pack', 'approval_timeline_tail', 'activity_tail', 'attested_record', 'board_item', 'tenant_stream', 'outbox', 'agent_memory_projection_metering_receipt', 'agent_memory_projection_head', 'agent_memory_projection_erase_fence', 'agent_egress_event', 'device_request_receipts', 'proof_request_receipt', 'task', 'device_presence', 'device_assertion_replay', 'device_stream', 'inbound_dedup', 'auth_nonce', 'pairing_code', 'device'];
|
|
4
|
+
/** Every tenant-owned table as of 0017, in child-before-parent deletion order. */
|
|
5
|
+
export declare const TENANT_ERASURE_TABLES: readonly ['object_reference', 'object_manifest', 'storage_reservation', 'storage_usage', 'storage_entitlement', 'gc_cursor', 'cleanup_job', 'tenant_retention_policy', 'skill_pack_file', 'skill_pack', 'approval_timeline_tail', 'activity_tail', 'attested_record', 'board_item', 'tenant_stream', 'outbox', 'agent_memory_projection_metering_receipt', 'agent_memory_projection_head', 'agent_memory_projection_erase_fence', 'agent_egress_event', 'device_request_receipts', 'proof_request_receipt', 'agent_message_admission', 'task', 'device_presence', 'device_assertion_replay', 'device_stream', 'inbound_dedup', 'auth_nonce', 'pairing_code', 'device'];
|
|
6
6
|
export declare const TENANT_ERASURE_ERROR_CODES: {
|
|
7
7
|
readonly tenant_erasure_invalid_input: 'tenant_erasure_invalid_input';
|
|
8
8
|
readonly tenant_erasure_schema_drift: 'tenant_erasure_schema_drift';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byok-sdk/cloud-dataplane",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "BYOK SDK hosted data plane: canonical Postgres + R2 stores, migrations, truth transactions, and maintenance",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"clean": "rm -rf dist"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@byok-sdk/cloud": "0.
|
|
53
|
-
"@byok-sdk/core": "0.
|
|
54
|
-
"@byok-sdk/protocol": "0.
|
|
52
|
+
"@byok-sdk/cloud": "0.12.0",
|
|
53
|
+
"@byok-sdk/core": "0.12.0",
|
|
54
|
+
"@byok-sdk/protocol": "0.12.0",
|
|
55
55
|
"aws4fetch": "1.0.20",
|
|
56
56
|
"fast-xml-parser": "^5.10.1",
|
|
57
57
|
"pg": "^8.22.0"
|