feat: prepara web con bun:sqlite y soporte env/db/hooks
Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>webui
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…
Reference in New Issue