fix: añadir fallback de migraciones y export de crypto

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
webui
borja 2 weeks ago
parent 73ae69892f
commit 331b21ec71

@ -1,19 +1 @@
/**
* Genera un token aleatorio en base64url (sin padding).
*/
export function randomTokenBase64Url(bytes: number = 32): string {
const arr = new Uint8Array(bytes);
crypto.getRandomValues(arr);
const b64 = Buffer.from(arr).toString('base64');
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
/**
* Calcula SHA-256 en hexadecimal (minúsculas).
*/
export async function sha256Hex(input: string): Promise<string> {
const data = new TextEncoder().encode(input);
const hashBuf = await crypto.subtle.digest('SHA-256', data);
const bytes = new Uint8Array(hashBuf);
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
}
export { randomTokenBase64Url, sha256Hex } from '../../../../../src/utils/crypto';

@ -3,6 +3,7 @@ import { normalizeWhatsAppId } from './utils/whatsapp';
import { mkdirSync } from 'fs';
import { join, resolve, dirname } from 'path';
import { Migrator } from './db/migrator';
import { migrations } from './db/migrations';
function applyDefaultPragmas(instance: Database): void {
try {
@ -60,12 +61,48 @@ export function initializeDatabase(instance: Database) {
// Aplicar PRAGMAs por defecto (WAL, busy_timeout, FK, etc.)
applyDefaultPragmas(instance);
// Ejecutar migraciones up-only (sin baseline por defecto). Evitar backup duplicado aquí.
// Ejecutar migraciones con el Migrator; si no deja el esquema listo, aplicar fallback.
let migratorError: unknown = null;
try {
Migrator.migrateToLatest(instance, { withBackup: false, allowBaseline: false });
} catch (e) {
console.error('[initializeDatabase] Error al aplicar migraciones:', e);
throw e;
migratorError = e;
console.error('[initializeDatabase] Error al aplicar migraciones con Migrator:', e);
}
// Verificación mínima: si las tablas base no existen, aplicar fallback secuencial.
const tableExists = (name: string): boolean => {
try {
const row = instance
.query(`SELECT name FROM sqlite_master WHERE type='table' AND name = ?`)
.get(name) as any;
return Boolean(row && row.name === name);
} catch {
return false;
}
};
const needsFallback =
!tableExists('users') ||
!tableExists('tasks') ||
!tableExists('response_queue');
if (needsFallback) {
console.warn('[initializeDatabase] Migrator no dejó el esquema listo; aplicando fallback de migraciones secuenciales');
try {
instance.transaction(() => {
try { instance.exec(`PRAGMA foreign_keys = ON;`); } catch {}
for (const m of migrations) {
m.up(instance);
}
})();
} catch (fallbackErr) {
console.error('[initializeDatabase] Fallback de migraciones falló:', fallbackErr);
throw fallbackErr;
}
} else if (migratorError) {
// Si el Migrator falló pero el esquema ya está correcto, sólo loggeamos.
console.warn('[initializeDatabase] Migrator reportó error, pero el esquema parece estar correcto. Continuando.');
}
}

Loading…
Cancel
Save