@byok-sdk/cloud-dataplane 0.6.0 → 0.7.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 CHANGED
@@ -3,11 +3,11 @@ import { DEDUP_RING_CAPACITY, NONCE_TTL_MS, validateActivityAppend, projectTimel
3
3
  import { contentHash, ByokCoreError, assertCanonicalTimestamp, isContentHash, tenantObjectKey, objectKeyPrefix, CoreConflictError, isLegalBoardTransition, checkSkillPackManifest, checkSkillPackEntry, SKILL_PACK_ENTRY_PATH, tenantId, SKILL_PACK_MANIFEST_SCHEMA_ID } from '@byok-sdk/core';
4
4
  import { AwsClient } from 'aws4fetch';
5
5
  import { XMLParser } from 'fast-xml-parser';
6
+ import { decodeEnvelope, isServerToDaemonType, EnvelopeSchema, encodeEnvelope, AgentEgressReliablePayloadSchema } from '@byok-sdk/protocol';
6
7
  import { createHash, randomUUID } from 'crypto';
7
8
  import { readdir, readFile } from 'fs/promises';
8
9
  import { join } from 'path';
9
10
  import { fileURLToPath } from 'url';
10
- import { decodeEnvelope, isServerToDaemonType, EnvelopeSchema, encodeEnvelope } from '@byok-sdk/protocol';
11
11
 
12
12
  // src/pool.ts
13
13
  var defaultTypeParser = pg.types.getTypeParser;
@@ -802,10 +802,11 @@ function toRecord(row) {
802
802
  devicePublicKey: row.device_public_key,
803
803
  proofKeyId: row.proof_key_id,
804
804
  proofKeyEpoch: row.proof_key_epoch,
805
- revoked: row.revoked
805
+ revoked: row.revoked,
806
+ ...row.capabilities == null ? {} : { capabilities: Object.freeze([...row.capabilities]) }
806
807
  };
807
808
  }
808
- var SELECT_COLUMNS = "tenant_id, device_id, product_id, device_name, device_public_key, proof_key_id, proof_key_epoch, revoked";
809
+ var SELECT_COLUMNS = "tenant_id, device_id, product_id, device_name, device_public_key, proof_key_id, proof_key_epoch, revoked, capabilities";
809
810
  var PostgresDeviceDirectory = class {
810
811
  #pool;
811
812
  #clock;
@@ -826,7 +827,8 @@ var PostgresDeviceDirectory = class {
826
827
  device_public_key = EXCLUDED.device_public_key,
827
828
  proof_key_id = EXCLUDED.proof_key_id,
828
829
  proof_key_epoch = EXCLUDED.proof_key_epoch,
829
- revoked = false
830
+ revoked = false,
831
+ capabilities = NULL
830
832
  RETURNING ${SELECT_COLUMNS}`,
831
833
  [
832
834
  tenant,
@@ -854,6 +856,17 @@ var PostgresDeviceDirectory = class {
854
856
  deviceId
855
857
  ]);
856
858
  }
859
+ async recordCapabilities(tenant, input) {
860
+ const result = await this.#pool.query(
861
+ `UPDATE device
862
+ SET capabilities = $3::jsonb
863
+ WHERE tenant_id = $1 AND device_id = $2 AND revoked = false
864
+ RETURNING ${SELECT_COLUMNS}`,
865
+ [tenant, input.deviceId, JSON.stringify([...input.capabilities])]
866
+ );
867
+ const row = result.rows[0];
868
+ return row === void 0 ? void 0 : toRecord(row);
869
+ }
857
870
  async list(tenant) {
858
871
  const result = await this.#pool.query(
859
872
  `SELECT ${SELECT_COLUMNS} FROM device WHERE tenant_id = $1 ORDER BY device_id`,
@@ -1151,18 +1164,25 @@ var PostgresProofRequestReceiptStore = class {
1151
1164
  };
1152
1165
 
1153
1166
  // src/stores/task-attempts.ts
1154
- var TASK_SELECT_COLUMNS = "tenant_id, task_id, device_id, owner_device_id, status, cancel_requested_at, cancel_reason, cancel_message_id, updated_at";
1167
+ var TASK_SELECT_COLUMNS = "tenant_id, task_id, device_id, agent_id, agent_profile_revision, owner_device_id, status, terminal_cause, cancel_requested_at, cancel_reason, cancel_message_id, updated_at";
1155
1168
  function taskRowToAttempt(row) {
1156
1169
  return {
1157
1170
  tenantId: row.tenant_id,
1158
1171
  taskId: row.task_id,
1159
1172
  deviceId: row.device_id,
1173
+ ...row.agent_id == null || row.agent_profile_revision == null ? {} : {
1174
+ agentRef: {
1175
+ agentId: row.agent_id,
1176
+ profileRevision: row.agent_profile_revision
1177
+ }
1178
+ },
1160
1179
  // `exactOptionalPropertyTypes` is off here, but an explicit absent key is
1161
1180
  // still what the in-memory reference produces for an unclaimed attempt, and
1162
1181
  // `toEqual` in the suite treats `undefined` and absent alike only for the
1163
1182
  // former.
1164
1183
  ...row.owner_device_id === null ? {} : { ownerDeviceId: row.owner_device_id },
1165
1184
  status: row.status,
1185
+ ...row.terminal_cause == null ? {} : { terminalCause: row.terminal_cause },
1166
1186
  ...row.cancel_requested_at === null ? {} : {
1167
1187
  cancellation: {
1168
1188
  requestedAt: row.cancel_requested_at.toISOString(),
@@ -1181,11 +1201,21 @@ var PostgresTaskAttemptStore = class {
1181
1201
  }
1182
1202
  async open(tenant, input) {
1183
1203
  const inserted = await this.#pool.query(
1184
- `INSERT INTO task (tenant_id, task_id, device_id, owner_device_id, status, updated_at)
1185
- VALUES ($1, $2, $3, NULL, 'offered', $4)
1204
+ `INSERT INTO task (
1205
+ tenant_id, task_id, device_id, agent_id, agent_profile_revision,
1206
+ owner_device_id, status, updated_at
1207
+ )
1208
+ VALUES ($1, $2, $3, $4, $5, NULL, 'offered', $6)
1186
1209
  ON CONFLICT (tenant_id, task_id) DO NOTHING
1187
1210
  RETURNING ${TASK_SELECT_COLUMNS}`,
1188
- [tenant, input.taskId, input.deviceId, this.#now()]
1211
+ [
1212
+ tenant,
1213
+ input.taskId,
1214
+ input.deviceId,
1215
+ input.agentRef?.agentId ?? null,
1216
+ input.agentRef?.profileRevision ?? null,
1217
+ this.#now()
1218
+ ]
1189
1219
  );
1190
1220
  const created = inserted.rows[0];
1191
1221
  if (created !== void 0) return taskRowToAttempt(created);
@@ -1193,6 +1223,23 @@ var PostgresTaskAttemptStore = class {
1193
1223
  if (existing === void 0) throw new Error(`task ${input.taskId} vanished during open`);
1194
1224
  return existing;
1195
1225
  }
1226
+ async reserveAgentOffer(tenant, input) {
1227
+ const inserted = await this.#pool.query(
1228
+ `INSERT INTO task (
1229
+ tenant_id, task_id, device_id, agent_id, agent_profile_revision,
1230
+ owner_device_id, status, updated_at
1231
+ )
1232
+ VALUES ($1, $2, $3, $4, $5, NULL, 'offered', $6)
1233
+ ON CONFLICT (tenant_id, task_id) DO NOTHING
1234
+ RETURNING ${TASK_SELECT_COLUMNS}`,
1235
+ [tenant, input.taskId, input.deviceId, input.agentRef.agentId, input.agentRef.profileRevision, this.#now()]
1236
+ );
1237
+ const created = inserted.rows[0];
1238
+ if (created !== void 0) return { attempt: taskRowToAttempt(created), created: true };
1239
+ const existing = await this.get(tenant, input.taskId);
1240
+ if (existing === void 0) throw new Error(`task ${input.taskId} vanished during Agent offer reservation`);
1241
+ return { attempt: existing, created: false };
1242
+ }
1196
1243
  async get(tenant, taskId) {
1197
1244
  const result = await this.#pool.query(
1198
1245
  `SELECT ${TASK_SELECT_COLUMNS} FROM task WHERE tenant_id = $1 AND task_id = $2`,
@@ -1225,14 +1272,28 @@ var PostgresTaskAttemptStore = class {
1225
1272
  async recordStatus(tenant, input) {
1226
1273
  const result = await this.#pool.query(
1227
1274
  `UPDATE task
1228
- SET status = $3, updated_at = $4
1275
+ SET status = $3,
1276
+ terminal_cause = COALESCE($7, terminal_cause),
1277
+ updated_at = $4
1229
1278
  WHERE tenant_id = $1 AND task_id = $2
1279
+ AND (
1280
+ (agent_id IS NULL AND agent_profile_revision IS NULL AND $5::text IS NULL AND $6::text IS NULL)
1281
+ OR (agent_id = $5 AND agent_profile_revision = $6)
1282
+ )
1230
1283
  AND (
1231
1284
  (cancel_requested_at IS NULL AND status NOT IN ('complete', 'failed', 'cancelled'))
1232
1285
  OR (cancel_requested_at IS NOT NULL AND $3 = 'cancelled' AND status <> 'cancelled')
1233
1286
  )
1234
1287
  RETURNING ${TASK_SELECT_COLUMNS}`,
1235
- [tenant, input.taskId, input.status, this.#now()]
1288
+ [
1289
+ tenant,
1290
+ input.taskId,
1291
+ input.status,
1292
+ this.#now(),
1293
+ input.agentRef?.agentId ?? null,
1294
+ input.agentRef?.profileRevision ?? null,
1295
+ input.terminalCause ?? null
1296
+ ]
1236
1297
  );
1237
1298
  const row = result.rows[0];
1238
1299
  return row === void 0 ? this.get(tenant, input.taskId) : taskRowToAttempt(row);
@@ -1790,6 +1851,87 @@ var PostgresApprovalTimelineStore = class {
1790
1851
  return row === void 0 ? void 0 : toTail2(row);
1791
1852
  }
1792
1853
  };
1854
+ var SELECT_COLUMNS4 = [
1855
+ "tenant_id",
1856
+ "device_id",
1857
+ "event_id",
1858
+ "agent_id",
1859
+ "agent_profile_revision",
1860
+ "session_ref",
1861
+ "policy_revision",
1862
+ "cursor",
1863
+ "payload_json",
1864
+ "content_hash",
1865
+ "byte_count",
1866
+ "receipt_id",
1867
+ "recorded_at"
1868
+ ].join(", ");
1869
+ function toRecord2(row) {
1870
+ const payload = AgentEgressReliablePayloadSchema.parse({
1871
+ agentRef: { agentId: row.agent_id, profileRevision: row.agent_profile_revision },
1872
+ sessionRef: row.session_ref,
1873
+ policyRevision: row.policy_revision,
1874
+ eventId: row.event_id,
1875
+ cursor: Number(row.cursor),
1876
+ payload: row.payload_json,
1877
+ contentHash: row.content_hash,
1878
+ byteCount: row.byte_count
1879
+ });
1880
+ return {
1881
+ tenantId: row.tenant_id,
1882
+ deviceId: row.device_id,
1883
+ payload,
1884
+ receiptId: row.receipt_id,
1885
+ recordedAt: row.recorded_at.toISOString()
1886
+ };
1887
+ }
1888
+ var PostgresAgentEgressStore = class {
1889
+ constructor(pool, clock) {
1890
+ this.pool = pool;
1891
+ this.clock = clock;
1892
+ }
1893
+ pool;
1894
+ clock;
1895
+ async record(tenant, input) {
1896
+ const payload = AgentEgressReliablePayloadSchema.parse(input.payload);
1897
+ const inserted = await this.pool.query(
1898
+ `INSERT INTO agent_egress_event (${SELECT_COLUMNS4})
1899
+ VALUES ($1, $2, $3::uuid, $4, $5, $6, $7, $8::bigint, $9::jsonb, $10, $11::integer, $12::uuid, $13)
1900
+ ON CONFLICT (tenant_id, device_id, event_id) DO NOTHING
1901
+ RETURNING ${SELECT_COLUMNS4}`,
1902
+ [
1903
+ tenant,
1904
+ input.deviceId,
1905
+ payload.eventId,
1906
+ payload.agentRef.agentId,
1907
+ payload.agentRef.profileRevision,
1908
+ payload.sessionRef,
1909
+ payload.policyRevision,
1910
+ payload.cursor,
1911
+ JSON.stringify(payload.payload),
1912
+ payload.contentHash,
1913
+ payload.byteCount,
1914
+ input.receiptId,
1915
+ this.clock.now().toISOString()
1916
+ ]
1917
+ );
1918
+ const row = inserted.rows[0];
1919
+ if (row !== void 0) return { record: toRecord2(row), created: true };
1920
+ const existing = await this.get(tenant, input.deviceId, payload.eventId);
1921
+ if (existing === void 0) throw new Error(`Agent egress ${payload.eventId} vanished during first-write record.`);
1922
+ return { record: existing, created: false };
1923
+ }
1924
+ async get(tenant, deviceId, eventId) {
1925
+ const result = await this.pool.query(
1926
+ `SELECT ${SELECT_COLUMNS4}
1927
+ FROM agent_egress_event
1928
+ WHERE tenant_id = $1 AND device_id = $2 AND event_id = $3::uuid`,
1929
+ [tenant, deviceId, eventId]
1930
+ );
1931
+ const row = result.rows[0];
1932
+ return row === void 0 ? void 0 : toRecord2(row);
1933
+ }
1934
+ };
1793
1935
 
1794
1936
  // src/stores/device-assertion-replay.ts
1795
1937
  var PostgresDeviceAssertionReplayAuthority = class {
@@ -1853,6 +1995,7 @@ function createPostgresCloudStores(options) {
1853
1995
  tasks: new PostgresTaskAttemptStore(pool, clock),
1854
1996
  cancellations: new PostgresTaskCancellationStore(pool, clock),
1855
1997
  receipts: new PostgresRequestReceiptStore(pool, clock),
1998
+ egress: new PostgresAgentEgressStore(pool, clock),
1856
1999
  proofReceipts: new PostgresProofRequestReceiptStore(pool, clock),
1857
2000
  // A second `PostgresObjectStore` instance, not a shared one: it is a
1858
2001
  // stateless wrapper over the pool, so the two read and write the same rows
@@ -2929,7 +3072,7 @@ var RECORD_COLUMNS = "tenant_id, kind, subject_id, rev, content_hash, byte_size,
2929
3072
  function toBody(row) {
2930
3073
  return row.body_kind === "inline" ? { kind: "inline", body: row.body_inline ?? "" } : { kind: "object", hash: row.body_object_hash ?? "" };
2931
3074
  }
2932
- function toRecord2(row) {
3075
+ function toRecord3(row) {
2933
3076
  return {
2934
3077
  tenantId: row.tenant_id,
2935
3078
  kind: row.kind,
@@ -2974,7 +3117,7 @@ var PostgresTruthStore = class {
2974
3117
  ]
2975
3118
  );
2976
3119
  const row = inserted.rows[0];
2977
- if (row !== void 0) return toRecord2(row);
3120
+ if (row !== void 0) return toRecord3(row);
2978
3121
  const existing = await this.getRecord(tenant, {
2979
3122
  kind: "task.terminal",
2980
3123
  recordKey: input.taskId
@@ -3040,7 +3183,7 @@ var PostgresTruthStore = class {
3040
3183
  ]
3041
3184
  );
3042
3185
  const row = written.rows[0];
3043
- if (row !== void 0) return toRecord2(row);
3186
+ if (row !== void 0) return toRecord3(row);
3044
3187
  const current = await this.getRecord(tenant, {
3045
3188
  kind: input.kind,
3046
3189
  recordKey: input.recordKey
@@ -3059,7 +3202,7 @@ var PostgresTruthStore = class {
3059
3202
  [tenant, selector.kind, selector.recordKey]
3060
3203
  );
3061
3204
  const row = result.rows[0];
3062
- return row === void 0 ? void 0 : toRecord2(row);
3205
+ return row === void 0 ? void 0 : toRecord3(row);
3063
3206
  }
3064
3207
  async listManifest(tenant, query) {
3065
3208
  const result = await this.#pool.query(
@@ -3107,7 +3250,7 @@ var RECEIPT_COLUMNS = "tenant_id, device_id, request_id, operation, resource, bo
3107
3250
  function toBody2(row) {
3108
3251
  return row.body_kind === "inline" ? { kind: "inline", body: row.body_inline ?? "" } : { kind: "object", hash: row.body_object_hash ?? "" };
3109
3252
  }
3110
- function toRecord3(tenant, row) {
3253
+ function toRecord4(tenant, row) {
3111
3254
  return {
3112
3255
  tenantId: tenant,
3113
3256
  kind: row.kind,
@@ -3284,7 +3427,7 @@ var PostgresTruthCommitter = class {
3284
3427
  );
3285
3428
  current.set(
3286
3429
  writeKey(write),
3287
- result.rows[0] === void 0 ? void 0 : toRecord3(tenant, result.rows[0])
3430
+ result.rows[0] === void 0 ? void 0 : toRecord4(tenant, result.rows[0])
3288
3431
  );
3289
3432
  }
3290
3433
  return current;
@@ -3497,7 +3640,7 @@ var PostgresTruthCommitter = class {
3497
3640
  applied.push({
3498
3641
  input: write,
3499
3642
  before,
3500
- record: toRecord3(tenant, result.rows[0]),
3643
+ record: toRecord4(tenant, result.rows[0]),
3501
3644
  mutated: true
3502
3645
  });
3503
3646
  }
@@ -4761,6 +4904,7 @@ var TENANT_ERASURE_TABLES = [
4761
4904
  "board_item",
4762
4905
  "tenant_stream",
4763
4906
  "outbox",
4907
+ "agent_egress_event",
4764
4908
  "device_request_receipts",
4765
4909
  "proof_request_receipt",
4766
4910
  "task",