import express from 'express'; import cors from 'cors'; import { initDb, getUsuarioByDni, getUsuarioById, getAllUsuarios, createUsuario, updateUsuario, deleteUsuario, verifyPassword, hashPassword, getAllPacientes, getPacienteById, createPaciente, updatePaciente, deletePaciente, getAllAreas, createArea, updateArea, deleteArea, getAllCamas, getCamaById, createCama, updateCama, deleteCama, getAllInternaciones, getInternacionById, createInternacion, updateInternacion, deleteInternacion, getAllEvoluciones, createEvolucion, updateEvolucion, deleteEvolucion, getAllLaboratorios, createLaboratorio, updateLaboratorio, deleteLaboratorio, getAllOtrosLaboratorios, createOtroLaboratorio, updateOtroLaboratorio, deleteOtroLaboratorio, getAllGlucemias, createGlucemia, updateGlucemia, deleteGlucemia, getAllAcidosBase, createAcidoBase, updateAcidoBase, deleteAcidoBase, getAllCultivos, createCultivo, updateCultivo, deleteCultivo, getAllEstudiosComplementarios, createEstudioComplementario, updateEstudioComplementario, deleteEstudioComplementario, getAllInterconsultas, createInterconsulta, updateInterconsulta, deleteInterconsulta, getAllAtb, createAtb, updateAtb, deleteAtb, getAllIndicaciones, createIndicacion, updateIndicacion, deleteIndicacion, getAllMovimientosIndicaciones, createMovimientoIndicacion, getAllPendientes, createPendiente, updatePendiente, deletePendiente, getValue, setValue, getDb, exportAllData, importAllData } from './db-mongodb.js'; // Capture live logs in-memory const logBuffer = []; const originalLog = console.log; const originalError = console.error; const originalWarn = console.warn; function addLog(type, args) { const message = args.map(arg => { if (typeof arg === 'object') { try { return JSON.stringify(arg); } catch { return String(arg); } } return String(arg); }).join(' '); const logEntry = `[${new Date().toISOString()}] [${type}] ${message}`; logBuffer.push(logEntry); if (logBuffer.length > 500) { logBuffer.shift(); } } console.log = (...args) => { addLog('INFO', args); originalLog.apply(console, args); }; console.error = (...args) => { addLog('ERROR', args); originalError.apply(console, args); }; console.warn = (...args) => { addLog('WARN', args); originalWarn.apply(console, args); }; const app = express(); app.use(cors({ origin: true, credentials: true })); app.use(express.json({ limit: '50mb' })); // UUID generator function generateUUID() { if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } // ========== STATE ENDPOINT (initial load) ========== app.get('/api/state', async (req, res) => { try { const areasList = await getAllAreas(); const usuariosList = await getAllUsuarios(); const state = { pacientes: await getAllPacientes(), areas: areasList, grupos: areasList, camas: await getAllCamas(), internaciones: await getAllInternaciones(), evoluciones: (await getAllEvoluciones()).map(e => ({ ...e, signosVitales: typeof e.signosVitales === 'string' ? JSON.parse(e.signosVitales) : e.signosVitales, examenFisico: typeof e.examenFisico === 'string' ? JSON.parse(e.examenFisico) : e.examenFisico })), laboratorios: (await getAllLaboratorios()).map(l => ({ ...l, resultados: typeof l.resultados === 'string' ? JSON.parse(l.resultados) : l.resultados })), otrosLaboratorios: await getAllOtrosLaboratorios(), glucemias: await getAllGlucemias(), acidosBase: await getAllAcidosBase(), cultivos: await getAllCultivos(), estudiosComplementarios: await getAllEstudiosComplementarios(), interconsultas: (await getAllInterconsultas()).map(ic => ({ ...ic, realizada: !!ic.realizada })), atb: await getAllAtb(), indicaciones: await getAllIndicaciones(), movimientosIndicaciones: await getAllMovimientosIndicaciones(), pendientes: await getAllPendientes(), usuarios: usuariosList.map(({ passwordHash, ...u }) => u), vistaActual: 'dashboard', currentInternacionId: null }; res.json(state); } catch (err) { console.error(err); res.status(500).json({ error: 'failed to read state' }); } }); // ========== USUARIOS ========== app.get('/api/usuarios', async (req, res) => { try { const usuarios = await getAllUsuarios(); const usuariosSinPassword = usuarios.map(({ passwordHash, ...u }) => u); res.json(usuariosSinPassword); } catch (err) { res.status(500).json({ error: 'Error al obtener usuarios' }); } }); app.post('/api/usuarios', async (req, res) => { try { const { apellido, nombre, dni, fechaNacimiento, email, rol, matriculaProfesional, password, areaId } = req.body; if (!apellido || !nombre || !dni || !fechaNacimiento || !email || !rol || !password) { return res.status(400).json({ error: 'Todos los campos obligatorios deben estar presentes' }); } const existente = await getUsuarioByDni(dni); if (existente) { return res.status(400).json({ error: 'Ya existe un usuario con ese DNI' }); } const passwordHash = hashPassword(password); const usuario = { id: generateUUID(), apellido, nombre, dni, fechaNacimiento, email, rol, matriculaProfesional: matriculaProfesional || null, passwordHash, areaId: areaId || null, fechaCreacion: new Date().toISOString().split('T')[0] }; await createUsuario(usuario); res.json({ ...usuario, passwordHash: undefined }); } catch (err) { res.status(500).json({ error: 'Error al crear usuario' }); } }); app.put('/api/usuarios/:id', async (req, res) => { try { const { id } = req.params; const { apellido, nombre, fechaNacimiento, email, rol, matriculaProfesional, areaId, password } = req.body; const usuario = await getUsuarioById(id); if (!usuario) { return res.status(404).json({ error: 'Usuario no encontrado' }); } const datos = {}; if (apellido !== undefined) datos.apellido = apellido; if (nombre !== undefined) datos.nombre = nombre; if (fechaNacimiento !== undefined) datos.fechaNacimiento = fechaNacimiento; if (email !== undefined) datos.email = email; if (rol !== undefined) datos.rol = rol; if (matriculaProfesional !== undefined) datos.matriculaProfesional = matriculaProfesional; if (areaId !== undefined) datos.areaId = areaId; if (password) datos.passwordHash = hashPassword(password); await updateUsuario(id, datos); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar usuario' }); } }); app.delete('/api/usuarios/:id', async (req, res) => { try { await deleteUsuario(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar usuario' }); } }); // ========== PACIENTES ========== app.get('/api/pacientes', async (req, res) => { try { res.json(await getAllPacientes()); } catch (err) { res.status(500).json({ error: 'Error al obtener pacientes' }); } }); app.post('/api/pacientes', async (req, res) => { try { const paciente = { ...req.body, id: req.body.id || generateUUID() }; await createPaciente(paciente); res.json(paciente); } catch (err) { res.status(500).json({ error: 'Error al crear paciente' }); } }); app.put('/api/pacientes/:id', async (req, res) => { try { await updatePaciente(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar paciente' }); } }); app.delete('/api/pacientes/:id', async (req, res) => { try { await deletePaciente(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar paciente' }); } }); // ========== AREAS & GRUPOS ========== app.get(['/api/areas', '/api/grupos'], async (req, res) => { try { res.json(await getAllAreas()); } catch (err) { res.status(500).json({ error: 'Error al obtener áreas/grupos' }); } }); app.post(['/api/areas', '/api/grupos'], async (req, res) => { try { const area = { ...req.body, id: req.body.id || generateUUID() }; await createArea(area); res.json(area); } catch (err) { res.status(500).json({ error: 'Error al crear área/grupo' }); } }); app.put(['/api/areas/:id', '/api/grupos/:id'], async (req, res) => { try { await updateArea(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar área/grupo' }); } }); app.delete(['/api/areas/:id', '/api/grupos/:id'], async (req, res) => { try { await deleteArea(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar área/grupo' }); } }); // ========== CAMAS ========== app.get('/api/camas', async (req, res) => { try { res.json(await getAllCamas()); } catch (err) { res.status(500).json({ error: 'Error al obtener camas' }); } }); app.put('/api/camas/:id', async (req, res) => { try { await updateCama(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar cama' }); } }); app.post('/api/camas', async (req, res) => { try { const cama = req.body; if (!cama.id) { cama.id = generateUUID(); } await createCama(cama); res.json(cama); } catch (err) { res.status(500).json({ error: 'Error al crear cama' }); } }); app.delete('/api/camas/:id', async (req, res) => { try { await deleteCama(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar cama' }); } }); // ========== INTERNACIONES ========== app.get('/api/internaciones', async (req, res) => { try { res.json(await getAllInternaciones()); } catch (err) { res.status(500).json({ error: 'Error al obtener internaciones' }); } }); app.post('/api/internaciones', async (req, res) => { try { const internacion = { ...req.body, id: req.body.id || generateUUID(), activa: req.body.activa !== undefined ? req.body.activa : true }; await createInternacion(internacion); res.json(internacion); } catch (err) { res.status(500).json({ error: 'Error al crear internacion' }); } }); app.put('/api/internaciones/:id', async (req, res) => { try { await updateInternacion(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar internacion' }); } }); app.delete('/api/internaciones/:id', async (req, res) => { try { await deleteInternacion(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar internacion' }); } }); // ========== EVOLUCIONES ========== app.get('/api/evoluciones', async (req, res) => { try { res.json(await getAllEvoluciones()); } catch (err) { res.status(500).json({ error: 'Error al obtener evoluciones' }); } }); app.post('/api/evoluciones', async (req, res) => { try { const evolucion = { ...req.body, id: req.body.id || generateUUID() }; await createEvolucion(evolucion); res.json(evolucion); } catch (err) { res.status(500).json({ error: 'Error al crear evolucion' }); } }); app.put('/api/evoluciones/:id', async (req, res) => { try { await updateEvolucion(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar evolucion' }); } }); app.delete('/api/evoluciones/:id', async (req, res) => { try { await deleteEvolucion(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar evolucion' }); } }); // ========== LABORATORIOS ========== app.get('/api/laboratorios', async (req, res) => { try { res.json(await getAllLaboratorios()); } catch (err) { res.status(500).json({ error: 'Error al obtener laboratorios' }); } }); app.post('/api/laboratorios', async (req, res) => { try { const laboratorio = { ...req.body, id: req.body.id || generateUUID() }; await createLaboratorio(laboratorio); res.json(laboratorio); } catch (err) { res.status(500).json({ error: 'Error al crear laboratorio' }); } }); app.put('/api/laboratorios/:id', async (req, res) => { try { await updateLaboratorio(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar laboratorio' }); } }); app.delete('/api/laboratorios/:id', async (req, res) => { try { await deleteLaboratorio(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar laboratorio' }); } }); // ========== OTROS LABORATORIOS ========== app.get('/api/otros-laboratorios', async (req, res) => { try { const records = await getAllOtrosLaboratorios(); res.json(records); } catch (error) { console.error('Error fetching otros-laboratorios:', error); res.status(500).json({ error: 'Failed to fetch otros-laboratorios' }); } }); app.post('/api/otros-laboratorios', async (req, res) => { try { const { pacienteId, fecha } = req.body; if (!pacienteId || !fecha) { return res.status(400).json({ error: 'pacienteId and fecha are required' }); } const record = { id: generateUUID(), observaciones: '', ...req.body }; const newRecord = await createOtroLaboratorio(record); res.status(201).json(newRecord); } catch (error) { console.error('Error creating otro laboratorio:', error); res.status(500).json({ error: 'Failed to create otro laboratorio' }); } }); app.put('/api/otros-laboratorios/:id', async (req, res) => { try { const result = await updateOtroLaboratorio(req.params.id, req.body); if (!result.success) return res.status(404).json({ error: 'Record not found' }); res.json(result); } catch (error) { console.error('Error updating otro laboratorio:', error); res.status(500).json({ error: 'Failed to update otro laboratorio' }); } }); app.delete('/api/otros-laboratorios/:id', async (req, res) => { try { const result = await deleteOtroLaboratorio(req.params.id); if (!result.success) return res.status(404).json({ error: 'Record not found' }); res.json({ message: 'Deleted successfully' }); } catch (error) { console.error('Error deleting otro laboratorio:', error); res.status(500).json({ error: 'Failed to delete otro laboratorio' }); } }); // ========== GLUCEMIAS ========== app.get('/api/glucemias', async (req, res) => { try { res.json(await getAllGlucemias()); } catch (err) { res.status(500).json({ error: 'Error al obtener glucemias' }); } }); app.post('/api/glucemias', async (req, res) => { try { const glucemia = { ...req.body, id: req.body.id || generateUUID() }; await createGlucemia(glucemia); res.json(glucemia); } catch (err) { res.status(500).json({ error: 'Error al crear glucemia' }); } }); app.put('/api/glucemias/:id', async (req, res) => { try { await updateGlucemia(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar glucemia' }); } }); app.delete('/api/glucemias/:id', async (req, res) => { try { await deleteGlucemia(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar glucemia' }); } }); // ========== ACIDOS BASE ========== app.get('/api/acid-os-base', async (req, res) => { try { res.json(await getAllAcidosBase()); } catch (err) { res.status(500).json({ error: 'Error al obtener acidos base' }); } }); app.post('/api/acid-os-base', async (req, res) => { try { const acido = { ...req.body, id: req.body.id || generateUUID() }; await createAcidoBase(acido); res.json(acido); } catch (err) { res.status(500).json({ error: 'Error al crear acido base' }); } }); app.put('/api/acid-os-base/:id', async (req, res) => { try { await updateAcidoBase(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar acido base' }); } }); app.delete('/api/acid-os-base/:id', async (req, res) => { try { await deleteAcidoBase(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar acido base' }); } }); // ========== CULTIVOS ========== app.get('/api/cultivos', async (req, res) => { try { res.json(await getAllCultivos()); } catch (err) { res.status(500).json({ error: 'Error al obtener cultivos' }); } }); app.post('/api/cultivos', async (req, res) => { try { const cultivo = { ...req.body, id: req.body.id || generateUUID() }; await createCultivo(cultivo); res.json(cultivo); } catch (err) { res.status(500).json({ error: 'Error al crear cultivo' }); } }); app.put('/api/cultivos/:id', async (req, res) => { try { await updateCultivo(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar cultivo' }); } }); app.delete('/api/cultivos/:id', async (req, res) => { try { await deleteCultivo(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar cultivo' }); } }); // ========== ESTUDIOS COMPLEMENTARIOS ========== app.get('/api/estudios-complementarios', async (req, res) => { try { res.json(await getAllEstudiosComplementarios()); } catch (err) { res.status(500).json({ error: 'Error al obtener estudios' }); } }); app.post('/api/estudios-complementarios', async (req, res) => { try { const estudio = { ...req.body, id: req.body.id || generateUUID() }; await createEstudioComplementario(estudio); res.json(estudio); } catch (err) { res.status(500).json({ error: 'Error al crear estudio' }); } }); app.put('/api/estudios-complementarios/:id', async (req, res) => { try { await updateEstudioComplementario(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar estudio' }); } }); app.delete('/api/estudios-complementarios/:id', async (req, res) => { try { await deleteEstudioComplementario(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar estudio' }); } }); // ========== INTERCONSULTAS ========== app.get('/api/interconsultas', async (req, res) => { try { res.json(await getAllInterconsultas()); } catch (err) { res.status(500).json({ error: 'Error al obtener interconsultas' }); } }); app.post('/api/interconsultas', async (req, res) => { try { const interconsulta = { ...req.body, id: req.body.id || generateUUID() }; await createInterconsulta(interconsulta); res.json(interconsulta); } catch (err) { res.status(500).json({ error: 'Error al crear interconsulta' }); } }); app.put('/api/interconsultas/:id', async (req, res) => { try { await updateInterconsulta(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar interconsulta' }); } }); app.delete('/api/interconsultas/:id', async (req, res) => { try { await deleteInterconsulta(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar interconsulta' }); } }); // ========== ATB ========== app.get('/api/atb', async (req, res) => { try { res.json(await getAllAtb()); } catch (err) { res.status(500).json({ error: 'Error al obtener ATB' }); } }); app.post('/api/atb', async (req, res) => { try { const atb = { ...req.body, id: req.body.id || generateUUID() }; await createAtb(atb); res.json(atb); } catch (err) { res.status(500).json({ error: 'Error al crear ATB' }); } }); app.put('/api/atb/:id', async (req, res) => { try { await updateAtb(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar ATB' }); } }); app.delete('/api/atb/:id', async (req, res) => { try { await deleteAtb(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar ATB' }); } }); // ========== INDICACIONES ========== app.get('/api/indicaciones', async (req, res) => { try { res.json(await getAllIndicaciones()); } catch (err) { res.status(500).json({ error: 'Error al obtener indicaciones' }); } }); app.post('/api/indicaciones', async (req, res) => { try { const indicacion = { ...req.body, id: req.body.id || generateUUID() }; await createIndicacion(indicacion); res.json(indicacion); } catch (err) { res.status(500).json({ error: 'Error al crear indicacion' }); } }); app.put('/api/indicaciones/:id', async (req, res) => { try { await updateIndicacion(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar indicacion' }); } }); app.delete('/api/indicaciones/:id', async (req, res) => { try { await deleteIndicacion(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar indicacion' }); } }); // ========== MOVIMIENTOS INDICACIONES ========== app.get('/api/movimientos-indicaciones', async (req, res) => { try { res.json(await getAllMovimientosIndicaciones()); } catch (err) { res.status(500).json({ error: 'Error al obtener movimientos' }); } }); app.post('/api/movimientos-indicaciones', async (req, res) => { try { const movimiento = { ...req.body, id: req.body.id || generateUUID() }; console.log('Creating movimiento:', movimiento); await createMovimientoIndicacion(movimiento); res.json(movimiento); } catch (err) { console.error('Error creating movimiento:', err); res.status(500).json({ error: err.message || 'Error al crear movimiento' }); } }); // ========== PENDIENTES ========== app.get('/api/pendientes', async (req, res) => { try { res.json(await getAllPendientes()); } catch (err) { res.status(500).json({ error: 'Error al obtener pendientes' }); } }); app.post('/api/pendientes', async (req, res) => { try { const pendiente = { ...req.body, id: req.body.id || generateUUID() }; await createPendiente(pendiente); res.json(pendiente); } catch (err) { res.status(500).json({ error: 'Error al crear pendiente' }); } }); app.put('/api/pendientes/:id', async (req, res) => { try { await updatePendiente(req.params.id, req.body); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar pendiente' }); } }); app.delete('/api/pendientes/:id', async (req, res) => { try { await deletePendiente(req.params.id); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al eliminar pendiente' }); } }); // ========== AUTH ========== app.post('/api/auth/login', async (req, res) => { try { const { dni, password } = req.body; if (!dni || !password) { return res.status(400).json({ error: 'DNI y contraseña requeridos' }); } const usuario = await getUsuarioByDni(dni); if (!usuario) { return res.status(401).json({ error: 'Usuario no encontrado' }); } const validPassword = await verifyPassword(dni, password); if (!validPassword) { return res.status(401).json({ error: 'Contraseña incorrecta' }); } const { passwordHash, ...userWithoutPassword } = usuario; res.json(userWithoutPassword); } catch (err) { res.status(500).json({ error: 'Error en autenticación' }); } }); app.post('/api/auth/change-password', async (req, res) => { try { const { dni, oldPassword, newPassword } = req.body; if (!dni || !oldPassword || !newPassword) { return res.status(400).json({ error: 'Todos los campos son requeridos' }); } const validPassword = await verifyPassword(dni, oldPassword); if (!validPassword) { return res.status(401).json({ error: 'Contraseña actual incorrecta' }); } const newHash = hashPassword(newPassword); const usuario = await getUsuarioByDni(dni); if (usuario) { await updateUsuario(usuario.id, { passwordHash: newHash }); } res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al cambiar contraseña' }); } }); app.put('/api/auth/update-email', async (req, res) => { try { const { dni, newEmail } = req.body; if (!dni || !newEmail) { return res.status(400).json({ error: 'DNI y email son requeridos' }); } const usuario = await getUsuarioByDni(dni); if (usuario) { await updateUsuario(usuario.id, { email: newEmail }); } res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al actualizar email' }); } }); // ========== ADMIN SYSTEM ENDPOINTS ========== app.post('/api/admin/mongosh', async (req, res) => { try { const { command } = req.body; if (!command) { return res.status(400).json({ error: 'Comando requerido' }); } const dbInstance = getDb(); if (!dbInstance) { return res.json({ result: 'Advertencia: MongoDB no está conectado. Utilizando store en memoria. Las consultas de mongosh no están disponibles.', isMemStore: true }); } const dbProxy = new Proxy(dbInstance, { get(target, prop) { if (typeof target[prop] !== 'undefined') { if (typeof target[prop] === 'function') { return target[prop].bind(target); } return target[prop]; } return target.collection(prop); } }); const { ObjectId } = await import('mongodb'); const evalFn = new Function('db', 'ObjectId', ` return (async () => { ${command.trim().includes('return') || command.trim().startsWith('{') || command.trim().includes(';') ? command : 'return (' + command + ')'} })(); `); let finalResult = await evalFn(dbProxy, ObjectId); // Si el resultado es un cursor de MongoDB (ej. db.collection.find()), lo convertimos a array if (finalResult && typeof finalResult === 'object' && typeof finalResult.toArray === 'function') { finalResult = await finalResult.toArray(); } res.json({ result: finalResult }); } catch (err) { res.status(400).json({ error: err.message || String(err) }); } }); app.get('/api/admin/db/export', async (req, res) => { try { const dump = await exportAllData(); res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Disposition', 'attachment; filename=hospital_backup.json'); res.json(dump); } catch (err) { res.status(500).json({ error: 'Error al exportar base de datos: ' + err.message }); } }); app.post('/api/admin/db/import', async (req, res) => { try { const dump = req.body; if (!dump || typeof dump !== 'object') { return res.status(400).json({ error: 'Formato de importación inválido' }); } await importAllData(dump); res.json({ ok: true }); } catch (err) { res.status(500).json({ error: 'Error al importar base de datos: ' + err.message }); } }); app.get('/api/admin/logs', async (req, res) => { try { let fileLogs = ''; try { const fs = await import('fs/promises'); fileLogs = await fs.readFile('server_log.txt', 'utf8'); } catch { // ignore } const memoryLogs = logBuffer.join('\n'); const combined = [fileLogs, '\n--- LOGS DE LA SESION EN VIVO ---', memoryLogs].filter(Boolean).join('\n'); res.setHeader('Content-Type', 'text/plain; charset=utf-8'); res.send(combined); } catch (err) { res.status(500).send('Error al leer logs: ' + err.message); } }); // Initialize DB and start server const PORT = process.env.PORT || 4000; const HOST = process.env.HOST || '0.0.0.0'; if (import.meta.url === `file://${process.argv[1]}`) { initDb() .then(() => { app.listen(PORT, HOST, () => { console.log(`Backend API running on http://${HOST}:${PORT}`); }); }) .catch((err) => { console.error('Failed to initialize MongoDB in standalone mode:', err); process.exit(1); }); } export { initDb }; export default app;