@axiom-lattice/pg-stores 3.1.5 → 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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +29 -0
- package/dist/index.d.mts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +137 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +135 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/PostgreSQLAgentWebAppStore.migrations.test.ts +2 -1
- package/src/__tests__/PostgreSQLAgentWebAppStore.test.ts +1 -0
- package/src/__tests__/PostgreSQLMcpServerConfigStore.test.ts +79 -0
- package/src/__tests__/PostgreSQLProjectRoomReadStateStore.test.ts +136 -0
- package/src/createPgStoreConfig.ts +6 -1
- package/src/index.ts +1 -0
- package/src/migrations/add_agent_web_apps_identity_migration.ts +18 -0
- package/src/migrations/project_room_migration.ts +26 -0
- package/src/stores/PostgreSQLAgentWebAppStore.ts +25 -3
- package/src/stores/PostgreSQLMcpServerConfigStore.ts +23 -0
- package/src/stores/PostgreSQLProjectRoomMessageStore.ts +16 -0
- package/src/stores/PostgreSQLProjectRoomReadStateStore.ts +47 -0
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
|
};
|
|
@@ -6320,6 +6340,22 @@ var createAgentWebAppsTable = {
|
|
|
6320
6340
|
}
|
|
6321
6341
|
};
|
|
6322
6342
|
|
|
6343
|
+
// src/migrations/add_agent_web_apps_identity_migration.ts
|
|
6344
|
+
var addAgentWebAppsIdentity = {
|
|
6345
|
+
version: 176,
|
|
6346
|
+
name: "add_agent_web_apps_identity",
|
|
6347
|
+
up: async (client) => {
|
|
6348
|
+
await client.query(
|
|
6349
|
+
"ALTER TABLE lattice_agent_web_apps ADD COLUMN IF NOT EXISTS identity JSONB"
|
|
6350
|
+
);
|
|
6351
|
+
},
|
|
6352
|
+
down: async (client) => {
|
|
6353
|
+
await client.query(
|
|
6354
|
+
"ALTER TABLE lattice_agent_web_apps DROP COLUMN IF EXISTS identity"
|
|
6355
|
+
);
|
|
6356
|
+
}
|
|
6357
|
+
};
|
|
6358
|
+
|
|
6323
6359
|
// src/stores/PostgreSQLAgentWebAppStore.ts
|
|
6324
6360
|
function isRecord(value) {
|
|
6325
6361
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -6334,16 +6370,23 @@ function isScope(value) {
|
|
|
6334
6370
|
return isRecord(value) && typeof value.defaultProjectId === "string" && isStringArray(value.allowedProjectIds) && (value.defaultModelKey === void 0 || typeof value.defaultModelKey === "string") && (value.allowedModelKeys === void 0 || isStringArray(value.allowedModelKeys));
|
|
6335
6371
|
}
|
|
6336
6372
|
function isFeatures(value) {
|
|
6337
|
-
return isRecord(value) && typeof value.projectSelector === "boolean" && typeof value.modelSelector === "boolean" && typeof value.threadManagement === "boolean" && typeof value.attachments === "boolean" && typeof value.hitl === "boolean" && typeof value.genUI === "boolean";
|
|
6373
|
+
return isRecord(value) && typeof value.projectSelector === "boolean" && typeof value.modelSelector === "boolean" && typeof value.threadManagement === "boolean" && typeof value.attachments === "boolean" && typeof value.hitl === "boolean" && typeof value.genUI === "boolean" && (value.files === void 0 || typeof value.files === "boolean");
|
|
6338
6374
|
}
|
|
6339
6375
|
function isAppearance(value) {
|
|
6340
6376
|
return isRecord(value) && (value.title === void 0 || typeof value.title === "string") && (value.welcomeMessage === void 0 || typeof value.welcomeMessage === "string") && (value.primaryColor === void 0 || typeof value.primaryColor === "string");
|
|
6341
6377
|
}
|
|
6378
|
+
function isIdentity(value) {
|
|
6379
|
+
if (value === null || value === void 0) return true;
|
|
6380
|
+
if (!isRecord(value)) return false;
|
|
6381
|
+
const policyOk = value.policy === "unverified" || value.policy === "verified" || value.policy === "both";
|
|
6382
|
+
const issuersOk = Array.isArray(value.issuers) && value.issuers.every((issuer) => isRecord(issuer) && typeof issuer.iss === "string" && typeof issuer.aud === "string" && (issuer.alg === "HS256" || issuer.alg === "RS256"));
|
|
6383
|
+
return policyOk && issuersOk;
|
|
6384
|
+
}
|
|
6342
6385
|
function isStatus(value) {
|
|
6343
6386
|
return value === "draft" || value === "active" || value === "disabled";
|
|
6344
6387
|
}
|
|
6345
6388
|
function mapRow(row) {
|
|
6346
|
-
if (!isStatus(row.status) || !isIntegration(row.integration) || !isScope(row.scope) || !isFeatures(row.features) || !isAppearance(row.appearance)) {
|
|
6389
|
+
if (!isStatus(row.status) || !isIntegration(row.integration) || !isScope(row.scope) || !isFeatures(row.features) || !isAppearance(row.appearance) || !isIdentity(row.identity)) {
|
|
6347
6390
|
throw new Error(`Invalid agent web app row: ${row.id}`);
|
|
6348
6391
|
}
|
|
6349
6392
|
return {
|
|
@@ -6357,6 +6400,7 @@ function mapRow(row) {
|
|
|
6357
6400
|
scope: row.scope,
|
|
6358
6401
|
features: row.features,
|
|
6359
6402
|
appearance: row.appearance,
|
|
6403
|
+
identity: row.identity === null ? void 0 : row.identity,
|
|
6360
6404
|
createdAt: row.created_at,
|
|
6361
6405
|
updatedAt: row.updated_at
|
|
6362
6406
|
};
|
|
@@ -6377,6 +6421,7 @@ var PostgreSQLAgentWebAppStore = class {
|
|
|
6377
6421
|
})();
|
|
6378
6422
|
this.migrationManager = new MigrationManager(this.pool);
|
|
6379
6423
|
this.migrationManager.register(createAgentWebAppsTable);
|
|
6424
|
+
this.migrationManager.register(addAgentWebAppsIdentity);
|
|
6380
6425
|
if (options.autoMigrate !== false) {
|
|
6381
6426
|
this.startInitialization();
|
|
6382
6427
|
}
|
|
@@ -6437,8 +6482,8 @@ var PostgreSQLAgentWebAppStore = class {
|
|
|
6437
6482
|
const id = `webapp_${randomUUID2().replace(/-/g, "")}`;
|
|
6438
6483
|
const result = await this.pool.query(
|
|
6439
6484
|
`INSERT INTO lattice_agent_web_apps
|
|
6440
|
-
(id, tenant_id, assistant_id, name, description, status, integration, scope, features, appearance)
|
|
6441
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8::jsonb, $9::jsonb, $10::jsonb)
|
|
6485
|
+
(id, tenant_id, assistant_id, name, description, status, integration, scope, features, appearance, identity)
|
|
6486
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8::jsonb, $9::jsonb, $10::jsonb, $11::jsonb)
|
|
6442
6487
|
RETURNING *`,
|
|
6443
6488
|
[
|
|
6444
6489
|
id,
|
|
@@ -6450,7 +6495,8 @@ var PostgreSQLAgentWebAppStore = class {
|
|
|
6450
6495
|
JSON.stringify(input.integration),
|
|
6451
6496
|
JSON.stringify(input.scope),
|
|
6452
6497
|
JSON.stringify(input.features),
|
|
6453
|
-
JSON.stringify(input.appearance)
|
|
6498
|
+
JSON.stringify(input.appearance),
|
|
6499
|
+
input.identity ? JSON.stringify(input.identity) : null
|
|
6454
6500
|
]
|
|
6455
6501
|
);
|
|
6456
6502
|
return mapRow(result.rows[0]);
|
|
@@ -6476,6 +6522,9 @@ var PostgreSQLAgentWebAppStore = class {
|
|
|
6476
6522
|
if (patch.appearance !== void 0) {
|
|
6477
6523
|
add("appearance", JSON.stringify(patch.appearance));
|
|
6478
6524
|
}
|
|
6525
|
+
if (patch.identity !== void 0) {
|
|
6526
|
+
add("identity", JSON.stringify(patch.identity));
|
|
6527
|
+
}
|
|
6479
6528
|
if (patch.status !== void 0) add("status", patch.status);
|
|
6480
6529
|
if (assignments.length === 0) return this.getById(tenantId, webAppId);
|
|
6481
6530
|
values.push(tenantId, webAppId);
|
|
@@ -9557,6 +9606,30 @@ var createProjectRoomTables = {
|
|
|
9557
9606
|
await client.query("DROP TABLE IF EXISTS lattice_project_rooms");
|
|
9558
9607
|
}
|
|
9559
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
|
+
};
|
|
9560
9633
|
|
|
9561
9634
|
// src/stores/PostgreSQLCapabilityBundleStore.ts
|
|
9562
9635
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
@@ -10344,6 +10417,19 @@ var PostgreSQLProjectRoomMessageStore = class {
|
|
|
10344
10417
|
);
|
|
10345
10418
|
return result.rows[0] ? mapRow5(result.rows[0]) : null;
|
|
10346
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
|
+
}
|
|
10347
10433
|
parameters(input) {
|
|
10348
10434
|
return [
|
|
10349
10435
|
input.id,
|
|
@@ -10362,6 +10448,45 @@ var PostgreSQLProjectRoomMessageStore = class {
|
|
|
10362
10448
|
}
|
|
10363
10449
|
};
|
|
10364
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
|
+
|
|
10365
10490
|
// src/createPgStoreConfig.ts
|
|
10366
10491
|
async function createPgStoreConfig(connectionString) {
|
|
10367
10492
|
const pool = new Pool26({ connectionString });
|
|
@@ -10424,6 +10549,8 @@ async function createPgStoreConfig(connectionString) {
|
|
|
10424
10549
|
mm.register(createProjectRoomTables);
|
|
10425
10550
|
mm.register(addTrustedRunContextColumn);
|
|
10426
10551
|
mm.register(addProjectLifecycleEventIndex);
|
|
10552
|
+
mm.register(addAgentWebAppsIdentity);
|
|
10553
|
+
mm.register(createProjectRoomReadStates);
|
|
10427
10554
|
await mm.migrate();
|
|
10428
10555
|
const checkpoint = PostgresSaver.fromConnString(connectionString);
|
|
10429
10556
|
checkpoint.setup().catch((err) => {
|
|
@@ -10461,6 +10588,7 @@ async function createPgStoreConfig(connectionString) {
|
|
|
10461
10588
|
projectMembership: new PostgreSQLProjectMembershipStore(opts),
|
|
10462
10589
|
projectBotMembership: new PostgreSQLProjectBotMembershipStore(opts),
|
|
10463
10590
|
projectRoomMessage: new PostgreSQLProjectRoomMessageStore(opts),
|
|
10591
|
+
projectRoomReadState: new PostgreSQLProjectRoomReadStateStore(opts),
|
|
10464
10592
|
vectorStoreProvider: new PGVectorStoreProvider(pool, connectionString),
|
|
10465
10593
|
checkpoint
|
|
10466
10594
|
};
|
|
@@ -11036,6 +11164,7 @@ export {
|
|
|
11036
11164
|
PostgreSQLProjectBotMembershipStore,
|
|
11037
11165
|
PostgreSQLProjectMembershipStore,
|
|
11038
11166
|
PostgreSQLProjectRoomMessageStore,
|
|
11167
|
+
PostgreSQLProjectRoomReadStateStore,
|
|
11039
11168
|
PostgreSQLProjectRoomStore,
|
|
11040
11169
|
PostgreSQLProjectStore,
|
|
11041
11170
|
PostgreSQLScheduleStorage,
|
|
@@ -11088,6 +11217,7 @@ export {
|
|
|
11088
11217
|
createMetricsConfigsTable,
|
|
11089
11218
|
createPGVectorStoreProvider,
|
|
11090
11219
|
createPgStoreConfig,
|
|
11220
|
+
createProjectRoomReadStates,
|
|
11091
11221
|
createProjectRoomTables,
|
|
11092
11222
|
createProjectsTable,
|
|
11093
11223
|
createScheduledTasksTable,
|