This commit is contained in:
David Arranz 2025-04-28 10:54:34 +02:00
parent 9e9ddcceb3
commit 0065c4d4d3
10 changed files with 52 additions and 113 deletions

2
.vscode/launch.json vendored
View File

@ -53,7 +53,7 @@
"command": "pnpm run dev --filter=server",
"skipFiles": ["<node_internals>/**"],
"env": {
"NODE_OPTIONS": "--inspect"
"NODE_OPTIONS": "--inspect=0"
}
}
]

View File

@ -44,9 +44,6 @@ export function createApp(): Application {
next();
});
// Registrar rutas de la API
// app.use("/api/v1", v1Routes());
// Gestión global de errores.
// Siempre al final de la cadena de middlewares
// y después de las rutas.

View File

@ -1,66 +0,0 @@
import * as glob from "glob";
import * as path from "path";
import { DataTypes } from "sequelize";
import { sequelize } from "./database";
import { logger } from "@rdx/logger";
/**
* 🔹 Registra todos los modelos en Sequelize
*/
export const registerModels = async () => {
const cwd = path.resolve(`${__dirname}/../`);
const models: { [key: string]: any } = {};
// Opciones para buscar los modelos
const globOptions = {
cwd,
nocase: true,
nodir: true,
absolute: false,
};
try {
logger.info(`🔎 Searching models in: ${cwd}`);
// Buscamos los ficheros que terminen en .model.js o .model.ts
glob.sync("**/*.model.{js,ts}", globOptions).forEach((file) => {
//logger.info(`📄 File >> ${file}...`);
const modelDef = require(path.join(file)).default;
const model = typeof modelDef === "function" ? modelDef(sequelize, DataTypes) : false;
if (model) {
models[model.name] = model;
logger.info(`🔸 Model >> ${model.name} (${file})`);
} else {
logger.info(`🚫 No model`);
}
});
// Asociaciones y hooks de los modelos, si existen
for (const modelName in models) {
const model = models[modelName];
if (model.associate) {
model.associate(sequelize, models);
}
if (model.hooks) {
model.hooks(sequelize);
}
}
} catch (error) {
logger.error("❌ Error registering models:", error);
process.exit(1);
}
try {
// Sincronizamos DB en modo desarrollo
if (process.env.NODE_ENV !== "production") {
await sequelize.sync({ force: false, alter: true });
logger.info(`✔️${" "}Database synchronized successfully.`);
} else {
logger.warning("⚠️ Running in production mode - Skipping database sync.");
}
} catch (error) {
logger.error("❌ Error synchronizing database:", error);
process.exit(1);
}
};

View File

@ -1,6 +1,5 @@
import { logger } from "@rdx/logger";
import { ModelInitializer } from "@rdx/modules";
import { Sequelize } from "sequelize";
import { ModelInitializer, ModuleParams } from "@rdx/modules";
const registeredModels: Map<string, any> = new Map();
const initializedModels = new Set<string>();
@ -8,22 +7,23 @@ const initializedModels = new Set<string>();
/**
* 🔹 Registra todos los modelos en Sequelize
*/
export const registerModel = (models: ModelInitializer[], database: Sequelize) => {
export const registerModel = (models: ModelInitializer[], params: ModuleParams) => {
for (const initModelFn of models) {
const model = initModelFn(database);
const model = initModelFn();
if (model) {
registeredModels.set(model.name, model);
}
}
};
export const initModels = async (sequelize: Sequelize) => {
registeredModels.forEach((_, name) => loadModel(name, sequelize));
export const initModels = async (params: ModuleParams) => {
registeredModels.forEach((_, name) => loadModel(name, params));
try {
// Sincronizamos DB en modo desarrollo
const { database } = params;
if (process.env.NODE_ENV !== "production") {
await sequelize.sync({ force: false, alter: true });
await database.sync({ force: false, alter: true });
logger.info(`✔️${" "}Database synchronized successfully.`);
} else {
logger.warning("⚠️ Running in production mode - Skipping database sync.");
@ -34,19 +34,21 @@ export const initModels = async (sequelize: Sequelize) => {
}
};
export const loadModel = (name: string, sequelize: Sequelize) => {
export const loadModel = (name: string, params: ModuleParams) => {
if (initializedModels.has(name)) return;
const model = registeredModels.get(name);
if (!model) throw new Error(`❌ Model "${name}" not found.`);
const { database } = params;
// Asociaciones y hooks de los modelos, si existen
if (model.associate) {
model.associate(sequelize);
model.associate(database);
}
if (model.hooks) {
model.hooks(sequelize);
model.hooks(database);
}
initializedModels.add(name);

View File

@ -1,7 +1,5 @@
import { logger } from "@rdx/logger";
import { IModuleServer } from "@rdx/modules";
import { Application } from "express";
import { Sequelize } from "sequelize";
import { IModuleServer, ModuleParams } from "@rdx/modules";
import { initModels, registerModel } from "./model-loader";
import { registerService } from "./service-registry";
@ -15,14 +13,14 @@ export function registerModule(pkg: IModuleServer) {
registeredModules.set(pkg.metadata.name, pkg);
}
export function initModules(app: Application, database: Sequelize) {
export function initModules(params: ModuleParams) {
registeredModules.forEach((_, name) => {
loadModule(name, app, database);
loadModule(name, params);
});
initModels(database);
initModels(params);
}
const loadModule = (name: string, app: Application, database: Sequelize) => {
const loadModule = (name: string, params: ModuleParams) => {
if (initializedModules.has(name)) return;
const pkg = registeredModules.get(name);
@ -30,16 +28,16 @@ const loadModule = (name: string, app: Application, database: Sequelize) => {
// Resolver dependencias primero
const deps = pkg.metadata.dependencies || [];
deps.forEach((dep) => loadModule(dep, app, database));
deps.forEach((dep) => loadModule(dep, params));
// Inicializar el module
pkg.init(app);
pkg.init(params);
const pkgApi = pkg.registerDependencies?.();
const pkgApi = pkg.registerDependencies?.(params);
// Registrar modelos de Sequelize, si los expone
if (pkgApi?.models) {
registerModel(pkgApi.models, database);
registerModel(pkgApi.models, params);
}
// Registrar sus servicios, si los expone

View File

@ -3,7 +3,7 @@ import http from "http";
import { DateTime } from "luxon";
import { createApp } from "./app";
import { ENV } from "./config";
import { connectToDatabase, sequelize } from "./config/database";
import { connectToDatabase, sequelize as database } from "./config/database";
import { initModules } from "./core/helpers";
import { registerModules } from "./modules";
@ -68,11 +68,12 @@ const serverConnection = (conn: any) => {
//const sequelizeConn = createSequelizeAdapter();
//const firebirdConn = createFirebirdAdapter();
// Registrar paquetes de la aplicación
registerModules();
const app = createApp();
// Registrar paquetes de la aplicación
// Crea el servidor HTTP
const server = http
.createServer(app)
@ -125,7 +126,7 @@ process.on("uncaughtException", (error: Error) => {
// initStructure(sequelizeConn.connection);
// insertUsers();
initModules(app, sequelize);
initModules({ app, database: database, baseRoutePath: "/api/v1" });
server.listen(currentState.port, () => {
logger.info("To shut down your server, press <CTRL> + C at any time");

View File

@ -1,8 +1,7 @@
/* import { getService } from "@apps/server/src/core/service-registry"; */
import { logger } from "@rdx/logger";
import { IModuleServer } from "@rdx/modules";
import { Application } from "express";
import { initInvoiceModel } from "./intrastructure";
import { IModuleServer, ModuleParams } from "@rdx/modules";
import { initInvoiceModel, invoicesRouter } from "./intrastructure";
export const invoicesModule: IModuleServer = {
metadata: {
@ -10,15 +9,16 @@ export const invoicesModule: IModuleServer = {
version: "1.0.0",
dependencies: [],
},
init(app: Application) {
init(params: ModuleParams) {
// const contacts = getService<ContactsService>("contacts");
//invoicesRouter(app);
logger.info("🚀 Invoices module initialized");
invoicesRouter(params);
logger.info({ message: "🚀 Invoices module initialized", label: "invoices" });
},
registerDependencies() {
logger.info("🚀 Invoices module dependencies registered");
registerDependencies(params) {
const { database } = params;
logger.info({ message: "🚀 Invoices module dependencies registered", label: "invoices" });
return {
models: [(sequelize) => initInvoiceModel(sequelize)],
models: [() => initInvoiceModel(database)],
services: {
getInvoice: () => {},
/*...*/

View File

@ -1,4 +1,3 @@
import { Express } from "express";
import {
buildGetInvoiceController,
buildListInvoicesController,
@ -7,10 +6,17 @@ import {
import { buildCreateInvoiceController } from "#/server/presentation/controllers/create-invoice";
import { validateAndParseBody } from "@rdx/core";
import { NextFunction, Request, Response, Router } from "express";
import { ModuleParams } from "@rdx/modules";
import { Application, NextFunction, Request, Response, Router } from "express";
import { Sequelize } from "sequelize";
export const invoicesRouter = (app: Express, database: Sequelize) => {
export const invoicesRouter = (params: ModuleParams) => {
const { app, database, baseRoutePath } = params as {
app: Application;
database: Sequelize;
baseRoutePath: string;
};
const routes: Router = Router({ mergeParams: true });
routes.get(
@ -62,5 +68,5 @@ export const invoicesRouter = (app: Express, database: Sequelize) => {
}
);*/
app.use("/invoices", routes);
app.use(`${baseRoutePath}/invoices`, routes);
};

View File

@ -1,10 +1,9 @@
//Contrato para los Modules backend (Node.js)
import { Application } from "express";
import { ModuleDependencies, ModuleMetadata } from "./types";
import { ModuleDependencies, ModuleMetadata, ModuleParams } from "./types";
export interface IModuleServer {
metadata: ModuleMetadata;
init(app: Application): void;
registerDependencies?(): ModuleDependencies;
init(params: ModuleParams): void;
registerDependencies?(params: ModuleParams): ModuleDependencies;
}

View File

@ -1,8 +1,10 @@
// Contiene tipos comunes entre cliente y servidor
import { Sequelize } from "sequelize";
export type ModuleParams = {
[key: string]: any;
};
export type ModelInitializer = (sequelize: Sequelize) => any;
export type ModelInitializer = () => any;
export interface ModuleMetadata {
name: string;