feat: prepara web con bun:sqlite y soporte env/db/hooks

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
webui
brobert 2 weeks ago
parent 32f1011fcf
commit 9347d86065

@ -0,0 +1,14 @@
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
// Handler mínimo (sin sesión aún). Añadimos cabeceras de seguridad básicas.
const response = await resolve(event);
try {
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('Referrer-Policy', 'no-referrer');
response.headers.set('X-Content-Type-Options', 'nosniff');
} catch {
// Ignorar si la implementación de Response no permite set()
}
return response;
};

@ -0,0 +1,39 @@
import { Database } from 'bun:sqlite';
import { mkdirSync } from 'fs';
import { dirname } from 'path';
import { resolveDbAbsolutePath } from './env';
function applyDefaultPragmas(instance: Database): void {
try {
instance.exec(`PRAGMA busy_timeout = 5000;`);
// Intentar activar WAL (si no es soportado, SQLite devolverá 'memory' u otro modo)
instance.query(`PRAGMA journal_mode = WAL`).get();
instance.exec(`PRAGMA synchronous = NORMAL;`);
instance.exec(`PRAGMA wal_autocheckpoint = 1000;`);
// Asegurar claves foráneas siempre activas
instance.exec(`PRAGMA foreign_keys = ON;`);
} catch (e) {
console.warn('[web/db] No se pudieron aplicar PRAGMAs (WAL, busy_timeout...):', e);
}
}
/**
* Abre la BD compartida sin ejecutar migraciones (las realiza el proceso del bot).
*/
export function openDb(filename: string = 'tasks.db'): Database {
const absolutePath = resolveDbAbsolutePath(filename);
// Crear directorio padre si no existe
try {
mkdirSync(dirname(absolutePath), { recursive: true });
} catch (err: any) {
if (err?.code !== 'EEXIST') throw err;
}
const instance = new Database(absolutePath);
applyDefaultPragmas(instance);
return instance;
}
// Instancia por defecto
export const db = openDb();

@ -0,0 +1,27 @@
import { join, resolve } from 'path';
const env = process.env;
/**
* Resuelve la ruta absoluta al archivo de la base de datos SQLite compartida.
* Prioridad:
* 1) DB_PATH (ruta completa al archivo)
* 2) DATA_DIR + filename (por defecto ./data/tasks.db)
*/
export function resolveDbAbsolutePath(filename: string = 'tasks.db'): string {
const dbPathEnv = (env.DB_PATH || '').trim();
if (dbPathEnv) {
return resolve(dbPathEnv);
}
const dataDir = env.DATA_DIR ? String(env.DATA_DIR) : 'data';
return resolve(join(dataDir, filename));
}
export const WEB_BASE_URL = (env.WEB_BASE_URL || '').trim();
export const COOKIE_SECRET = (env.COOKIE_SECRET || '').trim();
const SESSION_IDLE_TTL_MIN = Number(env.SESSION_IDLE_TTL_MIN || 120);
export const sessionIdleTtlMs = Math.max(1, Math.floor(SESSION_IDLE_TTL_MIN)) * 60 * 1000;
export const NODE_ENV = (env.NODE_ENV || 'development').trim().toLowerCase();
export const isProd = () => NODE_ENV === 'production';
Loading…
Cancel
Save