@jmlq/auth 0.0.1-alpha.23 → 0.0.1-alpha.25

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.
@@ -1 +1,14 @@
1
+ /**
2
+ * Regla canónica de dominio para el claim estándar `aud` (audience).
3
+ *
4
+ * Propósito:
5
+ * - Aceptar `aud` como string o string[] (según librería/plugin).
6
+ * - Rechazar valores vacíos.
7
+ * - Si es array: normalizar de forma determinista (dedupe + sort),
8
+ * útil para tests y debugging.
9
+ *
10
+ * Importante:
11
+ * - Esta validación es del CORE (@jmlq/auth).
12
+ * - Los plugins JWT NO deben validar audience; solo entregan payload verificado.
13
+ */
1
14
  export declare function optionalAudience(value: unknown): string | string[] | undefined;
@@ -2,9 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.optionalAudience = optionalAudience;
4
4
  const errors_1 = require("../../errors");
5
+ /**
6
+ * Regla canónica de dominio para el claim estándar `aud` (audience).
7
+ *
8
+ * Propósito:
9
+ * - Aceptar `aud` como string o string[] (según librería/plugin).
10
+ * - Rechazar valores vacíos.
11
+ * - Si es array: normalizar de forma determinista (dedupe + sort),
12
+ * útil para tests y debugging.
13
+ *
14
+ * Importante:
15
+ * - Esta validación es del CORE (@jmlq/auth).
16
+ * - Los plugins JWT NO deben validar audience; solo entregan payload verificado.
17
+ */
5
18
  function optionalAudience(value) {
19
+ // aud ausente => ok
6
20
  if (value == null)
7
21
  return undefined;
22
+ // aud como string
8
23
  if (typeof value === "string") {
9
24
  const v = value.trim();
10
25
  if (!v) {
@@ -14,19 +29,19 @@ function optionalAudience(value) {
14
29
  }
15
30
  return v;
16
31
  }
32
+ // aud como string[]
17
33
  if (Array.isArray(value)) {
18
34
  const items = value
19
35
  .filter((x) => typeof x === "string")
20
36
  .map((x) => x.trim())
21
37
  .filter((x) => x.length > 0);
22
38
  if (items.length === 0) {
23
- throw new errors_1.InvalidJwtPayloadError("JWT payload.aud must contain at least one non-empty string", {
24
- field: "aud",
25
- });
39
+ throw new errors_1.InvalidJwtPayloadError("JWT payload.aud must contain at least one non-empty string", { field: "aud" });
26
40
  }
27
- // Determinista (útil para test/debug)
41
+ // Determinista: sin duplicados y ordenado
28
42
  return Array.from(new Set(items)).sort((a, b) => a.localeCompare(b));
29
43
  }
44
+ // Tipo inválido
30
45
  throw new errors_1.InvalidJwtPayloadError("JWT payload.aud must be a string or string[]", {
31
46
  field: "aud",
32
47
  receivedType: typeof value,
@@ -4,12 +4,16 @@ import type { IJWTPayload } from "../ports";
4
4
  * --------------
5
5
  * Normaliza y valida un payload JWT según las reglas del dominio.
6
6
  *
7
- * - Entrada: unknown (claims verificados por infraestructura)
7
+ * - Entrada: unknown (claims verificados por infraestructura/plugin)
8
8
  * - Salida: IJWTPayload tipado y confiable
9
9
  *
10
10
  * Importante:
11
11
  * - NO verifica firma
12
12
  * - NO parsea JWT
13
13
  * - Define únicamente reglas de dominio
14
+ *
15
+ * Contrato:
16
+ * - `aud` se valida exclusivamente aquí vía `optionalAudience()`.
17
+ * - Cualquier error de `aud` debe provenir de `InvalidJwtPayloadError`.
14
18
  */
15
19
  export declare function normalizeJwtPayload(input: unknown): IJWTPayload;
@@ -8,13 +8,17 @@ const helpers_1 = require("./helpers");
8
8
  * --------------
9
9
  * Normaliza y valida un payload JWT según las reglas del dominio.
10
10
  *
11
- * - Entrada: unknown (claims verificados por infraestructura)
11
+ * - Entrada: unknown (claims verificados por infraestructura/plugin)
12
12
  * - Salida: IJWTPayload tipado y confiable
13
13
  *
14
14
  * Importante:
15
15
  * - NO verifica firma
16
16
  * - NO parsea JWT
17
17
  * - Define únicamente reglas de dominio
18
+ *
19
+ * Contrato:
20
+ * - `aud` se valida exclusivamente aquí vía `optionalAudience()`.
21
+ * - Cualquier error de `aud` debe provenir de `InvalidJwtPayloadError`.
18
22
  */
19
23
  function normalizeJwtPayload(input) {
20
24
  if (input == null || typeof input !== "object") {
@@ -23,12 +27,20 @@ function normalizeJwtPayload(input) {
23
27
  });
24
28
  }
25
29
  const obj = input;
30
+ // Required
26
31
  const sub = (0, helpers_1.requireNonEmptyString)(obj.sub, "sub");
27
32
  const sid = (0, helpers_1.requireNonEmptyString)(obj.sid, "sid");
28
33
  const jti = (0, helpers_1.requireNonEmptyString)(obj.jti, "jti");
29
34
  const iat = (0, helpers_1.requireFiniteNumber)(obj.iat, "iat");
30
35
  const exp = (0, helpers_1.requireFiniteNumber)(obj.exp, "exp");
36
+ // Optional
31
37
  const iss = (0, helpers_1.optionalNonEmptyString)(obj.iss);
38
+ /**
39
+ * Canonical audience rule (core):
40
+ * - string | string[] | undefined
41
+ * - empty string or empty array => InvalidJwtPayloadError
42
+ * - array => dedupe + sort
43
+ */
32
44
  const aud = (0, helpers_1.optionalAudience)(obj.aud);
33
45
  const roles = (0, helpers_1.optionalRoles)(obj.roles);
34
46
  const customClaims = (0, helpers_1.optionalRecord)(obj.customClaims, "customClaims");
package/dist/index.d.ts CHANGED
@@ -1,6 +1,17 @@
1
1
  export type { IAuthServiceContainer } from "./infrastructure/types";
2
2
  export { AuthServiceFactoryOptions } from "./application/types";
3
- export { normalizeJwtPayload } from "./domain/services/";
3
+ /**
4
+ * Contrato público (JWT payload):
5
+ * - Los plugins devuelven payload verificado criptográficamente como unknown.
6
+ * - El core normaliza/valida y expone API estable para consumo externo.
7
+ */
8
+ export { normalizeJwtPayload } from "./domain/services";
9
+ /**
10
+ * Export explícito (contractual):
11
+ * Aunque ya se exporta vía `export * from "./domain/errors"`,
12
+ * se expone de forma directa para que el host/plugins lo consuman sin ambigüedad.
13
+ */
14
+ export { InvalidJwtPayloadError } from "./domain/errors";
4
15
  export * from "./domain/ports";
5
16
  export * from "./domain/entities";
6
17
  export * from "./domain/object-values";
@@ -8,3 +19,4 @@ export * from "./domain/props";
8
19
  export * from "./domain/errors";
9
20
  export * from "./application/dtos";
10
21
  export * from "./application/facades";
22
+ export * from "./shared";
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // export { BcryptPasswordHasher } from "./infrastructure/security";
3
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
3
  if (k2 === undefined) k2 = k;
5
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -15,23 +14,33 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
15
  };
17
16
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.normalizeJwtPayload = void 0;
19
- var services_1 = require("./domain/services/");
17
+ exports.InvalidJwtPayloadError = exports.normalizeJwtPayload = void 0;
18
+ /**
19
+ * Contrato público (JWT payload):
20
+ * - Los plugins devuelven payload verificado criptográficamente como unknown.
21
+ * - El core normaliza/valida y expone API estable para consumo externo.
22
+ */
23
+ var services_1 = require("./domain/services");
20
24
  Object.defineProperty(exports, "normalizeJwtPayload", { enumerable: true, get: function () { return services_1.normalizeJwtPayload; } });
25
+ /**
26
+ * Export explícito (contractual):
27
+ * Aunque ya se exporta vía `export * from "./domain/errors"`,
28
+ * se expone de forma directa para que el host/plugins lo consuman sin ambigüedad.
29
+ */
30
+ var errors_1 = require("./domain/errors");
31
+ Object.defineProperty(exports, "InvalidJwtPayloadError", { enumerable: true, get: function () { return errors_1.InvalidJwtPayloadError; } });
21
32
  // Contratos (ports) + config
22
33
  __exportStar(require("./domain/ports"), exports);
23
34
  // Entities
24
35
  __exportStar(require("./domain/entities"), exports);
25
36
  // VOs
26
37
  __exportStar(require("./domain/object-values"), exports);
27
- // Contratos (ports) + config
38
+ // Props (JWT generation inputs, etc.)
28
39
  __exportStar(require("./domain/props"), exports);
29
40
  // Errores públicos
30
41
  __exportStar(require("./domain/errors"), exports);
31
42
  // DTOs (solo types)
32
43
  __exportStar(require("./application/dtos"), exports);
33
- // Entry point principal
34
- // export * from "./application/factories";
44
+ // Facades (entrypoint recomendado para hosts)
35
45
  __exportStar(require("./application/facades"), exports);
36
- // adapters útiles para tests/demos
37
- // export * from "./infrastructure/repositories/in-memory";
46
+ __exportStar(require("./shared"), exports);
@@ -1 +1,2 @@
1
1
  export * from "./utils";
2
+ export * from "./jwt-plugin";
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./utils"), exports);
18
+ __exportStar(require("./jwt-plugin"), exports);
@@ -0,0 +1,6 @@
1
+ export * from "./normalize-clock-skew-seconds";
2
+ export * from "./normalize-default-expires-in";
3
+ export * from "./read-expires-in";
4
+ export * from "./read-custom-claims";
5
+ export * from "./resolve-expires-in";
6
+ export * from "./is-retryable-auth-code";
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./normalize-clock-skew-seconds"), exports);
18
+ __exportStar(require("./normalize-default-expires-in"), exports);
19
+ __exportStar(require("./read-expires-in"), exports);
20
+ __exportStar(require("./read-custom-claims"), exports);
21
+ __exportStar(require("./resolve-expires-in"), exports);
22
+ __exportStar(require("./is-retryable-auth-code"), exports);
@@ -0,0 +1,8 @@
1
+ import type { AuthErrorCode } from "../../domain/errors";
2
+ /**
3
+ * Determina si un error del core (por código) es "retryable".
4
+ *
5
+ * Responsabilidad única:
6
+ * - Decidir reintento SOLO por `code` (sin jose, sin message, sin heurísticas).
7
+ */
8
+ export declare function isRetryableAuthCode(code: AuthErrorCode): boolean;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRetryableAuthCode = isRetryableAuthCode;
4
+ /**
5
+ * Determina si un error del core (por código) es "retryable".
6
+ *
7
+ * Responsabilidad única:
8
+ * - Decidir reintento SOLO por `code` (sin jose, sin message, sin heurísticas).
9
+ */
10
+ function isRetryableAuthCode(code) {
11
+ return (code === "SIGNATURE_INVALID" ||
12
+ code === "ALGORITHM_UNSUPPORTED" ||
13
+ code === "KEY_MISMATCH" ||
14
+ code === "KEY_NOT_FOUND");
15
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Normaliza clockSkewSeconds (en segundos).
3
+ *
4
+ * Responsabilidad única:
5
+ * - Aceptar únicamente números válidos
6
+ * - Convertir a entero (floor)
7
+ * - Asegurar >= 0
8
+ *
9
+ * Reglas:
10
+ * - no number / NaN => undefined
11
+ * - < 0 => 0
12
+ * - >== 0 => floor(value)
13
+ */
14
+ export declare function normalizeClockSkewSeconds(value: number | undefined): number | undefined;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeClockSkewSeconds = normalizeClockSkewSeconds;
4
+ /**
5
+ * Normaliza clockSkewSeconds (en segundos).
6
+ *
7
+ * Responsabilidad única:
8
+ * - Aceptar únicamente números válidos
9
+ * - Convertir a entero (floor)
10
+ * - Asegurar >= 0
11
+ *
12
+ * Reglas:
13
+ * - no number / NaN => undefined
14
+ * - < 0 => 0
15
+ * - >== 0 => floor(value)
16
+ */
17
+ function normalizeClockSkewSeconds(value) {
18
+ if (typeof value !== "number" || Number.isNaN(value))
19
+ return undefined;
20
+ if (value < 0)
21
+ return 0;
22
+ return Math.floor(value);
23
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Normaliza defaults de expiración usados por plugins JWT.
3
+ *
4
+ * Responsabilidad única:
5
+ * - Aceptar un shape compatible con { accessToken?, refreshToken? }
6
+ * - Trim de strings
7
+ * - Vacío => omitido
8
+ * - Si queda vacío => undefined
9
+ *
10
+ * Importante:
11
+ * - No depende de types de plugins para evitar acoplamiento.
12
+ */
13
+ export declare function normalizeDefaultExpiresIn<T extends {
14
+ accessToken?: string;
15
+ refreshToken?: string;
16
+ }>(value: T | undefined): T | undefined;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeDefaultExpiresIn = normalizeDefaultExpiresIn;
4
+ /**
5
+ * Normaliza defaults de expiración usados por plugins JWT.
6
+ *
7
+ * Responsabilidad única:
8
+ * - Aceptar un shape compatible con { accessToken?, refreshToken? }
9
+ * - Trim de strings
10
+ * - Vacío => omitido
11
+ * - Si queda vacío => undefined
12
+ *
13
+ * Importante:
14
+ * - No depende de types de plugins para evitar acoplamiento.
15
+ */
16
+ function normalizeDefaultExpiresIn(value) {
17
+ if (!value)
18
+ return undefined;
19
+ const out = {};
20
+ const accessToken = normalizeOptionalNonEmptyString(value.accessToken);
21
+ if (accessToken)
22
+ out.accessToken = accessToken;
23
+ const refreshToken = normalizeOptionalNonEmptyString(value.refreshToken);
24
+ if (refreshToken)
25
+ out.refreshToken = refreshToken;
26
+ return Object.keys(out).length > 0 ? out : undefined;
27
+ }
28
+ /**
29
+ * Helper local (mínimo) para evitar dependencia circular en exports del core.
30
+ */
31
+ function normalizeOptionalNonEmptyString(value) {
32
+ if (typeof value !== "string")
33
+ return undefined;
34
+ const v = value.trim();
35
+ return v.length > 0 ? v : undefined;
36
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Lee `customClaims` desde unknown.
3
+ *
4
+ * Responsabilidad única:
5
+ * - Aceptar únicamente un objeto plano serializable (Record<string, unknown>)
6
+ *
7
+ * Reglas:
8
+ * - undefined/null => undefined
9
+ * - arrays => undefined
10
+ * - objetos => Record<string, unknown>
11
+ */
12
+ export declare function readCustomClaims(value: unknown): Record<string, unknown> | undefined;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readCustomClaims = readCustomClaims;
4
+ /**
5
+ * Lee `customClaims` desde unknown.
6
+ *
7
+ * Responsabilidad única:
8
+ * - Aceptar únicamente un objeto plano serializable (Record<string, unknown>)
9
+ *
10
+ * Reglas:
11
+ * - undefined/null => undefined
12
+ * - arrays => undefined
13
+ * - objetos => Record<string, unknown>
14
+ */
15
+ function readCustomClaims(value) {
16
+ if (!value || typeof value !== "object")
17
+ return undefined;
18
+ if (Array.isArray(value))
19
+ return undefined;
20
+ return value;
21
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Lee `expiresIn` desde unknown.
3
+ *
4
+ * Responsabilidad única:
5
+ * - Normalizar un valor desconocido a `string | undefined`
6
+ *
7
+ * Reglas:
8
+ * - no string => undefined
9
+ * - string vacío => undefined
10
+ * - string con espacios => trim()
11
+ */
12
+ export declare function readExpiresIn(value: unknown): string | undefined;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readExpiresIn = readExpiresIn;
4
+ /**
5
+ * Lee `expiresIn` desde unknown.
6
+ *
7
+ * Responsabilidad única:
8
+ * - Normalizar un valor desconocido a `string | undefined`
9
+ *
10
+ * Reglas:
11
+ * - no string => undefined
12
+ * - string vacío => undefined
13
+ * - string con espacios => trim()
14
+ */
15
+ function readExpiresIn(value) {
16
+ if (typeof value !== "string")
17
+ return undefined;
18
+ const trimmed = value.trim();
19
+ return trimmed.length > 0 ? trimmed : undefined;
20
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Resuelve `expiresIn` para generación de tokens (regla canónica para plugins).
3
+ *
4
+ * Responsabilidad única:
5
+ * - Aplicar precedencia:
6
+ * 1) expiresIn provisto por props
7
+ * 2) defaultExpiresIn del plugin por tokenKind
8
+ * - Si ninguno existe: lanzar InvalidJwtPayloadError (error canónico del core)
9
+ */
10
+ export declare function resolveExpiresIn(args: {
11
+ expiresInFromProps?: string;
12
+ defaultExpiresIn?: string;
13
+ operation: "generateAccessToken" | "generateRefreshToken";
14
+ }): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveExpiresIn = resolveExpiresIn;
4
+ const errors_1 = require("../../domain/errors");
5
+ /**
6
+ * Resuelve `expiresIn` para generación de tokens (regla canónica para plugins).
7
+ *
8
+ * Responsabilidad única:
9
+ * - Aplicar precedencia:
10
+ * 1) expiresIn provisto por props
11
+ * 2) defaultExpiresIn del plugin por tokenKind
12
+ * - Si ninguno existe: lanzar InvalidJwtPayloadError (error canónico del core)
13
+ */
14
+ function resolveExpiresIn(args) {
15
+ const fromProps = normalizeOptionalNonEmptyString(args.expiresInFromProps);
16
+ if (fromProps)
17
+ return fromProps;
18
+ const fromDefault = normalizeOptionalNonEmptyString(args.defaultExpiresIn);
19
+ if (fromDefault)
20
+ return fromDefault;
21
+ throw new errors_1.InvalidJwtPayloadError("expiresIn is required", {
22
+ field: "expiresIn",
23
+ operation: args.operation,
24
+ });
25
+ }
26
+ function normalizeOptionalNonEmptyString(value) {
27
+ if (typeof value !== "string")
28
+ return undefined;
29
+ const v = value.trim();
30
+ return v.length > 0 ? v : undefined;
31
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jmlq/auth",
3
3
  "description": "JWT authentication package with clean architecture",
4
- "version": "0.0.1-alpha.23",
4
+ "version": "0.0.1-alpha.25",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {