@axiom-lattice/pg-stores 3.1.6 → 3.1.9

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 (29) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +29 -0
  3. package/dist/index.d.mts +54 -2
  4. package/dist/index.d.ts +54 -2
  5. package/dist/index.js +424 -47
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +421 -47
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +3 -3
  10. package/src/__tests__/PostgreSQLA2AApiKeyStore.migrations.test.ts +2 -1
  11. package/src/__tests__/PostgreSQLA2AApiKeyStore.test.ts +45 -0
  12. package/src/__tests__/PostgreSQLMcpServerConfigStore.test.ts +79 -0
  13. package/src/__tests__/PostgreSQLOpenAuditStore.test.ts +100 -0
  14. package/src/__tests__/PostgreSQLProjectRoomMessageStore.test.ts +14 -0
  15. package/src/__tests__/PostgreSQLProjectRoomReadStateStore.test.ts +136 -0
  16. package/src/__tests__/PostgresSharedResourceStore.openGrants.test.ts +62 -0
  17. package/src/__tests__/create_open_audit_table.test.ts +40 -0
  18. package/src/createPgStoreConfig.ts +12 -1
  19. package/src/index.ts +2 -0
  20. package/src/migrations/add_api_key_grants.ts +25 -0
  21. package/src/migrations/add_share_open_grants.ts +23 -0
  22. package/src/migrations/create_open_audit_table.ts +36 -0
  23. package/src/migrations/project_room_migration.ts +26 -0
  24. package/src/stores/PostgreSQLA2AApiKeyStore.ts +90 -14
  25. package/src/stores/PostgreSQLMcpServerConfigStore.ts +23 -0
  26. package/src/stores/PostgreSQLOpenAuditStore.ts +143 -0
  27. package/src/stores/PostgreSQLProjectRoomMessageStore.ts +36 -1
  28. package/src/stores/PostgreSQLProjectRoomReadStateStore.ts +47 -0
  29. package/src/stores/PostgresSharedResourceStore.ts +5 -2
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ __export(index_exports, {
37
37
  MenuStore: () => MenuStore,
38
38
  MigrationManager: () => MigrationManager,
39
39
  PGVectorStoreProvider: () => PGVectorStoreProvider,
40
- Pool: () => import_pg29.Pool,
40
+ Pool: () => import_pg30.Pool,
41
41
  PostgreSQLA2AApiKeyStore: () => PostgreSQLA2AApiKeyStore,
42
42
  PostgreSQLAgentWebAppStore: () => PostgreSQLAgentWebAppStore,
43
43
  PostgreSQLAssistantStore: () => PostgreSQLAssistantStore,
@@ -49,9 +49,11 @@ __export(index_exports, {
49
49
  PostgreSQLEvalStore: () => PostgreSQLEvalStore,
50
50
  PostgreSQLMcpServerConfigStore: () => PostgreSQLMcpServerConfigStore,
51
51
  PostgreSQLMetricsServerConfigStore: () => PostgreSQLMetricsServerConfigStore,
52
+ PostgreSQLOpenAuditStore: () => PostgreSQLOpenAuditStore,
52
53
  PostgreSQLProjectBotMembershipStore: () => PostgreSQLProjectBotMembershipStore,
53
54
  PostgreSQLProjectMembershipStore: () => PostgreSQLProjectMembershipStore,
54
55
  PostgreSQLProjectRoomMessageStore: () => PostgreSQLProjectRoomMessageStore,
56
+ PostgreSQLProjectRoomReadStateStore: () => PostgreSQLProjectRoomReadStateStore,
55
57
  PostgreSQLProjectRoomStore: () => PostgreSQLProjectRoomStore,
56
58
  PostgreSQLProjectStore: () => PostgreSQLProjectStore,
57
59
  PostgreSQLScheduleStorage: () => PostgreSQLScheduleStorage,
@@ -104,6 +106,7 @@ __export(index_exports, {
104
106
  createMetricsConfigsTable: () => createMetricsConfigsTable,
105
107
  createPGVectorStoreProvider: () => createPGVectorStoreProvider,
106
108
  createPgStoreConfig: () => createPgStoreConfig,
109
+ createProjectRoomReadStates: () => createProjectRoomReadStates,
107
110
  createProjectRoomTables: () => createProjectRoomTables,
108
111
  createProjectsTable: () => createProjectsTable,
109
112
  createScheduledTasksTable: () => createScheduledTasksTable,
@@ -122,10 +125,10 @@ __export(index_exports, {
122
125
  safeParse: () => safeParse
123
126
  });
124
127
  module.exports = __toCommonJS(index_exports);
125
- var import_pg29 = require("pg");
128
+ var import_pg30 = require("pg");
126
129
 
127
130
  // src/createPgStoreConfig.ts
128
- var import_pg26 = require("pg");
131
+ var import_pg27 = require("pg");
129
132
 
130
133
  // src/migrations/migration.ts
131
134
  var MigrationManager = class {
@@ -2139,6 +2142,18 @@ var PostgreSQLMcpServerConfigStore = class {
2139
2142
  throw new Error("Failed to decrypt MCP server configuration");
2140
2143
  }
2141
2144
  }
2145
+ if (config.headers && row.is_env_encrypted) {
2146
+ try {
2147
+ const decryptedHeaders = {};
2148
+ for (const [key, value] of Object.entries(config.headers)) {
2149
+ decryptedHeaders[key] = (0, import_core3.decrypt)(value);
2150
+ }
2151
+ config.headers = decryptedHeaders;
2152
+ } catch (error) {
2153
+ console.error("Failed to decrypt MCP server headers:", error);
2154
+ throw new Error("Failed to decrypt MCP server configuration");
2155
+ }
2156
+ }
2142
2157
  return {
2143
2158
  id: row.id,
2144
2159
  tenantId: row.tenant_id,
@@ -2167,6 +2182,14 @@ var PostgreSQLMcpServerConfigStore = class {
2167
2182
  configCopy.env = encryptedEnv;
2168
2183
  isEnvEncrypted = true;
2169
2184
  }
2185
+ if (configCopy.headers && Object.keys(configCopy.headers).length > 0) {
2186
+ const encryptedHeaders = {};
2187
+ for (const [key, value] of Object.entries(configCopy.headers)) {
2188
+ encryptedHeaders[key] = (0, import_core3.encrypt)(value);
2189
+ }
2190
+ configCopy.headers = encryptedHeaders;
2191
+ isEnvEncrypted = true;
2192
+ }
2170
2193
  return { config: configCopy, isEnvEncrypted };
2171
2194
  }
2172
2195
  };
@@ -6233,6 +6256,24 @@ var addA2AKeyAssistantIds = {
6233
6256
  }
6234
6257
  };
6235
6258
 
6259
+ // src/migrations/add_api_key_grants.ts
6260
+ var addApiKeyGrants = {
6261
+ version: 178,
6262
+ name: "add_api_key_grants",
6263
+ up: async (client) => {
6264
+ await client.query(`
6265
+ ALTER TABLE lattice_a2a_api_keys
6266
+ ADD COLUMN IF NOT EXISTS grants JSONB
6267
+ `);
6268
+ },
6269
+ down: async (client) => {
6270
+ await client.query(`
6271
+ ALTER TABLE lattice_a2a_api_keys
6272
+ DROP COLUMN IF EXISTS grants
6273
+ `);
6274
+ }
6275
+ };
6276
+
6236
6277
  // src/stores/PostgreSQLA2AApiKeyStore.ts
6237
6278
  var import_core5 = require("@axiom-lattice/core");
6238
6279
  var import_crypto2 = require("crypto");
@@ -6246,6 +6287,7 @@ function mapRowToRecord(row) {
6246
6287
  tenantId: row.tenant_id,
6247
6288
  projectId: row.project_id,
6248
6289
  assistantIds: row.assistant_ids ?? void 0,
6290
+ grants: row.grants ?? void 0,
6249
6291
  label: row.label || void 0,
6250
6292
  enabled: row.enabled,
6251
6293
  createdAt: row.created_at,
@@ -6269,6 +6311,7 @@ var PostgreSQLA2AApiKeyStore = class {
6269
6311
  this.migrationManager = new MigrationManager(this.pool);
6270
6312
  this.migrationManager.register(createA2AApiKeysTable);
6271
6313
  this.migrationManager.register(addA2AKeyAssistantIds);
6314
+ this.migrationManager.register(addApiKeyGrants);
6272
6315
  if (options.autoMigrate !== false) {
6273
6316
  this.initialize().catch((error) => {
6274
6317
  console.error("Failed to initialize PostgreSQLA2AApiKeyStore:", error);
@@ -6297,13 +6340,28 @@ var PostgreSQLA2AApiKeyStore = class {
6297
6340
  async ensureInitialized() {
6298
6341
  if (!this.initialized) await this.initialize();
6299
6342
  }
6343
+ /** Map rows that decrypt cleanly; skip rows under an unknown key. */
6344
+ safeMap(rows) {
6345
+ const out = [];
6346
+ for (const row of rows) {
6347
+ try {
6348
+ out.push(mapRowToRecord(row));
6349
+ } catch {
6350
+ }
6351
+ }
6352
+ return out;
6353
+ }
6300
6354
  async findByKey(key) {
6301
6355
  await this.ensureInitialized();
6302
6356
  const all = await this.pool.query(
6303
6357
  `SELECT * FROM lattice_a2a_api_keys WHERE enabled = true`
6304
6358
  );
6305
6359
  for (const row of all.rows) {
6306
- if ((0, import_core5.decrypt)(row.key_value) === key) return mapRowToRecord(row);
6360
+ try {
6361
+ if ((0, import_core5.decrypt)(row.key_value) === key) return mapRowToRecord(row);
6362
+ } catch {
6363
+ continue;
6364
+ }
6307
6365
  }
6308
6366
  return null;
6309
6367
  }
@@ -6313,7 +6371,12 @@ var PostgreSQLA2AApiKeyStore = class {
6313
6371
  `SELECT * FROM lattice_a2a_api_keys WHERE id = $1`,
6314
6372
  [id]
6315
6373
  );
6316
- return result.rows[0] ? mapRowToRecord(result.rows[0]) : null;
6374
+ if (!result.rows[0]) return null;
6375
+ try {
6376
+ return mapRowToRecord(result.rows[0]);
6377
+ } catch {
6378
+ return null;
6379
+ }
6317
6380
  }
6318
6381
  async list(params) {
6319
6382
  await this.ensureInitialized();
@@ -6324,26 +6387,67 @@ var PostgreSQLA2AApiKeyStore = class {
6324
6387
  `SELECT * FROM lattice_a2a_api_keys WHERE tenant_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`,
6325
6388
  [params.tenantId, limit, offset]
6326
6389
  );
6327
- return result2.rows.map(mapRowToRecord);
6390
+ return this.safeMap(result2.rows);
6328
6391
  }
6329
6392
  const result = await this.pool.query(
6330
6393
  `SELECT * FROM lattice_a2a_api_keys ORDER BY created_at DESC LIMIT $1 OFFSET $2`,
6331
6394
  [limit, offset]
6332
6395
  );
6333
- return result.rows.map(mapRowToRecord);
6396
+ return this.safeMap(result.rows);
6334
6397
  }
6335
6398
  async create(input) {
6336
6399
  await this.ensureInitialized();
6337
6400
  const key = generateApiKey();
6338
6401
  const result = await this.pool.query(
6339
- `INSERT INTO lattice_a2a_api_keys (key_value, tenant_id, project_id, assistant_ids, label)
6340
- VALUES ($1, $2, $3, $4, $5) RETURNING *`,
6341
- [(0, import_core5.encrypt)(key), input.tenantId, input.projectId, input.assistantIds ? JSON.stringify(input.assistantIds) : null, input.label || null]
6402
+ `INSERT INTO lattice_a2a_api_keys (key_value, tenant_id, project_id, assistant_ids, grants, label)
6403
+ VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
6404
+ [
6405
+ (0, import_core5.encrypt)(key),
6406
+ input.tenantId,
6407
+ input.projectId,
6408
+ input.assistantIds ? JSON.stringify(input.assistantIds) : null,
6409
+ input.grants ? JSON.stringify(input.grants) : null,
6410
+ input.label || null
6411
+ ]
6342
6412
  );
6343
6413
  const record = mapRowToRecord(result.rows[0]);
6344
6414
  record.key = key;
6345
6415
  return record;
6346
6416
  }
6417
+ async update(id, input) {
6418
+ await this.ensureInitialized();
6419
+ const sets = [];
6420
+ const values = [];
6421
+ if (input.label !== void 0) {
6422
+ values.push(input.label || null);
6423
+ sets.push(`label = $${values.length}`);
6424
+ }
6425
+ if (input.projectId !== void 0) {
6426
+ values.push(input.projectId);
6427
+ sets.push(`project_id = $${values.length}`);
6428
+ }
6429
+ if (input.assistantIds !== void 0) {
6430
+ values.push(input.assistantIds ? JSON.stringify(input.assistantIds) : null);
6431
+ sets.push(`assistant_ids = $${values.length}`);
6432
+ }
6433
+ if (input.grants !== void 0) {
6434
+ values.push(input.grants ? JSON.stringify(input.grants) : null);
6435
+ sets.push(`grants = $${values.length}`);
6436
+ }
6437
+ if (sets.length === 0) {
6438
+ const existing = await this.findById(id);
6439
+ if (!existing) throw new Error(`A2A API key not found: ${id}`);
6440
+ return existing;
6441
+ }
6442
+ sets.push("updated_at = NOW()");
6443
+ values.push(id);
6444
+ const result = await this.pool.query(
6445
+ `UPDATE lattice_a2a_api_keys SET ${sets.join(", ")} WHERE id = $${values.length} RETURNING *`,
6446
+ values
6447
+ );
6448
+ if (result.rows.length === 0) throw new Error(`A2A API key not found: ${id}`);
6449
+ return mapRowToRecord(result.rows[0]);
6450
+ }
6347
6451
  async disable(id) {
6348
6452
  await this.ensureInitialized();
6349
6453
  const result = await this.pool.query(
@@ -6385,21 +6489,173 @@ var PostgreSQLA2AApiKeyStore = class {
6385
6489
  );
6386
6490
  const map2 = /* @__PURE__ */ new Map();
6387
6491
  for (const row of result.rows) {
6388
- const key = (0, import_core5.decrypt)(row.key_value);
6389
- map2.set(key, {
6390
- key,
6391
- tenantId: row.tenant_id,
6392
- projectId: row.project_id,
6393
- assistantIds: row.assistant_ids ?? void 0
6394
- });
6492
+ try {
6493
+ const key = (0, import_core5.decrypt)(row.key_value);
6494
+ map2.set(key, {
6495
+ key,
6496
+ tenantId: row.tenant_id,
6497
+ projectId: row.project_id,
6498
+ assistantIds: row.assistant_ids ?? void 0,
6499
+ grants: row.grants ?? void 0
6500
+ });
6501
+ } catch {
6502
+ }
6395
6503
  }
6396
6504
  return map2;
6397
6505
  }
6398
6506
  };
6399
6507
 
6508
+ // src/stores/PostgreSQLOpenAuditStore.ts
6509
+ var import_pg17 = require("pg");
6510
+
6511
+ // src/migrations/create_open_audit_table.ts
6512
+ var createOpenAuditTable = {
6513
+ version: 179,
6514
+ name: "create_open_audit_table",
6515
+ up: async (client) => {
6516
+ await client.query(`
6517
+ CREATE TABLE IF NOT EXISTS lattice_open_audit (
6518
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6519
+ tenant_id VARCHAR(255) NOT NULL,
6520
+ credential_id VARCHAR(255) NOT NULL,
6521
+ credential_kind VARCHAR(32) NOT NULL,
6522
+ project_id VARCHAR(255) NOT NULL,
6523
+ domain VARCHAR(255) NOT NULL,
6524
+ action VARCHAR(255) NOT NULL,
6525
+ args JSONB,
6526
+ status VARCHAR(16) NOT NULL,
6527
+ error_code VARCHAR(64),
6528
+ duration_ms INTEGER NOT NULL,
6529
+ created_at TIMESTAMP NOT NULL DEFAULT NOW()
6530
+ )
6531
+ `);
6532
+ await client.query(`
6533
+ CREATE INDEX IF NOT EXISTS idx_lattice_open_audit_tenant_created
6534
+ ON lattice_open_audit(tenant_id, created_at DESC)
6535
+ `);
6536
+ },
6537
+ down: async (client) => {
6538
+ await client.query("DROP TABLE IF EXISTS lattice_open_audit");
6539
+ }
6540
+ };
6541
+
6542
+ // src/stores/PostgreSQLOpenAuditStore.ts
6543
+ var PostgreSQLOpenAuditStore = class {
6544
+ constructor(options) {
6545
+ this.initialized = false;
6546
+ this.ownsPool = true;
6547
+ this.initPromise = null;
6548
+ if (options.pool) {
6549
+ this.pool = options.pool;
6550
+ this.ownsPool = false;
6551
+ this.initialized = true;
6552
+ return;
6553
+ }
6554
+ this.pool = typeof options.poolConfig === "string" ? new import_pg17.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg17.Pool(options.poolConfig) : (() => {
6555
+ throw new Error("Either pool or poolConfig must be provided");
6556
+ })();
6557
+ this.migrationManager = new MigrationManager(this.pool);
6558
+ this.migrationManager.register(createOpenAuditTable);
6559
+ if (options.autoMigrate !== false) {
6560
+ this.initialize().catch((error) => {
6561
+ console.error("Failed to initialize PostgreSQLOpenAuditStore:", error);
6562
+ throw error;
6563
+ });
6564
+ }
6565
+ }
6566
+ async initialize() {
6567
+ if (this.initialized) return;
6568
+ if (this.initPromise) return this.initPromise;
6569
+ this.initPromise = (async () => {
6570
+ try {
6571
+ await this.migrationManager.migrate();
6572
+ this.initialized = true;
6573
+ } finally {
6574
+ this.initPromise = null;
6575
+ }
6576
+ })();
6577
+ return this.initPromise;
6578
+ }
6579
+ async dispose() {
6580
+ if (this.ownsPool && this.pool) await this.pool.end();
6581
+ }
6582
+ async ensureInitialized() {
6583
+ if (!this.initialized) await this.initialize();
6584
+ }
6585
+ async query(params) {
6586
+ await this.ensureInitialized();
6587
+ const clauses = ["tenant_id = $1"];
6588
+ const values = [params.tenantId];
6589
+ if (params.credentialId) {
6590
+ values.push(params.credentialId);
6591
+ clauses.push(`credential_id = $${values.length}`);
6592
+ }
6593
+ if (params.domain) {
6594
+ values.push(params.domain);
6595
+ clauses.push(`domain = $${values.length}`);
6596
+ }
6597
+ if (params.status) {
6598
+ values.push(params.status);
6599
+ clauses.push(`status = $${values.length}`);
6600
+ }
6601
+ if (params.from) {
6602
+ values.push(params.from);
6603
+ clauses.push(`created_at >= $${values.length}`);
6604
+ }
6605
+ if (params.to) {
6606
+ values.push(params.to);
6607
+ clauses.push(`created_at < $${values.length}`);
6608
+ }
6609
+ const limit = params.limit ?? 100;
6610
+ const offset = params.offset ?? 0;
6611
+ values.push(limit, offset);
6612
+ const { rows } = await this.pool.query(
6613
+ `SELECT * FROM lattice_open_audit
6614
+ WHERE ${clauses.join(" AND ")}
6615
+ ORDER BY created_at DESC
6616
+ LIMIT $${values.length - 1} OFFSET $${values.length}`,
6617
+ values
6618
+ );
6619
+ return rows.map((row) => ({
6620
+ id: row.id,
6621
+ tenantId: row.tenant_id,
6622
+ credentialId: row.credential_id,
6623
+ credentialKind: row.credential_kind,
6624
+ projectId: row.project_id,
6625
+ domain: row.domain,
6626
+ action: row.action,
6627
+ args: row.args,
6628
+ status: row.status,
6629
+ errorCode: row.error_code ?? void 0,
6630
+ durationMs: row.duration_ms,
6631
+ createdAt: row.created_at
6632
+ }));
6633
+ }
6634
+ async append(record) {
6635
+ await this.ensureInitialized();
6636
+ await this.pool.query(
6637
+ `INSERT INTO lattice_open_audit
6638
+ (tenant_id, credential_id, credential_kind, project_id, domain, action, args, status, error_code, duration_ms)
6639
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)`,
6640
+ [
6641
+ record.tenantId,
6642
+ record.credentialId,
6643
+ record.credentialKind,
6644
+ record.projectId,
6645
+ record.domain,
6646
+ record.action,
6647
+ record.args === void 0 ? null : JSON.stringify(record.args),
6648
+ record.status,
6649
+ record.errorCode ?? null,
6650
+ Math.max(0, Math.round(record.durationMs))
6651
+ ]
6652
+ );
6653
+ }
6654
+ };
6655
+
6400
6656
  // src/stores/PostgreSQLAgentWebAppStore.ts
6401
6657
  var import_crypto3 = require("crypto");
6402
- var import_pg17 = require("pg");
6658
+ var import_pg18 = require("pg");
6403
6659
 
6404
6660
  // src/migrations/agent_web_apps_migration.ts
6405
6661
  var createAgentWebAppsTable = {
@@ -6512,7 +6768,7 @@ var PostgreSQLAgentWebAppStore = class {
6512
6768
  this.initialized = true;
6513
6769
  return;
6514
6770
  }
6515
- this.pool = typeof options.poolConfig === "string" ? new import_pg17.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg17.Pool(options.poolConfig) : (() => {
6771
+ this.pool = typeof options.poolConfig === "string" ? new import_pg18.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg18.Pool(options.poolConfig) : (() => {
6516
6772
  throw new Error("Either pool or poolConfig must be provided");
6517
6773
  })();
6518
6774
  this.migrationManager = new MigrationManager(this.pool);
@@ -6651,7 +6907,7 @@ var PostgreSQLAgentWebAppStore = class {
6651
6907
  };
6652
6908
 
6653
6909
  // src/stores/PostgreSQLScheduleStorage.ts
6654
- var import_pg18 = require("pg");
6910
+ var import_pg19 = require("pg");
6655
6911
  var import_protocols4 = require("@axiom-lattice/protocols");
6656
6912
 
6657
6913
  // src/migrations/schedule_migrations.ts
@@ -6826,9 +7082,9 @@ var PostgreSQLScheduleStorage = class {
6826
7082
  return;
6827
7083
  }
6828
7084
  if (typeof options.poolConfig === "string") {
6829
- this.pool = new import_pg18.Pool({ connectionString: options.poolConfig });
7085
+ this.pool = new import_pg19.Pool({ connectionString: options.poolConfig });
6830
7086
  } else if (options.poolConfig) {
6831
- this.pool = new import_pg18.Pool(options.poolConfig);
7087
+ this.pool = new import_pg19.Pool(options.poolConfig);
6832
7088
  } else {
6833
7089
  throw new Error("Either pool or poolConfig must be provided");
6834
7090
  }
@@ -7266,7 +7522,7 @@ var PostgreSQLScheduleStorage = class {
7266
7522
  };
7267
7523
 
7268
7524
  // src/stores/PostgreSQLTaskStore.ts
7269
- var import_pg19 = require("pg");
7525
+ var import_pg20 = require("pg");
7270
7526
 
7271
7527
  // src/migrations/task_migration.ts
7272
7528
  var createTasksTable = {
@@ -7481,9 +7737,9 @@ var PostgreSQLTaskStore = class {
7481
7737
  return;
7482
7738
  }
7483
7739
  if (typeof options.poolConfig === "string") {
7484
- this.pool = new import_pg19.Pool({ connectionString: options.poolConfig });
7740
+ this.pool = new import_pg20.Pool({ connectionString: options.poolConfig });
7485
7741
  } else if (options.poolConfig) {
7486
- this.pool = new import_pg19.Pool(options.poolConfig);
7742
+ this.pool = new import_pg20.Pool(options.poolConfig);
7487
7743
  } else {
7488
7744
  throw new Error("Either pool or poolConfig must be provided");
7489
7745
  }
@@ -8223,7 +8479,7 @@ var PostgreSQLTaskStore = class {
8223
8479
  };
8224
8480
 
8225
8481
  // src/stores/PostgreSQLTaskWorkItemStore.ts
8226
- var import_pg20 = require("pg");
8482
+ var import_pg21 = require("pg");
8227
8483
  var import_protocols5 = require("@axiom-lattice/protocols");
8228
8484
  var import_uuid4 = require("uuid");
8229
8485
 
@@ -8357,7 +8613,7 @@ var PostgreSQLTaskWorkItemStore = class {
8357
8613
  this.initialized = true;
8358
8614
  return;
8359
8615
  }
8360
- this.pool = typeof options.poolConfig === "string" ? new import_pg20.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg20.Pool(options.poolConfig) : (() => {
8616
+ this.pool = typeof options.poolConfig === "string" ? new import_pg21.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg21.Pool(options.poolConfig) : (() => {
8361
8617
  throw new Error("Either pool or poolConfig must be provided");
8362
8618
  })();
8363
8619
  this.ownsPool = true;
@@ -8610,7 +8866,7 @@ var PostgreSQLTaskWorkItemStore = class {
8610
8866
  };
8611
8867
 
8612
8868
  // src/stores/MenuStore.ts
8613
- var import_pg21 = require("pg");
8869
+ var import_pg22 = require("pg");
8614
8870
 
8615
8871
  // src/migrations/menu_items_migration.ts
8616
8872
  var createMenuItemsTable = {
@@ -8687,7 +8943,7 @@ var MenuStore = class {
8687
8943
  this.initialized = true;
8688
8944
  return;
8689
8945
  }
8690
- this.pool = typeof options.poolConfig === "string" ? new import_pg21.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg21.Pool(options.poolConfig) : (() => {
8946
+ this.pool = typeof options.poolConfig === "string" ? new import_pg22.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg22.Pool(options.poolConfig) : (() => {
8691
8947
  throw new Error("Either pool or poolConfig must be provided");
8692
8948
  })();
8693
8949
  this.migrationManager = new MigrationManager(this.pool);
@@ -8842,7 +9098,7 @@ var MenuStore = class {
8842
9098
  };
8843
9099
 
8844
9100
  // src/stores/PostgresSharedResourceStore.ts
8845
- var import_pg22 = require("pg");
9101
+ var import_pg23 = require("pg");
8846
9102
 
8847
9103
  // src/migrations/shared_resources_migration.ts
8848
9104
  var createSharedResourcesTable = {
@@ -8896,7 +9152,7 @@ var PostgresSharedResourceStore = class {
8896
9152
  this.initialized = true;
8897
9153
  return;
8898
9154
  }
8899
- this.pool = typeof options.poolConfig === "string" ? new import_pg22.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg22.Pool(options.poolConfig) : (() => {
9155
+ this.pool = typeof options.poolConfig === "string" ? new import_pg23.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg23.Pool(options.poolConfig) : (() => {
8900
9156
  throw new Error("Either pool or poolConfig must be provided");
8901
9157
  })();
8902
9158
  this.migrationManager = new MigrationManager(this.pool);
@@ -8944,8 +9200,8 @@ var PostgresSharedResourceStore = class {
8944
9200
  `INSERT INTO lattice_shared_resources
8945
9201
  (token, address, title, created_by, tenant_id, workspace_id, project_id,
8946
9202
  assistant_id, vm_isolation, visibility, password_hash,
8947
- expires_at, max_access, revoked)
8948
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)
9203
+ expires_at, max_access, open_grants, revoked)
9204
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
8949
9205
  RETURNING *`,
8950
9206
  [
8951
9207
  record.token,
@@ -8961,6 +9217,7 @@ var PostgresSharedResourceStore = class {
8961
9217
  record.passwordHash,
8962
9218
  record.expiresAt ? record.expiresAt.toISOString() : null,
8963
9219
  record.maxAccess,
9220
+ record.openGrants ? JSON.stringify(record.openGrants) : null,
8964
9221
  record.revoked
8965
9222
  ]
8966
9223
  );
@@ -9056,6 +9313,7 @@ var PostgresSharedResourceStore = class {
9056
9313
  passwordHash: row.password_hash,
9057
9314
  expiresAt: row.expires_at ? new Date(row.expires_at) : null,
9058
9315
  maxAccess: row.max_access,
9316
+ openGrants: row.open_grants ?? void 0,
9059
9317
  accessCount: row.access_count ?? 0,
9060
9318
  revoked: row.revoked ?? false,
9061
9319
  createdAt: new Date(row.created_at),
@@ -9065,7 +9323,7 @@ var PostgresSharedResourceStore = class {
9065
9323
  };
9066
9324
 
9067
9325
  // src/stores/PostgreSQLCollectionStore.ts
9068
- var import_pg23 = require("pg");
9326
+ var import_pg24 = require("pg");
9069
9327
  var PostgreSQLCollectionStore = class {
9070
9328
  constructor(options) {
9071
9329
  this.initialized = false;
@@ -9078,9 +9336,9 @@ var PostgreSQLCollectionStore = class {
9078
9336
  return;
9079
9337
  }
9080
9338
  if (typeof options.poolConfig === "string") {
9081
- this.pool = new import_pg23.Pool({ connectionString: options.poolConfig });
9339
+ this.pool = new import_pg24.Pool({ connectionString: options.poolConfig });
9082
9340
  } else if (options.poolConfig) {
9083
- this.pool = new import_pg23.Pool(options.poolConfig);
9341
+ this.pool = new import_pg24.Pool(options.poolConfig);
9084
9342
  } else {
9085
9343
  throw new Error("Either pool or poolConfig must be provided");
9086
9344
  }
@@ -9195,7 +9453,7 @@ var PostgreSQLCollectionStore = class {
9195
9453
  var import_langgraph_checkpoint_postgres = require("@langchain/langgraph-checkpoint-postgres");
9196
9454
 
9197
9455
  // src/PGVectorStoreProvider.ts
9198
- var import_pg24 = require("pg");
9456
+ var import_pg25 = require("pg");
9199
9457
  var import_pgvector = require("@langchain/community/vectorstores/pgvector");
9200
9458
  var import_documents = require("@langchain/core/documents");
9201
9459
  var import_core6 = require("@axiom-lattice/core");
@@ -9269,7 +9527,7 @@ var PGVectorStoreProvider = class {
9269
9527
  }
9270
9528
  };
9271
9529
  function createPGVectorStoreProvider(connectionString) {
9272
- const pool = new import_pg24.Pool({ connectionString });
9530
+ const pool = new import_pg25.Pool({ connectionString });
9273
9531
  return {
9274
9532
  provider: new PGVectorStoreProvider(pool, connectionString),
9275
9533
  pool
@@ -9524,6 +9782,24 @@ var createConnectionConfigsTable = {
9524
9782
  }
9525
9783
  };
9526
9784
 
9785
+ // src/migrations/add_share_open_grants.ts
9786
+ var addShareOpenGrants = {
9787
+ version: 180,
9788
+ name: "add_share_open_grants",
9789
+ up: async (client) => {
9790
+ await client.query(`
9791
+ ALTER TABLE lattice_shared_resources
9792
+ ADD COLUMN IF NOT EXISTS open_grants JSONB
9793
+ `);
9794
+ },
9795
+ down: async (client) => {
9796
+ await client.query(`
9797
+ ALTER TABLE lattice_shared_resources
9798
+ DROP COLUMN IF EXISTS open_grants
9799
+ `);
9800
+ }
9801
+ };
9802
+
9527
9803
  // src/migrations/collection_migrations.ts
9528
9804
  var createCollectionsTable = {
9529
9805
  version: 137,
@@ -9700,10 +9976,34 @@ var createProjectRoomTables = {
9700
9976
  await client.query("DROP TABLE IF EXISTS lattice_project_rooms");
9701
9977
  }
9702
9978
  };
9979
+ var createProjectRoomReadStates = {
9980
+ version: 177,
9981
+ name: "create_project_room_read_states",
9982
+ up: async (client) => {
9983
+ await client.query(`
9984
+ CREATE TABLE IF NOT EXISTS lattice_project_room_read_states (
9985
+ tenant_id VARCHAR(255) NOT NULL,
9986
+ room_id VARCHAR(255) NOT NULL,
9987
+ user_id VARCHAR(255) NOT NULL,
9988
+ last_read_at TIMESTAMPTZ NOT NULL,
9989
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
9990
+ PRIMARY KEY (tenant_id, room_id, user_id)
9991
+ )
9992
+ `);
9993
+ await client.query(`
9994
+ CREATE INDEX IF NOT EXISTS idx_lattice_project_room_read_states_user
9995
+ ON lattice_project_room_read_states (tenant_id, user_id)
9996
+ `);
9997
+ },
9998
+ down: async (client) => {
9999
+ await client.query("DROP INDEX IF EXISTS idx_lattice_project_room_read_states_user");
10000
+ await client.query("DROP TABLE IF EXISTS lattice_project_room_read_states");
10001
+ }
10002
+ };
9703
10003
 
9704
10004
  // src/stores/PostgreSQLCapabilityBundleStore.ts
9705
10005
  var import_crypto4 = require("crypto");
9706
- var import_pg25 = require("pg");
10006
+ var import_pg26 = require("pg");
9707
10007
  var duplicateMessage = "Capability bundle key already exists for tenant";
9708
10008
  function map(row) {
9709
10009
  return {
@@ -9736,7 +10036,7 @@ var PostgreSQLCapabilityBundleStore = class {
9736
10036
  this.initialized = true;
9737
10037
  return;
9738
10038
  }
9739
- this.pool = typeof options.poolConfig === "string" ? new import_pg25.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg25.Pool(options.poolConfig) : (() => {
10039
+ this.pool = typeof options.poolConfig === "string" ? new import_pg26.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg26.Pool(options.poolConfig) : (() => {
9740
10040
  throw new Error("Either pool or poolConfig must be provided");
9741
10041
  })();
9742
10042
  this.migrationManager = new MigrationManager(this.pool);
@@ -10412,6 +10712,22 @@ function mapRow5(row) {
10412
10712
  createdAt: row.created_at
10413
10713
  };
10414
10714
  }
10715
+ function mapRowsTolerant(rows, scope) {
10716
+ const messages = [];
10717
+ for (const row of rows) {
10718
+ try {
10719
+ messages.push(mapRow5(row));
10720
+ } catch (error) {
10721
+ console.warn("[ProjectRoomMessageStore] Skipping invalid message row", {
10722
+ tenantId: scope.tenantId,
10723
+ roomId: scope.roomId,
10724
+ rowId: typeof row.id === "string" ? row.id : void 0,
10725
+ reason: error instanceof Error ? error.message : String(error)
10726
+ });
10727
+ }
10728
+ }
10729
+ return messages;
10730
+ }
10415
10731
  function isUniqueViolation2(error) {
10416
10732
  return typeof error === "object" && error !== null && "code" in error && error.code === "23505";
10417
10733
  }
@@ -10477,7 +10793,7 @@ var PostgreSQLProjectRoomMessageStore = class {
10477
10793
  WHERE tenant_id = $1 AND room_id = $2 ORDER BY created_at DESC, id DESC LIMIT $3`,
10478
10794
  [input.tenantId, input.roomId, limit]
10479
10795
  );
10480
- return result.rows.map(mapRow5);
10796
+ return mapRowsTolerant(result.rows, { tenantId: input.tenantId, roomId: input.roomId });
10481
10797
  }
10482
10798
  /** Finds a message by tenant-scoped ID. */
10483
10799
  async findById(tenantId, id) {
@@ -10487,6 +10803,19 @@ var PostgreSQLProjectRoomMessageStore = class {
10487
10803
  );
10488
10804
  return result.rows[0] ? mapRow5(result.rows[0]) : null;
10489
10805
  }
10806
+ /** Counts messages created strictly after a horizon, optionally excluding one human author. */
10807
+ async countAfter(input) {
10808
+ if (!(input.after instanceof Date) || Number.isNaN(input.after.getTime())) {
10809
+ throw new RangeError("Project room message count horizon date is invalid");
10810
+ }
10811
+ const result = await this.pool.query(
10812
+ `SELECT COUNT(*)::int AS count FROM lattice_project_room_messages
10813
+ WHERE tenant_id = $1 AND room_id = $2 AND created_at > $3
10814
+ AND ($4::text IS NULL OR author->>'type' <> 'human' OR author->>'userId' <> $4)`,
10815
+ [input.tenantId, input.roomId, input.after, input.excludeAuthorUserId ?? null]
10816
+ );
10817
+ return result.rows[0]?.count ?? 0;
10818
+ }
10490
10819
  parameters(input) {
10491
10820
  return [
10492
10821
  input.id,
@@ -10505,9 +10834,48 @@ var PostgreSQLProjectRoomMessageStore = class {
10505
10834
  }
10506
10835
  };
10507
10836
 
10837
+ // src/stores/PostgreSQLProjectRoomReadStateStore.ts
10838
+ function mapRow6(row) {
10839
+ if (typeof row.tenant_id !== "string" || typeof row.room_id !== "string" || typeof row.user_id !== "string" || !(row.last_read_at instanceof Date) || Number.isNaN(row.last_read_at.getTime()) || !(row.updated_at instanceof Date) || Number.isNaN(row.updated_at.getTime())) {
10840
+ throw new Error("Invalid project room read state row");
10841
+ }
10842
+ return { tenantId: row.tenant_id, roomId: row.room_id, userId: row.user_id, lastReadAt: row.last_read_at, updatedAt: row.updated_at };
10843
+ }
10844
+ var PostgreSQLProjectRoomReadStateStore = class {
10845
+ /** Creates a store using an externally managed shared pool. */
10846
+ constructor(options) {
10847
+ this.pool = options.pool;
10848
+ }
10849
+ /** Returns the user's read marker for a room, or null when never reported. */
10850
+ async get(tenantId, roomId, userId) {
10851
+ const result = await this.pool.query(
10852
+ `SELECT tenant_id, room_id, user_id, last_read_at, updated_at
10853
+ FROM lattice_project_room_read_states WHERE tenant_id = $1 AND room_id = $2 AND user_id = $3`,
10854
+ [tenantId, roomId, userId]
10855
+ );
10856
+ return result.rows[0] ? mapRow6(result.rows[0]) : null;
10857
+ }
10858
+ /** Upserts the marker monotonically using GREATEST so older reports never regress it. */
10859
+ async markRead(input) {
10860
+ if (!(input.lastReadAt instanceof Date) || Number.isNaN(input.lastReadAt.getTime())) {
10861
+ throw new RangeError("Project room read state lastReadAt is invalid");
10862
+ }
10863
+ const result = await this.pool.query(
10864
+ `INSERT INTO lattice_project_room_read_states (tenant_id, room_id, user_id, last_read_at, updated_at)
10865
+ VALUES ($1, $2, $3, $4, NOW())
10866
+ ON CONFLICT (tenant_id, room_id, user_id) DO UPDATE
10867
+ SET last_read_at = GREATEST(lattice_project_room_read_states.last_read_at, EXCLUDED.last_read_at),
10868
+ updated_at = NOW()
10869
+ RETURNING tenant_id, room_id, user_id, last_read_at, updated_at`,
10870
+ [input.tenantId, input.roomId, input.userId, input.lastReadAt]
10871
+ );
10872
+ return mapRow6(result.rows[0]);
10873
+ }
10874
+ };
10875
+
10508
10876
  // src/createPgStoreConfig.ts
10509
10877
  async function createPgStoreConfig(connectionString) {
10510
- const pool = new import_pg26.Pool({ connectionString });
10878
+ const pool = new import_pg27.Pool({ connectionString });
10511
10879
  const mm = new MigrationManager(pool);
10512
10880
  mm.register(createThreadsTable);
10513
10881
  mm.register(createScheduledTasksTable);
@@ -10560,6 +10928,9 @@ async function createPgStoreConfig(connectionString) {
10560
10928
  mm.register(addWorkflowRunsTenantStatusUpdatedIndex);
10561
10929
  mm.register(addProjectKindColumn);
10562
10930
  mm.register(addA2AKeyAssistantIds);
10931
+ mm.register(addApiKeyGrants);
10932
+ mm.register(createOpenAuditTable);
10933
+ mm.register(addShareOpenGrants);
10563
10934
  mm.register(addTaskWorkItemEventKeyMigration);
10564
10935
  mm.register(createAgentWebAppsTable);
10565
10936
  mm.register(createCapabilityBundlesTable);
@@ -10568,6 +10939,7 @@ async function createPgStoreConfig(connectionString) {
10568
10939
  mm.register(addTrustedRunContextColumn);
10569
10940
  mm.register(addProjectLifecycleEventIndex);
10570
10941
  mm.register(addAgentWebAppsIdentity);
10942
+ mm.register(createProjectRoomReadStates);
10571
10943
  await mm.migrate();
10572
10944
  const checkpoint = import_langgraph_checkpoint_postgres.PostgresSaver.fromConnString(connectionString);
10573
10945
  checkpoint.setup().catch((err) => {
@@ -10595,6 +10967,7 @@ async function createPgStoreConfig(connectionString) {
10595
10967
  task: new PostgreSQLTaskStore(opts),
10596
10968
  taskWorkItem: taskWorkItemStore,
10597
10969
  a2aApiKey: new PostgreSQLA2AApiKeyStore(opts),
10970
+ openAudit: new PostgreSQLOpenAuditStore(opts),
10598
10971
  agentWebApp: new PostgreSQLAgentWebAppStore(opts),
10599
10972
  capabilityBundle: new PostgreSQLCapabilityBundleStore(opts),
10600
10973
  schedule: new PostgreSQLScheduleStorage(opts),
@@ -10605,13 +10978,14 @@ async function createPgStoreConfig(connectionString) {
10605
10978
  projectMembership: new PostgreSQLProjectMembershipStore(opts),
10606
10979
  projectBotMembership: new PostgreSQLProjectBotMembershipStore(opts),
10607
10980
  projectRoomMessage: new PostgreSQLProjectRoomMessageStore(opts),
10981
+ projectRoomReadState: new PostgreSQLProjectRoomReadStateStore(opts),
10608
10982
  vectorStoreProvider: new PGVectorStoreProvider(pool, connectionString),
10609
10983
  checkpoint
10610
10984
  };
10611
10985
  }
10612
10986
 
10613
10987
  // src/stores/PostgreSQLSkillStore.ts
10614
- var import_pg27 = require("pg");
10988
+ var import_pg28 = require("pg");
10615
10989
  var PostgreSQLSkillStore = class {
10616
10990
  constructor(options) {
10617
10991
  this.initialized = false;
@@ -10624,9 +10998,9 @@ var PostgreSQLSkillStore = class {
10624
10998
  return;
10625
10999
  }
10626
11000
  if (typeof options.poolConfig === "string") {
10627
- this.pool = new import_pg27.Pool({ connectionString: options.poolConfig });
11001
+ this.pool = new import_pg28.Pool({ connectionString: options.poolConfig });
10628
11002
  } else if (options.poolConfig) {
10629
- this.pool = new import_pg27.Pool(options.poolConfig);
11003
+ this.pool = new import_pg28.Pool(options.poolConfig);
10630
11004
  } else {
10631
11005
  throw new Error("Either pool or poolConfig must be provided");
10632
11006
  }
@@ -10927,7 +11301,7 @@ var PostgreSQLSkillStore = class {
10927
11301
  };
10928
11302
 
10929
11303
  // src/stores/ChannelIdentityMappingStore.ts
10930
- var import_pg28 = require("pg");
11304
+ var import_pg29 = require("pg");
10931
11305
  var ChannelIdentityMappingStore = class {
10932
11306
  constructor(options) {
10933
11307
  this.initialized = false;
@@ -10939,7 +11313,7 @@ var ChannelIdentityMappingStore = class {
10939
11313
  this.initialized = true;
10940
11314
  return;
10941
11315
  }
10942
- this.pool = typeof options.poolConfig === "string" ? new import_pg28.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg28.Pool(options.poolConfig) : (() => {
11316
+ this.pool = typeof options.poolConfig === "string" ? new import_pg29.Pool({ connectionString: options.poolConfig }) : options.poolConfig ? new import_pg29.Pool(options.poolConfig) : (() => {
10943
11317
  throw new Error("Either pool or poolConfig must be provided");
10944
11318
  })();
10945
11319
  this.migrationManager = new MigrationManager(this.pool);
@@ -11178,9 +11552,11 @@ function mapRowToChannelIdentityMapping(row) {
11178
11552
  PostgreSQLEvalStore,
11179
11553
  PostgreSQLMcpServerConfigStore,
11180
11554
  PostgreSQLMetricsServerConfigStore,
11555
+ PostgreSQLOpenAuditStore,
11181
11556
  PostgreSQLProjectBotMembershipStore,
11182
11557
  PostgreSQLProjectMembershipStore,
11183
11558
  PostgreSQLProjectRoomMessageStore,
11559
+ PostgreSQLProjectRoomReadStateStore,
11184
11560
  PostgreSQLProjectRoomStore,
11185
11561
  PostgreSQLProjectStore,
11186
11562
  PostgreSQLScheduleStorage,
@@ -11233,6 +11609,7 @@ function mapRowToChannelIdentityMapping(row) {
11233
11609
  createMetricsConfigsTable,
11234
11610
  createPGVectorStoreProvider,
11235
11611
  createPgStoreConfig,
11612
+ createProjectRoomReadStates,
11236
11613
  createProjectRoomTables,
11237
11614
  createProjectsTable,
11238
11615
  createScheduledTasksTable,