@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.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  // src/index.ts
2
- import { Pool as Pool29 } from "pg";
2
+ import { Pool as Pool30 } from "pg";
3
3
 
4
4
  // src/createPgStoreConfig.ts
5
- import { Pool as Pool26 } from "pg";
5
+ import { Pool as Pool27 } from "pg";
6
6
 
7
7
  // src/migrations/migration.ts
8
8
  var MigrationManager = class {
@@ -2016,6 +2016,18 @@ var PostgreSQLMcpServerConfigStore = class {
2016
2016
  throw new Error("Failed to decrypt MCP server configuration");
2017
2017
  }
2018
2018
  }
2019
+ if (config.headers && row.is_env_encrypted) {
2020
+ try {
2021
+ const decryptedHeaders = {};
2022
+ for (const [key, value] of Object.entries(config.headers)) {
2023
+ decryptedHeaders[key] = decrypt3(value);
2024
+ }
2025
+ config.headers = decryptedHeaders;
2026
+ } catch (error) {
2027
+ console.error("Failed to decrypt MCP server headers:", error);
2028
+ throw new Error("Failed to decrypt MCP server configuration");
2029
+ }
2030
+ }
2019
2031
  return {
2020
2032
  id: row.id,
2021
2033
  tenantId: row.tenant_id,
@@ -2044,6 +2056,14 @@ var PostgreSQLMcpServerConfigStore = class {
2044
2056
  configCopy.env = encryptedEnv;
2045
2057
  isEnvEncrypted = true;
2046
2058
  }
2059
+ if (configCopy.headers && Object.keys(configCopy.headers).length > 0) {
2060
+ const encryptedHeaders = {};
2061
+ for (const [key, value] of Object.entries(configCopy.headers)) {
2062
+ encryptedHeaders[key] = encrypt3(value);
2063
+ }
2064
+ configCopy.headers = encryptedHeaders;
2065
+ isEnvEncrypted = true;
2066
+ }
2047
2067
  return { config: configCopy, isEnvEncrypted };
2048
2068
  }
2049
2069
  };
@@ -6117,6 +6137,24 @@ var addA2AKeyAssistantIds = {
6117
6137
  }
6118
6138
  };
6119
6139
 
6140
+ // src/migrations/add_api_key_grants.ts
6141
+ var addApiKeyGrants = {
6142
+ version: 178,
6143
+ name: "add_api_key_grants",
6144
+ up: async (client) => {
6145
+ await client.query(`
6146
+ ALTER TABLE lattice_a2a_api_keys
6147
+ ADD COLUMN IF NOT EXISTS grants JSONB
6148
+ `);
6149
+ },
6150
+ down: async (client) => {
6151
+ await client.query(`
6152
+ ALTER TABLE lattice_a2a_api_keys
6153
+ DROP COLUMN IF EXISTS grants
6154
+ `);
6155
+ }
6156
+ };
6157
+
6120
6158
  // src/stores/PostgreSQLA2AApiKeyStore.ts
6121
6159
  import { encrypt as encrypt5, decrypt as decrypt5 } from "@axiom-lattice/core";
6122
6160
  import { randomUUID } from "crypto";
@@ -6130,6 +6168,7 @@ function mapRowToRecord(row) {
6130
6168
  tenantId: row.tenant_id,
6131
6169
  projectId: row.project_id,
6132
6170
  assistantIds: row.assistant_ids ?? void 0,
6171
+ grants: row.grants ?? void 0,
6133
6172
  label: row.label || void 0,
6134
6173
  enabled: row.enabled,
6135
6174
  createdAt: row.created_at,
@@ -6153,6 +6192,7 @@ var PostgreSQLA2AApiKeyStore = class {
6153
6192
  this.migrationManager = new MigrationManager(this.pool);
6154
6193
  this.migrationManager.register(createA2AApiKeysTable);
6155
6194
  this.migrationManager.register(addA2AKeyAssistantIds);
6195
+ this.migrationManager.register(addApiKeyGrants);
6156
6196
  if (options.autoMigrate !== false) {
6157
6197
  this.initialize().catch((error) => {
6158
6198
  console.error("Failed to initialize PostgreSQLA2AApiKeyStore:", error);
@@ -6181,13 +6221,28 @@ var PostgreSQLA2AApiKeyStore = class {
6181
6221
  async ensureInitialized() {
6182
6222
  if (!this.initialized) await this.initialize();
6183
6223
  }
6224
+ /** Map rows that decrypt cleanly; skip rows under an unknown key. */
6225
+ safeMap(rows) {
6226
+ const out = [];
6227
+ for (const row of rows) {
6228
+ try {
6229
+ out.push(mapRowToRecord(row));
6230
+ } catch {
6231
+ }
6232
+ }
6233
+ return out;
6234
+ }
6184
6235
  async findByKey(key) {
6185
6236
  await this.ensureInitialized();
6186
6237
  const all = await this.pool.query(
6187
6238
  `SELECT * FROM lattice_a2a_api_keys WHERE enabled = true`
6188
6239
  );
6189
6240
  for (const row of all.rows) {
6190
- if (decrypt5(row.key_value) === key) return mapRowToRecord(row);
6241
+ try {
6242
+ if (decrypt5(row.key_value) === key) return mapRowToRecord(row);
6243
+ } catch {
6244
+ continue;
6245
+ }
6191
6246
  }
6192
6247
  return null;
6193
6248
  }
@@ -6197,7 +6252,12 @@ var PostgreSQLA2AApiKeyStore = class {
6197
6252
  `SELECT * FROM lattice_a2a_api_keys WHERE id = $1`,
6198
6253
  [id]
6199
6254
  );
6200
- return result.rows[0] ? mapRowToRecord(result.rows[0]) : null;
6255
+ if (!result.rows[0]) return null;
6256
+ try {
6257
+ return mapRowToRecord(result.rows[0]);
6258
+ } catch {
6259
+ return null;
6260
+ }
6201
6261
  }
6202
6262
  async list(params) {
6203
6263
  await this.ensureInitialized();
@@ -6208,26 +6268,67 @@ var PostgreSQLA2AApiKeyStore = class {
6208
6268
  `SELECT * FROM lattice_a2a_api_keys WHERE tenant_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`,
6209
6269
  [params.tenantId, limit, offset]
6210
6270
  );
6211
- return result2.rows.map(mapRowToRecord);
6271
+ return this.safeMap(result2.rows);
6212
6272
  }
6213
6273
  const result = await this.pool.query(
6214
6274
  `SELECT * FROM lattice_a2a_api_keys ORDER BY created_at DESC LIMIT $1 OFFSET $2`,
6215
6275
  [limit, offset]
6216
6276
  );
6217
- return result.rows.map(mapRowToRecord);
6277
+ return this.safeMap(result.rows);
6218
6278
  }
6219
6279
  async create(input) {
6220
6280
  await this.ensureInitialized();
6221
6281
  const key = generateApiKey();
6222
6282
  const result = await this.pool.query(
6223
- `INSERT INTO lattice_a2a_api_keys (key_value, tenant_id, project_id, assistant_ids, label)
6224
- VALUES ($1, $2, $3, $4, $5) RETURNING *`,
6225
- [encrypt5(key), input.tenantId, input.projectId, input.assistantIds ? JSON.stringify(input.assistantIds) : null, input.label || null]
6283
+ `INSERT INTO lattice_a2a_api_keys (key_value, tenant_id, project_id, assistant_ids, grants, label)
6284
+ VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
6285
+ [
6286
+ encrypt5(key),
6287
+ input.tenantId,
6288
+ input.projectId,
6289
+ input.assistantIds ? JSON.stringify(input.assistantIds) : null,
6290
+ input.grants ? JSON.stringify(input.grants) : null,
6291
+ input.label || null
6292
+ ]
6226
6293
  );
6227
6294
  const record = mapRowToRecord(result.rows[0]);
6228
6295
  record.key = key;
6229
6296
  return record;
6230
6297
  }
6298
+ async update(id, input) {
6299
+ await this.ensureInitialized();
6300
+ const sets = [];
6301
+ const values = [];
6302
+ if (input.label !== void 0) {
6303
+ values.push(input.label || null);
6304
+ sets.push(`label = $${values.length}`);
6305
+ }
6306
+ if (input.projectId !== void 0) {
6307
+ values.push(input.projectId);
6308
+ sets.push(`project_id = $${values.length}`);
6309
+ }
6310
+ if (input.assistantIds !== void 0) {
6311
+ values.push(input.assistantIds ? JSON.stringify(input.assistantIds) : null);
6312
+ sets.push(`assistant_ids = $${values.length}`);
6313
+ }
6314
+ if (input.grants !== void 0) {
6315
+ values.push(input.grants ? JSON.stringify(input.grants) : null);
6316
+ sets.push(`grants = $${values.length}`);
6317
+ }
6318
+ if (sets.length === 0) {
6319
+ const existing = await this.findById(id);
6320
+ if (!existing) throw new Error(`A2A API key not found: ${id}`);
6321
+ return existing;
6322
+ }
6323
+ sets.push("updated_at = NOW()");
6324
+ values.push(id);
6325
+ const result = await this.pool.query(
6326
+ `UPDATE lattice_a2a_api_keys SET ${sets.join(", ")} WHERE id = $${values.length} RETURNING *`,
6327
+ values
6328
+ );
6329
+ if (result.rows.length === 0) throw new Error(`A2A API key not found: ${id}`);
6330
+ return mapRowToRecord(result.rows[0]);
6331
+ }
6231
6332
  async disable(id) {
6232
6333
  await this.ensureInitialized();
6233
6334
  const result = await this.pool.query(
@@ -6269,21 +6370,173 @@ var PostgreSQLA2AApiKeyStore = class {
6269
6370
  );
6270
6371
  const map2 = /* @__PURE__ */ new Map();
6271
6372
  for (const row of result.rows) {
6272
- const key = decrypt5(row.key_value);
6273
- map2.set(key, {
6274
- key,
6275
- tenantId: row.tenant_id,
6276
- projectId: row.project_id,
6277
- assistantIds: row.assistant_ids ?? void 0
6278
- });
6373
+ try {
6374
+ const key = decrypt5(row.key_value);
6375
+ map2.set(key, {
6376
+ key,
6377
+ tenantId: row.tenant_id,
6378
+ projectId: row.project_id,
6379
+ assistantIds: row.assistant_ids ?? void 0,
6380
+ grants: row.grants ?? void 0
6381
+ });
6382
+ } catch {
6383
+ }
6279
6384
  }
6280
6385
  return map2;
6281
6386
  }
6282
6387
  };
6283
6388
 
6389
+ // src/stores/PostgreSQLOpenAuditStore.ts
6390
+ import { Pool as Pool17 } from "pg";
6391
+
6392
+ // src/migrations/create_open_audit_table.ts
6393
+ var createOpenAuditTable = {
6394
+ version: 179,
6395
+ name: "create_open_audit_table",
6396
+ up: async (client) => {
6397
+ await client.query(`
6398
+ CREATE TABLE IF NOT EXISTS lattice_open_audit (
6399
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
6400
+ tenant_id VARCHAR(255) NOT NULL,
6401
+ credential_id VARCHAR(255) NOT NULL,
6402
+ credential_kind VARCHAR(32) NOT NULL,
6403
+ project_id VARCHAR(255) NOT NULL,
6404
+ domain VARCHAR(255) NOT NULL,
6405
+ action VARCHAR(255) NOT NULL,
6406
+ args JSONB,
6407
+ status VARCHAR(16) NOT NULL,
6408
+ error_code VARCHAR(64),
6409
+ duration_ms INTEGER NOT NULL,
6410
+ created_at TIMESTAMP NOT NULL DEFAULT NOW()
6411
+ )
6412
+ `);
6413
+ await client.query(`
6414
+ CREATE INDEX IF NOT EXISTS idx_lattice_open_audit_tenant_created
6415
+ ON lattice_open_audit(tenant_id, created_at DESC)
6416
+ `);
6417
+ },
6418
+ down: async (client) => {
6419
+ await client.query("DROP TABLE IF EXISTS lattice_open_audit");
6420
+ }
6421
+ };
6422
+
6423
+ // src/stores/PostgreSQLOpenAuditStore.ts
6424
+ var PostgreSQLOpenAuditStore = class {
6425
+ constructor(options) {
6426
+ this.initialized = false;
6427
+ this.ownsPool = true;
6428
+ this.initPromise = null;
6429
+ if (options.pool) {
6430
+ this.pool = options.pool;
6431
+ this.ownsPool = false;
6432
+ this.initialized = true;
6433
+ return;
6434
+ }
6435
+ this.pool = typeof options.poolConfig === "string" ? new Pool17({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool17(options.poolConfig) : (() => {
6436
+ throw new Error("Either pool or poolConfig must be provided");
6437
+ })();
6438
+ this.migrationManager = new MigrationManager(this.pool);
6439
+ this.migrationManager.register(createOpenAuditTable);
6440
+ if (options.autoMigrate !== false) {
6441
+ this.initialize().catch((error) => {
6442
+ console.error("Failed to initialize PostgreSQLOpenAuditStore:", error);
6443
+ throw error;
6444
+ });
6445
+ }
6446
+ }
6447
+ async initialize() {
6448
+ if (this.initialized) return;
6449
+ if (this.initPromise) return this.initPromise;
6450
+ this.initPromise = (async () => {
6451
+ try {
6452
+ await this.migrationManager.migrate();
6453
+ this.initialized = true;
6454
+ } finally {
6455
+ this.initPromise = null;
6456
+ }
6457
+ })();
6458
+ return this.initPromise;
6459
+ }
6460
+ async dispose() {
6461
+ if (this.ownsPool && this.pool) await this.pool.end();
6462
+ }
6463
+ async ensureInitialized() {
6464
+ if (!this.initialized) await this.initialize();
6465
+ }
6466
+ async query(params) {
6467
+ await this.ensureInitialized();
6468
+ const clauses = ["tenant_id = $1"];
6469
+ const values = [params.tenantId];
6470
+ if (params.credentialId) {
6471
+ values.push(params.credentialId);
6472
+ clauses.push(`credential_id = $${values.length}`);
6473
+ }
6474
+ if (params.domain) {
6475
+ values.push(params.domain);
6476
+ clauses.push(`domain = $${values.length}`);
6477
+ }
6478
+ if (params.status) {
6479
+ values.push(params.status);
6480
+ clauses.push(`status = $${values.length}`);
6481
+ }
6482
+ if (params.from) {
6483
+ values.push(params.from);
6484
+ clauses.push(`created_at >= $${values.length}`);
6485
+ }
6486
+ if (params.to) {
6487
+ values.push(params.to);
6488
+ clauses.push(`created_at < $${values.length}`);
6489
+ }
6490
+ const limit = params.limit ?? 100;
6491
+ const offset = params.offset ?? 0;
6492
+ values.push(limit, offset);
6493
+ const { rows } = await this.pool.query(
6494
+ `SELECT * FROM lattice_open_audit
6495
+ WHERE ${clauses.join(" AND ")}
6496
+ ORDER BY created_at DESC
6497
+ LIMIT $${values.length - 1} OFFSET $${values.length}`,
6498
+ values
6499
+ );
6500
+ return rows.map((row) => ({
6501
+ id: row.id,
6502
+ tenantId: row.tenant_id,
6503
+ credentialId: row.credential_id,
6504
+ credentialKind: row.credential_kind,
6505
+ projectId: row.project_id,
6506
+ domain: row.domain,
6507
+ action: row.action,
6508
+ args: row.args,
6509
+ status: row.status,
6510
+ errorCode: row.error_code ?? void 0,
6511
+ durationMs: row.duration_ms,
6512
+ createdAt: row.created_at
6513
+ }));
6514
+ }
6515
+ async append(record) {
6516
+ await this.ensureInitialized();
6517
+ await this.pool.query(
6518
+ `INSERT INTO lattice_open_audit
6519
+ (tenant_id, credential_id, credential_kind, project_id, domain, action, args, status, error_code, duration_ms)
6520
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)`,
6521
+ [
6522
+ record.tenantId,
6523
+ record.credentialId,
6524
+ record.credentialKind,
6525
+ record.projectId,
6526
+ record.domain,
6527
+ record.action,
6528
+ record.args === void 0 ? null : JSON.stringify(record.args),
6529
+ record.status,
6530
+ record.errorCode ?? null,
6531
+ Math.max(0, Math.round(record.durationMs))
6532
+ ]
6533
+ );
6534
+ }
6535
+ };
6536
+
6284
6537
  // src/stores/PostgreSQLAgentWebAppStore.ts
6285
6538
  import { randomUUID as randomUUID2 } from "crypto";
6286
- import { Pool as Pool17 } from "pg";
6539
+ import { Pool as Pool18 } from "pg";
6287
6540
 
6288
6541
  // src/migrations/agent_web_apps_migration.ts
6289
6542
  var createAgentWebAppsTable = {
@@ -6396,7 +6649,7 @@ var PostgreSQLAgentWebAppStore = class {
6396
6649
  this.initialized = true;
6397
6650
  return;
6398
6651
  }
6399
- this.pool = typeof options.poolConfig === "string" ? new Pool17({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool17(options.poolConfig) : (() => {
6652
+ this.pool = typeof options.poolConfig === "string" ? new Pool18({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool18(options.poolConfig) : (() => {
6400
6653
  throw new Error("Either pool or poolConfig must be provided");
6401
6654
  })();
6402
6655
  this.migrationManager = new MigrationManager(this.pool);
@@ -6535,7 +6788,7 @@ var PostgreSQLAgentWebAppStore = class {
6535
6788
  };
6536
6789
 
6537
6790
  // src/stores/PostgreSQLScheduleStorage.ts
6538
- import { Pool as Pool18 } from "pg";
6791
+ import { Pool as Pool19 } from "pg";
6539
6792
  import {
6540
6793
  ScheduledTaskStatus
6541
6794
  } from "@axiom-lattice/protocols";
@@ -6712,9 +6965,9 @@ var PostgreSQLScheduleStorage = class {
6712
6965
  return;
6713
6966
  }
6714
6967
  if (typeof options.poolConfig === "string") {
6715
- this.pool = new Pool18({ connectionString: options.poolConfig });
6968
+ this.pool = new Pool19({ connectionString: options.poolConfig });
6716
6969
  } else if (options.poolConfig) {
6717
- this.pool = new Pool18(options.poolConfig);
6970
+ this.pool = new Pool19(options.poolConfig);
6718
6971
  } else {
6719
6972
  throw new Error("Either pool or poolConfig must be provided");
6720
6973
  }
@@ -7152,7 +7405,7 @@ var PostgreSQLScheduleStorage = class {
7152
7405
  };
7153
7406
 
7154
7407
  // src/stores/PostgreSQLTaskStore.ts
7155
- import { Pool as Pool19 } from "pg";
7408
+ import { Pool as Pool20 } from "pg";
7156
7409
 
7157
7410
  // src/migrations/task_migration.ts
7158
7411
  var createTasksTable = {
@@ -7367,9 +7620,9 @@ var PostgreSQLTaskStore = class {
7367
7620
  return;
7368
7621
  }
7369
7622
  if (typeof options.poolConfig === "string") {
7370
- this.pool = new Pool19({ connectionString: options.poolConfig });
7623
+ this.pool = new Pool20({ connectionString: options.poolConfig });
7371
7624
  } else if (options.poolConfig) {
7372
- this.pool = new Pool19(options.poolConfig);
7625
+ this.pool = new Pool20(options.poolConfig);
7373
7626
  } else {
7374
7627
  throw new Error("Either pool or poolConfig must be provided");
7375
7628
  }
@@ -8109,7 +8362,7 @@ var PostgreSQLTaskStore = class {
8109
8362
  };
8110
8363
 
8111
8364
  // src/stores/PostgreSQLTaskWorkItemStore.ts
8112
- import { Pool as Pool20 } from "pg";
8365
+ import { Pool as Pool21 } from "pg";
8113
8366
  import { MAX_PENDING_EXECUTION_RESULTS_LIMIT } from "@axiom-lattice/protocols";
8114
8367
  import { v4 } from "uuid";
8115
8368
 
@@ -8243,7 +8496,7 @@ var PostgreSQLTaskWorkItemStore = class {
8243
8496
  this.initialized = true;
8244
8497
  return;
8245
8498
  }
8246
- this.pool = typeof options.poolConfig === "string" ? new Pool20({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool20(options.poolConfig) : (() => {
8499
+ this.pool = typeof options.poolConfig === "string" ? new Pool21({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool21(options.poolConfig) : (() => {
8247
8500
  throw new Error("Either pool or poolConfig must be provided");
8248
8501
  })();
8249
8502
  this.ownsPool = true;
@@ -8496,7 +8749,7 @@ var PostgreSQLTaskWorkItemStore = class {
8496
8749
  };
8497
8750
 
8498
8751
  // src/stores/MenuStore.ts
8499
- import { Pool as Pool21 } from "pg";
8752
+ import { Pool as Pool22 } from "pg";
8500
8753
 
8501
8754
  // src/migrations/menu_items_migration.ts
8502
8755
  var createMenuItemsTable = {
@@ -8573,7 +8826,7 @@ var MenuStore = class {
8573
8826
  this.initialized = true;
8574
8827
  return;
8575
8828
  }
8576
- this.pool = typeof options.poolConfig === "string" ? new Pool21({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool21(options.poolConfig) : (() => {
8829
+ this.pool = typeof options.poolConfig === "string" ? new Pool22({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool22(options.poolConfig) : (() => {
8577
8830
  throw new Error("Either pool or poolConfig must be provided");
8578
8831
  })();
8579
8832
  this.migrationManager = new MigrationManager(this.pool);
@@ -8728,7 +8981,7 @@ var MenuStore = class {
8728
8981
  };
8729
8982
 
8730
8983
  // src/stores/PostgresSharedResourceStore.ts
8731
- import { Pool as Pool22 } from "pg";
8984
+ import { Pool as Pool23 } from "pg";
8732
8985
 
8733
8986
  // src/migrations/shared_resources_migration.ts
8734
8987
  var createSharedResourcesTable = {
@@ -8782,7 +9035,7 @@ var PostgresSharedResourceStore = class {
8782
9035
  this.initialized = true;
8783
9036
  return;
8784
9037
  }
8785
- this.pool = typeof options.poolConfig === "string" ? new Pool22({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool22(options.poolConfig) : (() => {
9038
+ this.pool = typeof options.poolConfig === "string" ? new Pool23({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool23(options.poolConfig) : (() => {
8786
9039
  throw new Error("Either pool or poolConfig must be provided");
8787
9040
  })();
8788
9041
  this.migrationManager = new MigrationManager(this.pool);
@@ -8830,8 +9083,8 @@ var PostgresSharedResourceStore = class {
8830
9083
  `INSERT INTO lattice_shared_resources
8831
9084
  (token, address, title, created_by, tenant_id, workspace_id, project_id,
8832
9085
  assistant_id, vm_isolation, visibility, password_hash,
8833
- expires_at, max_access, revoked)
8834
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)
9086
+ expires_at, max_access, open_grants, revoked)
9087
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
8835
9088
  RETURNING *`,
8836
9089
  [
8837
9090
  record.token,
@@ -8847,6 +9100,7 @@ var PostgresSharedResourceStore = class {
8847
9100
  record.passwordHash,
8848
9101
  record.expiresAt ? record.expiresAt.toISOString() : null,
8849
9102
  record.maxAccess,
9103
+ record.openGrants ? JSON.stringify(record.openGrants) : null,
8850
9104
  record.revoked
8851
9105
  ]
8852
9106
  );
@@ -8942,6 +9196,7 @@ var PostgresSharedResourceStore = class {
8942
9196
  passwordHash: row.password_hash,
8943
9197
  expiresAt: row.expires_at ? new Date(row.expires_at) : null,
8944
9198
  maxAccess: row.max_access,
9199
+ openGrants: row.open_grants ?? void 0,
8945
9200
  accessCount: row.access_count ?? 0,
8946
9201
  revoked: row.revoked ?? false,
8947
9202
  createdAt: new Date(row.created_at),
@@ -8951,7 +9206,7 @@ var PostgresSharedResourceStore = class {
8951
9206
  };
8952
9207
 
8953
9208
  // src/stores/PostgreSQLCollectionStore.ts
8954
- import { Pool as Pool23 } from "pg";
9209
+ import { Pool as Pool24 } from "pg";
8955
9210
  var PostgreSQLCollectionStore = class {
8956
9211
  constructor(options) {
8957
9212
  this.initialized = false;
@@ -8964,9 +9219,9 @@ var PostgreSQLCollectionStore = class {
8964
9219
  return;
8965
9220
  }
8966
9221
  if (typeof options.poolConfig === "string") {
8967
- this.pool = new Pool23({ connectionString: options.poolConfig });
9222
+ this.pool = new Pool24({ connectionString: options.poolConfig });
8968
9223
  } else if (options.poolConfig) {
8969
- this.pool = new Pool23(options.poolConfig);
9224
+ this.pool = new Pool24(options.poolConfig);
8970
9225
  } else {
8971
9226
  throw new Error("Either pool or poolConfig must be provided");
8972
9227
  }
@@ -9081,7 +9336,7 @@ var PostgreSQLCollectionStore = class {
9081
9336
  import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
9082
9337
 
9083
9338
  // src/PGVectorStoreProvider.ts
9084
- import { Pool as Pool24 } from "pg";
9339
+ import { Pool as Pool25 } from "pg";
9085
9340
  import { PGVectorStore } from "@langchain/community/vectorstores/pgvector";
9086
9341
  import { Document } from "@langchain/core/documents";
9087
9342
  import { embeddingsLatticeManager } from "@axiom-lattice/core";
@@ -9155,7 +9410,7 @@ var PGVectorStoreProvider = class {
9155
9410
  }
9156
9411
  };
9157
9412
  function createPGVectorStoreProvider(connectionString) {
9158
- const pool = new Pool24({ connectionString });
9413
+ const pool = new Pool25({ connectionString });
9159
9414
  return {
9160
9415
  provider: new PGVectorStoreProvider(pool, connectionString),
9161
9416
  pool
@@ -9410,6 +9665,24 @@ var createConnectionConfigsTable = {
9410
9665
  }
9411
9666
  };
9412
9667
 
9668
+ // src/migrations/add_share_open_grants.ts
9669
+ var addShareOpenGrants = {
9670
+ version: 180,
9671
+ name: "add_share_open_grants",
9672
+ up: async (client) => {
9673
+ await client.query(`
9674
+ ALTER TABLE lattice_shared_resources
9675
+ ADD COLUMN IF NOT EXISTS open_grants JSONB
9676
+ `);
9677
+ },
9678
+ down: async (client) => {
9679
+ await client.query(`
9680
+ ALTER TABLE lattice_shared_resources
9681
+ DROP COLUMN IF EXISTS open_grants
9682
+ `);
9683
+ }
9684
+ };
9685
+
9413
9686
  // src/migrations/collection_migrations.ts
9414
9687
  var createCollectionsTable = {
9415
9688
  version: 137,
@@ -9586,10 +9859,34 @@ var createProjectRoomTables = {
9586
9859
  await client.query("DROP TABLE IF EXISTS lattice_project_rooms");
9587
9860
  }
9588
9861
  };
9862
+ var createProjectRoomReadStates = {
9863
+ version: 177,
9864
+ name: "create_project_room_read_states",
9865
+ up: async (client) => {
9866
+ await client.query(`
9867
+ CREATE TABLE IF NOT EXISTS lattice_project_room_read_states (
9868
+ tenant_id VARCHAR(255) NOT NULL,
9869
+ room_id VARCHAR(255) NOT NULL,
9870
+ user_id VARCHAR(255) NOT NULL,
9871
+ last_read_at TIMESTAMPTZ NOT NULL,
9872
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
9873
+ PRIMARY KEY (tenant_id, room_id, user_id)
9874
+ )
9875
+ `);
9876
+ await client.query(`
9877
+ CREATE INDEX IF NOT EXISTS idx_lattice_project_room_read_states_user
9878
+ ON lattice_project_room_read_states (tenant_id, user_id)
9879
+ `);
9880
+ },
9881
+ down: async (client) => {
9882
+ await client.query("DROP INDEX IF EXISTS idx_lattice_project_room_read_states_user");
9883
+ await client.query("DROP TABLE IF EXISTS lattice_project_room_read_states");
9884
+ }
9885
+ };
9589
9886
 
9590
9887
  // src/stores/PostgreSQLCapabilityBundleStore.ts
9591
9888
  import { randomUUID as randomUUID3 } from "crypto";
9592
- import { Pool as Pool25 } from "pg";
9889
+ import { Pool as Pool26 } from "pg";
9593
9890
  var duplicateMessage = "Capability bundle key already exists for tenant";
9594
9891
  function map(row) {
9595
9892
  return {
@@ -9622,7 +9919,7 @@ var PostgreSQLCapabilityBundleStore = class {
9622
9919
  this.initialized = true;
9623
9920
  return;
9624
9921
  }
9625
- this.pool = typeof options.poolConfig === "string" ? new Pool25({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool25(options.poolConfig) : (() => {
9922
+ this.pool = typeof options.poolConfig === "string" ? new Pool26({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool26(options.poolConfig) : (() => {
9626
9923
  throw new Error("Either pool or poolConfig must be provided");
9627
9924
  })();
9628
9925
  this.migrationManager = new MigrationManager(this.pool);
@@ -10298,6 +10595,22 @@ function mapRow5(row) {
10298
10595
  createdAt: row.created_at
10299
10596
  };
10300
10597
  }
10598
+ function mapRowsTolerant(rows, scope) {
10599
+ const messages = [];
10600
+ for (const row of rows) {
10601
+ try {
10602
+ messages.push(mapRow5(row));
10603
+ } catch (error) {
10604
+ console.warn("[ProjectRoomMessageStore] Skipping invalid message row", {
10605
+ tenantId: scope.tenantId,
10606
+ roomId: scope.roomId,
10607
+ rowId: typeof row.id === "string" ? row.id : void 0,
10608
+ reason: error instanceof Error ? error.message : String(error)
10609
+ });
10610
+ }
10611
+ }
10612
+ return messages;
10613
+ }
10301
10614
  function isUniqueViolation2(error) {
10302
10615
  return typeof error === "object" && error !== null && "code" in error && error.code === "23505";
10303
10616
  }
@@ -10363,7 +10676,7 @@ var PostgreSQLProjectRoomMessageStore = class {
10363
10676
  WHERE tenant_id = $1 AND room_id = $2 ORDER BY created_at DESC, id DESC LIMIT $3`,
10364
10677
  [input.tenantId, input.roomId, limit]
10365
10678
  );
10366
- return result.rows.map(mapRow5);
10679
+ return mapRowsTolerant(result.rows, { tenantId: input.tenantId, roomId: input.roomId });
10367
10680
  }
10368
10681
  /** Finds a message by tenant-scoped ID. */
10369
10682
  async findById(tenantId, id) {
@@ -10373,6 +10686,19 @@ var PostgreSQLProjectRoomMessageStore = class {
10373
10686
  );
10374
10687
  return result.rows[0] ? mapRow5(result.rows[0]) : null;
10375
10688
  }
10689
+ /** Counts messages created strictly after a horizon, optionally excluding one human author. */
10690
+ async countAfter(input) {
10691
+ if (!(input.after instanceof Date) || Number.isNaN(input.after.getTime())) {
10692
+ throw new RangeError("Project room message count horizon date is invalid");
10693
+ }
10694
+ const result = await this.pool.query(
10695
+ `SELECT COUNT(*)::int AS count FROM lattice_project_room_messages
10696
+ WHERE tenant_id = $1 AND room_id = $2 AND created_at > $3
10697
+ AND ($4::text IS NULL OR author->>'type' <> 'human' OR author->>'userId' <> $4)`,
10698
+ [input.tenantId, input.roomId, input.after, input.excludeAuthorUserId ?? null]
10699
+ );
10700
+ return result.rows[0]?.count ?? 0;
10701
+ }
10376
10702
  parameters(input) {
10377
10703
  return [
10378
10704
  input.id,
@@ -10391,9 +10717,48 @@ var PostgreSQLProjectRoomMessageStore = class {
10391
10717
  }
10392
10718
  };
10393
10719
 
10720
+ // src/stores/PostgreSQLProjectRoomReadStateStore.ts
10721
+ function mapRow6(row) {
10722
+ 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())) {
10723
+ throw new Error("Invalid project room read state row");
10724
+ }
10725
+ return { tenantId: row.tenant_id, roomId: row.room_id, userId: row.user_id, lastReadAt: row.last_read_at, updatedAt: row.updated_at };
10726
+ }
10727
+ var PostgreSQLProjectRoomReadStateStore = class {
10728
+ /** Creates a store using an externally managed shared pool. */
10729
+ constructor(options) {
10730
+ this.pool = options.pool;
10731
+ }
10732
+ /** Returns the user's read marker for a room, or null when never reported. */
10733
+ async get(tenantId, roomId, userId) {
10734
+ const result = await this.pool.query(
10735
+ `SELECT tenant_id, room_id, user_id, last_read_at, updated_at
10736
+ FROM lattice_project_room_read_states WHERE tenant_id = $1 AND room_id = $2 AND user_id = $3`,
10737
+ [tenantId, roomId, userId]
10738
+ );
10739
+ return result.rows[0] ? mapRow6(result.rows[0]) : null;
10740
+ }
10741
+ /** Upserts the marker monotonically using GREATEST so older reports never regress it. */
10742
+ async markRead(input) {
10743
+ if (!(input.lastReadAt instanceof Date) || Number.isNaN(input.lastReadAt.getTime())) {
10744
+ throw new RangeError("Project room read state lastReadAt is invalid");
10745
+ }
10746
+ const result = await this.pool.query(
10747
+ `INSERT INTO lattice_project_room_read_states (tenant_id, room_id, user_id, last_read_at, updated_at)
10748
+ VALUES ($1, $2, $3, $4, NOW())
10749
+ ON CONFLICT (tenant_id, room_id, user_id) DO UPDATE
10750
+ SET last_read_at = GREATEST(lattice_project_room_read_states.last_read_at, EXCLUDED.last_read_at),
10751
+ updated_at = NOW()
10752
+ RETURNING tenant_id, room_id, user_id, last_read_at, updated_at`,
10753
+ [input.tenantId, input.roomId, input.userId, input.lastReadAt]
10754
+ );
10755
+ return mapRow6(result.rows[0]);
10756
+ }
10757
+ };
10758
+
10394
10759
  // src/createPgStoreConfig.ts
10395
10760
  async function createPgStoreConfig(connectionString) {
10396
- const pool = new Pool26({ connectionString });
10761
+ const pool = new Pool27({ connectionString });
10397
10762
  const mm = new MigrationManager(pool);
10398
10763
  mm.register(createThreadsTable);
10399
10764
  mm.register(createScheduledTasksTable);
@@ -10446,6 +10811,9 @@ async function createPgStoreConfig(connectionString) {
10446
10811
  mm.register(addWorkflowRunsTenantStatusUpdatedIndex);
10447
10812
  mm.register(addProjectKindColumn);
10448
10813
  mm.register(addA2AKeyAssistantIds);
10814
+ mm.register(addApiKeyGrants);
10815
+ mm.register(createOpenAuditTable);
10816
+ mm.register(addShareOpenGrants);
10449
10817
  mm.register(addTaskWorkItemEventKeyMigration);
10450
10818
  mm.register(createAgentWebAppsTable);
10451
10819
  mm.register(createCapabilityBundlesTable);
@@ -10454,6 +10822,7 @@ async function createPgStoreConfig(connectionString) {
10454
10822
  mm.register(addTrustedRunContextColumn);
10455
10823
  mm.register(addProjectLifecycleEventIndex);
10456
10824
  mm.register(addAgentWebAppsIdentity);
10825
+ mm.register(createProjectRoomReadStates);
10457
10826
  await mm.migrate();
10458
10827
  const checkpoint = PostgresSaver.fromConnString(connectionString);
10459
10828
  checkpoint.setup().catch((err) => {
@@ -10481,6 +10850,7 @@ async function createPgStoreConfig(connectionString) {
10481
10850
  task: new PostgreSQLTaskStore(opts),
10482
10851
  taskWorkItem: taskWorkItemStore,
10483
10852
  a2aApiKey: new PostgreSQLA2AApiKeyStore(opts),
10853
+ openAudit: new PostgreSQLOpenAuditStore(opts),
10484
10854
  agentWebApp: new PostgreSQLAgentWebAppStore(opts),
10485
10855
  capabilityBundle: new PostgreSQLCapabilityBundleStore(opts),
10486
10856
  schedule: new PostgreSQLScheduleStorage(opts),
@@ -10491,13 +10861,14 @@ async function createPgStoreConfig(connectionString) {
10491
10861
  projectMembership: new PostgreSQLProjectMembershipStore(opts),
10492
10862
  projectBotMembership: new PostgreSQLProjectBotMembershipStore(opts),
10493
10863
  projectRoomMessage: new PostgreSQLProjectRoomMessageStore(opts),
10864
+ projectRoomReadState: new PostgreSQLProjectRoomReadStateStore(opts),
10494
10865
  vectorStoreProvider: new PGVectorStoreProvider(pool, connectionString),
10495
10866
  checkpoint
10496
10867
  };
10497
10868
  }
10498
10869
 
10499
10870
  // src/stores/PostgreSQLSkillStore.ts
10500
- import { Pool as Pool27 } from "pg";
10871
+ import { Pool as Pool28 } from "pg";
10501
10872
  var PostgreSQLSkillStore = class {
10502
10873
  constructor(options) {
10503
10874
  this.initialized = false;
@@ -10510,9 +10881,9 @@ var PostgreSQLSkillStore = class {
10510
10881
  return;
10511
10882
  }
10512
10883
  if (typeof options.poolConfig === "string") {
10513
- this.pool = new Pool27({ connectionString: options.poolConfig });
10884
+ this.pool = new Pool28({ connectionString: options.poolConfig });
10514
10885
  } else if (options.poolConfig) {
10515
- this.pool = new Pool27(options.poolConfig);
10886
+ this.pool = new Pool28(options.poolConfig);
10516
10887
  } else {
10517
10888
  throw new Error("Either pool or poolConfig must be provided");
10518
10889
  }
@@ -10813,7 +11184,7 @@ var PostgreSQLSkillStore = class {
10813
11184
  };
10814
11185
 
10815
11186
  // src/stores/ChannelIdentityMappingStore.ts
10816
- import { Pool as Pool28 } from "pg";
11187
+ import { Pool as Pool29 } from "pg";
10817
11188
  var ChannelIdentityMappingStore = class {
10818
11189
  constructor(options) {
10819
11190
  this.initialized = false;
@@ -10825,7 +11196,7 @@ var ChannelIdentityMappingStore = class {
10825
11196
  this.initialized = true;
10826
11197
  return;
10827
11198
  }
10828
- this.pool = typeof options.poolConfig === "string" ? new Pool28({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool28(options.poolConfig) : (() => {
11199
+ this.pool = typeof options.poolConfig === "string" ? new Pool29({ connectionString: options.poolConfig }) : options.poolConfig ? new Pool29(options.poolConfig) : (() => {
10829
11200
  throw new Error("Either pool or poolConfig must be provided");
10830
11201
  })();
10831
11202
  this.migrationManager = new MigrationManager(this.pool);
@@ -11051,7 +11422,7 @@ export {
11051
11422
  MenuStore,
11052
11423
  MigrationManager,
11053
11424
  PGVectorStoreProvider,
11054
- Pool29 as Pool,
11425
+ Pool30 as Pool,
11055
11426
  PostgreSQLA2AApiKeyStore,
11056
11427
  PostgreSQLAgentWebAppStore,
11057
11428
  PostgreSQLAssistantStore,
@@ -11063,9 +11434,11 @@ export {
11063
11434
  PostgreSQLEvalStore,
11064
11435
  PostgreSQLMcpServerConfigStore,
11065
11436
  PostgreSQLMetricsServerConfigStore,
11437
+ PostgreSQLOpenAuditStore,
11066
11438
  PostgreSQLProjectBotMembershipStore,
11067
11439
  PostgreSQLProjectMembershipStore,
11068
11440
  PostgreSQLProjectRoomMessageStore,
11441
+ PostgreSQLProjectRoomReadStateStore,
11069
11442
  PostgreSQLProjectRoomStore,
11070
11443
  PostgreSQLProjectStore,
11071
11444
  PostgreSQLScheduleStorage,
@@ -11118,6 +11491,7 @@ export {
11118
11491
  createMetricsConfigsTable,
11119
11492
  createPGVectorStoreProvider,
11120
11493
  createPgStoreConfig,
11494
+ createProjectRoomReadStates,
11121
11495
  createProjectRoomTables,
11122
11496
  createProjectsTable,
11123
11497
  createScheduledTasksTable,