@verdict-ai/db 0.0.0-stage → 0.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 (47) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +21 -2
  3. package/dist/auth.d.ts +34 -0
  4. package/dist/auth.js +80 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/d1.d.ts +1034 -0
  7. package/dist/d1.js +21 -0
  8. package/dist/d1.js.map +1 -0
  9. package/dist/dialects.d.ts +14 -0
  10. package/dist/dialects.js +66 -0
  11. package/dist/dialects.js.map +1 -0
  12. package/dist/documents.d.ts +87 -0
  13. package/dist/documents.js +45 -0
  14. package/dist/documents.js.map +1 -0
  15. package/dist/errors.d.ts +7 -0
  16. package/dist/errors.js +21 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/index.d.ts +9 -0
  19. package/dist/index.js +12 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/postgres.d.ts +1925 -0
  22. package/dist/postgres.js +63 -0
  23. package/dist/postgres.js.map +1 -0
  24. package/dist/queries.d.ts +31 -0
  25. package/dist/queries.js +68 -0
  26. package/dist/queries.js.map +1 -0
  27. package/dist/schema/pg.d.ts +1892 -0
  28. package/dist/schema/pg.js +90 -0
  29. package/dist/schema/pg.js.map +1 -0
  30. package/dist/schema/sqlite.d.ts +2050 -0
  31. package/dist/schema/sqlite.js +90 -0
  32. package/dist/schema/sqlite.js.map +1 -0
  33. package/dist/sqlite.d.ts +25 -0
  34. package/dist/sqlite.js +64 -0
  35. package/dist/sqlite.js.map +1 -0
  36. package/dist/store.d.ts +47 -0
  37. package/dist/store.js +149 -0
  38. package/dist/store.js.map +1 -0
  39. package/drizzle/0000_init.sql +66 -0
  40. package/drizzle/0001_idempotency.sql +12 -0
  41. package/drizzle/meta/0000_snapshot.json +452 -0
  42. package/drizzle/meta/0001_snapshot.json +527 -0
  43. package/drizzle/meta/_journal.json +20 -0
  44. package/drizzle/pg/0000_init.sql +78 -0
  45. package/drizzle/pg/meta/0000_snapshot.json +605 -0
  46. package/drizzle/pg/meta/_journal.json +13 -0
  47. package/package.json +81 -3
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Defines SQLite and D1 document tables and query indexes.
3
+ * JSON documents hold full domain state; dialect-compatible columns preserve shared persistence contracts.
4
+ */
5
+ /**
6
+ * Drizzle schema — SQLite dialect (Cloudflare D1 and local files; mirrored for Postgres in `pg.ts`).
7
+ *
8
+ * Design: documents (rubric / evaluation) are stored as JSON blobs — their shapes are owned by the zod schemas in
9
+ * @verdict-ai/core and evolve quickly. Columns exist only for what we query or report on: tenant, status, score, timestamps,
10
+ * and a denormalized `ratings` table for calibration / inter-rater analytics.
11
+ */
12
+ import { index, integer, real, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
13
+ export const rubrics = sqliteTable("rubrics", {
14
+ id: text("id").primaryKey(),
15
+ tenantId: text("tenant_id"),
16
+ name: text("name").notNull(),
17
+ version: text("version").notNull().default("1"),
18
+ /** Full StoredRubric JSON (zod-validated by core). */
19
+ doc: text("doc", { mode: "json" }).notNull().$type(),
20
+ createdAt: text("created_at").notNull(),
21
+ updatedAt: text("updated_at").notNull(),
22
+ }, (t) => [index("rubrics_tenant_created").on(t.tenantId, t.createdAt)]);
23
+ export const evaluations = sqliteTable("evaluations", {
24
+ id: text("id").primaryKey(),
25
+ tenantId: text("tenant_id"),
26
+ rubricId: text("rubric_id"),
27
+ rubricName: text("rubric_name").notNull(),
28
+ subjectName: text("subject_name"),
29
+ status: text("status").notNull(), // queued | running | pending_human | completed | failed
30
+ score: real("score"),
31
+ grade: text("grade"),
32
+ passed: integer("passed", { mode: "boolean" }),
33
+ pendingHuman: integer("pending_human").notNull().default(0),
34
+ decisionCalls: integer("decision_calls").notNull().default(0),
35
+ llmCalls: integer("llm_calls").notNull().default(0),
36
+ inputTokens: integer("input_tokens").notNull().default(0),
37
+ durationMs: integer("duration_ms").notNull().default(0),
38
+ /** Full Evaluation JSON (frozen rubric, evidence, criteria, ratings). */
39
+ doc: text("doc", { mode: "json" }).notNull().$type(),
40
+ createdAt: text("created_at").notNull(),
41
+ updatedAt: text("updated_at").notNull(),
42
+ }, (t) => [
43
+ index("evaluations_tenant_created").on(t.tenantId, t.createdAt),
44
+ index("evaluations_rubric_created").on(t.rubricId, t.createdAt),
45
+ index("evaluations_tenant_status").on(t.tenantId, t.status),
46
+ ]);
47
+ /** One row per rating — lets you ask "how do Jev's confidences track human agreement for rubric X" with plain SQL. */
48
+ export const ratings = sqliteTable("ratings", {
49
+ id: text("id").primaryKey(),
50
+ evaluationId: text("evaluation_id").notNull(),
51
+ tenantId: text("tenant_id"),
52
+ rubricId: text("rubric_id"),
53
+ criterionId: text("criterion_id").notNull(),
54
+ raterId: text("rater_id").notNull(),
55
+ judgeType: text("judge_type").notNull(), // decision | llm | human | benchmark | panel
56
+ status: text("status").notNull(), // scored | pending | error
57
+ score: real("score"),
58
+ normalized: real("normalized"),
59
+ confidence: real("confidence"),
60
+ model: text("model"),
61
+ createdAt: text("created_at").notNull(),
62
+ }, (t) => [
63
+ index("ratings_evaluation").on(t.evaluationId),
64
+ index("ratings_rubric_criterion").on(t.rubricId, t.criterionId),
65
+ index("ratings_tenant_judge").on(t.tenantId, t.judgeType),
66
+ ]);
67
+ export const apiKeys = sqliteTable("api_keys", {
68
+ id: text("id").primaryKey(),
69
+ tenantId: text("tenant_id").notNull(),
70
+ name: text("name").notNull(),
71
+ /** sha256(hex) of the plaintext key; the plaintext is shown once at creation. */
72
+ keyHash: text("key_hash").notNull(),
73
+ /** First 8 chars of the key, for display (`vk_live_ab12…`). */
74
+ prefix: text("prefix").notNull(),
75
+ createdAt: text("created_at").notNull(),
76
+ lastUsedAt: text("last_used_at"),
77
+ revokedAt: text("revoked_at"),
78
+ }, (t) => [uniqueIndex("api_keys_hash").on(t.keyHash), index("api_keys_tenant").on(t.tenantId)]);
79
+ export const idempotencyKeys = sqliteTable("idempotency_keys", {
80
+ tenantId: text("tenant_id"),
81
+ key: text("key").notNull(),
82
+ fingerprint: text("fingerprint").notNull(),
83
+ targetType: text("target_type").notNull().$type(),
84
+ targetId: text("target_id"),
85
+ targetIds: text("target_ids", { mode: "json" }).$type(),
86
+ createdAt: text("created_at").notNull(),
87
+ expiresAt: text("expires_at").notNull(),
88
+ }, t => [uniqueIndex("idempotency_keys_tenant_key").on(t.tenantId, t.key)]);
89
+ export const schema = { rubrics, evaluations, ratings, apiKeys, idempotencyKeys };
90
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/schema/sqlite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type BetterSqlite3 from "better-sqlite3";
2
+ import { DrizzleStore, type SqliteDb } from "./store.js";
3
+ import { DrizzleAuth, type KeyAuth } from "./auth.js";
4
+ /**
5
+ * Node: a local SQLite file (or ":memory:") through better-sqlite3 — same schema and migrations as D1.
6
+ * better-sqlite3 is an optional dependency; it is imported lazily so Workers bundles never see it.
7
+ */
8
+ export interface SqliteHandle {
9
+ db: SqliteDb;
10
+ sqlite: BetterSqlite3.Database;
11
+ store: DrizzleStore;
12
+ auth: DrizzleAuth;
13
+ }
14
+ /** Opens and migrates SQLite; rejects unavailable drivers, inaccessible paths or migration failures. */
15
+ export declare function fromSqliteFile(path: string, fallbackAuth?: KeyAuth, loadDriver?: () => Promise<{
16
+ default: typeof BetterSqlite3;
17
+ }>): Promise<SqliteHandle>;
18
+ /** Minimal surface shared by every Drizzle SQLite driver (sync or async). */
19
+ interface MigratableDb {
20
+ run(query: unknown): unknown;
21
+ all(query: unknown): unknown;
22
+ }
23
+ /** Apply the drizzle-kit generated SQL files in order, tracked in `__migrations`. D1 uses `wrangler d1 migrations apply` instead. */
24
+ export declare function applyMigrations(db: MigratableDb, dir?: string): Promise<void>;
25
+ export {};
package/dist/sqlite.js ADDED
@@ -0,0 +1,64 @@
1
+ import { StoreError, storeOperation } from "./errors.js";
2
+ /**
3
+ * Opens local SQLite storage and applies generated migrations in order.
4
+ * The optional native driver loads only in Node; migration tracking prevents replaying applied SQL.
5
+ */
6
+ import { FileAccessError } from "@verdict-ai/core";
7
+ import { readdir, readFile } from "node:fs/promises";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { schema } from "./schema/sqlite.js";
11
+ import { DrizzleStore } from "./store.js";
12
+ import { DrizzleAuth } from "./auth.js";
13
+ /** Opens and migrates SQLite; rejects unavailable drivers, inaccessible paths or migration failures. */
14
+ export async function fromSqliteFile(path, fallbackAuth, loadDriver = () => import("better-sqlite3")) {
15
+ const { default: Database } = await loadDriver();
16
+ const { drizzle } = await import("drizzle-orm/better-sqlite3");
17
+ const sqlite = openSqlite(Database, path);
18
+ try {
19
+ // why: WAL lets readers continue while the local evaluation store writes.
20
+ sqlite.pragma("journal_mode = WAL");
21
+ const db = drizzle(sqlite, { schema });
22
+ await applyMigrations(db);
23
+ return { db, sqlite, store: new DrizzleStore(db), auth: new DrizzleAuth(db, fallbackAuth) };
24
+ }
25
+ catch (cause) {
26
+ sqlite.close();
27
+ throw new StoreError(`initialize SQLite ${path}`, cause);
28
+ }
29
+ }
30
+ /** Apply the drizzle-kit generated SQL files in order, tracked in `__migrations`. D1 uses `wrangler d1 migrations apply` instead. */
31
+ export async function applyMigrations(db, dir = defaultMigrationsDir()) {
32
+ return storeOperation("applyMigrations", async () => {
33
+ const { sql } = await import("drizzle-orm");
34
+ await db.run(sql `create table if not exists __migrations (name text primary key, applied_at text not null)`);
35
+ const applied = new Set((await db.all(sql `select name from __migrations`)).map((r) => r.name));
36
+ const files = (await readdir(dir)).filter((f) => f.endsWith(".sql")).sort();
37
+ for (const f of files) {
38
+ // why: generated file order is migration order; the ledger prevents applying committed migrations twice.
39
+ if (applied.has(f))
40
+ continue;
41
+ const text = await readFile(join(dir, f), "utf8");
42
+ for (const stmt of text.split("--> statement-breakpoint")) {
43
+ const s = stmt.trim();
44
+ if (s)
45
+ await db.run(sql.raw(s));
46
+ }
47
+ await db.run(sql `insert into __migrations (name, applied_at) values (${f}, ${new Date().toISOString()})`);
48
+ }
49
+ });
50
+ }
51
+ /** Returns the generated SQLite migration directory relative to this module; performs no I/O. */
52
+ function defaultMigrationsDir() {
53
+ return join(dirname(fileURLToPath(import.meta.url)), "..", "drizzle");
54
+ }
55
+ // Release belongs to the factory only after opening succeeds; failed migrations must not leak native handles.
56
+ function openSqlite(Database, path) {
57
+ try {
58
+ return new Database(path);
59
+ }
60
+ catch (cause) {
61
+ throw new FileAccessError(path, "open SQLite database", cause);
62
+ }
63
+ }
64
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { DocumentQueries } from "./queries.js";
2
+ import { type SQL } from "drizzle-orm";
3
+ import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
4
+ import type { IdempotencyRecord, Evaluation, ListOptions, Store, StoredRubric } from "@verdict-ai/core";
5
+ import { type Schema } from "./schema/sqlite.js";
6
+ import { type Dialect, type PgDb } from "./dialects.js";
7
+ /** D1, better-sqlite3 and libsql share this SQLite driver contract. */
8
+ export type SqliteDb = BaseSQLiteDatabase<"async" | "sync", unknown, Schema>;
9
+ /**
10
+ * Store implementation on Drizzle. Documents live in `doc` JSON columns; indexed columns are derived on write so
11
+ * listings and analytics never parse blobs. Tenant scoping is enforced in every read.
12
+ */
13
+ export declare class DrizzleStore implements Store {
14
+ private queries;
15
+ private reserve;
16
+ constructor(db: SqliteDb | DocumentQueries, atomicBatch?: (statements: SQL[]) => Promise<void>, dialect?: Dialect, reserve?: (record: IdempotencyRecord, initial: Evaluation[]) => Promise<void>);
17
+ reserveIdempotency(r: IdempotencyRecord, initial: Evaluation[]): Promise<boolean>;
18
+ putIdempotency(r: IdempotencyRecord): Promise<void>;
19
+ getIdempotency(tenantId: string | undefined, key: string): Promise<IdempotencyRecord | undefined>;
20
+ putRubric(r: StoredRubric): Promise<void>;
21
+ getRubric(id: string, tenantId?: string): Promise<StoredRubric | undefined>;
22
+ listRubrics(o?: ListOptions): Promise<StoredRubric[]>;
23
+ deleteRubric(id: string, tenantId?: string): Promise<boolean>;
24
+ putEvaluation(e: Evaluation): Promise<void>;
25
+ getEvaluation(id: string, tenantId?: string): Promise<Evaluation | undefined>;
26
+ listEvaluations(o?: ListOptions): Promise<Evaluation[]>;
27
+ /** Per-criterion rating rows for a rubric (feeds calibration: confidence vs. human agreement). */
28
+ ratingsForRubric(rubricId: string, tenantId?: string, judgeTypes?: string[]): Promise<{
29
+ id: string;
30
+ tenantId: string | null;
31
+ createdAt: string;
32
+ rubricId: string | null;
33
+ status: string;
34
+ score: number | null;
35
+ evaluationId: string;
36
+ criterionId: string;
37
+ raterId: string;
38
+ judgeType: string;
39
+ normalized: number | null;
40
+ confidence: number | null;
41
+ model: string | null;
42
+ }[]>;
43
+ }
44
+ /** Postgres facade over the shared document and rating logic. */
45
+ export declare class PgStore extends DrizzleStore {
46
+ constructor(db: PgDb);
47
+ }
package/dist/store.js ADDED
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Every read respects tenant scope; D1 parameter limits require chunked rating writes.
3
+ */
4
+ import { storeOperation } from "./errors.js";
5
+ import { DocumentQueries, sqliteQueries, postgresQueries } from "./queries.js";
6
+ import { readDocument, evaluationRow, ratingRows } from "./documents.js";
7
+ import { and, desc, eq, inArray } from "drizzle-orm";
8
+ import { sqliteDialect, pgDialect } from "./dialects.js";
9
+ // why: rating projections bind many columns; chunking stays below D1's per-statement parameter budget.
10
+ const RATING_INSERT_CHUNK_SIZE = 50;
11
+ /**
12
+ * Store implementation on Drizzle. Documents live in `doc` JSON columns; indexed columns are derived on write so
13
+ * listings and analytics never parse blobs. Tenant scoping is enforced in every read.
14
+ */
15
+ export class DrizzleStore {
16
+ queries;
17
+ reserve;
18
+ constructor(db, atomicBatch, dialect = sqliteDialect, reserve) {
19
+ this.queries = db instanceof DocumentQueries ? db : sqliteQueries(db, dialect.tables);
20
+ if (db instanceof DocumentQueries) {
21
+ if (!reserve)
22
+ throw new TypeError("document query adapters require a reservation function");
23
+ this.reserve = reserve;
24
+ }
25
+ else {
26
+ this.reserve = (record, initial) => dialect.reserve(db, record, initial, atomicBatch);
27
+ }
28
+ }
29
+ async reserveIdempotency(r, initial) {
30
+ return storeOperation(`reserveIdempotency:${r.key}`, async () => {
31
+ const existing = await this.getIdempotency(r.tenantId, r.key);
32
+ if (existing && existing.expiresAt > r.createdAt) {
33
+ const ids = existing.targetType === "batch" ? existing.evaluationIds ?? [] : [existing.targetId];
34
+ const targets = await Promise.all(ids.map(id => this.getEvaluation(id, r.tenantId)));
35
+ if (targets.every(Boolean))
36
+ return false;
37
+ }
38
+ await this.reserve(r, initial);
39
+ const record = await this.getIdempotency(r.tenantId, r.key);
40
+ return record?.targetId === r.targetId && JSON.stringify(record?.evaluationIds) === JSON.stringify(r.evaluationIds);
41
+ });
42
+ }
43
+ async putIdempotency(r) {
44
+ return storeOperation(`putIdempotency:${r.key}`, async () => {
45
+ const row = {
46
+ tenantId: r.tenantId ?? "", key: r.key, fingerprint: r.fingerprint, targetType: r.targetType,
47
+ targetId: r.targetId ?? null, targetIds: r.evaluationIds ?? null, createdAt: r.createdAt, expiresAt: r.expiresAt
48
+ };
49
+ await this.queries.insert("idempotencyKeys", [row], { keys: ["tenantId", "key"], set: row });
50
+ });
51
+ }
52
+ async getIdempotency(tenantId, key) {
53
+ return storeOperation(`getIdempotency:${key}`, async () => {
54
+ const { idempotencyKeys } = this.queries.tables;
55
+ const [row] = await this.queries.select("idempotencyKeys", { where: and(eq(idempotencyKeys.tenantId, tenantId ?? ""), eq(idempotencyKeys.key, key)), limit: 1 });
56
+ return row ? {
57
+ tenantId: row.tenantId || undefined, key: row.key, fingerprint: row.fingerprint, targetType: row.targetType,
58
+ targetId: row.targetId ?? undefined, evaluationIds: row.targetIds ?? undefined, createdAt: row.createdAt, expiresAt: row.expiresAt
59
+ } : undefined;
60
+ });
61
+ }
62
+ /* ---------------- rubrics ---------------- */
63
+ async putRubric(r) {
64
+ return storeOperation(`putRubric:${r.id}`, async () => {
65
+ const row = { id: r.id, tenantId: r.tenantId ?? null, name: r.name, version: r.version, doc: { ...r }, createdAt: r.createdAt, updatedAt: r.updatedAt };
66
+ await this.queries.insert("rubrics", [row], { keys: ["id"], set: { tenantId: row.tenantId, name: row.name, version: row.version, doc: row.doc, updatedAt: row.updatedAt } });
67
+ });
68
+ }
69
+ async getRubric(id, tenantId) {
70
+ return storeOperation(`getRubric:${id}`, async () => {
71
+ const { rubrics } = this.queries.tables;
72
+ const rows = await this.queries.select("rubrics", { where: eq(rubrics.id, id), limit: 1 });
73
+ const row = rows[0];
74
+ if (!row || (tenantId !== undefined && row.tenantId !== tenantId))
75
+ return undefined;
76
+ return readDocument(row.doc);
77
+ });
78
+ }
79
+ async listRubrics(o = {}) {
80
+ return storeOperation("listRubrics", async () => {
81
+ const { rubrics } = this.queries.tables;
82
+ const where = o.tenantId === undefined ? undefined : eq(rubrics.tenantId, o.tenantId);
83
+ const rows = await this.queries.select("rubrics", { where, orderBy: desc(rubrics.createdAt), limit: o.limit ?? 100 });
84
+ return rows.map((r) => readDocument(r.doc));
85
+ });
86
+ }
87
+ async deleteRubric(id, tenantId) {
88
+ return storeOperation(`deleteRubric:${id}`, async () => {
89
+ const { rubrics } = this.queries.tables;
90
+ if (!(await this.getRubric(id, tenantId)))
91
+ return false;
92
+ await this.queries.delete("rubrics", eq(rubrics.id, id));
93
+ return true;
94
+ });
95
+ }
96
+ /* ---------------- evaluations ---------------- */
97
+ async putEvaluation(e) {
98
+ return storeOperation(`putEvaluation:${e.id}`, async () => {
99
+ const { ratings } = this.queries.tables;
100
+ const row = evaluationRow(e);
101
+ const { id: _id, createdAt: _c, ...set } = row;
102
+ await this.queries.insert("evaluations", [row], { keys: ["id"], set });
103
+ // Denormalized ratings: replace the evaluation's rows (ratings change when humans submit).
104
+ await this.queries.delete("ratings", eq(ratings.evaluationId, e.id));
105
+ const rows = ratingRows(e);
106
+ // D1 caps bound parameters per statement; insert in modest chunks.
107
+ for (let i = 0; i < rows.length; i += RATING_INSERT_CHUNK_SIZE)
108
+ await this.queries.insert("ratings", rows.slice(i, i + RATING_INSERT_CHUNK_SIZE));
109
+ });
110
+ }
111
+ async getEvaluation(id, tenantId) {
112
+ return storeOperation(`getEvaluation:${id}`, async () => {
113
+ const { evaluations } = this.queries.tables;
114
+ const rows = await this.queries.select("evaluations", { where: eq(evaluations.id, id), limit: 1 });
115
+ const row = rows[0];
116
+ if (!row || (tenantId !== undefined && row.tenantId !== tenantId))
117
+ return undefined;
118
+ return readDocument(row.doc);
119
+ });
120
+ }
121
+ async listEvaluations(o = {}) {
122
+ return storeOperation("listEvaluations", async () => {
123
+ const { evaluations } = this.queries.tables;
124
+ const conds = [
125
+ o.tenantId === undefined ? undefined : eq(evaluations.tenantId, o.tenantId),
126
+ o.rubricId ? eq(evaluations.rubricId, o.rubricId) : undefined,
127
+ o.status ? eq(evaluations.status, o.status) : undefined,
128
+ ].filter((c) => !!c);
129
+ const rows = await this.queries.select("evaluations", { where: and(...conds), orderBy: desc(evaluations.createdAt), limit: o.limit ?? 100 });
130
+ return rows.map((r) => readDocument(r.doc));
131
+ });
132
+ }
133
+ /* ---------------- analytics helpers ---------------- */
134
+ /** Per-criterion rating rows for a rubric (feeds calibration: confidence vs. human agreement). */
135
+ async ratingsForRubric(rubricId, tenantId, judgeTypes) {
136
+ return storeOperation(`ratingsForRubric:${rubricId}`, async () => {
137
+ const { ratings } = this.queries.tables;
138
+ const conds = [eq(ratings.rubricId, rubricId), tenantId === undefined ? undefined : eq(ratings.tenantId, tenantId), judgeTypes?.length ? inArray(ratings.judgeType, judgeTypes) : undefined].filter((c) => !!c);
139
+ return this.queries.select("ratings", { where: and(...conds) });
140
+ });
141
+ }
142
+ }
143
+ /** Postgres facade over the shared document and rating logic. */
144
+ export class PgStore extends DrizzleStore {
145
+ constructor(db) {
146
+ super(postgresQueries(db, pgDialect.tables), undefined, undefined, (record, initial) => pgDialect.reserve(db, record, initial));
147
+ }
148
+ }
149
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ CREATE TABLE `api_keys` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `tenant_id` text NOT NULL,
4
+ `name` text NOT NULL,
5
+ `key_hash` text NOT NULL,
6
+ `prefix` text NOT NULL,
7
+ `created_at` text NOT NULL,
8
+ `last_used_at` text,
9
+ `revoked_at` text
10
+ );
11
+ --> statement-breakpoint
12
+ CREATE UNIQUE INDEX `api_keys_hash` ON `api_keys` (`key_hash`);--> statement-breakpoint
13
+ CREATE INDEX `api_keys_tenant` ON `api_keys` (`tenant_id`);--> statement-breakpoint
14
+ CREATE TABLE `evaluations` (
15
+ `id` text PRIMARY KEY NOT NULL,
16
+ `tenant_id` text,
17
+ `rubric_id` text,
18
+ `rubric_name` text NOT NULL,
19
+ `subject_name` text,
20
+ `status` text NOT NULL,
21
+ `score` real,
22
+ `grade` text,
23
+ `passed` integer,
24
+ `pending_human` integer DEFAULT 0 NOT NULL,
25
+ `decision_calls` integer DEFAULT 0 NOT NULL,
26
+ `llm_calls` integer DEFAULT 0 NOT NULL,
27
+ `input_tokens` integer DEFAULT 0 NOT NULL,
28
+ `duration_ms` integer DEFAULT 0 NOT NULL,
29
+ `doc` text NOT NULL,
30
+ `created_at` text NOT NULL,
31
+ `updated_at` text NOT NULL
32
+ );
33
+ --> statement-breakpoint
34
+ CREATE INDEX `evaluations_tenant_created` ON `evaluations` (`tenant_id`,`created_at`);--> statement-breakpoint
35
+ CREATE INDEX `evaluations_rubric_created` ON `evaluations` (`rubric_id`,`created_at`);--> statement-breakpoint
36
+ CREATE INDEX `evaluations_tenant_status` ON `evaluations` (`tenant_id`,`status`);--> statement-breakpoint
37
+ CREATE TABLE `ratings` (
38
+ `id` text PRIMARY KEY NOT NULL,
39
+ `evaluation_id` text NOT NULL,
40
+ `tenant_id` text,
41
+ `rubric_id` text,
42
+ `criterion_id` text NOT NULL,
43
+ `rater_id` text NOT NULL,
44
+ `judge_type` text NOT NULL,
45
+ `status` text NOT NULL,
46
+ `score` real,
47
+ `normalized` real,
48
+ `confidence` real,
49
+ `model` text,
50
+ `created_at` text NOT NULL
51
+ );
52
+ --> statement-breakpoint
53
+ CREATE INDEX `ratings_evaluation` ON `ratings` (`evaluation_id`);--> statement-breakpoint
54
+ CREATE INDEX `ratings_rubric_criterion` ON `ratings` (`rubric_id`,`criterion_id`);--> statement-breakpoint
55
+ CREATE INDEX `ratings_tenant_judge` ON `ratings` (`tenant_id`,`judge_type`);--> statement-breakpoint
56
+ CREATE TABLE `rubrics` (
57
+ `id` text PRIMARY KEY NOT NULL,
58
+ `tenant_id` text,
59
+ `name` text NOT NULL,
60
+ `version` text DEFAULT '1' NOT NULL,
61
+ `doc` text NOT NULL,
62
+ `created_at` text NOT NULL,
63
+ `updated_at` text NOT NULL
64
+ );
65
+ --> statement-breakpoint
66
+ CREATE INDEX `rubrics_tenant_created` ON `rubrics` (`tenant_id`,`created_at`);
@@ -0,0 +1,12 @@
1
+ CREATE TABLE `idempotency_keys` (
2
+ `tenant_id` text,
3
+ `key` text NOT NULL,
4
+ `fingerprint` text NOT NULL,
5
+ `target_type` text NOT NULL,
6
+ `target_id` text,
7
+ `target_ids` text,
8
+ `created_at` text NOT NULL,
9
+ `expires_at` text NOT NULL
10
+ );
11
+ --> statement-breakpoint
12
+ CREATE UNIQUE INDEX `idempotency_keys_tenant_key` ON `idempotency_keys` (`tenant_id`,`key`);