From 2669d4287cbe25ee0dea6ea756c2b35e33327404 Mon Sep 17 00:00:00 2001 From: brobert Date: Mon, 10 Nov 2025 15:40:50 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20centralizar=20resoluci=C3=B3n=20de=20DB?= =?UTF-8?q?=20y=20reexport=20en=20web?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: aider (openrouter/openai/gpt-5) --- apps/web/src/lib/server/env.ts | 17 +---------------- apps/web/vite.config.ts | 10 ++++++++-- src/db.ts | 34 ++++++++-------------------------- src/env/db-path.ts | 18 ++++++++++++++++++ tsconfig.core.json | 1 + 5 files changed, 36 insertions(+), 44 deletions(-) create mode 100644 src/env/db-path.ts diff --git a/apps/web/src/lib/server/env.ts b/apps/web/src/lib/server/env.ts index b78715c..c439d2f 100644 --- a/apps/web/src/lib/server/env.ts +++ b/apps/web/src/lib/server/env.ts @@ -1,4 +1,3 @@ -import { join, resolve } from 'path'; // Carga compatible del entorno: en SvelteKit usa $env/dynamic/private; // en tests/ejecución fuera de SvelteKit cae a process.env. @@ -10,21 +9,7 @@ try { env = process.env as any; } -/** - * 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 (en prod por defecto /app/data; en dev por defecto ./tmp) - */ -export function resolveDbAbsolutePath(filename: string = 'tasks.db'): string { - const dbPathEnv = (env.DB_PATH || '').trim(); - if (dbPathEnv) { - return resolve(dbPathEnv); - } - const isProdEnv = String(env.NODE_ENV || 'development').trim().toLowerCase() === 'production'; - const dataDir = env.DATA_DIR ? String(env.DATA_DIR) : (isProdEnv ? '/app/data' : 'tmp'); - return resolve(join(dataDir, filename)); -} +export { resolveDbAbsolutePath } from '../../../../../src/env/db-path'; export const WEB_BASE_URL = (env.WEB_BASE_URL || '').trim(); export const COOKIE_SECRET = (env.COOKIE_SECRET || '').trim(); diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 548d260..257986e 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -1,5 +1,11 @@ import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; +import { fileURLToPath } from 'node:url'; +import { dirname, resolve as resolvePath } from 'node:path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const repoRoot = resolvePath(__dirname, '..', '..'); export default defineConfig(({ mode }) => { const isDev = mode === 'development'; @@ -19,7 +25,7 @@ export default defineConfig(({ mode }) => { // Evitar prebundling de drivers nativos exclude: ['bun:sqlite', 'better-sqlite3'] }, - // Permitir host remoto en desarrollo - server: isDev ? { allowedHosts: ['server.brobert.net'] } : undefined + // Permitir host remoto en desarrollo y permitir importar fuera del root (reexport desde core) + server: isDev ? { allowedHosts: ['server.brobert.net'], fs: { allow: [repoRoot] } } : undefined }; }); diff --git a/src/db.ts b/src/db.ts index 0c7ab68..9f62427 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,9 +1,10 @@ import { Database } from 'bun:sqlite'; import { normalizeWhatsAppId } from './utils/whatsapp'; import { mkdirSync } from 'fs'; -import { join, resolve, dirname } from 'path'; +import { dirname } from 'path'; import { Migrator } from './db/migrator'; import { migrations } from './db/migrations'; +import { resolveDbAbsolutePath } from './env/db-path'; function applyDefaultPragmas(instance: Database): void { try { @@ -19,38 +20,19 @@ function applyDefaultPragmas(instance: Database): void { } } - // Function to get a database instance. Defaults to 'data/tasks.db' + // Function to get a database instance. Defaults to 'tmp/tasks.db' in dev and '/app/data/tasks.db' in prod (overridable via DB_PATH/DATA_DIR) export function getDb(filename: string = 'tasks.db'): Database { - // Prioridad 1: DB_PATH (ruta completa al archivo). Si está definida, se usa tal cual. - const dbPathEnv = process?.env?.DB_PATH ? String(process.env.DB_PATH).trim() : ''; - if (dbPathEnv) { - const absolutePath = resolve(dbPathEnv); - // Crear directorio padre si no existe - try { - mkdirSync(dirname(absolutePath), { recursive: true }); - } catch (err) { - const code = (err && typeof err === 'object') ? (err as { code?: string }).code : undefined; - if (code !== 'EEXIST') throw err; // Solo ignorar "ya existe" - } - const instance = new Database(absolutePath); - applyDefaultPragmas(instance); - return instance; - } - - // Prioridad 2: DATA_DIR + filename (comportamiento actual) - // Determine base directory for the database (env DATA_DIR or default './data'), resolve to absolute - const dataDir = process?.env?.DATA_DIR ? String(process.env.DATA_DIR) : 'data'; - const dirPath = resolve(dataDir); + const absolutePath = resolveDbAbsolutePath(filename); - // Try to create data directory if it doesn't exist (ignore if already exists) + // Asegurar directorio padre try { - mkdirSync(dirPath, { recursive: true }); + mkdirSync(dirname(absolutePath), { recursive: true }); } catch (err) { const code = (err && typeof err === 'object') ? (err as { code?: string }).code : undefined; - if (code !== 'EEXIST') throw err; // Only ignore "already exists" errors + if (code !== 'EEXIST') throw err; } - const instance = new Database(join(dirPath, filename)); + const instance = new Database(absolutePath); applyDefaultPragmas(instance); return instance; } diff --git a/src/env/db-path.ts b/src/env/db-path.ts new file mode 100644 index 0000000..d2c2fcb --- /dev/null +++ b/src/env/db-path.ts @@ -0,0 +1,18 @@ +import { join, resolve } from 'path'; + +/** + * 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 + * - En producción (NODE_ENV=production) por defecto '/app/data' + * - En no-producción por defecto './tmp' + */ +export function resolveDbAbsolutePath(filename: string = 'tasks.db'): string { + const dbPathEnv = String(process.env.DB_PATH || '').trim(); + if (dbPathEnv) return resolve(dbPathEnv); + + const isProdEnv = String(process.env.NODE_ENV || 'development').trim().toLowerCase() === 'production'; + const dataDir = process.env.DATA_DIR ? String(process.env.DATA_DIR) : (isProdEnv ? '/app/data' : 'tmp'); + return resolve(join(dataDir, filename)); +} diff --git a/tsconfig.core.json b/tsconfig.core.json index 655e549..fff44bd 100644 --- a/tsconfig.core.json +++ b/tsconfig.core.json @@ -18,6 +18,7 @@ "src/tasks/**/*.ts", "src/tasks/**/*.d.ts", "src/services/**/*.ts", + "src/env/**/*.ts", "src/types/**/*.d.ts", "proxy.ts" ],