@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.
- package/LICENSE +9 -0
- package/README.md +21 -2
- package/dist/auth.d.ts +34 -0
- package/dist/auth.js +80 -0
- package/dist/auth.js.map +1 -0
- package/dist/d1.d.ts +1034 -0
- package/dist/d1.js +21 -0
- package/dist/d1.js.map +1 -0
- package/dist/dialects.d.ts +14 -0
- package/dist/dialects.js +66 -0
- package/dist/dialects.js.map +1 -0
- package/dist/documents.d.ts +87 -0
- package/dist/documents.js +45 -0
- package/dist/documents.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/postgres.d.ts +1925 -0
- package/dist/postgres.js +63 -0
- package/dist/postgres.js.map +1 -0
- package/dist/queries.d.ts +31 -0
- package/dist/queries.js +68 -0
- package/dist/queries.js.map +1 -0
- package/dist/schema/pg.d.ts +1892 -0
- package/dist/schema/pg.js +90 -0
- package/dist/schema/pg.js.map +1 -0
- package/dist/schema/sqlite.d.ts +2050 -0
- package/dist/schema/sqlite.js +90 -0
- package/dist/schema/sqlite.js.map +1 -0
- package/dist/sqlite.d.ts +25 -0
- package/dist/sqlite.js +64 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/store.d.ts +47 -0
- package/dist/store.js +149 -0
- package/dist/store.js.map +1 -0
- package/drizzle/0000_init.sql +66 -0
- package/drizzle/0001_idempotency.sql +12 -0
- package/drizzle/meta/0000_snapshot.json +452 -0
- package/drizzle/meta/0001_snapshot.json +527 -0
- package/drizzle/meta/_journal.json +20 -0
- package/drizzle/pg/0000_init.sql +78 -0
- package/drizzle/pg/meta/0000_snapshot.json +605 -0
- package/drizzle/pg/meta/_journal.json +13 -0
- 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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"}
|
package/dist/sqlite.d.ts
ADDED
|
@@ -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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"}
|
package/dist/store.d.ts
ADDED
|
@@ -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`);
|