Files
OmniRoute/src/lib/db/middleware.ts
Webman 50bc8ab8aa fix(barrel): delete the @/lib/localDb barrel — every consumer migrated (#11795 Phase 5) (#12055)
Resynced onto the release tip after #12051/#12052/#12053 landed. Same LKGP-clear conflict as #12053 (kept the current clearStaleLKGP() helper at both call sites). One additional issue this final phase's combined-worktree validation surfaced: clearStaleLKGP() itself (added by #12013, which none of the 4 phase PRs could have seen since it landed after they were authored) still had a dynamic `await import("@/lib/localDb")` — a real break once this PR deletes the barrel. Fixed to `await import("@/lib/db/settings")`, matching the direct-import pattern used at every other call site. typecheck:core, check-db-rules, check:cycles, and the eslint-import-boundaries regression test (3/3, including "G14 rejects localDb barrel imports") all green after resync — zero barrel-importing production files remain. Nice clean 5-phase migration, and thanks for taking on the full #11795 cleanup.
2026-08-30 02:36:26 -03:00

179 lines
5.4 KiB
TypeScript

/**
* Middleware Hooks DB — CRUD operations for middleware_hooks table
*
* Module: src/lib/db/middleware.ts
* Table: middleware_hooks
* Logs: middleware_logs
*/
import { getDbInstance } from "@/lib/db/core";
import type { HookConfig, HookConfigRow, HookLogEntry } from "@/lib/middleware/types";
// ── Helpers ───────────────────────────────────────────────────────────────
function rowToHookConfig(row: HookConfigRow): HookConfig {
return {
name: row.name,
description: row.description,
priority: row.priority,
scope:
row.scope_type === "combo" && row.combo_id
? { type: "combo", comboId: row.combo_id }
: { type: "global" },
enabled: row.enabled === 1,
code: row.code,
createdAt: row.created_at,
updatedAt: row.updated_at,
runCount: row.run_count,
lastError: row.last_error || undefined,
};
}
function hookConfigToRow(config: HookConfig): HookConfigRow {
return {
name: config.name,
description: config.description,
priority: config.priority,
scope_type: config.scope.type,
combo_id: config.scope.type === "combo" ? config.scope.comboId : null,
enabled: config.enabled ? 1 : 0,
code: config.code,
created_at: config.createdAt || new Date().toISOString(),
updated_at: new Date().toISOString(),
run_count: config.runCount || 0,
last_error: config.lastError,
};
}
// ── CRUD Operations ───────────────────────────────────────────────────────
/**
* Get all hooks from DB.
*/
export function getAllMiddlewareHooks(): HookConfig[] {
const db = getDbInstance() as any;
const rows = db
.prepare("SELECT * FROM middleware_hooks ORDER BY priority ASC, name ASC")
.all() as HookConfigRow[];
return rows.map(rowToHookConfig);
}
/**
* Get enabled hooks from DB (for runtime loading).
*/
export function getEnabledMiddlewareHooks(): HookConfig[] {
const db = getDbInstance() as any;
const rows = db
.prepare("SELECT * FROM middleware_hooks WHERE enabled = 1 ORDER BY priority ASC")
.all() as HookConfigRow[];
return rows.map(rowToHookConfig);
}
/**
* Get a single hook by name.
*/
export function getMiddlewareHook(name: string): HookConfig | undefined {
const db = getDbInstance() as any;
const row = db.prepare("SELECT * FROM middleware_hooks WHERE name = ?").get(name) as
HookConfigRow | undefined;
return row ? rowToHookConfig(row) : undefined;
}
/**
* Create a new middleware hook.
*/
export function createMiddlewareHook(config: HookConfig): HookConfig {
const db = getDbInstance() as any;
const row = hookConfigToRow(config);
row.created_at = new Date().toISOString();
row.updated_at = row.created_at;
db.prepare(
`
INSERT INTO middleware_hooks (name, description, priority, scope_type, combo_id, enabled, code, created_at, updated_at, run_count, last_error)
VALUES (@name, @description, @priority, @scope_type, @combo_id, @enabled, @code, @created_at, @updated_at, @run_count, @last_error)
`
).run(row);
return getMiddlewareHook(config.name)!;
}
/**
* Update an existing middleware hook.
*/
export function updateMiddlewareHook(
name: string,
updates: Partial<HookConfig>
): HookConfig | undefined {
const existing = getMiddlewareHook(name);
if (!existing) return undefined;
const updated = { ...existing, ...updates, updatedAt: new Date().toISOString() };
const row = hookConfigToRow(updated);
const db = getDbInstance() as any;
db.prepare(
`
UPDATE middleware_hooks SET
description = @description,
priority = @priority,
scope_type = @scope_type,
combo_id = @combo_id,
enabled = @enabled,
code = @code,
updated_at = @updated_at,
run_count = @run_count,
last_error = @last_error
WHERE name = @name
`
).run(row);
return getMiddlewareHook(name);
}
/**
* Delete a middleware hook.
*/
export function deleteMiddlewareHook(name: string): boolean {
const db = getDbInstance() as any;
const result = db.prepare("DELETE FROM middleware_hooks WHERE name = ?").run(name);
return result.changes > 0;
}
/**
* Increment run count and optionally update last error.
*/
export function recordHookExecution(name: string, error?: string): void {
const db = getDbInstance() as any;
if (error) {
db.prepare(
"UPDATE middleware_hooks SET run_count = run_count + 1, last_error = ?, updated_at = datetime('now') WHERE name = ?"
).run(error, name);
} else {
db.prepare(
"UPDATE middleware_hooks SET run_count = run_count + 1, last_error = NULL, updated_at = datetime('now') WHERE name = ?"
).run(name);
}
}
export function getHookLogs(hookName?: string, limit = 50): HookLogEntry[] {
const db = getDbInstance() as any;
let rows: any[];
if (hookName) {
rows = db
.prepare("SELECT * FROM middleware_logs WHERE hook_name = ? ORDER BY timestamp DESC LIMIT ?")
.all(hookName, limit);
} else {
rows = db.prepare("SELECT * FROM middleware_logs ORDER BY timestamp DESC LIMIT ?").all(limit);
}
return rows.map((r: any) => ({
id: r.id,
hookName: r.hook_name,
requestId: r.request_id,
durationMs: r.duration_ms,
mutated: r.mutated === 1,
skipped: r.skipped === 1,
error: r.error,
timestamp: r.timestamp,
}));
}