first commit

This commit is contained in:
2026-10-03 13:40:26 +02:00
parent 732a5b5a16
commit 566f415fa7
555 changed files with 62704 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
# api-shared-presenters
Adaptadores de entrada comunes.
- **Import**: `@task-stream/api/shared/presenters`
- **Capa**: `presenters` · **Tags**: `scope:api-shared`, `type:presenters`
## Contenido
- `DomainErrorFilter`: convierte los errores de dominio en errores GraphQL (`extensions.code`) o respuestas HTTP.
## Comandos
```sh
npx nx lint api-shared-presenters
npx nx test api-shared-presenters # Jest
```
Reglas de dependencia entre capas: [Arquitectura](../../../../docs/02-arquitectura.md#21-capas-hexagonales).

View File

@@ -0,0 +1,3 @@
import baseConfig from '../../../../eslint.config.mjs';
export default [...baseConfig];

View File

@@ -0,0 +1,11 @@
module.exports = {
displayName: 'api-shared-presenters',
preset: '../../../../jest.preset.js',
testEnvironment: 'node',
passWithNoTests: true,
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../../../coverage/libs/api/shared/presenters',
};

View File

@@ -0,0 +1,12 @@
{
"name": "api-shared-presenters",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/api/shared/presenters/src",
"projectType": "library",
"tags": [
"scope:api-shared",
"type:presenters"
],
"// targets": "to see all targets run: nx show project api-shared-presenters --web",
"targets": {}
}

View File

@@ -0,0 +1 @@
export * from './lib/filters/domain-error.filter';

View File

@@ -0,0 +1,40 @@
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpStatus,
Logger,
} from '@nestjs/common';
import { GqlContextType } from '@nestjs/graphql';
import { DomainError, DomainErrorCode } from '@task-stream/api/shared/domain';
import { Response } from 'express';
import { GraphQLError } from 'graphql';
const HTTP_STATUS: Record<DomainErrorCode, HttpStatus> = {
NOT_FOUND: HttpStatus.NOT_FOUND,
FORBIDDEN: HttpStatus.FORBIDDEN,
VALIDATION: HttpStatus.BAD_REQUEST,
CONFLICT: HttpStatus.CONFLICT,
BUSINESS_RULE: HttpStatus.UNPROCESSABLE_ENTITY,
};
/** Translates domain errors into GraphQL errors (extensions.code) or HTTP responses. */
@Catch(DomainError)
export class DomainErrorFilter implements ExceptionFilter {
private readonly logger = new Logger(DomainErrorFilter.name);
catch(error: DomainError, host: ArgumentsHost): unknown {
this.logger.debug(`${error.name}: ${error.message}`);
if (host.getType<GqlContextType>() === 'graphql') {
return new GraphQLError(error.message, {
extensions: { code: error.code },
});
}
const response = host.switchToHttp().getResponse<Response>();
return response.status(HTTP_STATUS[error.code]).json({
statusCode: HTTP_STATUS[error.code],
code: error.code,
message: error.message,
});
}
}

View File

@@ -0,0 +1,23 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"importHelpers": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@@ -0,0 +1,23 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"],
"target": "es2021",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*.ts"],
"exclude": [
"jest.config.ts",
"jest.config.cts",
"src/**/*.spec.ts",
"src/**/*.test.ts"
]
}

View File

@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"module": "commonjs",
"moduleResolution": "bundler",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"jest.config.cts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}