@data-club/ai-hub-server 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/argon2.d.ts +72 -0
- package/dist/auth/argon2.d.ts.map +1 -0
- package/dist/auth/argon2.js +145 -0
- package/dist/auth/argon2.js.map +1 -0
- package/dist/auth/encryption.d.ts +52 -0
- package/dist/auth/encryption.d.ts.map +1 -0
- package/dist/auth/encryption.js +98 -0
- package/dist/auth/encryption.js.map +1 -0
- package/dist/auth/jwt.d.ts +133 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +147 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/middleware.d.ts +101 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +161 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/passwordPolicy.d.ts +72 -0
- package/dist/auth/passwordPolicy.d.ts.map +1 -0
- package/dist/auth/passwordPolicy.js +88 -0
- package/dist/auth/passwordPolicy.js.map +1 -0
- package/dist/auth/roleRules.d.ts +200 -0
- package/dist/auth/roleRules.d.ts.map +1 -0
- package/dist/auth/roleRules.js +365 -0
- package/dist/auth/roleRules.js.map +1 -0
- package/dist/auth/userView.d.ts +55 -0
- package/dist/auth/userView.d.ts.map +1 -0
- package/dist/auth/userView.js +77 -0
- package/dist/auth/userView.js.map +1 -0
- package/dist/bootstrap.d.ts +104 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +160 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/db/connection.d.ts +39 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +62 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrate.d.ts +31 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +197 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +1902 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +662 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/seed.d.ts +92 -0
- package/dist/db/seed.d.ts.map +1 -0
- package/dist/db/seed.js +160 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/handlers/fetch.d.ts +89 -0
- package/dist/handlers/fetch.d.ts.map +1 -0
- package/dist/handlers/fetch.js +173 -0
- package/dist/handlers/fetch.js.map +1 -0
- package/dist/handlers/nextjs.d.ts +40 -0
- package/dist/handlers/nextjs.d.ts.map +1 -0
- package/dist/handlers/nextjs.js +42 -0
- package/dist/handlers/nextjs.js.map +1 -0
- package/dist/handlers/responses.d.ts +46 -0
- package/dist/handlers/responses.d.ts.map +1 -0
- package/dist/handlers/responses.js +74 -0
- package/dist/handlers/responses.js.map +1 -0
- package/dist/handlers/routeTable.d.ts +21 -0
- package/dist/handlers/routeTable.d.ts.map +1 -0
- package/dist/handlers/routeTable.js +133 -0
- package/dist/handlers/routeTable.js.map +1 -0
- package/dist/handlers/router.d.ts +37 -0
- package/dist/handlers/router.d.ts.map +1 -0
- package/dist/handlers/router.js +82 -0
- package/dist/handlers/router.js.map +1 -0
- package/dist/handlers/sse.d.ts +38 -0
- package/dist/handlers/sse.d.ts.map +1 -0
- package/dist/handlers/sse.js +52 -0
- package/dist/handlers/sse.js.map +1 -0
- package/dist/handlers/types.d.ts +96 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/types.js +14 -0
- package/dist/handlers/types.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/letta/client.d.ts +355 -0
- package/dist/letta/client.d.ts.map +1 -0
- package/dist/letta/client.js +529 -0
- package/dist/letta/client.js.map +1 -0
- package/dist/letta/eventTranslator.d.ts +166 -0
- package/dist/letta/eventTranslator.d.ts.map +1 -0
- package/dist/letta/eventTranslator.js +532 -0
- package/dist/letta/eventTranslator.js.map +1 -0
- package/dist/letta/index.d.ts +13 -0
- package/dist/letta/index.d.ts.map +1 -0
- package/dist/letta/index.js +12 -0
- package/dist/letta/index.js.map +1 -0
- package/dist/letta/modelSettings.d.ts +176 -0
- package/dist/letta/modelSettings.d.ts.map +1 -0
- package/dist/letta/modelSettings.js +314 -0
- package/dist/letta/modelSettings.js.map +1 -0
- package/dist/letta/promptWrapping.d.ts +141 -0
- package/dist/letta/promptWrapping.d.ts.map +1 -0
- package/dist/letta/promptWrapping.js +213 -0
- package/dist/letta/promptWrapping.js.map +1 -0
- package/dist/letta/sandbox.d.ts +100 -0
- package/dist/letta/sandbox.d.ts.map +1 -0
- package/dist/letta/sandbox.js +151 -0
- package/dist/letta/sandbox.js.map +1 -0
- package/dist/letta/settingsFileSeed.d.ts +146 -0
- package/dist/letta/settingsFileSeed.d.ts.map +1 -0
- package/dist/letta/settingsFileSeed.js +177 -0
- package/dist/letta/settingsFileSeed.js.map +1 -0
- package/dist/letta/subprocessThrottle.d.ts +151 -0
- package/dist/letta/subprocessThrottle.d.ts.map +1 -0
- package/dist/letta/subprocessThrottle.js +195 -0
- package/dist/letta/subprocessThrottle.js.map +1 -0
- package/dist/letta/tpmRecovery.d.ts +202 -0
- package/dist/letta/tpmRecovery.d.ts.map +1 -0
- package/dist/letta/tpmRecovery.js +314 -0
- package/dist/letta/tpmRecovery.js.map +1 -0
- package/dist/letta/types.d.ts +54 -0
- package/dist/letta/types.d.ts.map +1 -0
- package/dist/letta/types.js +16 -0
- package/dist/letta/types.js.map +1 -0
- package/dist/observability/logger.d.ts +48 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +81 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +53 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +92 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/routes/admin/agents.d.ts +63 -0
- package/dist/routes/admin/agents.d.ts.map +1 -0
- package/dist/routes/admin/agents.js +461 -0
- package/dist/routes/admin/agents.js.map +1 -0
- package/dist/routes/admin/rotatingMessages.d.ts +51 -0
- package/dist/routes/admin/rotatingMessages.d.ts.map +1 -0
- package/dist/routes/admin/rotatingMessages.js +292 -0
- package/dist/routes/admin/rotatingMessages.js.map +1 -0
- package/dist/routes/admin/sessions.d.ts +61 -0
- package/dist/routes/admin/sessions.d.ts.map +1 -0
- package/dist/routes/admin/sessions.js +232 -0
- package/dist/routes/admin/sessions.js.map +1 -0
- package/dist/routes/admin/settings.d.ts +110 -0
- package/dist/routes/admin/settings.d.ts.map +1 -0
- package/dist/routes/admin/settings.js +401 -0
- package/dist/routes/admin/settings.js.map +1 -0
- package/dist/routes/admin/users.d.ts +115 -0
- package/dist/routes/admin/users.d.ts.map +1 -0
- package/dist/routes/admin/users.js +374 -0
- package/dist/routes/admin/users.js.map +1 -0
- package/dist/routes/agents.d.ts +30 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +55 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/auth.d.ts +121 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +422 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/chat.d.ts +97 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +484 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/featureToggles.d.ts +34 -0
- package/dist/routes/featureToggles.d.ts.map +1 -0
- package/dist/routes/featureToggles.js +47 -0
- package/dist/routes/featureToggles.js.map +1 -0
- package/dist/routes/health.d.ts +24 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +37 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/metrics.d.ts +35 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +106 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/sessions.d.ts +161 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +1501 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stubs.d.ts +25 -0
- package/dist/routes/stubs.d.ts.map +1 -0
- package/dist/routes/stubs.js +25 -0
- package/dist/routes/stubs.js.map +1 -0
- package/dist/state/cron.d.ts +58 -0
- package/dist/state/cron.d.ts.map +1 -0
- package/dist/state/cron.js +160 -0
- package/dist/state/cron.js.map +1 -0
- package/dist/state/rotationRunner.d.ts +96 -0
- package/dist/state/rotationRunner.d.ts.map +1 -0
- package/dist/state/rotationRunner.js +246 -0
- package/dist/state/rotationRunner.js.map +1 -0
- package/dist/state/rotationScheduler.d.ts +76 -0
- package/dist/state/rotationScheduler.d.ts.map +1 -0
- package/dist/state/rotationScheduler.js +124 -0
- package/dist/state/rotationScheduler.js.map +1 -0
- package/dist/state/turnRegistry.d.ts +95 -0
- package/dist/state/turnRegistry.d.ts.map +1 -0
- package/dist/state/turnRegistry.js +149 -0
- package/dist/state/turnRegistry.js.map +1 -0
- package/dist/state/turnRunner.d.ts +134 -0
- package/dist/state/turnRunner.d.ts.map +1 -0
- package/dist/state/turnRunner.js +476 -0
- package/dist/state/turnRunner.js.map +1 -0
- package/package.json +47 -0
- package/src/auth/argon2.ts +152 -0
- package/src/auth/encryption.ts +110 -0
- package/src/auth/jwt.ts +217 -0
- package/src/auth/middleware.ts +250 -0
- package/src/auth/passwordPolicy.ts +99 -0
- package/src/auth/roleRules.ts +497 -0
- package/src/auth/userView.ts +88 -0
- package/src/bootstrap.ts +254 -0
- package/src/db/connection.ts +75 -0
- package/src/db/migrate.ts +212 -0
- package/src/db/schema.ts +750 -0
- package/src/db/seed.ts +236 -0
- package/src/handlers/fetch.ts +251 -0
- package/src/handlers/nextjs.ts +49 -0
- package/src/handlers/responses.ts +95 -0
- package/src/handlers/routeTable.ts +188 -0
- package/src/handlers/router.ts +96 -0
- package/src/handlers/sse.ts +55 -0
- package/src/handlers/types.ts +104 -0
- package/src/index.ts +60 -0
- package/src/letta/client.ts +860 -0
- package/src/letta/eventTranslator.ts +667 -0
- package/src/letta/index.ts +46 -0
- package/src/letta/lettaCliShim.mjs +40 -0
- package/src/letta/sandbox.ts +167 -0
- package/src/letta/settingsFileSeed.ts +254 -0
- package/src/letta/subprocessThrottle.ts +251 -0
- package/src/letta/types.ts +65 -0
- package/src/observability/logger.ts +103 -0
- package/src/observability/metrics.ts +114 -0
- package/src/routes/admin/agents.ts +574 -0
- package/src/routes/admin/rotatingMessages.ts +351 -0
- package/src/routes/admin/sessions.ts +283 -0
- package/src/routes/admin/settings.ts +463 -0
- package/src/routes/admin/users.ts +455 -0
- package/src/routes/agents.ts +66 -0
- package/src/routes/auth.ts +513 -0
- package/src/routes/chat.ts +534 -0
- package/src/routes/featureToggles.ts +52 -0
- package/src/routes/health.ts +44 -0
- package/src/routes/metrics.ts +111 -0
- package/src/routes/sessions.ts +1878 -0
- package/src/state/cron.ts +179 -0
- package/src/state/rotationRunner.ts +326 -0
- package/src/state/rotationScheduler.ts +164 -0
- package/src/state/turnRegistry.ts +210 -0
- package/src/state/turnRunner.ts +588 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot orchestration: env → open DB → migrate → seed → ready.
|
|
3
|
+
*
|
|
4
|
+
* The pieces that compose this (env loader, `openDb`, `runMigrations`,
|
|
5
|
+
* `runFirstBootSeed`, `createLogger`) are independently importable so tests
|
|
6
|
+
* and embedders can wire bespoke combinations. `bootServer` is the
|
|
7
|
+
* convenience entry point the `dev/server.ts` runner and the per-customer
|
|
8
|
+
* wrapper's Next.js mount call.
|
|
9
|
+
*
|
|
10
|
+
* @see SPECIFICATIONS.md §12.1 — env vars
|
|
11
|
+
* @see SPECIFICATIONS.md §6.7 — signing key bootstrap
|
|
12
|
+
* @see SPECIFICATIONS.md §6.10 — metrics token bootstrap
|
|
13
|
+
*/
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { parseEncryptionKey } from "./auth/encryption.js";
|
|
16
|
+
import { openDb } from "./db/connection.js";
|
|
17
|
+
import { runMigrations } from "./db/migrate.js";
|
|
18
|
+
import { runFirstBootSeed } from "./db/seed.js";
|
|
19
|
+
import { createFetchHandler } from "./handlers/fetch.js";
|
|
20
|
+
import { createLogger } from "./observability/logger.js";
|
|
21
|
+
/**
|
|
22
|
+
* Parses `process.env` (or a test-supplied stand-in) into an `EnvConfig`.
|
|
23
|
+
* Throws on any required-but-missing variable so the operator gets a clear
|
|
24
|
+
* error on first boot instead of a confusing runtime failure.
|
|
25
|
+
*
|
|
26
|
+
* @param env - the env-var record to read from.
|
|
27
|
+
* @returns the parsed config.
|
|
28
|
+
*/
|
|
29
|
+
export function parseEnvConfig(env) {
|
|
30
|
+
const encRaw = env.AI_HUB_ENCRYPTION_KEY;
|
|
31
|
+
if (!encRaw) {
|
|
32
|
+
throw new Error("AI_HUB_ENCRYPTION_KEY is required (see docs/operations/env-vars.md).");
|
|
33
|
+
}
|
|
34
|
+
const encryptionKey = parseEncryptionKey(encRaw);
|
|
35
|
+
const dataDir = env.AI_HUB_DATA_DIR ?? "./data";
|
|
36
|
+
const databaseUrl = env.DATABASE_URL ?? `file:${join(dataDir, "ai_hub.db")}`;
|
|
37
|
+
return {
|
|
38
|
+
dataDir,
|
|
39
|
+
databaseUrl,
|
|
40
|
+
encryptionKey,
|
|
41
|
+
signingKeyFromEnv: parseSigningKey(env.SERVICE_TOKEN_SIGNING_KEY),
|
|
42
|
+
metricsScrapeTokenFromEnv: env.METRICS_SCRAPE_TOKEN || undefined,
|
|
43
|
+
lettaApiKey: env.LETTA_API_KEY || undefined,
|
|
44
|
+
// Letta Code's CLI reads `LETTA_BASE_URL` from process.env and
|
|
45
|
+
// appends `/v1/...` to it. Operators who set the env value
|
|
46
|
+
// matching the Letta Client SDK's expectation (`http://host/v1`)
|
|
47
|
+
// would otherwise get double-v1 URLs in the spawned CLI subprocess.
|
|
48
|
+
// Strip the trailing /v1 once at boot so both ai-hub-server's own
|
|
49
|
+
// direct API calls (already strip defensively in `letta/client.ts`)
|
|
50
|
+
// and Letta Code subprocess spawns see the bare host:port form.
|
|
51
|
+
// Mutating process.env here propagates to every later subprocess
|
|
52
|
+
// spawn — Letta Code SDK forwards `{...process.env}` verbatim.
|
|
53
|
+
lettaBaseUrl: normalizeLettaBaseUrl(env.LETTA_BASE_URL),
|
|
54
|
+
lettaAdeUrl: env.LETTA_ADE_URL || undefined,
|
|
55
|
+
logLevel: env.LOG_LEVEL ?? "info",
|
|
56
|
+
corsAllowedOrigins: env.CORS_ALLOWED_ORIGINS ?? "",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Decodes the bootstrap `SERVICE_TOKEN_SIGNING_KEY` env value.
|
|
61
|
+
*
|
|
62
|
+
* Accepts hex (any length, even number of chars) or base64 / base64url. If
|
|
63
|
+
* the input is neither, treats it as raw utf-8 bytes (operators who paste
|
|
64
|
+
* a passphrase get a deterministic key from it). Returns `undefined` when
|
|
65
|
+
* the env is unset.
|
|
66
|
+
*
|
|
67
|
+
* @param raw - the raw env value, if present.
|
|
68
|
+
* @returns the decoded key, or undefined.
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* Strips a trailing `/v1` from `LETTA_BASE_URL` and writes the cleaned
|
|
72
|
+
* value back to `process.env` so subprocess spawns inherit the normalized
|
|
73
|
+
* form. Idempotent — bare-host inputs pass through unchanged. Returns
|
|
74
|
+
* the normalized value (or `undefined` when the env var is unset).
|
|
75
|
+
*
|
|
76
|
+
* @param raw - the raw `process.env.LETTA_BASE_URL`, possibly undefined.
|
|
77
|
+
* @returns the normalized base URL, or undefined when unset.
|
|
78
|
+
*/
|
|
79
|
+
function normalizeLettaBaseUrl(raw) {
|
|
80
|
+
if (!raw)
|
|
81
|
+
return undefined;
|
|
82
|
+
const stripped = raw.replace(/\/v1\/?$/i, "");
|
|
83
|
+
if (stripped !== raw) {
|
|
84
|
+
process.env.LETTA_BASE_URL = stripped;
|
|
85
|
+
}
|
|
86
|
+
return stripped;
|
|
87
|
+
}
|
|
88
|
+
function parseSigningKey(raw) {
|
|
89
|
+
if (!raw)
|
|
90
|
+
return undefined;
|
|
91
|
+
const trimmed = raw.trim();
|
|
92
|
+
if (/^[0-9a-fA-F]+$/.test(trimmed) && trimmed.length % 2 === 0) {
|
|
93
|
+
return Buffer.from(trimmed, "hex");
|
|
94
|
+
}
|
|
95
|
+
// Try base64 / base64url.
|
|
96
|
+
const normalized = trimmed.replace(/-/g, "+").replace(/_/g, "/");
|
|
97
|
+
const padded = normalized + "===".slice((normalized.length + 3) % 4);
|
|
98
|
+
try {
|
|
99
|
+
const buf = Buffer.from(padded, "base64");
|
|
100
|
+
// Reject obviously broken decodes (base64 length != original).
|
|
101
|
+
if (buf.length > 0 && buf.toString("base64").replace(/=+$/, "") === normalized.replace(/=+$/, "")) {
|
|
102
|
+
return buf;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* fall through */
|
|
107
|
+
}
|
|
108
|
+
// Fallback: treat as raw utf-8 bytes.
|
|
109
|
+
return Buffer.from(trimmed, "utf8");
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* One-shot boot: parses env, opens the DB, runs migrations, runs the
|
|
113
|
+
* first-boot seed (idempotent), and returns the Fetch handler.
|
|
114
|
+
*
|
|
115
|
+
* Called by `dev/server.ts` and by per-customer wrappers' Next.js mount
|
|
116
|
+
* (typically wrapped in a module-level singleton so it runs once per
|
|
117
|
+
* Next.js process).
|
|
118
|
+
*
|
|
119
|
+
* @param opts - optional overrides for testing.
|
|
120
|
+
* @returns the booted server bundle.
|
|
121
|
+
*/
|
|
122
|
+
export async function bootServer(opts = {}) {
|
|
123
|
+
const env = opts.env ?? process.env;
|
|
124
|
+
const config = parseEnvConfig(env);
|
|
125
|
+
const logger = opts.logger ?? createLogger({ level: config.logLevel });
|
|
126
|
+
const databaseUrl = opts.databaseUrl ?? config.databaseUrl;
|
|
127
|
+
const handle = openDb(databaseUrl);
|
|
128
|
+
runMigrations(handle);
|
|
129
|
+
const seedReport = await runFirstBootSeed(handle, {
|
|
130
|
+
encryptionKey: config.encryptionKey,
|
|
131
|
+
signingKeyFromEnv: config.signingKeyFromEnv,
|
|
132
|
+
metricsScrapeTokenFromEnv: config.metricsScrapeTokenFromEnv,
|
|
133
|
+
lettaApiKey: config.lettaApiKey,
|
|
134
|
+
lettaBaseUrl: config.lettaBaseUrl,
|
|
135
|
+
lettaAdeUrl: config.lettaAdeUrl,
|
|
136
|
+
}, logger);
|
|
137
|
+
const fetchHandler = createFetchHandler({
|
|
138
|
+
db: handle.db,
|
|
139
|
+
sqlite: handle.raw,
|
|
140
|
+
logger,
|
|
141
|
+
encryptionKey: config.encryptionKey,
|
|
142
|
+
// Pass the booted env through as the runtime fallback source. Tests
|
|
143
|
+
// synthesize an env record; production uses process.env (the default
|
|
144
|
+
// inside createFetchHandler). Threading it explicitly here means
|
|
145
|
+
// bootTestServer's `env:` parameter actually reaches resolveApiKey
|
|
146
|
+
// in letta/client.ts.
|
|
147
|
+
envSource: env,
|
|
148
|
+
...(opts.lettaClient !== undefined ? { lettaClient: opts.lettaClient } : {}),
|
|
149
|
+
});
|
|
150
|
+
return {
|
|
151
|
+
fetchHandler,
|
|
152
|
+
db: handle.db,
|
|
153
|
+
sqlite: handle.raw,
|
|
154
|
+
logger,
|
|
155
|
+
config,
|
|
156
|
+
seedReport,
|
|
157
|
+
close: () => handle.raw.close(),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAiC,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAmB,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAqB,MAAM,qBAAqB,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAe,MAAM,2BAA2B,CAAC;AAoCtE;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY;IACzC,MAAM,MAAM,GAAG,GAAG,CAAC,qBAAqB,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAC;IACJ,CAAC;IACD,MAAM,aAAa,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,IAAI,QAAQ,CAAC;IAChD,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;IAE7E,OAAO;QACL,OAAO;QACP,WAAW;QACX,aAAa;QACb,iBAAiB,EAAE,eAAe,CAAC,GAAG,CAAC,yBAAyB,CAAC;QACjE,yBAAyB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;QAChE,WAAW,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;QAC3C,+DAA+D;QAC/D,2DAA2D;QAC3D,iEAAiE;QACjE,oEAAoE;QACpE,kEAAkE;QAClE,oEAAoE;QACpE,gEAAgE;QAChE,iEAAiE;QACjE,+DAA+D;QAC/D,YAAY,EAAE,qBAAqB,CAAC,GAAG,CAAC,cAAc,CAAC;QACvD,WAAW,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;QAC3C,QAAQ,EAAE,GAAG,CAAC,SAAS,IAAI,MAAM;QACjC,kBAAkB,EAAE,GAAG,CAAC,oBAAoB,IAAI,EAAE;KACnD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;AACH,SAAS,qBAAqB,CAAC,GAAuB;IACpD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC9C,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,QAAQ,CAAC;IACxC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,GAAuB;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IACD,0BAA0B;IAC1B,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC1C,+DAA+D;QAC/D,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;YAClG,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,sCAAsC;IACtC,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACtC,CAAC;AA2CD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAA0B,EAAE;IAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAK,OAAO,CAAC,GAAe,CAAC;IACjD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEvE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC;IAC3D,MAAM,MAAM,GAAa,MAAM,CAAC,WAAW,CAAC,CAAC;IAE7C,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CACvC,MAAM,EACN;QACE,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;QAC3C,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;QAC3D,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,EACD,MAAM,CACP,CAAC;IAEF,MAAM,YAAY,GAAG,kBAAkB,CAAC;QACtC,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,MAAM,EAAE,MAAM,CAAC,GAAG;QAClB,MAAM;QACN,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,oEAAoE;QACpE,qEAAqE;QACrE,iEAAiE;QACjE,mEAAmE;QACnE,sBAAsB;QACtB,SAAS,EAAE,GAAG;QACd,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7E,CAAC,CAAC;IAEH,OAAO;QACL,YAAY;QACZ,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,MAAM,EAAE,MAAM,CAAC,GAAG;QAClB,MAAM;QACN,MAAM;QACN,UAAU;QACV,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* better-sqlite3 connection + Drizzle wiring.
|
|
3
|
+
*
|
|
4
|
+
* On open we set the two PRAGMAs the spec requires (§6.8): `journal_mode=WAL`
|
|
5
|
+
* for concurrency under multiple readers + one writer, and `foreign_keys=ON`
|
|
6
|
+
* because SQLite ships them off by default.
|
|
7
|
+
*
|
|
8
|
+
* The connection is intentionally a per-server-instance singleton — Drizzle's
|
|
9
|
+
* client wraps better-sqlite3, and better-sqlite3 itself is fully synchronous
|
|
10
|
+
* (no connection pool needed; one handle is enough). Tests open their own
|
|
11
|
+
* handle against a `:memory:` or tmp-file path.
|
|
12
|
+
*
|
|
13
|
+
* @see SPECIFICATIONS.md §6.8 — persistence
|
|
14
|
+
* @see SPECIFICATIONS.md §11 — data model
|
|
15
|
+
*/
|
|
16
|
+
import Database from "better-sqlite3";
|
|
17
|
+
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
18
|
+
import * as schema from "./schema.js";
|
|
19
|
+
/** The Drizzle client type our handlers consume. */
|
|
20
|
+
export type DrizzleDB = ReturnType<typeof drizzle<typeof schema>>;
|
|
21
|
+
/** Bundles the raw better-sqlite3 handle alongside the Drizzle wrapper. */
|
|
22
|
+
export interface DbHandle {
|
|
23
|
+
/** Drizzle client — typed against the schema. */
|
|
24
|
+
db: DrizzleDB;
|
|
25
|
+
/** Raw better-sqlite3 handle (used for PRAGMAs and `.close()`). */
|
|
26
|
+
raw: Database.Database;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Opens the SQLite database at `path` and applies the spec's PRAGMAs.
|
|
30
|
+
*
|
|
31
|
+
* `:memory:` is recognized verbatim and skipped from path-resolution +
|
|
32
|
+
* directory-creation logic (used by tests).
|
|
33
|
+
*
|
|
34
|
+
* @param path - filesystem path, a `file:`-prefixed URI, or `:memory:`.
|
|
35
|
+
* @returns Drizzle wrapper + raw better-sqlite3 handle.
|
|
36
|
+
*/
|
|
37
|
+
export declare function openDb(path: string): DbHandle;
|
|
38
|
+
export { schema };
|
|
39
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,oDAAoD;AACpD,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC;AAElE,2EAA2E;AAC3E,MAAM,WAAW,QAAQ;IACvB,iDAAiD;IACjD,EAAE,EAAE,SAAS,CAAC;IACd,mEAAmE;IACnE,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAU7C;AAoBD,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* better-sqlite3 connection + Drizzle wiring.
|
|
3
|
+
*
|
|
4
|
+
* On open we set the two PRAGMAs the spec requires (§6.8): `journal_mode=WAL`
|
|
5
|
+
* for concurrency under multiple readers + one writer, and `foreign_keys=ON`
|
|
6
|
+
* because SQLite ships them off by default.
|
|
7
|
+
*
|
|
8
|
+
* The connection is intentionally a per-server-instance singleton — Drizzle's
|
|
9
|
+
* client wraps better-sqlite3, and better-sqlite3 itself is fully synchronous
|
|
10
|
+
* (no connection pool needed; one handle is enough). Tests open their own
|
|
11
|
+
* handle against a `:memory:` or tmp-file path.
|
|
12
|
+
*
|
|
13
|
+
* @see SPECIFICATIONS.md §6.8 — persistence
|
|
14
|
+
* @see SPECIFICATIONS.md §11 — data model
|
|
15
|
+
*/
|
|
16
|
+
import { mkdirSync } from "node:fs";
|
|
17
|
+
import { dirname, isAbsolute, resolve as pathResolve } from "node:path";
|
|
18
|
+
import Database from "better-sqlite3";
|
|
19
|
+
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
20
|
+
import * as schema from "./schema.js";
|
|
21
|
+
/**
|
|
22
|
+
* Opens the SQLite database at `path` and applies the spec's PRAGMAs.
|
|
23
|
+
*
|
|
24
|
+
* `:memory:` is recognized verbatim and skipped from path-resolution +
|
|
25
|
+
* directory-creation logic (used by tests).
|
|
26
|
+
*
|
|
27
|
+
* @param path - filesystem path, a `file:`-prefixed URI, or `:memory:`.
|
|
28
|
+
* @returns Drizzle wrapper + raw better-sqlite3 handle.
|
|
29
|
+
*/
|
|
30
|
+
export function openDb(path) {
|
|
31
|
+
const resolvedPath = resolveDbPath(path);
|
|
32
|
+
if (resolvedPath !== ":memory:") {
|
|
33
|
+
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
const raw = new Database(resolvedPath);
|
|
36
|
+
raw.pragma("journal_mode = WAL");
|
|
37
|
+
raw.pragma("foreign_keys = ON");
|
|
38
|
+
const db = drizzle(raw, { schema });
|
|
39
|
+
return { db, raw };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolves a path that may be `:memory:`, a `file:` URI from `DATABASE_URL`,
|
|
43
|
+
* or an ordinary filesystem path (relative or absolute).
|
|
44
|
+
*
|
|
45
|
+
* @param path - raw path string from env or caller.
|
|
46
|
+
* @returns absolute filesystem path or `:memory:`.
|
|
47
|
+
*/
|
|
48
|
+
function resolveDbPath(path) {
|
|
49
|
+
if (path === ":memory:")
|
|
50
|
+
return path;
|
|
51
|
+
let stripped = path;
|
|
52
|
+
if (stripped.startsWith("file:")) {
|
|
53
|
+
stripped = stripped.slice("file:".length);
|
|
54
|
+
if (stripped.startsWith("//"))
|
|
55
|
+
stripped = stripped.slice(2);
|
|
56
|
+
}
|
|
57
|
+
if (stripped === ":memory:")
|
|
58
|
+
return stripped;
|
|
59
|
+
return isAbsolute(stripped) ? stripped : pathResolve(stripped);
|
|
60
|
+
}
|
|
61
|
+
export { schema };
|
|
62
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAExE,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAatC;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,YAAY,KAAK,UAAU,EAAE,CAAC;QAChC,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvC,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACjC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,QAAQ,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC;IAC7C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot-time migrations runner.
|
|
3
|
+
*
|
|
4
|
+
* Currently a single `0001_init` migration that builds the entire §11 schema
|
|
5
|
+
* idempotently via `CREATE TABLE IF NOT EXISTS`. Tracked in
|
|
6
|
+
* `_ai_hub_migrations` so future migrations can append additional steps and
|
|
7
|
+
* skip already-applied ones.
|
|
8
|
+
*
|
|
9
|
+
* **Why hand-rolled SQL instead of `drizzle-kit migrate`**: shipping
|
|
10
|
+
* `drizzle-kit` and a generated `drizzle/` SQL folder as runtime artifacts
|
|
11
|
+
* adds a build step that the per-customer wrapper doesn't want to think about.
|
|
12
|
+
* The schema is small and stable; CREATE-TABLE-IF-NOT-EXISTS is sufficient,
|
|
13
|
+
* and Drizzle's typed query builder already protects us from drift between
|
|
14
|
+
* the runtime SQL and `schema.ts`. (If migrations ever get complex enough
|
|
15
|
+
* that this breaks down, we move to drizzle-kit then — not pre-emptively.)
|
|
16
|
+
*
|
|
17
|
+
* @see SPECIFICATIONS.md §11 — data model the schema mirrors 1:1
|
|
18
|
+
*/
|
|
19
|
+
import type { DbHandle } from "./connection.js";
|
|
20
|
+
/**
|
|
21
|
+
* Runs every not-yet-applied migration on `handle.raw`.
|
|
22
|
+
*
|
|
23
|
+
* Idempotent: running this on a fresh SQLite produces the v1 schema; running
|
|
24
|
+
* it on an already-migrated DB is a no-op. The migrations are wrapped in a
|
|
25
|
+
* single transaction so a partial failure can't leave the schema in a
|
|
26
|
+
* half-applied state.
|
|
27
|
+
*
|
|
28
|
+
* @param handle - the db handle returned from `openDb`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runMigrations(handle: DbHandle): void;
|
|
31
|
+
//# sourceMappingURL=migrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAwBpD"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot-time migrations runner.
|
|
3
|
+
*
|
|
4
|
+
* Currently a single `0001_init` migration that builds the entire §11 schema
|
|
5
|
+
* idempotently via `CREATE TABLE IF NOT EXISTS`. Tracked in
|
|
6
|
+
* `_ai_hub_migrations` so future migrations can append additional steps and
|
|
7
|
+
* skip already-applied ones.
|
|
8
|
+
*
|
|
9
|
+
* **Why hand-rolled SQL instead of `drizzle-kit migrate`**: shipping
|
|
10
|
+
* `drizzle-kit` and a generated `drizzle/` SQL folder as runtime artifacts
|
|
11
|
+
* adds a build step that the per-customer wrapper doesn't want to think about.
|
|
12
|
+
* The schema is small and stable; CREATE-TABLE-IF-NOT-EXISTS is sufficient,
|
|
13
|
+
* and Drizzle's typed query builder already protects us from drift between
|
|
14
|
+
* the runtime SQL and `schema.ts`. (If migrations ever get complex enough
|
|
15
|
+
* that this breaks down, we move to drizzle-kit then — not pre-emptively.)
|
|
16
|
+
*
|
|
17
|
+
* @see SPECIFICATIONS.md §11 — data model the schema mirrors 1:1
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Runs every not-yet-applied migration on `handle.raw`.
|
|
21
|
+
*
|
|
22
|
+
* Idempotent: running this on a fresh SQLite produces the v1 schema; running
|
|
23
|
+
* it on an already-migrated DB is a no-op. The migrations are wrapped in a
|
|
24
|
+
* single transaction so a partial failure can't leave the schema in a
|
|
25
|
+
* half-applied state.
|
|
26
|
+
*
|
|
27
|
+
* @param handle - the db handle returned from `openDb`.
|
|
28
|
+
*/
|
|
29
|
+
export function runMigrations(handle) {
|
|
30
|
+
const { raw } = handle;
|
|
31
|
+
raw.exec(`
|
|
32
|
+
CREATE TABLE IF NOT EXISTS _ai_hub_migrations (
|
|
33
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
34
|
+
name TEXT NOT NULL UNIQUE,
|
|
35
|
+
applied_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
36
|
+
)
|
|
37
|
+
`);
|
|
38
|
+
for (const m of MIGRATIONS) {
|
|
39
|
+
const already = raw
|
|
40
|
+
.prepare("SELECT 1 FROM _ai_hub_migrations WHERE name = ?")
|
|
41
|
+
.get(m.name);
|
|
42
|
+
if (already)
|
|
43
|
+
continue;
|
|
44
|
+
const apply = raw.transaction(() => {
|
|
45
|
+
raw.exec(m.sql);
|
|
46
|
+
raw
|
|
47
|
+
.prepare("INSERT INTO _ai_hub_migrations (name) VALUES (?)")
|
|
48
|
+
.run(m.name);
|
|
49
|
+
});
|
|
50
|
+
apply();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The canonical migration list. Append-only — never edit a past entry, only
|
|
55
|
+
* add a new one with a higher number. (Same convention as Drizzle / Prisma /
|
|
56
|
+
* Rails.)
|
|
57
|
+
*/
|
|
58
|
+
const MIGRATIONS = [
|
|
59
|
+
{
|
|
60
|
+
name: "0001_init",
|
|
61
|
+
sql: `
|
|
62
|
+
CREATE TABLE user (
|
|
63
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
64
|
+
username TEXT NOT NULL UNIQUE,
|
|
65
|
+
display_name TEXT,
|
|
66
|
+
password_hash TEXT,
|
|
67
|
+
identity_source TEXT NOT NULL DEFAULT 'local',
|
|
68
|
+
is_initial_password INTEGER NOT NULL DEFAULT 0,
|
|
69
|
+
role TEXT NOT NULL DEFAULT 'user',
|
|
70
|
+
theme_preference TEXT,
|
|
71
|
+
password_changed_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
72
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
73
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
74
|
+
);
|
|
75
|
+
CREATE INDEX user_role_idx ON user (role);
|
|
76
|
+
|
|
77
|
+
CREATE TABLE agent (
|
|
78
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
79
|
+
display_name TEXT NOT NULL,
|
|
80
|
+
letta_agent_id TEXT NOT NULL,
|
|
81
|
+
tpm_recovery_enabled INTEGER NOT NULL DEFAULT 0,
|
|
82
|
+
max_recovery_attempts INTEGER NOT NULL DEFAULT 2,
|
|
83
|
+
default_retry_after_seconds INTEGER NOT NULL DEFAULT 65,
|
|
84
|
+
stream_idle_timeout_seconds INTEGER NOT NULL DEFAULT 60,
|
|
85
|
+
sandbox_seed_name TEXT,
|
|
86
|
+
fork_source_conversation_id TEXT,
|
|
87
|
+
is_archived INTEGER NOT NULL DEFAULT 0,
|
|
88
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
89
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
CREATE TABLE session (
|
|
93
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
94
|
+
user_id TEXT NOT NULL REFERENCES user(id) ON DELETE CASCADE,
|
|
95
|
+
agent_id TEXT NOT NULL REFERENCES agent(id) ON DELETE RESTRICT,
|
|
96
|
+
letta_conversation_id TEXT NOT NULL,
|
|
97
|
+
letta_agent_id TEXT NOT NULL,
|
|
98
|
+
title TEXT NOT NULL,
|
|
99
|
+
is_archived INTEGER NOT NULL DEFAULT 0,
|
|
100
|
+
reasoning_effort TEXT,
|
|
101
|
+
verbosity TEXT,
|
|
102
|
+
thinking_budget INTEGER,
|
|
103
|
+
sandbox_dir TEXT,
|
|
104
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
105
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
106
|
+
);
|
|
107
|
+
CREATE INDEX session_user_agent_idx ON session (user_id, agent_id);
|
|
108
|
+
|
|
109
|
+
CREATE TABLE turn (
|
|
110
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
111
|
+
session_id TEXT NOT NULL REFERENCES session(id) ON DELETE CASCADE,
|
|
112
|
+
status TEXT NOT NULL,
|
|
113
|
+
phase TEXT,
|
|
114
|
+
last_seq INTEGER NOT NULL DEFAULT 0,
|
|
115
|
+
idempotency_key TEXT,
|
|
116
|
+
started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
117
|
+
finished_at TEXT
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
CREATE TABLE turn_event (
|
|
121
|
+
turn_id TEXT NOT NULL REFERENCES turn(id) ON DELETE CASCADE,
|
|
122
|
+
seq INTEGER NOT NULL,
|
|
123
|
+
event_name TEXT NOT NULL,
|
|
124
|
+
data TEXT NOT NULL,
|
|
125
|
+
state TEXT NOT NULL,
|
|
126
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
127
|
+
PRIMARY KEY (turn_id, seq)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
CREATE TABLE admin_setting (
|
|
131
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
132
|
+
letta_api_key_encrypted BLOB,
|
|
133
|
+
letta_base_url TEXT,
|
|
134
|
+
letta_ade_url TEXT,
|
|
135
|
+
feature_toggles TEXT NOT NULL DEFAULT '{}',
|
|
136
|
+
theme_switcher_enabled INTEGER NOT NULL DEFAULT 1,
|
|
137
|
+
theme_default TEXT NOT NULL DEFAULT 'light',
|
|
138
|
+
service_token_signing_key BLOB,
|
|
139
|
+
metrics_scrape_token TEXT,
|
|
140
|
+
metrics_scrape_token_rotated_at TEXT,
|
|
141
|
+
signing_key_rotated_at TEXT,
|
|
142
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
CREATE TABLE message_override (
|
|
146
|
+
conversation_id TEXT NOT NULL,
|
|
147
|
+
ordinal_position INTEGER NOT NULL,
|
|
148
|
+
system_override TEXT,
|
|
149
|
+
user_override TEXT,
|
|
150
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
151
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
152
|
+
PRIMARY KEY (conversation_id, ordinal_position),
|
|
153
|
+
CHECK (system_override IS NOT NULL OR user_override IS NOT NULL)
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
CREATE TABLE message_usage (
|
|
157
|
+
letta_message_id TEXT NOT NULL PRIMARY KEY,
|
|
158
|
+
session_id TEXT NOT NULL REFERENCES session(id) ON DELETE CASCADE,
|
|
159
|
+
prompt_tokens INTEGER,
|
|
160
|
+
completion_tokens INTEGER,
|
|
161
|
+
total_tokens INTEGER,
|
|
162
|
+
cached_input_tokens INTEGER,
|
|
163
|
+
cache_write_tokens INTEGER,
|
|
164
|
+
reasoning_tokens INTEGER,
|
|
165
|
+
context_tokens INTEGER,
|
|
166
|
+
run_id TEXT,
|
|
167
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
168
|
+
);
|
|
169
|
+
CREATE INDEX message_usage_session_idx ON message_usage(session_id);
|
|
170
|
+
`,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "0002_rotating_message",
|
|
174
|
+
sql: `
|
|
175
|
+
CREATE TABLE rotating_message (
|
|
176
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
177
|
+
display_name TEXT NOT NULL,
|
|
178
|
+
prompt TEXT NOT NULL,
|
|
179
|
+
letta_agent_id TEXT NOT NULL,
|
|
180
|
+
schedule_kind TEXT NOT NULL,
|
|
181
|
+
interval_seconds INTEGER,
|
|
182
|
+
daily_time TEXT,
|
|
183
|
+
cron_expression TEXT,
|
|
184
|
+
current_conversation_id TEXT,
|
|
185
|
+
last_status TEXT NOT NULL DEFAULT 'pending',
|
|
186
|
+
last_error TEXT,
|
|
187
|
+
last_rotated_at TEXT,
|
|
188
|
+
next_rotation_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
189
|
+
is_archived INTEGER NOT NULL DEFAULT 0,
|
|
190
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
191
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
192
|
+
);
|
|
193
|
+
CREATE INDEX rotating_message_due_idx ON rotating_message (is_archived, next_rotation_at);
|
|
194
|
+
`,
|
|
195
|
+
},
|
|
196
|
+
];
|
|
197
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,MAAgB;IAC5C,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;IAEvB,GAAG,CAAC,IAAI,CAAC;;;;;;GAMR,CAAC,CAAC;IAEH,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG;aAChB,OAAO,CAAC,iDAAiD,CAAC;aAC1D,GAAG,CAAC,CAAC,CAAC,IAAI,CAA8B,CAAC;QAC5C,IAAI,OAAO;YAAE,SAAS;QACtB,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;YACjC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAChB,GAAG;iBACA,OAAO,CAAC,kDAAkD,CAAC;iBAC3D,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;QACH,KAAK,EAAE,CAAC;IACV,CAAC;AACH,CAAC;AAaD;;;;GAIG;AACH,MAAM,UAAU,GAA6B;IAC3C;QACE,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6GJ;KACF;IACD;QACE,IAAI,EAAE,uBAAuB;QAC7B,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;KAoBJ;KACF;CACF,CAAC"}
|