@opentrust/db 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/client.d.ts +3 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +51 -0
  4. package/dist/dialect.d.ts +3 -0
  5. package/dist/dialect.d.ts.map +1 -0
  6. package/dist/dialect.js +12 -0
  7. package/dist/generate.d.ts +2 -0
  8. package/dist/generate.d.ts.map +1 -0
  9. package/dist/generate.js +20 -0
  10. package/dist/helpers.d.ts +11 -0
  11. package/dist/helpers.d.ts.map +1 -0
  12. package/dist/helpers.js +32 -0
  13. package/dist/index.d.ts +13 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +12 -0
  16. package/dist/migrate.d.ts +2 -0
  17. package/dist/migrate.d.ts.map +1 -0
  18. package/dist/migrate.js +61 -0
  19. package/dist/queries/agents.d.ts +25 -0
  20. package/dist/queries/agents.d.ts.map +1 -0
  21. package/dist/queries/agents.js +46 -0
  22. package/dist/queries/auth.d.ts +18 -0
  23. package/dist/queries/auth.d.ts.map +1 -0
  24. package/dist/queries/auth.js +77 -0
  25. package/dist/queries/detection-results.d.ts +24 -0
  26. package/dist/queries/detection-results.d.ts.map +1 -0
  27. package/dist/queries/detection-results.js +43 -0
  28. package/dist/queries/observations.d.ts +58 -0
  29. package/dist/queries/observations.d.ts.map +1 -0
  30. package/dist/queries/observations.js +212 -0
  31. package/dist/queries/policies.d.ts +25 -0
  32. package/dist/queries/policies.d.ts.map +1 -0
  33. package/dist/queries/policies.js +38 -0
  34. package/dist/queries/scanners.d.ts +25 -0
  35. package/dist/queries/scanners.d.ts.map +1 -0
  36. package/dist/queries/scanners.js +56 -0
  37. package/dist/queries/settings.d.ts +8 -0
  38. package/dist/queries/settings.d.ts.map +1 -0
  39. package/dist/queries/settings.js +30 -0
  40. package/dist/queries/usage.d.ts +18 -0
  41. package/dist/queries/usage.d.ts.map +1 -0
  42. package/dist/queries/usage.js +54 -0
  43. package/dist/schema/index.d.ts +4415 -0
  44. package/dist/schema/index.d.ts.map +1 -0
  45. package/dist/schema/index.js +19 -0
  46. package/dist/schema/mysql.d.ts +1479 -0
  47. package/dist/schema/mysql.d.ts.map +1 -0
  48. package/dist/schema/mysql.js +151 -0
  49. package/dist/schema/pg.d.ts +1479 -0
  50. package/dist/schema/pg.d.ts.map +1 -0
  51. package/dist/schema/pg.js +151 -0
  52. package/dist/schema/sqlite.d.ts +1479 -0
  53. package/dist/schema/sqlite.d.ts.map +1 -0
  54. package/dist/schema/sqlite.js +153 -0
  55. package/dist/seed.d.ts +2 -0
  56. package/dist/seed.d.ts.map +1 -0
  57. package/dist/seed.js +49 -0
  58. package/drizzle/sqlite/0000_serious_martin_li.sql +143 -0
  59. package/drizzle/sqlite/meta/0000_snapshot.json +945 -0
  60. package/drizzle/sqlite/meta/_journal.json +13 -0
  61. package/drizzle.config.mysql.ts +10 -0
  62. package/drizzle.config.pg.ts +10 -0
  63. package/drizzle.config.sqlite.ts +10 -0
  64. package/package.json +55 -0
  65. package/src/client.ts +66 -0
  66. package/src/dialect.ts +13 -0
  67. package/src/generate.ts +26 -0
  68. package/src/helpers.ts +47 -0
  69. package/src/index.ts +12 -0
  70. package/src/migrate.ts +74 -0
  71. package/src/queries/agents.ts +68 -0
  72. package/src/queries/auth.ts +94 -0
  73. package/src/queries/detection-results.ts +58 -0
  74. package/src/queries/observations.ts +275 -0
  75. package/src/queries/policies.ts +59 -0
  76. package/src/queries/scanners.ts +74 -0
  77. package/src/queries/settings.ts +34 -0
  78. package/src/queries/usage.ts +69 -0
  79. package/src/schema/index.ts +22 -0
  80. package/src/schema/mysql.ts +207 -0
  81. package/src/schema/pg.ts +208 -0
  82. package/src/schema/sqlite.ts +199 -0
  83. package/src/seed.ts +56 -0
@@ -0,0 +1,3 @@
1
+ export declare const db: any;
2
+ export type Database = any;
3
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAgEA,eAAO,MAAM,EAAE,EAAE,GAAsB,CAAC;AACxC,MAAM,MAAM,QAAQ,GAAG,GAAG,CAAC"}
package/dist/client.js ADDED
@@ -0,0 +1,51 @@
1
+ import { config } from "dotenv";
2
+ import { resolve, dirname, join } from "path";
3
+ import { mkdirSync, existsSync } from "fs";
4
+ import { fileURLToPath } from "url";
5
+ import { getDialect } from "./dialect.js";
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ // Load .env from project root if DATABASE_URL is not already set
9
+ if (!process.env.DATABASE_URL && !process.env.DB_DIALECT) {
10
+ config({ path: resolve(__dirname, "../../../.env") });
11
+ }
12
+ const dialect = getDialect();
13
+ // Database path configuration:
14
+ // - DASHBOARD_DATA_DIR: directory for data files (default: dashboard/data)
15
+ // - DATABASE_URL: full path to SQLite file (overrides DASHBOARD_DATA_DIR for SQLite)
16
+ function getDefaultDbPath() {
17
+ const dataDir = process.env.DASHBOARD_DATA_DIR || resolve(__dirname, "../../../data");
18
+ return join(dataDir, "dashboard.db");
19
+ }
20
+ async function createDb() {
21
+ if (dialect === "sqlite") {
22
+ const { default: Database } = await import("better-sqlite3");
23
+ const { drizzle } = await import("drizzle-orm/better-sqlite3");
24
+ const schema = await import("./schema/sqlite.js");
25
+ const rawUrl = process.env.DATABASE_URL || getDefaultDbPath();
26
+ const dbPath = rawUrl.replace(/^file:/, "");
27
+ // Ensure directory exists
28
+ const dir = dirname(dbPath);
29
+ if (!existsSync(dir)) {
30
+ mkdirSync(dir, { recursive: true });
31
+ }
32
+ const sqlite = new Database(dbPath);
33
+ sqlite.pragma("journal_mode = WAL");
34
+ sqlite.pragma("foreign_keys = ON");
35
+ return drizzle(sqlite, { schema });
36
+ }
37
+ if (dialect === "mysql") {
38
+ const mysql2 = await import("mysql2/promise");
39
+ const { drizzle } = await import("drizzle-orm/mysql2");
40
+ const schema = await import("./schema/mysql.js");
41
+ const pool = mysql2.createPool(process.env.DATABASE_URL);
42
+ return drizzle(pool, { schema, mode: "default" });
43
+ }
44
+ // postgresql (default)
45
+ const pg = await import("postgres");
46
+ const { drizzle } = await import("drizzle-orm/postgres-js");
47
+ const schema = await import("./schema/pg.js");
48
+ const queryClient = pg.default(process.env.DATABASE_URL);
49
+ return drizzle(queryClient, { schema });
50
+ }
51
+ export const db = await createDb();
@@ -0,0 +1,3 @@
1
+ export type Dialect = "sqlite" | "mysql" | "postgresql";
2
+ export declare function getDialect(): Dialect;
3
+ //# sourceMappingURL=dialect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../src/dialect.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,CAAC;AAExD,wBAAgB,UAAU,IAAI,OAAO,CAUpC"}
@@ -0,0 +1,12 @@
1
+ export function getDialect() {
2
+ const explicit = process.env.DB_DIALECT;
3
+ if (explicit === "sqlite" || explicit === "mysql" || explicit === "postgresql") {
4
+ return explicit;
5
+ }
6
+ const url = process.env.DATABASE_URL || "";
7
+ if (url.startsWith("mysql://") || url.startsWith("mysql2://"))
8
+ return "mysql";
9
+ if (url.startsWith("postgres://") || url.startsWith("postgresql://"))
10
+ return "postgresql";
11
+ return "sqlite";
12
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import { config } from "dotenv";
2
+ import { resolve, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { execSync } from "child_process";
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ config({ path: resolve(__dirname, "../../../.env") });
8
+ const { getDialect } = await import("./dialect.js");
9
+ const dialect = getDialect();
10
+ const configMap = {
11
+ sqlite: "drizzle.config.sqlite.ts",
12
+ mysql: "drizzle.config.mysql.ts",
13
+ postgresql: "drizzle.config.pg.ts",
14
+ };
15
+ const configFile = configMap[dialect];
16
+ console.log(`Generating migrations for dialect: ${dialect}`);
17
+ execSync(`npx drizzle-kit generate --config=${configFile}`, {
18
+ cwd: resolve(__dirname, ".."),
19
+ stdio: "inherit",
20
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Cross-dialect insert with returning.
3
+ * PostgreSQL and SQLite support .returning(), MySQL does not.
4
+ * All dialects generate UUID client-side for predictability.
5
+ */
6
+ export declare function insertReturning<T>(db: any, table: any, values: Record<string, unknown>): Promise<T>;
7
+ /**
8
+ * Cross-dialect update with returning.
9
+ */
10
+ export declare function updateReturning<T>(db: any, table: any, where: any, values: Record<string, unknown>): Promise<T | null>;
11
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,GAAG,EACP,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,CAAC,CAAC,CAaZ;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,GAAG,EACP,KAAK,EAAE,GAAG,EACV,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAWnB"}
@@ -0,0 +1,32 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { getDialect } from "./dialect.js";
3
+ /**
4
+ * Cross-dialect insert with returning.
5
+ * PostgreSQL and SQLite support .returning(), MySQL does not.
6
+ * All dialects generate UUID client-side for predictability.
7
+ */
8
+ export async function insertReturning(db, table, values) {
9
+ const dialect = getDialect();
10
+ const id = crypto.randomUUID();
11
+ const row = { ...values, id };
12
+ if (dialect === "mysql") {
13
+ await db.insert(table).values(row);
14
+ const result = await db.select().from(table).where(eq(table.id, id)).limit(1);
15
+ return result[0];
16
+ }
17
+ const result = await db.insert(table).values(row).returning();
18
+ return result[0];
19
+ }
20
+ /**
21
+ * Cross-dialect update with returning.
22
+ */
23
+ export async function updateReturning(db, table, where, values) {
24
+ const dialect = getDialect();
25
+ if (dialect === "mysql") {
26
+ await db.update(table).set(values).where(where);
27
+ const result = await db.select().from(table).where(where).limit(1);
28
+ return result[0] ?? null;
29
+ }
30
+ const result = await db.update(table).set(values).where(where).returning();
31
+ return result[0] ?? null;
32
+ }
@@ -0,0 +1,13 @@
1
+ export { db, type Database } from "./client.js";
2
+ export { getDialect, type Dialect } from "./dialect.js";
3
+ export * from "./schema/index.js";
4
+ export { insertReturning, updateReturning } from "./helpers.js";
5
+ export { agentQueries } from "./queries/agents.js";
6
+ export { scannerQueries } from "./queries/scanners.js";
7
+ export { policyQueries } from "./queries/policies.js";
8
+ export { usageQueries } from "./queries/usage.js";
9
+ export { detectionResultQueries } from "./queries/detection-results.js";
10
+ export { settingsQueries } from "./queries/settings.js";
11
+ export { observationQueries, inferCategory, inferAccessPattern } from "./queries/observations.js";
12
+ export { authQueries } from "./queries/auth.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACxD,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export { db } from "./client.js";
2
+ export { getDialect } from "./dialect.js";
3
+ export * from "./schema/index.js";
4
+ export { insertReturning, updateReturning } from "./helpers.js";
5
+ export { agentQueries } from "./queries/agents.js";
6
+ export { scannerQueries } from "./queries/scanners.js";
7
+ export { policyQueries } from "./queries/policies.js";
8
+ export { usageQueries } from "./queries/usage.js";
9
+ export { detectionResultQueries } from "./queries/detection-results.js";
10
+ export { settingsQueries } from "./queries/settings.js";
11
+ export { observationQueries, inferCategory, inferAccessPattern } from "./queries/observations.js";
12
+ export { authQueries } from "./queries/auth.js";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":""}
@@ -0,0 +1,61 @@
1
+ import { config } from "dotenv";
2
+ import { resolve, dirname, join } from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ config({ path: resolve(__dirname, "../../../.env") });
7
+ // Database path configuration:
8
+ // - DASHBOARD_DATA_DIR: directory for data files (default: dashboard/data)
9
+ // - DATABASE_URL: full path to SQLite file (overrides DASHBOARD_DATA_DIR for SQLite)
10
+ function getDefaultDbPath() {
11
+ const dataDir = process.env.DASHBOARD_DATA_DIR || resolve(__dirname, "../../../data");
12
+ return join(dataDir, "dashboard.db");
13
+ }
14
+ async function runMigrations() {
15
+ const { getDialect } = await import("./dialect.js");
16
+ const dialect = getDialect();
17
+ console.log(`Running migrations for dialect: ${dialect}`);
18
+ if (dialect === "sqlite") {
19
+ const { default: Database } = await import("better-sqlite3");
20
+ const { drizzle } = await import("drizzle-orm/better-sqlite3");
21
+ const { migrate } = await import("drizzle-orm/better-sqlite3/migrator");
22
+ const { mkdirSync, existsSync } = await import("fs");
23
+ const { dirname } = await import("path");
24
+ const rawUrl = process.env.DATABASE_URL || getDefaultDbPath();
25
+ const dbPath = rawUrl.replace(/^file:/, "");
26
+ const dir = dirname(dbPath);
27
+ if (!existsSync(dir))
28
+ mkdirSync(dir, { recursive: true });
29
+ const sqlite = new Database(dbPath);
30
+ sqlite.pragma("journal_mode = WAL");
31
+ const db = drizzle(sqlite);
32
+ migrate(db, { migrationsFolder: resolve(__dirname, "../drizzle/sqlite") });
33
+ console.log("SQLite migrations complete.");
34
+ sqlite.close();
35
+ }
36
+ else if (dialect === "mysql") {
37
+ const mysql2 = await import("mysql2/promise");
38
+ const { drizzle } = await import("drizzle-orm/mysql2");
39
+ const { migrate } = await import("drizzle-orm/mysql2/migrator");
40
+ const pool = mysql2.createPool(process.env.DATABASE_URL);
41
+ const db = drizzle(pool);
42
+ await migrate(db, { migrationsFolder: resolve(__dirname, "../drizzle/mysql") });
43
+ console.log("MySQL migrations complete.");
44
+ await pool.end();
45
+ }
46
+ else {
47
+ const pg = await import("postgres");
48
+ const { drizzle } = await import("drizzle-orm/postgres-js");
49
+ const { migrate } = await import("drizzle-orm/postgres-js/migrator");
50
+ const queryClient = pg.default(process.env.DATABASE_URL, { max: 1 });
51
+ const db = drizzle(queryClient);
52
+ await migrate(db, { migrationsFolder: resolve(__dirname, "../drizzle/postgresql") });
53
+ console.log("PostgreSQL migrations complete.");
54
+ await queryClient.end();
55
+ }
56
+ process.exit(0);
57
+ }
58
+ runMigrations().catch((err) => {
59
+ console.error("Migration failed:", err);
60
+ process.exit(1);
61
+ });
@@ -0,0 +1,25 @@
1
+ import type { Database } from "../client.js";
2
+ export declare function agentQueries(db: Database): {
3
+ findById(id: string, tenantId?: string): Promise<any>;
4
+ findByName(name: string, tenantId?: string): Promise<any>;
5
+ findAll(tenantId?: string): Promise<any>;
6
+ countAll(tenantId?: string): Promise<any>;
7
+ create(data: {
8
+ name: string;
9
+ description?: string | null;
10
+ provider?: string;
11
+ metadata?: Record<string, unknown>;
12
+ tenantId?: string;
13
+ }): Promise<unknown>;
14
+ update(id: string, data: Partial<{
15
+ name: string;
16
+ description: string | null;
17
+ provider: string;
18
+ status: string;
19
+ lastSeenAt: Date | string;
20
+ metadata: Record<string, unknown>;
21
+ }>, tenantId?: string): Promise<unknown>;
22
+ delete(id: string, tenantId?: string): Promise<void>;
23
+ heartbeat(id: string, tenantId?: string): Promise<void>;
24
+ };
25
+ //# sourceMappingURL=agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/queries/agents.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAK7C,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ;iBAElB,MAAM,aAAY,MAAM;qBAKpB,MAAM,aAAY,MAAM;uBAKvB,MAAM;wBAIL,MAAM;iBAKZ;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;eASgB,MAAM,QAAQ,OAAO,CAAC;QACrC,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC;QAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC,aAAY,MAAM;eAOH,MAAM,aAAY,MAAM;kBAIrB,MAAM,aAAY,MAAM;EAO/C"}
@@ -0,0 +1,46 @@
1
+ import { eq, and, count } from "drizzle-orm";
2
+ import { agents } from "../schema/index.js";
3
+ import { insertReturning, updateReturning } from "../helpers.js";
4
+ import { DEFAULT_TENANT_ID } from "@opentrust/shared";
5
+ export function agentQueries(db) {
6
+ return {
7
+ async findById(id, tenantId = DEFAULT_TENANT_ID) {
8
+ const result = await db.select().from(agents).where(and(eq(agents.id, id), eq(agents.tenantId, tenantId))).limit(1);
9
+ return result[0] ?? null;
10
+ },
11
+ async findByName(name, tenantId = DEFAULT_TENANT_ID) {
12
+ const result = await db.select().from(agents).where(and(eq(agents.name, name), eq(agents.tenantId, tenantId))).limit(1);
13
+ return result[0] ?? null;
14
+ },
15
+ async findAll(tenantId = DEFAULT_TENANT_ID) {
16
+ return db.select().from(agents).where(eq(agents.tenantId, tenantId)).orderBy(agents.createdAt);
17
+ },
18
+ async countAll(tenantId = DEFAULT_TENANT_ID) {
19
+ const result = await db.select({ count: count() }).from(agents).where(eq(agents.tenantId, tenantId));
20
+ return result[0]?.count ?? 0;
21
+ },
22
+ async create(data) {
23
+ return insertReturning(db, agents, {
24
+ ...data,
25
+ provider: data.provider ?? "custom",
26
+ metadata: data.metadata ?? {},
27
+ tenantId: data.tenantId ?? DEFAULT_TENANT_ID,
28
+ });
29
+ },
30
+ async update(id, data, tenantId = DEFAULT_TENANT_ID) {
31
+ return updateReturning(db, agents, and(eq(agents.id, id), eq(agents.tenantId, tenantId)), {
32
+ ...data,
33
+ updatedAt: new Date().toISOString(),
34
+ });
35
+ },
36
+ async delete(id, tenantId = DEFAULT_TENANT_ID) {
37
+ await db.delete(agents).where(and(eq(agents.id, id), eq(agents.tenantId, tenantId)));
38
+ },
39
+ async heartbeat(id, tenantId = DEFAULT_TENANT_ID) {
40
+ await db
41
+ .update(agents)
42
+ .set({ status: "active", lastSeenAt: new Date().toISOString(), updatedAt: new Date().toISOString() })
43
+ .where(and(eq(agents.id, id), eq(agents.tenantId, tenantId)));
44
+ },
45
+ };
46
+ }
@@ -0,0 +1,18 @@
1
+ import type { Database } from "../client.js";
2
+ import { magicLinks, userSessions } from "../schema/index.js";
3
+ export declare function authQueries(db: Database): {
4
+ createMagicLink(email: string, token: string, expiresAt: string): any;
5
+ /** Returns the magic link only if valid (not used, not expired) */
6
+ findValidMagicLink(token: string): typeof magicLinks.$inferSelect | undefined;
7
+ /** Fetch by token regardless of status (for validation logic in route) */
8
+ findMagicLink(token: string): typeof magicLinks.$inferSelect | undefined;
9
+ markMagicLinkUsed(id: string): any;
10
+ /** Delete expired and used magic links (housekeeping) */
11
+ pruneExpiredMagicLinks(): any;
12
+ createSession(email: string, token: string, expiresAt: string): any;
13
+ findSession(token: string): typeof userSessions.$inferSelect | undefined;
14
+ deleteSession(token: string): any;
15
+ /** Delete expired sessions (housekeeping) */
16
+ pruneExpiredSessions(): any;
17
+ };
18
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/queries/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ;2BAIb,MAAM,SAAS,MAAM,aAAa,MAAM;IAQ/D,mEAAmE;8BACzC,MAAM,GAalB,OAAO,UAAU,CAAC,YAAY,GAAG,SAAS;IAGxD,0EAA0E;yBACrD,MAAM,GAKb,OAAO,UAAU,CAAC,YAAY,GAAG,SAAS;0BAGlC,MAAM;IAQ5B,yDAAyD;;yBAWpC,MAAM,SAAS,MAAM,aAAa,MAAM;uBAQ1C,MAAM,GAKX,OAAO,YAAY,CAAC,YAAY,GAAG,SAAS;yBAGrC,MAAM;IAO3B,6CAA6C;;EAShD"}
@@ -0,0 +1,77 @@
1
+ import { eq, lt, and, isNull } from "drizzle-orm";
2
+ import { magicLinks, userSessions } from "../schema/index.js";
3
+ export function authQueries(db) {
4
+ return {
5
+ // ── Magic Links ──────────────────────────────────────────────
6
+ createMagicLink(email, token, expiresAt) {
7
+ return db
8
+ .insert(magicLinks)
9
+ .values({ email, token, expiresAt })
10
+ .returning()
11
+ .get();
12
+ },
13
+ /** Returns the magic link only if valid (not used, not expired) */
14
+ findValidMagicLink(token) {
15
+ const now = new Date().toISOString();
16
+ return db
17
+ .select()
18
+ .from(magicLinks)
19
+ .where(and(eq(magicLinks.token, token), isNull(magicLinks.usedAt),
20
+ // expiresAt > now (string comparison works for ISO 8601)
21
+ lt(magicLinks.createdAt, magicLinks.expiresAt)))
22
+ .get();
23
+ },
24
+ /** Fetch by token regardless of status (for validation logic in route) */
25
+ findMagicLink(token) {
26
+ return db
27
+ .select()
28
+ .from(magicLinks)
29
+ .where(eq(magicLinks.token, token))
30
+ .get();
31
+ },
32
+ markMagicLinkUsed(id) {
33
+ return db
34
+ .update(magicLinks)
35
+ .set({ usedAt: new Date().toISOString() })
36
+ .where(eq(magicLinks.id, id))
37
+ .run();
38
+ },
39
+ /** Delete expired and used magic links (housekeeping) */
40
+ pruneExpiredMagicLinks() {
41
+ const now = new Date().toISOString();
42
+ return db
43
+ .delete(magicLinks)
44
+ .where(lt(magicLinks.expiresAt, now))
45
+ .run();
46
+ },
47
+ // ── User Sessions ────────────────────────────────────────────
48
+ createSession(email, token, expiresAt) {
49
+ return db
50
+ .insert(userSessions)
51
+ .values({ email, token, expiresAt })
52
+ .returning()
53
+ .get();
54
+ },
55
+ findSession(token) {
56
+ return db
57
+ .select()
58
+ .from(userSessions)
59
+ .where(eq(userSessions.token, token))
60
+ .get();
61
+ },
62
+ deleteSession(token) {
63
+ return db
64
+ .delete(userSessions)
65
+ .where(eq(userSessions.token, token))
66
+ .run();
67
+ },
68
+ /** Delete expired sessions (housekeeping) */
69
+ pruneExpiredSessions() {
70
+ const now = new Date().toISOString();
71
+ return db
72
+ .delete(userSessions)
73
+ .where(lt(userSessions.expiresAt, now))
74
+ .run();
75
+ },
76
+ };
77
+ }
@@ -0,0 +1,24 @@
1
+ import type { Database } from "../client.js";
2
+ export declare function detectionResultQueries(db: Database): {
3
+ create(data: {
4
+ agentId?: string | null;
5
+ safe: boolean;
6
+ categories: string[];
7
+ sensitivityScore: number;
8
+ findings: unknown[];
9
+ latencyMs: number;
10
+ requestId: string;
11
+ tenantId?: string;
12
+ }): Promise<void>;
13
+ findAll(options?: {
14
+ limit?: number;
15
+ offset?: number;
16
+ tenantId?: string;
17
+ }): Promise<any>;
18
+ findByAgentId(agentId: string, options?: {
19
+ limit?: number;
20
+ offset?: number;
21
+ tenantId?: string;
22
+ }): Promise<any>;
23
+ };
24
+ //# sourceMappingURL=detection-results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detection-results.d.ts","sourceRoot":"","sources":["../../src/queries/detection-results.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ;iBAE5B;QACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,EAAE,OAAO,CAAC;QACd,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;sBAOuB;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;2BAiBjD,MAAM,YAAY;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;EAiBxG"}
@@ -0,0 +1,43 @@
1
+ import { eq, and, desc } from "drizzle-orm";
2
+ import { detectionResults } from "../schema/index.js";
3
+ import { DEFAULT_TENANT_ID } from "@opentrust/shared";
4
+ export function detectionResultQueries(db) {
5
+ return {
6
+ async create(data) {
7
+ await db.insert(detectionResults).values({
8
+ ...data,
9
+ tenantId: data.tenantId ?? DEFAULT_TENANT_ID,
10
+ });
11
+ },
12
+ async findAll(options) {
13
+ const tenantId = options?.tenantId ?? DEFAULT_TENANT_ID;
14
+ let query = db
15
+ .select()
16
+ .from(detectionResults)
17
+ .where(eq(detectionResults.tenantId, tenantId))
18
+ .orderBy(desc(detectionResults.createdAt));
19
+ if (options?.limit) {
20
+ query = query.limit(options.limit);
21
+ }
22
+ if (options?.offset) {
23
+ query = query.offset(options.offset);
24
+ }
25
+ return query;
26
+ },
27
+ async findByAgentId(agentId, options) {
28
+ const tenantId = options?.tenantId ?? DEFAULT_TENANT_ID;
29
+ let query = db
30
+ .select()
31
+ .from(detectionResults)
32
+ .where(and(eq(detectionResults.agentId, agentId), eq(detectionResults.tenantId, tenantId)))
33
+ .orderBy(desc(detectionResults.createdAt));
34
+ if (options?.limit) {
35
+ query = query.limit(options.limit);
36
+ }
37
+ if (options?.offset) {
38
+ query = query.offset(options.offset);
39
+ }
40
+ return query;
41
+ },
42
+ };
43
+ }
@@ -0,0 +1,58 @@
1
+ import type { Database } from "../client.js";
2
+ export declare function inferCategory(toolName: string): string;
3
+ export declare function inferAccessPattern(toolName: string): "read" | "write" | "admin" | "unknown";
4
+ export declare function observationQueries(db: Database): {
5
+ /**
6
+ * Record a tool call observation.
7
+ */
8
+ record(data: {
9
+ agentId: string;
10
+ sessionKey?: string;
11
+ toolName: string;
12
+ params?: Record<string, unknown>;
13
+ phase: "before" | "after";
14
+ result?: unknown;
15
+ error?: string;
16
+ durationMs?: number;
17
+ blocked?: boolean;
18
+ blockReason?: string;
19
+ tenantId?: string;
20
+ }): Promise<void>;
21
+ /**
22
+ * Upsert an agent permission entry based on observed tool call.
23
+ */
24
+ upsertPermission(data: {
25
+ agentId: string;
26
+ toolName: string;
27
+ category: string;
28
+ accessPattern: string;
29
+ params?: Record<string, unknown>;
30
+ hasError: boolean;
31
+ tenantId: string;
32
+ }): Promise<void>;
33
+ /**
34
+ * Get recent observations, optionally filtered by agentId.
35
+ */
36
+ findRecent(opts?: {
37
+ agentId?: string;
38
+ limit?: number;
39
+ tenantId?: string;
40
+ }): Promise<any>;
41
+ /**
42
+ * Get the aggregated permission profile for an agent.
43
+ */
44
+ getPermissions(agentId: string, tenantId?: string): Promise<any>;
45
+ /**
46
+ * Get permissions for all agents (overview).
47
+ */
48
+ getAllPermissions(tenantId?: string): Promise<any>;
49
+ /**
50
+ * Find first-seen tool calls (anomalies) — permissions with callCount = 1.
51
+ */
52
+ findAnomalies(tenantId?: string, limit?: number): Promise<any>;
53
+ /**
54
+ * Get observation count summary per agent.
55
+ */
56
+ summary(tenantId?: string): Promise<any>;
57
+ };
58
+ //# sourceMappingURL=observations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observations.d.ts","sourceRoot":"","sources":["../../src/queries/observations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAU7C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkBtD;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAiB3F;AAID,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ;IAE3C;;OAEG;iBACgB;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;QAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;IAmCD;;OAEG;2BAC0B;QAC3B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB;IAgDD;;OAEG;sBACoB;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;IAiBD;;OAEG;4BAC2B,MAAM,aAAY,MAAM;IAatD;;OAEG;iCAC+B,MAAM;IAQxC;;OAEG;6BAC2B,MAAM,UAA6B,MAAM;IAcvE;;OAEG;uBACqB,MAAM;EAajC"}