This commit is contained in:
David Arranz 2025-05-09 12:45:32 +02:00
parent e0785a58e6
commit 4dbffbe7dc
357 changed files with 4659 additions and 4278 deletions

View File

@ -1,5 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@repo/eslint-config/index.js"],
};

View File

@ -1,3 +0,0 @@
module.exports = {
extends: ["@repo/eslint-config"],
};

View File

@ -12,9 +12,9 @@ import {
type IAccountProps,
type IAccountService,
} from "@/contexts/accounts/domain";
import { Maybe, Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { Maybe, Result } from "@repo/rdx-utils";
import { ICreateAccountRequestDTO } from "../presentation";
export class CreateAccountUseCase {

View File

@ -1,8 +1,8 @@
import { Account, IAccountService } from "@/contexts/accounts/domain";
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { Result } from "@repo/rdx-utils";
export class GetAccountUseCase {
constructor(

View File

@ -1,6 +1,6 @@
import { Account, IAccountService } from "@/contexts/accounts/domain";
import { Collection, Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { Collection, Result } from "@repo/rdx-utils";
export class ListAccountsUseCase {
constructor(

View File

@ -1,6 +1,6 @@
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { TransactionManager } from "@/core/common/infrastructure/database";
import { Result } from "@repo/rdx-utils";
import { AccountService } from "../domain";
import { UpdateAccountUseCase } from "./update-account.use-case";

View File

@ -7,9 +7,9 @@ import {
} from "@/core/common/domain";
import { Account, IAccountProps, IAccountService } from "@/contexts/accounts/domain";
import { Maybe, Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { Maybe, Result } from "@repo/rdx-utils";
import { IUpdateAccountRequestDTO } from "../presentation";
export class UpdateAccountUseCase {

View File

@ -6,7 +6,7 @@ import {
type TINNumber,
UniqueID,
} from "@/core";
import { Maybe, Result } from "@/core/common/helpers";
import { Maybe, Result } from "@repo/rdx-utils";
import { AccountStatus } from "../value-objects";
export interface IAccountProps {

View File

@ -1,5 +1,5 @@
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Account } from "../aggregates";
export interface IAccountRepository {

View File

@ -5,7 +5,7 @@ import {
TINNumber,
UniqueID,
} from "@/core/common/domain";
import { Maybe, Result } from "@/core/common/helpers";
import { Maybe, Result } from "@repo/rdx-utils";
import { Account, IAccountProps } from "../aggregates";
import { IAccountRepository } from "../repositories";
import { AccountStatus } from "../value-objects";

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Account, IAccountProps } from "../aggregates";
export interface IAccountService {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Transaction } from "sequelize";
import { Account, IAccountProps } from "../aggregates";
import { IAccountRepository } from "../repositories";

View File

@ -1,5 +1,5 @@
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
interface IAccountStatusProps {
value: string;

View File

@ -6,12 +6,12 @@ import {
TINNumber,
UniqueID,
} from "@/core/common/domain";
import { Maybe, Result } from "@/core/common/helpers";
import {
type ISequelizeMapper,
type MapperParamsType,
SequelizeMapper,
} from "@/core/common/infrastructure/sequelize/sequelize-mapper";
import { Maybe, Result } from "@repo/rdx-utils";
import { AccountCreationAttributes, AccountModel } from "../sequelize/account.model";
export interface IAccountMapper

View File

@ -1,8 +1,8 @@
import { Account } from "@/contexts/accounts/domain";
import { IAccountRepository } from "@/contexts/accounts/domain/repositories/account-repository.interface";
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { SequelizeRepository } from "@/core/common/infrastructure";
import { Collection, Result } from "@repo/rdx-utils";
import { Transaction } from "sequelize";
import { IAccountMapper, accountMapper } from "../mappers/account.mapper";
import { AccountModel } from "./account.model";

View File

@ -1,5 +1,5 @@
import { Account } from "@/contexts/accounts/domain";
import { ensureBoolean, ensureNumber, ensureString } from "@/core/common/helpers";
import { ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils";
import { ICreateAccountResponseDTO } from "../../dto";
export interface ICreateAccountPresenter {

View File

@ -1,5 +1,5 @@
import { Account } from "@/contexts/accounts/domain";
import { ensureBoolean, ensureNumber, ensureString } from "@/core/common/helpers";
import { ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils";
import { IGetAccountResponseDTO } from "../../dto";
export interface IGetAccountPresenter {

View File

@ -1,5 +1,5 @@
import { Account } from "@/contexts/accounts/domain";
import { Collection, ensureBoolean, ensureNumber, ensureString } from "@/core/common/helpers";
import { Collection, ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils";
import { IListAccountsResponseDTO } from "../../dto";
export interface IListAccountsPresenter {

View File

@ -1,5 +1,5 @@
import { Account } from "@/contexts/accounts/domain";
import { ensureBoolean, ensureNumber, ensureString } from "@/core/common/helpers";
import { ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils";
import { IUpdateAccountResponseDTO } from "../../dto";
export interface IUpdateAccountPresenter {

View File

@ -1,5 +1,5 @@
import { Collection, Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { Collection, Result } from "@repo/rdx-utils";
import { User } from "../../domain";
import { IUserService } from "../../domain/services";

View File

@ -1,6 +1,6 @@
import { Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { Result } from "@repo/rdx-utils";
import { RegisterData } from "../../domain";
import { IAuthService } from "../../domain/services";

View File

@ -1,4 +1,4 @@
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { AggregateRoot, EmailAddress, UniqueID } from "@/core/common/domain";
import { UserAuthenticatedEvent } from "../events";

View File

@ -1,5 +1,5 @@
import { AggregateRoot, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
export type IRoleProps = {};

View File

@ -1,5 +1,5 @@
import { AggregateRoot, EmailAddress, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { UserAuthenticatedEvent } from "../events";
import { Username } from "../value-objects";

View File

@ -1,5 +1,5 @@
import { DomainEntity, EmailAddress, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
export interface IJWTPayloadProps {
tabId: UniqueID;

View File

@ -1,5 +1,5 @@
import { DomainEntity, EmailAddress, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { PlainPassword } from "../value-objects";
export interface ILoginDataProps {

View File

@ -1,5 +1,5 @@
import { DomainEntity, EmailAddress, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
export interface ILogoutDataProps {
email: EmailAddress;

View File

@ -1,5 +1,5 @@
import { DomainEntity, EmailAddress } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { HashPassword, Username } from "../value-objects";
export interface IRegisterDataProps {

View File

@ -1,5 +1,5 @@
import { DomainEntity, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
export interface ITabContextProps {
tabId: UniqueID;

View File

@ -1,4 +1,4 @@
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { EmailAddress } from "@/core/common/domain";
import { AuthenticatedUser } from "../aggregates";

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { Transaction } from "sequelize";
import { TabContext } from "../entities";

View File

@ -1,5 +1,5 @@
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { User } from "../aggregates";
export interface IUserRepository {

View File

@ -1,5 +1,5 @@
import { EmailAddress } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import {
AuthenticatedUser,
IJWTPayload,

View File

@ -1,5 +1,5 @@
import { EmailAddress } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import {
AuthenticatedUser,
type IJWTPayload,

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { TabContext } from "../entities";
export interface ITabContextService {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { TabContext } from "../entities";
import { ITabContextRepository } from "../repositories";
import { ITabContextService } from "./tab-context-service.interface";

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { User } from "../aggregates";
export interface IUserService {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { IUserRepository, User } from "..";
import { IUserService } from "./user-service.interface";

View File

@ -1,5 +1,5 @@
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { z } from "zod";
const RoleSchema = z.enum(["Admin", "User", "Manager", "Editor"]);

View File

@ -1,6 +1,6 @@
import bcrypt from "bcrypt";
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import bcrypt from "bcrypt";
import { z } from "zod";
interface HashPasswordProps {

View File

@ -1,5 +1,5 @@
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { z } from "zod";
interface PlainPasswordProps {
@ -32,6 +32,5 @@ export class PlainPassword extends ValueObject<PlainPasswordProps> {
toPrimitive() {
return this.props.value;
}
}

View File

@ -1,5 +1,5 @@
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { z } from "zod";
interface TokenProps {
@ -32,6 +32,5 @@ export class Token extends ValueObject<TokenProps> {
toPrimitive() {
return this.props.value;
}
}

View File

@ -1,5 +1,5 @@
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { z } from "zod";
interface UsernameProps {

View File

@ -1,10 +1,10 @@
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import {
type ISequelizeMapper,
type MapperParamsType,
SequelizeMapper,
} from "@/core/common/infrastructure";
import { Result } from "@repo/rdx-utils";
import { TabContext } from "../../domain";
import { TabContextCreationAttributes, TabContextModel } from "../sequelize";

View File

@ -1,10 +1,10 @@
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import {
type ISequelizeMapper,
type MapperParamsType,
SequelizeMapper,
} from "@/core/common/infrastructure/sequelize/sequelize-mapper";
import { Result } from "@repo/rdx-utils";
import { User, Username } from "../../domain";
import { UserCreationAttributes, UserModel } from "../sequelize";

View File

@ -1,9 +1,9 @@
import { NextFunction, Response } from "express";
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { Result } from "@repo/rdx-utils";
import passport from "passport";
import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt";
import { TabContext } from "../../domain";

View File

@ -1,6 +1,6 @@
import { EmailAddress } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { SequelizeRepository } from "@/core/common/infrastructure";
import { Result } from "@repo/rdx-utils";
import { Sequelize, Transaction } from "sequelize";
import { AuthenticatedUser, IAuthenticatedUserRepository, Username } from "../../domain";
import { IAuthenticatedUserMapper } from "../mappers";

View File

@ -1,6 +1,6 @@
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { SequelizeRepository } from "@/core/common/infrastructure";
import { Result } from "@repo/rdx-utils";
import { Op, Sequelize, Transaction } from "sequelize";
import { ITabContextRepository, TabContext } from "../../domain/";
import { ITabContextMapper } from "../mappers";

View File

@ -1,6 +1,6 @@
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { SequelizeRepository } from "@/core/common/infrastructure";
import { Collection, Result } from "@repo/rdx-utils";
import { Sequelize, Transaction } from "sequelize";
import { IUserRepository, User } from "../../domain";
import { IUserMapper } from "../mappers";

View File

@ -1,4 +1,4 @@
import { Collection, ensureString } from "@/core/common/helpers";
import { Collection, ensureString } from "@repo/rdx-utils";
import { User } from "../../domain";
import { IListUsersResponseDTO } from "../../dto";

View File

@ -1,5 +1,5 @@
import { Collection, Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { Collection, Result } from "@repo/rdx-utils";
import { Contact, IContactService } from "../domain";
export class ListContactsUseCase {

View File

@ -6,7 +6,7 @@ import {
type TINNumber,
UniqueID,
} from "@/core/common/domain";
import { Maybe, Result } from "@/core/common/helpers";
import { Maybe, Result } from "@repo/rdx-utils";
export interface IContactProps {
reference: string;

View File

@ -1,5 +1,5 @@
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Contact } from "../aggregates";
export interface IContactRepository {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Contact } from "../aggregates";
export interface IContactService {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Contact } from "../aggregates";
import { IContactRepository } from "../repositories";
import { IContactService } from "./contact-service.interface";

View File

@ -5,12 +5,12 @@ import {
TINNumber,
UniqueID,
} from "@/core/common/domain";
import { Maybe, Result } from "@/core/common/helpers";
import {
type ISequelizeMapper,
type MapperParamsType,
SequelizeMapper,
} from "@/core/common/infrastructure/sequelize/sequelize-mapper";
import { Maybe, Result } from "@repo/rdx-utils";
import { Contact } from "../../domain";
import { ContactCreationAttributes, ContactModel } from "../sequelize/contact.model";

View File

@ -1,6 +1,6 @@
import { EmailAddress, UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { SequelizeRepository } from "@/core/common/infrastructure";
import { Collection, Result } from "@repo/rdx-utils";
import { Transaction } from "sequelize";
import { Contact, IContactRepository } from "../../domain";
import { IContactMapper, contactMapper } from "../mappers";

View File

@ -1,4 +1,4 @@
import { Collection, ensureBoolean, ensureNumber, ensureString } from "@/core/common/helpers";
import { Collection, ensureBoolean, ensureNumber, ensureString } from "@repo/rdx-utils";
import { Contact } from "../../../domain";
import { IListContactsResponseDTO } from "../../dto";

View File

@ -1,8 +1,8 @@
import { ICustomerInvoiceService } from "@/contexts/customer-billing/domain";
import { CustomerInvoice } from "@/contexts/customer-billing/domain/aggregates";
import { UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { Result } from "@repo/rdx-utils";
export class GetCustomerInvoiceUseCase {
constructor(

View File

@ -1,5 +1,5 @@
import { Collection, Result } from "@/core/common/helpers";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { Collection, Result } from "@repo/rdx-utils";
import { CustomerInvoice, ICustomerInvoiceService } from "../domain";
export class ListCustomerInvoicesUseCase {

View File

@ -1,5 +1,5 @@
import { AggregateRoot, UniqueID, UtcDate } from "@/core/common/domain";
import { Maybe, Result } from "@/core/common/helpers";
import { Maybe, Result } from "@repo/rdx-utils";
import { Customer, CustomerInvoiceItem } from "../entities";
import { InvoiceStatus } from "../value-objetcs";

View File

@ -1,6 +1,6 @@
import { DomainEntity, MoneyValue, Percentage, UniqueID } from "@/core/common/domain";
import { Quantity } from "@/core/common/domain/value-objects/quantity";
import { Maybe, Result } from "@/core/common/helpers";
import { Maybe, Result } from "@repo/rdx-utils";
export interface ICustomerInvoiceItemProps {
description: Maybe<string>; // Descripción del artículo o servicio

View File

@ -1,5 +1,5 @@
import { AggregateRoot, PostalAddress, TINNumber, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
export interface ICustomerProps {
name: string;

View File

@ -1,5 +1,5 @@
import { Slug } from "@/core/common/domain";
import { Collection } from "@/core/common/helpers";
import { Collection } from "@repo/rdx-utils";
import { Tax } from "./tax";
export class TaxCollection extends Collection<Tax> {

View File

@ -1,5 +1,5 @@
import { DomainEntity, Percentage, Slug, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
interface ITaxProps {
slug: Slug;

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { CustomerInvoice } from "../aggregates";
export interface ICustomerInvoiceRepository {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { CustomerInvoice } from "../aggregates";
export interface ICustomerInvoiceService {

View File

@ -1,5 +1,5 @@
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { CustomerInvoice } from "../aggregates";
import { ICustomerInvoiceRepository } from "../repositories";
import { ICustomerInvoiceService } from "./customer-invoice-service.interface";

View File

@ -1,5 +1,5 @@
import { ValueObject } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
interface IInvoiceStatusProps {
value: string;

View File

@ -1,12 +1,12 @@
import { Customer, CustomerInvoice } from "@/contexts/customer-billing/domain";
import { InvoiceStatus } from "@/contexts/customer-billing/domain/value-objetcs";
import { PostalAddress, TINNumber, UniqueID, UtcDate } from "@/core/common/domain";
import { Maybe, Result } from "@/core/common/helpers";
import {
type ISequelizeMapper,
type MapperParamsType,
SequelizeMapper,
} from "@/core/common/infrastructure/sequelize/sequelize-mapper";
import { Maybe, Result } from "@repo/rdx-utils";
import {
CustomerInvoiceCreationAttributes,
CustomerInvoiceModel,

View File

@ -1,7 +1,7 @@
import { CustomerInvoice, ICustomerInvoiceRepository } from "@/contexts/customer-billing/domain";
import { UniqueID } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { SequelizeRepository } from "@/core/common/infrastructure";
import { Collection, Result } from "@repo/rdx-utils";
import { Transaction } from "sequelize";
import {
type ICustomerInvoiceMapper,

View File

@ -1,4 +1,4 @@
import { Collection, ensureString } from "@/core/common/helpers";
import { Collection, ensureString } from "@repo/rdx-utils";
import { CustomerInvoice } from "@/contexts/customer-billing/domain";
import { IListCustomerInvoicesResponseDTO } from "../../../dto";

View File

@ -7,7 +7,7 @@
"build": "tsc && tsup",
"start:dev": "node --import=tsx --watch src/index.ts",
"start:prod": "node dist/index.js",
"clean": "rm -rf dist",
"clean": "rm -rf dist node_modules",
"typecheck": "tsc --noEmit",
"test": "jest --config=./jest.config.ts --verbose",
"lint": "biome lint --fix",
@ -27,7 +27,7 @@
"@types/jest": "^29.5.14",
"@types/jsonwebtoken": "^9.0.8",
"@types/luxon": "^3.4.2",
"@types/node": "^22.10.7",
"@types/node": "^22.15.12",
"@types/passport": "^1.0.16",
"@types/passport-jwt": "^4.0.1",
"@types/passport-local": "^1.0.38",
@ -40,14 +40,14 @@
"typescript": "^5.8.3"
},
"dependencies": {
"@erp/auth": "workspace:*",
"@erp/core": "workspace:*",
"bcrypt": "^5.1.1",
"cls-rtracer": "^2.6.3",
"cors": "^2.8.5",
"dinero.js": "^1.9.1",
"dotenv": "^16.5.0",
"esbuild": "^0.24.0",
"express": "^4.18.2",
"glob": "^11.0.1",
"helmet": "^8.0.0",
"http": "0.0.1-security",
"http-status": "^2.1.0",
@ -74,14 +74,9 @@
"node": ">=22"
},
"tsup": {
"entry": [
"src/index.ts"
],
"entry": ["src/index.ts"],
"outDir": "dist",
"format": [
"esm",
"cjs"
],
"format": ["esm", "cjs"],
"target": "es2020",
"sourcemap": true,
"clean": true,

View File

@ -3,9 +3,8 @@ import dotenv from "dotenv";
import express, { Application } from "express";
import helmet from "helmet";
import responseTime from "response-time";
import { logger } from "./core/common/infrastructure/logger";
import { globalErrorHandler } from "./core/common/presentation";
import { v1Routes } from "./routes";
import { logger } from "./core/logger";
dotenv.config();
@ -47,8 +46,8 @@ export function createApp(): Application {
});
// Registrar rutas de la API
app.use("/api/v1", v1Routes());
// initPackages(app, sequelize);
// app.use("/api/v1", v1Routes());
//initModules(app, database);
// Gestión global de errores.
// Siempre al final de la cadena de middlewares

View File

@ -1,4 +1,4 @@
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import dotenv from "dotenv";
import { Sequelize } from "sequelize";
import { registerModels } from "./register-models";

View File

@ -1,5 +1,5 @@
import * as path from "path";
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import * as glob from "glob";
import { DataTypes, Sequelize } from "sequelize";

View File

@ -1,6 +1,6 @@
import { IModuleServer, ModuleParams } from "@/core";
import { logger } from "@/core/common/infrastructure/logger";
import { invoicesRouter, models } from "./intrastructure";
import { logger } from "@/core/logger";
import { invoicesRouter, models } from "../../../../../modules/invoices/src/api/intrastructure";
export const invoicesModule: IModuleServer = {
metadata: {

View File

@ -1 +0,0 @@
export type IAggregateRootRepository<T> = {}

View File

@ -1,5 +0,0 @@
export * from "./collection";
export * from "./maybe";
export * from "./result";
export * from "./utils";
export * from "./modules";

View File

@ -1,92 +0,0 @@
export class Result<T, E extends Error = Error> {
private readonly _isSuccess: boolean;
private readonly _data?: T;
private readonly _error?: E;
private constructor(props: { isSuccess: boolean; error?: E; data?: T }) {
const { isSuccess, error, data } = props;
if (isSuccess && error) {
throw new Error(`InvalidOperation: A result cannot be successful and contain an error`);
}
if (!isSuccess && !error) {
throw new Error(`InvalidOperation: A failing result needs to contain an error message`);
}
this._isSuccess = isSuccess;
this._error = error;
this._data = data;
Object.freeze(this);
}
static ok<T>(data?: T): Result<T, never> {
return new Result<T, never>({ isSuccess: true, data });
}
static fail<E extends Error = Error>(error?: E): Result<never, E> {
return new Result<never, E>({ isSuccess: false, error });
}
static combine(results: Result<any, any>[]): Result<any, any> {
for (const result of results) {
if (result.isFailure) {
return result;
}
}
return Result.ok<any>();
}
get isSuccess(): boolean {
return this._isSuccess;
}
get isFailure(): boolean {
return !this._isSuccess;
}
get data(): T {
return this.getData();
}
get error(): E {
return this.getError();
}
getError(): E {
if (this._isSuccess) {
throw new Error("Cannot get error from a successful result.");
}
return this._error as E;
}
getData(): T {
if (!this._isSuccess) {
throw new Error("Cannot get value data from a failed result.");
}
return this._data as T;
}
map<U>(fn: (value: T) => U): Result<U, Error> {
if (this.isSuccess && this._data !== undefined) {
return Result.ok<U>(fn(this.data));
}
return Result.fail(this.error || new Error("Unknown error"));
}
/**
* 🔹 `getOrElse(defaultValue: T): T`
* Si el `Result` es un `ok`, devuelve `data`, de lo contrario, devuelve `defaultValue`.
*/
getOrElse(defaultValue: any): T | any {
return this._isSuccess ? this.data : defaultValue;
}
/**
* 🔹 `match<R>(onOk: (data: T) => R, onError: (error: E) => R): R`
* Evalúa el `Result`: ejecuta `onOk()` si es `ok` o `onError()` si es `fail`.
*/
match<R>(onOk: (data: T) => R, onError: (error: E) => R): R {
return this._isSuccess ? onOk(this.data) : onError(this.error);
}
}

View File

@ -1,4 +1,2 @@
export * from "./domain";
export * from "./helpers";
export * from "./infrastructure";
export * from "./presentation";

View File

@ -1,5 +1,4 @@
export * from "./sequelize";
export * from "./logger";
export * from "./database";
//export * from "./passport";
export * from "./sequelize";

View File

@ -1,111 +0,0 @@
import rTracer from "cls-rtracer";
import dotenv from "dotenv";
import path from "path";
import { createLogger, format, transports } from "winston";
import DailyRotateFile from "winston-daily-rotate-file";
dotenv.config();
//const splatSymbol = Symbol.for("splat");
const initLogger = () => {
const isProduction = process.env.NODE_ENV === "production";
const consoleFormat = format.combine(
format.errors({ stack: !isProduction }),
format.colorize(),
format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
format.align(),
format.splat(),
format.printf((info) => {
const { level, timestamp, stack, label, meta, error } = info;
const rid = rTracer.id();
let message = info.message;
if (typeof message === "object") {
message = JSON.stringify(message, null, 3);
}
let out = `${timestamp}`;
if (rid) {
out = `${out} [request-id:${rid}]`;
}
out = `${out} - ${level}: [${label}]: ${message}`;
if (stack) {
out = `${out} - ${stack}`;
}
if (meta) {
out = `${out} - ${JSON.stringify(meta, null, 3)}`;
}
if (error) {
out = `${out} - ${JSON.stringify(error, null, 3)}`;
}
return out;
})
);
const fileFormat = format.combine(
format.timestamp(),
format.splat(),
format.label({ label: path.basename(String(require.main?.filename)) }),
//format.metadata(),
format.metadata({ fillExcept: ["message", "level", "timestamp", "label"] }),
format.simple(),
format.json()
);
const logger = createLogger(
isProduction
? {
level: isProduction ? "error" : "debug",
format: fileFormat,
transports: [
new DailyRotateFile({
dirname: isProduction ? "/logs" : ".",
filename: "error-%DATE%.log",
datePattern: "YYYY-MM-DD",
utc: true,
level: "error",
maxSize: "5m",
maxFiles: "1d",
}),
new DailyRotateFile({
dirname: isProduction ? "/logs" : ".",
filename: "debug-%DATE%.log",
datePattern: "YYYY-MM-DD",
utc: true,
level: "debug",
maxSize: "5m",
maxFiles: "1d",
}),
],
}
: {}
);
//
// If we're not in production then log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (!isProduction) {
logger.add(
new transports.Console({
format: consoleFormat,
level: "debug",
})
);
}
return logger;
};
const logger = initLogger();
export { logger };

View File

@ -1,5 +1,5 @@
import { DomainEntity } from "@/core/common/domain";
import { Collection, Result } from "@/core/common/helpers";
import { Collection, Result } from "@repo/rdx-utils";
import { Model } from "sequelize";
export type MapperParamsType = Record<string, any>;

View File

@ -1,5 +1,5 @@
import { IAggregateRootRepository, UniqueID } from "@/core/common/domain";
import { Result } from "@/core/common/helpers";
import { Result } from "@repo/rdx-utils";
import { ModelDefined, Sequelize, Transaction } from "sequelize";
import { logger } from "../logger";

View File

@ -1,4 +1,4 @@
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { NextFunction, Request, Response } from "express";
import httpStatus from "http-status";
import { ApiError } from "./api-error";

View File

@ -1,4 +1,4 @@
import { logger } from "@/core/common/infrastructure/logger";
import { logger } from "@/core/logger";
import { NextFunction, Request, Response } from "express";
import { ApiError } from "../api-error";

View File

@ -1,5 +1,5 @@
import { ModuleParams } from "../common";
import { logger } from "../common/infrastructure/logger";
import { ModuleParams } from "@erp/core";
import { logger } from "../logger";
const allModelInitializers: any[] = [];
const registeredModels: { [key: string]: any } = {};
@ -12,13 +12,12 @@ export const registerModels = (models: any[], params?: ModuleParams) => {
};
export const initModels = async (params: ModuleParams) => {
logger.info({ message: "Init models...", label: "initModels" });
logger.info("Init models...", { label: "initModels" });
const { database } = params;
if (!database) {
const error = new Error("❌ Database not found.");
logger.error({
message: error.message,
logger.error(error.message, {
label: "initModels",
});
throw error;
@ -28,10 +27,7 @@ export const initModels = async (params: ModuleParams) => {
for (const initializer of allModelInitializers) {
const model = initializer(database);
registeredModels[model.name] = model;
logger.info({
message: `🔸 Model "${model.name}" registered (sequelize)`,
label: "registerModel",
});
logger.info(`🔸 Model "${model.name}" registered (sequelize)`, { label: "registerModel" });
}
// Configurar asociaciones
@ -45,16 +41,15 @@ export const initModels = async (params: ModuleParams) => {
// Sincronizamos DB en modo desarrollo
if (process.env.NODE_ENV !== "production") {
await database.sync({ force: false, alter: true });
logger.info({ message: `✔️${" "}Database synchronized successfully.`, label: "initModels" });
logger.info(`✔️${" "}Database synchronized successfully.`, { label: "initModels" });
} else {
logger.warning({
message: "⚠️ Running in production mode - Skipping database sync.",
logger.warn("⚠️ Running in production mode - Skipping database sync.", {
label: "initModels",
});
}
} catch (err) {
const error = err as Error;
logger.error({ message: "❌ Error synchronizing database:", error, label: "initModels" });
logger.error("❌ Error synchronizing database:", { error, label: "initModels" });
throw error;
}
};

View File

@ -1,4 +1,5 @@
import { IModuleServer, ModuleParams, logger } from "../common";
import { IModuleServer, ModuleParams } from "@erp/core";
import { logger } from "../logger";
import { initModels, registerModels } from "./model-loader";
import { registerService } from "./service-registry";
@ -48,5 +49,5 @@ const loadModule = (name: string, params: ModuleParams) => {
}
initializedModules.add(name);
logger.info({ message: `✅ Module "${name}" registered`, label: "loadModule" });
logger.info(`✅ Module "${name}" registered`, { label: "loadModule" });
};

View File

@ -0,0 +1 @@
export * from "./httpServer";

View File

@ -0,0 +1,15 @@
import { ILogger } from "@erp/core";
export class ConsoleLogger implements ILogger {
info(message: string, meta?: any) {
console.log(`[INFO] ${message}`, meta ?? "");
}
warn(message: string, meta?: any) {
console.warn(`[WARN] ${message}`, meta ?? "");
}
error(message: string, error?: Error | any) {
console.error(`[ERROR] ${message}`, error?.stack || error);
}
}

View File

@ -0,0 +1,8 @@
import { ILogger } from "@erp/core";
import { ConsoleLogger } from "./console-logger";
// Aquí podrías cambiar por SentryLogger en el futuro
const logger: ILogger = new ConsoleLogger();
export { logger };
export type { ILogger };

View File

@ -0,0 +1,22 @@
import { ILogger } from "@erp/core";
export class SentryLogger implements ILogger {
// biome-ignore lint/complexity/noUselessConstructor: <explanation>
constructor() {
//Sentry.init({ dsn: process.env.SENTRY_DSN });
}
info(message: string, meta?: any) {
console.log(`[INFO] ${message}`, meta);
}
warn(message: string, meta?: any) {
console.warn(`[WARN] ${message}`, meta);
//Sentry.captureMessage(message, "warning");
}
error(message: string, error?: any) {
console.error(`[ERROR] ${message}`, error);
//Sentry.captureException(error);
}
}

View File

@ -0,0 +1,60 @@
import { ILogger } from "@erp/core";
import rTracer from "cls-rtracer";
import { createLogger, format, transports } from "winston";
const winston = createLogger({
level: "info",
format: format.combine(
format.colorize(),
format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
format.errors({ stack: true }),
format.align(),
format.splat(),
format.json(),
format.printf((info) => {
const { level, timestamp, stack, label, meta, error } = info;
const rid = rTracer.id();
let message = info.message;
if (typeof message === "object") {
message = JSON.stringify(message, null, 3);
}
let out = `${timestamp}`;
if (rid) {
out = `${out} [request-id:${rid}]`;
}
out = `${out} - ${level}: [${label}]: ${message}`;
if (stack) {
out = `${out} - ${stack}`;
}
if (meta) {
out = `${out} - ${JSON.stringify(meta, null, 3)}`;
}
if (error) {
out = `${out} - ${JSON.stringify(error, null, 3)}`;
}
return out;
})
),
transports: [new transports.Console()],
});
export class WinstonLogger implements ILogger {
info(message: string, meta?: any) {
winston.info(message, meta ?? {});
}
warn(message: string, meta?: any) {
winston.warn(message, meta ?? {});
}
error(message: string, error?: any) {
winston.error(message, { error: error?.stack || error });
}
}

View File

@ -1,55 +0,0 @@
import { IPackageServer } from "@libs/package";
import { Express } from "express";
import { Sequelize } from "sequelize";
import { registerService } from "./service-registry.ts.bak";
const registeredPackages: Map<string, IPackageServer> = new Map();
const initializedPackages = new Set<string>();
export function registerPackage(pkg: IPackageServer) {
if (registeredPackages.has(pkg.metadata.name)) {
throw new Error(`❌ Paquete "${pkg.metadata.name}" ya registrado.`);
}
registeredPackages.set(pkg.metadata.name, pkg);
}
export function initPackages(app: Express, sequelize: Sequelize) {
for (const [name] of registeredPackages) {
loadPackage(name, app, sequelize);
}
}
function loadPackage(name: string, app: Express, sequelize: Sequelize) {
if (initializedPackages.has(name)) return;
const pkg = registeredPackages.get(name);
if (!pkg) throw new Error(`❌ Paquete "${name}" no encontrado.`);
// Resolver dependencias primero
const deps = pkg.metadata.dependencies || [];
deps.forEach((dep) => loadPackage(dep, app, sequelize));
// Inicializar el package
pkg.init(app);
const pkgApi = pkg.registerDependencies?.();
// Registrar modelos de Sequelize, si los expone
if (pkgApi?.models) {
for (const initModelFn of pkgApi.models) {
initModelFn(sequelize);
}
}
// Registrar sus servicios, si los expone
if (pkgApi?.services) {
const services = pkgApi.services;
if (services && typeof services === "object") {
registerService(pkg.metadata.name, services);
}
}
initializedPackages.add(name);
console.log(`✅ Paquete "${name}" inicializado.`);
}

View File

@ -1,36 +0,0 @@
const services: Record<string, any> = {};
/**
* Registra un objeto de servicio (API) bajo un nombre.
*/
export function registerService(name: string, api: any) {
if (services[name]) {
throw new Error(`❌ Servicio "${name}" ya fue registrado.`);
}
services[name] = api;
}
/**
* Recupera un servicio registrado, con tipado opcional.
*/
export function getService<T = any>(name: string): T {
const service = services[name];
if (!service) {
throw new Error(`❌ Servicio "${name}" no encontrado.`);
}
return service;
}
/**
* Permite saber si un servicio fue registrado.
*/
export function hasService(name: string): boolean {
return !!services[name];
}
/**
* Devuelve todos los servicios (para depuración o tests).
*/
export function listServices(): string[] {
return Object.keys(services);
}

View File

@ -1,10 +1,12 @@
import http from "http";
import http from "node:http";
import os from "node:os";
import { logger } from "@/core/logger";
import { DateTime } from "luxon";
import os from "os";
import { createApp } from "./app";
import { ENV } from "./config";
import { tryConnectToDatabase } from "./config/database";
import { logger } from "./core/common/infrastructure/logger";
import { initModules } from "./core/helpers";
import { registerModules } from "./register-modules";
// Guardamos información del estado del servidor
export const currentState = {
@ -41,17 +43,16 @@ const serverStop = (server: http.Server) => {
// Manejo de errores al iniciar el servidor
const serverError = (error: NodeJS.ErrnoException) => {
logger.error({
message: `⛔️ Server wasn't able to start properly.`,
logger.error(`⛔️ Server wasn't able to start properly.`, {
label: "serverError0",
error,
});
if (error.code === "EADDRINUSE") {
logger.error({ message: error.message, error, label: "serverError1" });
logger.error(error.message, { error, label: "serverError1" });
//logger.error(`The port ${error.port} is already used by another application.`);
} else {
logger.error({ message: error.message, error, label: "serverError2" });
logger.error(error.message, { error, label: "serverError2" });
}
// Dependiendo de la criticidad, podrías forzar el proceso a salir
@ -72,11 +73,13 @@ const serverConnection = (conn: any) => {
//const firebirdConn = createFirebirdAdapter();
// Cargar paquetes de la aplicación
// registerPackages();
registerModules();
const app = createApp();
// Crea el servidor HTTP
const server = http
.createServer(createApp())
.createServer(app)
.once("listening", () =>
process.on("SIGINT", async () => {
// Por ejemplo, podrías desconectar la base de datos aquí:
@ -99,7 +102,7 @@ const server = http
// Manejo de promesas no capturadas
process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
logger.error("❌ Unhandled rejection at:", promise, "reason:", reason);
logger.error(`❌ Unhandled rejection at:", ${promise}, "reason:", ${reason}`);
// Dependiendo de la aplicación, podrías desear una salida total o un cierre controlado
process.exit(1);
});
@ -107,7 +110,7 @@ process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
// Manejo de excepciones no controladas
process.on("uncaughtException", (error: Error) => {
// firebirdConn.disconnect();
logger.error(`❌ Uncaught exception:`, error.message);
logger.error(`❌ Uncaught exception: ${error.message}`);
logger.error(error.stack);
// process.exit(1);
});
@ -126,7 +129,7 @@ process.on("uncaughtException", (error: Error) => {
// initStructure(sequelizeConn.connection);
// insertUsers();
//await initModules({ app, database, baseRoutePath: "/api/v1" });
await initModules({ app, database, baseRoutePath: "/api/v1", logger });
server.listen(currentState.port, () => {
server.emit("listening");
@ -146,9 +149,10 @@ process.on("uncaughtException", (error: Error) => {
}
}
addresses.forEach((address) => {
for (const address in addresses) {
logger.info(`⚡️ Server accessible at: http://${address}:${currentState.port}`);
});
}
logger.info(`Server started at: ${DateTime.now().toLocaleString(DateTime.DATETIME_FULL)}`);
logger.info(`Server PID: ${process.pid}`);
logger.info(

View File

@ -1,8 +0,0 @@
//import { ContactsPackage } from '@modules/contacts/server';
//import { InvoicesPackage } from "@modules/invoices/server";
//import { registerPackage } from "@/core/module-loader";
export const registerPackages = () => {
//registerPackage(ContactsPackage);
//registerPackage(InvoicesPackage);
};

View File

@ -0,0 +1,7 @@
import { authAPIModule } from "@erp/auth";
import { registerModule } from "./core/helpers";
export const registerModules = () => {
//registerPackage(ContactsPackage);
registerModule(authAPIModule);
};

Some files were not shown because too many files have changed in this diff Show More