@hemia/core 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,10 @@ Paquete generado con [Hemia CLI](https://www.npmjs.com/package/@hemia/cli)
12
12
  npm install @hemia/hemia-core
13
13
  ```
14
14
 
15
+ ```bash
16
+ bun add @hemia/hemia-core
17
+ ```
18
+
15
19
  ---
16
20
 
17
21
  ## 🛠️ Scripts disponibles
@@ -32,5 +36,18 @@ npm install @hemia/hemia-core
32
36
 
33
37
  ---
34
38
 
39
+ ## 🚀 Funciones y Clases Exportadas
40
+
41
+ | Nombre | Tipo | Descripción breve |
42
+ |-------------------------|---------|-------------------|
43
+ | `HemiaFactory` | Clase | Inicializa la app Hemia conectando Express con Inversify y registra controladores. |
44
+ | `ResponseSerializer` | Clase | Transforma entidades a DTO usando class-transformer. |
45
+ | `GuardsConsumer` | Clase | Ejecuta guards secuencialmente y lanza error si alguno falla. |
46
+ | `AuthGuard` | Clase | Guard de autenticación y autorización basado en roles/permisos. |
47
+ | `HemiaExecutionContext` | Clase | Contexto de ejecución para requests HTTP, accede a argumentos y request/response. |
48
+ | `Reflector` | Clase | Utilidad para obtener metadata de clases y métodos (roles, permisos, etc). |
49
+
50
+ ---
51
+
35
52
  ## ✨ Generado con Hemia CLI
36
53
 
@@ -4,7 +4,8 @@ import { METADATA_KEYS, ParamType, isRedirectResponse, ApiResponse } from '@hemi
4
4
  import { TRACE_METADATA_KEY } from '@hemia/trace-manager';
5
5
  import { traceMiddleware } from '@hemia/app-context';
6
6
  import { plainToInstance } from 'class-transformer';
7
- import { injectable } from 'inversify';
7
+ import { injectable, inject } from 'inversify';
8
+ import { AUTH_SERVICE_ID, AuthService } from '@hemia/auth-sdk';
8
9
 
9
10
  class GuardsConsumer {
10
11
  /**
@@ -206,6 +207,10 @@ function __decorate(decorators, target, key, desc) {
206
207
  return c > 3 && r && Object.defineProperty(target, key, r), r;
207
208
  }
208
209
 
210
+ function __param(paramIndex, decorator) {
211
+ return function (target, key) { decorator(target, key, paramIndex); }
212
+ }
213
+
209
214
  function __metadata(metadataKey, metadataValue) {
210
215
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
211
216
  }
@@ -261,6 +266,11 @@ class HemiaFactory {
261
266
  const app = express();
262
267
  app.use(express.json());
263
268
  app.use(express.urlencoded({ extended: true }));
269
+ if (options.middlewares && Array.isArray(options.middlewares)) {
270
+ options.middlewares.forEach(middleware => {
271
+ app.use(middleware);
272
+ });
273
+ }
264
274
  app.use((req, res, next) => {
265
275
  const defaultHeaders = {
266
276
  'Access-Control-Allow-Origin': req.headers.origin || '*',
@@ -294,6 +304,10 @@ class HemiaFactory {
294
304
  }
295
305
  }
296
306
 
307
+ /**
308
+ * Guardia de autorización que verifica roles y permisos definidos en los controladores y métodos.
309
+ * Utiliza los metadatos definidos con los decoradores @Roles y @Permissions.
310
+ */
297
311
  let AuthGuard = class AuthGuard {
298
312
  constructor(reflector) {
299
313
  this.reflector = reflector;
@@ -310,17 +324,19 @@ let AuthGuard = class AuthGuard {
310
324
  }
311
325
  const request = context.switchToHttp().getRequest();
312
326
  const user = request.user;
313
- if (!user || !user.roles) {
327
+ const permissions = request.permissions;
328
+ const contextData = request.context;
329
+ if (!user) {
314
330
  return false;
315
331
  }
316
332
  if (requiredRoles) {
317
- const userRoleNames = user.roles.map((r) => r.name);
333
+ const userRoleNames = Array.isArray(contextData.roles) ? contextData.roles : [];
318
334
  const hasRole = requiredRoles.some((role) => userRoleNames.includes(role));
319
335
  if (!hasRole)
320
336
  return false;
321
337
  }
322
338
  if (requiredPermissions) {
323
- const userPermissions = user.roles.flatMap((r) => r.permissions || []);
339
+ const userPermissions = Array.isArray(permissions) ? permissions : [];
324
340
  const hasPermission = requiredPermissions.some((perm) => userPermissions.includes(perm));
325
341
  if (!hasPermission)
326
342
  return false;
@@ -333,4 +349,66 @@ AuthGuard = __decorate([
333
349
  __metadata("design:paramtypes", [Reflector])
334
350
  ], AuthGuard);
335
351
 
336
- export { AuthGuard, GuardsConsumer, HemiaExecutionContext, HemiaFactory, Reflector, ResponseSerializer, registerRoutes };
352
+ /**
353
+ * Guardia para validar la presencia y validez de una API Key en las solicitudes entrantes.
354
+ * La API Key se espera en el encabezado 'x-api-key' o como parámetro de consulta 'api_key'.
355
+ * Las claves válidas se configuran mediante la variable de entorno 'API_KEY' y pueden ser múltiples, separadas por comas.
356
+ */
357
+ let ApiKeyGuard = class ApiKeyGuard {
358
+ constructor() {
359
+ this.validApiKeys = (process.env.API_KEY || "")
360
+ .split(",")
361
+ .map(key => key.trim())
362
+ .filter(key => !!key);
363
+ }
364
+ canActivate(context) {
365
+ const request = context.switchToHttp().getRequest();
366
+ const apiKey = request.headers['x-api-key'] || request.query['api_key'];
367
+ if (!apiKey)
368
+ return false;
369
+ return this.validApiKeys.includes(apiKey);
370
+ }
371
+ };
372
+ ApiKeyGuard = __decorate([
373
+ injectable(),
374
+ __metadata("design:paramtypes", [])
375
+ ], ApiKeyGuard);
376
+
377
+ /**
378
+ * Guardia para validar y procesar tokens JWT en las solicitudes entrantes.
379
+ * Extrae el token de sesión del encabezado 'x-session' o de las cookies,
380
+ * y utiliza el AuthService para validar el token y obtener los datos del usuario.
381
+ * Si el token es válido, adjunta la información del usuario, permisos y contexto a la solicitud.
382
+ */
383
+ let JWTGuard = class JWTGuard {
384
+ constructor(authService) {
385
+ this.authService = authService;
386
+ }
387
+ async canActivate(context) {
388
+ const request = context.switchToHttp().getRequest();
389
+ const sessionId = request.headers['x-session'] || request.cookies['x-session'];
390
+ if (!sessionId) {
391
+ return false;
392
+ }
393
+ try {
394
+ const accessTokenData = await this.authService.getSessionAccess(sessionId);
395
+ if (!accessTokenData) {
396
+ return false;
397
+ }
398
+ request.user = accessTokenData.user;
399
+ request.permissions = accessTokenData.permissions;
400
+ request.context = accessTokenData.context;
401
+ return true;
402
+ }
403
+ catch (error) {
404
+ return false;
405
+ }
406
+ }
407
+ };
408
+ JWTGuard = __decorate([
409
+ injectable(),
410
+ __param(0, inject(AUTH_SERVICE_ID)),
411
+ __metadata("design:paramtypes", [AuthService])
412
+ ], JWTGuard);
413
+
414
+ export { ApiKeyGuard, AuthGuard, GuardsConsumer, HemiaExecutionContext, HemiaFactory, JWTGuard, Reflector, ResponseSerializer, registerRoutes };
@@ -7,6 +7,7 @@ var traceManager = require('@hemia/trace-manager');
7
7
  var appContext = require('@hemia/app-context');
8
8
  var classTransformer = require('class-transformer');
9
9
  var inversify = require('inversify');
10
+ var authSdk = require('@hemia/auth-sdk');
10
11
 
11
12
  class GuardsConsumer {
12
13
  /**
@@ -208,6 +209,10 @@ function __decorate(decorators, target, key, desc) {
208
209
  return c > 3 && r && Object.defineProperty(target, key, r), r;
209
210
  }
210
211
 
212
+ function __param(paramIndex, decorator) {
213
+ return function (target, key) { decorator(target, key, paramIndex); }
214
+ }
215
+
211
216
  function __metadata(metadataKey, metadataValue) {
212
217
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
213
218
  }
@@ -263,6 +268,11 @@ class HemiaFactory {
263
268
  const app = express();
264
269
  app.use(express.json());
265
270
  app.use(express.urlencoded({ extended: true }));
271
+ if (options.middlewares && Array.isArray(options.middlewares)) {
272
+ options.middlewares.forEach(middleware => {
273
+ app.use(middleware);
274
+ });
275
+ }
266
276
  app.use((req, res, next) => {
267
277
  const defaultHeaders = {
268
278
  'Access-Control-Allow-Origin': req.headers.origin || '*',
@@ -296,6 +306,10 @@ class HemiaFactory {
296
306
  }
297
307
  }
298
308
 
309
+ /**
310
+ * Guardia de autorización que verifica roles y permisos definidos en los controladores y métodos.
311
+ * Utiliza los metadatos definidos con los decoradores @Roles y @Permissions.
312
+ */
299
313
  exports.AuthGuard = class AuthGuard {
300
314
  constructor(reflector) {
301
315
  this.reflector = reflector;
@@ -312,17 +326,19 @@ exports.AuthGuard = class AuthGuard {
312
326
  }
313
327
  const request = context.switchToHttp().getRequest();
314
328
  const user = request.user;
315
- if (!user || !user.roles) {
329
+ const permissions = request.permissions;
330
+ const contextData = request.context;
331
+ if (!user) {
316
332
  return false;
317
333
  }
318
334
  if (requiredRoles) {
319
- const userRoleNames = user.roles.map((r) => r.name);
335
+ const userRoleNames = Array.isArray(contextData.roles) ? contextData.roles : [];
320
336
  const hasRole = requiredRoles.some((role) => userRoleNames.includes(role));
321
337
  if (!hasRole)
322
338
  return false;
323
339
  }
324
340
  if (requiredPermissions) {
325
- const userPermissions = user.roles.flatMap((r) => r.permissions || []);
341
+ const userPermissions = Array.isArray(permissions) ? permissions : [];
326
342
  const hasPermission = requiredPermissions.some((perm) => userPermissions.includes(perm));
327
343
  if (!hasPermission)
328
344
  return false;
@@ -335,6 +351,68 @@ exports.AuthGuard = __decorate([
335
351
  __metadata("design:paramtypes", [exports.Reflector])
336
352
  ], exports.AuthGuard);
337
353
 
354
+ /**
355
+ * Guardia para validar la presencia y validez de una API Key en las solicitudes entrantes.
356
+ * La API Key se espera en el encabezado 'x-api-key' o como parámetro de consulta 'api_key'.
357
+ * Las claves válidas se configuran mediante la variable de entorno 'API_KEY' y pueden ser múltiples, separadas por comas.
358
+ */
359
+ exports.ApiKeyGuard = class ApiKeyGuard {
360
+ constructor() {
361
+ this.validApiKeys = (process.env.API_KEY || "")
362
+ .split(",")
363
+ .map(key => key.trim())
364
+ .filter(key => !!key);
365
+ }
366
+ canActivate(context) {
367
+ const request = context.switchToHttp().getRequest();
368
+ const apiKey = request.headers['x-api-key'] || request.query['api_key'];
369
+ if (!apiKey)
370
+ return false;
371
+ return this.validApiKeys.includes(apiKey);
372
+ }
373
+ };
374
+ exports.ApiKeyGuard = __decorate([
375
+ inversify.injectable(),
376
+ __metadata("design:paramtypes", [])
377
+ ], exports.ApiKeyGuard);
378
+
379
+ /**
380
+ * Guardia para validar y procesar tokens JWT en las solicitudes entrantes.
381
+ * Extrae el token de sesión del encabezado 'x-session' o de las cookies,
382
+ * y utiliza el AuthService para validar el token y obtener los datos del usuario.
383
+ * Si el token es válido, adjunta la información del usuario, permisos y contexto a la solicitud.
384
+ */
385
+ exports.JWTGuard = class JWTGuard {
386
+ constructor(authService) {
387
+ this.authService = authService;
388
+ }
389
+ async canActivate(context) {
390
+ const request = context.switchToHttp().getRequest();
391
+ const sessionId = request.headers['x-session'] || request.cookies['x-session'];
392
+ if (!sessionId) {
393
+ return false;
394
+ }
395
+ try {
396
+ const accessTokenData = await this.authService.getSessionAccess(sessionId);
397
+ if (!accessTokenData) {
398
+ return false;
399
+ }
400
+ request.user = accessTokenData.user;
401
+ request.permissions = accessTokenData.permissions;
402
+ request.context = accessTokenData.context;
403
+ return true;
404
+ }
405
+ catch (error) {
406
+ return false;
407
+ }
408
+ }
409
+ };
410
+ exports.JWTGuard = __decorate([
411
+ inversify.injectable(),
412
+ __param(0, inversify.inject(authSdk.AUTH_SERVICE_ID)),
413
+ __metadata("design:paramtypes", [authSdk.AuthService])
414
+ ], exports.JWTGuard);
415
+
338
416
  exports.GuardsConsumer = GuardsConsumer;
339
417
  exports.HemiaExecutionContext = HemiaExecutionContext;
340
418
  exports.HemiaFactory = HemiaFactory;
@@ -0,0 +1,11 @@
1
+ import { CanActivate, ExecutionContext } from "@hemia/common";
2
+ /**
3
+ * Guardia para validar la presencia y validez de una API Key en las solicitudes entrantes.
4
+ * La API Key se espera en el encabezado 'x-api-key' o como parámetro de consulta 'api_key'.
5
+ * Las claves válidas se configuran mediante la variable de entorno 'API_KEY' y pueden ser múltiples, separadas por comas.
6
+ */
7
+ export declare class ApiKeyGuard implements CanActivate {
8
+ private readonly validApiKeys;
9
+ constructor();
10
+ canActivate(context: ExecutionContext): boolean;
11
+ }
@@ -1,5 +1,9 @@
1
1
  import { CanActivate, ExecutionContext } from '@hemia/common';
2
2
  import { Reflector } from '../services';
3
+ /**
4
+ * Guardia de autorización que verifica roles y permisos definidos en los controladores y métodos.
5
+ * Utiliza los metadatos definidos con los decoradores @Roles y @Permissions.
6
+ */
3
7
  export declare class AuthGuard implements CanActivate {
4
8
  private reflector;
5
9
  constructor(reflector: Reflector);
@@ -1,2 +1,4 @@
1
1
  export * from "./auth.guard";
2
2
  export * from "./guards-consumer";
3
+ export * from "./api-key.guard";
4
+ export * from "./jwt.guard";
@@ -0,0 +1,13 @@
1
+ import { CanActivate, ExecutionContext } from "@hemia/common";
2
+ import { AuthService } from "@hemia/auth-sdk";
3
+ /**
4
+ * Guardia para validar y procesar tokens JWT en las solicitudes entrantes.
5
+ * Extrae el token de sesión del encabezado 'x-session' o de las cookies,
6
+ * y utiliza el AuthService para validar el token y obtener los datos del usuario.
7
+ * Si el token es válido, adjunta la información del usuario, permisos y contexto a la solicitud.
8
+ */
9
+ export declare class JWTGuard implements CanActivate {
10
+ private readonly authService;
11
+ constructor(authService: AuthService);
12
+ canActivate(context: ExecutionContext): Promise<boolean>;
13
+ }
@@ -6,6 +6,7 @@ export interface HemiaFactoryOptions {
6
6
  onTraceFinish?: TraceFinishCallback;
7
7
  logger?: boolean;
8
8
  corsHeaders?: Record<string, string>;
9
+ middlewares?: any[];
9
10
  }
10
11
  export declare class HemiaFactory {
11
12
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hemia/core",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Core utilities for Hemia projects",
5
5
  "main": "dist/hemia-core.js",
6
6
  "module": "dist/hemia-core.esm.js",
@@ -17,9 +17,10 @@
17
17
  "@rollup/plugin-commonjs": "^26.0.1",
18
18
  "@rollup/plugin-json": "^6.1.0",
19
19
  "@rollup/plugin-node-resolve": "^15.2.3",
20
- "@hemia/common": "^0.0.4",
20
+ "@hemia/common": "^0.0.5",
21
21
  "@hemia/app-context": "^0.0.6",
22
22
  "@hemia/trace-manager": "^0.0.9",
23
+ "@hemia/auth-sdk": "^0.0.9",
23
24
  "@types/express": "^5.0.5",
24
25
  "express": "^5.1.0",
25
26
  "inversify": "^7.10.4",
@@ -45,6 +46,6 @@
45
46
  "class-transformer": "^0.5.1",
46
47
  "express": "^5.0.0",
47
48
  "inversify": "^7.0.0",
48
- "reflect-metadata": "^0.1.13"
49
+ "reflect-metadata": "^0.2.2"
49
50
  }
50
51
  }