@axiom-lattice/pg-stores 3.1.6 → 3.1.8

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.mjs CHANGED
@@ -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
  };
@@ -9586,6 +9606,30 @@ var createProjectRoomTables = {
9586
9606
  await client.query("DROP TABLE IF EXISTS lattice_project_rooms");
9587
9607
  }
9588
9608
  };
9609
+ var createProjectRoomReadStates = {
9610
+ version: 177,
9611
+ name: "create_project_room_read_states",
9612
+ up: async (client) => {
9613
+ await client.query(`
9614
+ CREATE TABLE IF NOT EXISTS lattice_project_room_read_states (
9615
+ tenant_id VARCHAR(255) NOT NULL,
9616
+ room_id VARCHAR(255) NOT NULL,
9617
+ user_id VARCHAR(255) NOT NULL,
9618
+ last_read_at TIMESTAMPTZ NOT NULL,
9619
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
9620
+ PRIMARY KEY (tenant_id, room_id, user_id)
9621
+ )
9622
+ `);
9623
+ await client.query(`
9624
+ CREATE INDEX IF NOT EXISTS idx_lattice_project_room_read_states_user
9625
+ ON lattice_project_room_read_states (tenant_id, user_id)
9626
+ `);
9627
+ },
9628
+ down: async (client) => {
9629
+ await client.query("DROP INDEX IF EXISTS idx_lattice_project_room_read_states_user");
9630
+ await client.query("DROP TABLE IF EXISTS lattice_project_room_read_states");
9631
+ }
9632
+ };
9589
9633
 
9590
9634
  // src/stores/PostgreSQLCapabilityBundleStore.ts
9591
9635
  import { randomUUID as randomUUID3 } from "crypto";
@@ -10373,6 +10417,19 @@ var PostgreSQLProjectRoomMessageStore = class {
10373
10417
  );
10374
10418
  return result.rows[0] ? mapRow5(result.rows[0]) : null;
10375
10419
  }
10420
+ /** Counts messages created strictly after a horizon, optionally excluding one human author. */
10421
+ async countAfter(input) {
10422
+ if (!(input.after instanceof Date) || Number.isNaN(input.after.getTime())) {
10423
+ throw new RangeError("Project room message count horizon date is invalid");
10424
+ }
10425
+ const result = await this.pool.query(
10426
+ `SELECT COUNT(*)::int AS count FROM lattice_project_room_messages
10427
+ WHERE tenant_id = $1 AND room_id = $2 AND created_at > $3
10428
+ AND ($4::text IS NULL OR author->>'type' <> 'human' OR author->>'userId' <> $4)`,
10429
+ [input.tenantId, input.roomId, input.after, input.excludeAuthorUserId ?? null]
10430
+ );
10431
+ return result.rows[0]?.count ?? 0;
10432
+ }
10376
10433
  parameters(input) {
10377
10434
  return [
10378
10435
  input.id,
@@ -10391,6 +10448,45 @@ var PostgreSQLProjectRoomMessageStore = class {
10391
10448
  }
10392
10449
  };
10393
10450
 
10451
+ // src/stores/PostgreSQLProjectRoomReadStateStore.ts
10452
+ function mapRow6(row) {
10453
+ 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())) {
10454
+ throw new Error("Invalid project room read state row");
10455
+ }
10456
+ return { tenantId: row.tenant_id, roomId: row.room_id, userId: row.user_id, lastReadAt: row.last_read_at, updatedAt: row.updated_at };
10457
+ }
10458
+ var PostgreSQLProjectRoomReadStateStore = class {
10459
+ /** Creates a store using an externally managed shared pool. */
10460
+ constructor(options) {
10461
+ this.pool = options.pool;
10462
+ }
10463
+ /** Returns the user's read marker for a room, or null when never reported. */
10464
+ async get(tenantId, roomId, userId) {
10465
+ const result = await this.pool.query(
10466
+ `SELECT tenant_id, room_id, user_id, last_read_at, updated_at
10467
+ FROM lattice_project_room_read_states WHERE tenant_id = $1 AND room_id = $2 AND user_id = $3`,
10468
+ [tenantId, roomId, userId]
10469
+ );
10470
+ return result.rows[0] ? mapRow6(result.rows[0]) : null;
10471
+ }
10472
+ /** Upserts the marker monotonically using GREATEST so older reports never regress it. */
10473
+ async markRead(input) {
10474
+ if (!(input.lastReadAt instanceof Date) || Number.isNaN(input.lastReadAt.getTime())) {
10475
+ throw new RangeError("Project room read state lastReadAt is invalid");
10476
+ }
10477
+ const result = await this.pool.query(
10478
+ `INSERT INTO lattice_project_room_read_states (tenant_id, room_id, user_id, last_read_at, updated_at)
10479
+ VALUES ($1, $2, $3, $4, NOW())
10480
+ ON CONFLICT (tenant_id, room_id, user_id) DO UPDATE
10481
+ SET last_read_at = GREATEST(lattice_project_room_read_states.last_read_at, EXCLUDED.last_read_at),
10482
+ updated_at = NOW()
10483
+ RETURNING tenant_id, room_id, user_id, last_read_at, updated_at`,
10484
+ [input.tenantId, input.roomId, input.userId, input.lastReadAt]
10485
+ );
10486
+ return mapRow6(result.rows[0]);
10487
+ }
10488
+ };
10489
+
10394
10490
  // src/createPgStoreConfig.ts
10395
10491
  async function createPgStoreConfig(connectionString) {
10396
10492
  const pool = new Pool26({ connectionString });
@@ -10454,6 +10550,7 @@ async function createPgStoreConfig(connectionString) {
10454
10550
  mm.register(addTrustedRunContextColumn);
10455
10551
  mm.register(addProjectLifecycleEventIndex);
10456
10552
  mm.register(addAgentWebAppsIdentity);
10553
+ mm.register(createProjectRoomReadStates);
10457
10554
  await mm.migrate();
10458
10555
  const checkpoint = PostgresSaver.fromConnString(connectionString);
10459
10556
  checkpoint.setup().catch((err) => {
@@ -10491,6 +10588,7 @@ async function createPgStoreConfig(connectionString) {
10491
10588
  projectMembership: new PostgreSQLProjectMembershipStore(opts),
10492
10589
  projectBotMembership: new PostgreSQLProjectBotMembershipStore(opts),
10493
10590
  projectRoomMessage: new PostgreSQLProjectRoomMessageStore(opts),
10591
+ projectRoomReadState: new PostgreSQLProjectRoomReadStateStore(opts),
10494
10592
  vectorStoreProvider: new PGVectorStoreProvider(pool, connectionString),
10495
10593
  checkpoint
10496
10594
  };
@@ -11066,6 +11164,7 @@ export {
11066
11164
  PostgreSQLProjectBotMembershipStore,
11067
11165
  PostgreSQLProjectMembershipStore,
11068
11166
  PostgreSQLProjectRoomMessageStore,
11167
+ PostgreSQLProjectRoomReadStateStore,
11069
11168
  PostgreSQLProjectRoomStore,
11070
11169
  PostgreSQLProjectStore,
11071
11170
  PostgreSQLScheduleStorage,
@@ -11118,6 +11217,7 @@ export {
11118
11217
  createMetricsConfigsTable,
11119
11218
  createPGVectorStoreProvider,
11120
11219
  createPgStoreConfig,
11220
+ createProjectRoomReadStates,
11121
11221
  createProjectRoomTables,
11122
11222
  createProjectsTable,
11123
11223
  createScheduledTasksTable,