import { Kysely, SqliteDialect } from 'kysely'; import SQLite from 'better-sqlite3'; import path from 'path'; import fs from 'fs'; export interface SessionTable { id: string; url: string; status: string; seed: number; max_states: number; states_visited: number; anomalies_found: number; started_at: number; finished_at: number | null; config_json: string; } export interface StateTable { id: string; session_id: string; url: string; title: string; dom_snapshot_path: string | null; visit_count: number; discovered_at: number; } export interface ActionTable { id: string; session_id: string; state_id: string; type: string; selector: string | null; value: string | null; url: string | null; seed: number; executed_at: number; sequence_order: number; } export interface AnomalyTable { id: string; session_id: string; type: string; severity: string; description: string; action_trace_json: string; evidence_json: string; screenshot_path: string | null; dom_snapshot_path: string | null; detected_at: number; ai_enrichment_json: string | null; ai_enriched_at: number | null; browser: string | null; browser_version: string | null; } export interface NotificationTable { id: string; anomaly_id: string; channel: string; status: string; sent_at: number | null; error: string | null; } export interface ScheduleTable { id: string; name: string; url: string; config_json: string; cron_expression: string; enabled: number; last_run_at: number | null; next_run_at: number | null; created_at: number; } export interface VisualBaselineTable { id: string; state_id: string; url: string; screenshot_path: string; approved_at: number; approved_by: string | null; width: number; height: number; } export interface VisualComparisonTable { id: string; session_id: string; state_id: string; baseline_id: string | null; current_screenshot_path: string; diff_screenshot_path: string | null; diff_pixels: number | null; diff_percent: number | null; status: string; created_at: number; } export interface PerformanceMetricTable { id: string; session_id: string; state_id: string; url: string; ttfb: number | null; dom_content_loaded: number | null; load_complete: number | null; lcp: number | null; cls: number | null; fid: number | null; inp: number | null; total_requests: number | null; failed_requests: number | null; total_transfer_size: number | null; captured_at: number; } export interface Database { sessions: SessionTable; states: StateTable; actions: ActionTable; anomalies: AnomalyTable; notifications: NotificationTable; schedules: ScheduleTable; visual_baselines: VisualBaselineTable; visual_comparisons: VisualComparisonTable; performance_metrics: PerformanceMetricTable; } export function createDatabase(config: { driver: string; path: string; url?: string }): Kysely { if (config.driver === 'postgres') { // eslint-disable-next-line @typescript-eslint/no-require-imports const { Pool } = require('pg') as { Pool: new (opts: { connectionString?: string }) => unknown }; // eslint-disable-next-line @typescript-eslint/no-require-imports const { PostgresDialect } = require('kysely') as { PostgresDialect: new (opts: { pool: unknown }) => SqliteDialect }; return new Kysely({ dialect: new PostgresDialect({ pool: new Pool({ connectionString: config.url }) }), }); } fs.mkdirSync(path.dirname(config.path), { recursive: true }); return new Kysely({ dialect: new SqliteDialect({ database: new SQLite(config.path) }), }); }