serverless-event-orchestrator 2.4.0 → 2.5.0

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 @@
1
- {"version":3,"file":"body-parser.d.ts","sourceRoot":"","sources":["../../src/http/body-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAe7G;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GAC5D,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,EACvF,KAAK,EAAE,CAAC,GACP,CAAC,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAKzC"}
1
+ {"version":3,"file":"body-parser.d.ts","sourceRoot":"","sources":["../../src/http/body-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAsB7G;AAoBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GAC5D,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,EACvF,KAAK,EAAE,CAAC,GACP,CAAC,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAKzC"}
@@ -20,6 +20,14 @@ function parseJsonBody(body, isBase64Encoded) {
20
20
  if (isBase64Encoded) {
21
21
  decodedBody = Buffer.from(body, 'base64').toString('utf-8');
22
22
  }
23
+ else {
24
+ // API Gateway puede entregar el body interpretando bytes UTF-8 como
25
+ // Latin-1 cuando el Content-Type no incluye `; charset=utf-8`,
26
+ // produciendo mojibake (`María` en lugar de `María`). Si detectamos
27
+ // el patrón típico (byte UTF-8 multibyte visto como Latin-1),
28
+ // revertimos re-codificando latin1 → utf-8.
29
+ decodedBody = fixUtf8Mojibake(decodedBody);
30
+ }
23
31
  const parsed = JSON.parse(decodedBody);
24
32
  return parsed ?? {};
25
33
  }
@@ -27,6 +35,24 @@ function parseJsonBody(body, isBase64Encoded) {
27
35
  return {};
28
36
  }
29
37
  }
38
+ /**
39
+ * Detecta mojibake UTF-8-as-Latin-1 y lo revierte. La heurística busca un
40
+ * primer byte UTF-8 multibyte (0xC2-0xF4) seguido de un byte de continuación
41
+ * (0x80-0xBF). En texto natural casi siempre indica corrupción de encoding;
42
+ * si no hay match, el body se considera limpio y se devuelve intacto, así
43
+ * los bodies ASCII puros o UTF-8 ya correctos no se ven afectados.
44
+ */
45
+ function fixUtf8Mojibake(input) {
46
+ if (!MOJIBAKE_PATTERN.test(input))
47
+ return input;
48
+ try {
49
+ return Buffer.from(input, 'latin1').toString('utf-8');
50
+ }
51
+ catch {
52
+ return input;
53
+ }
54
+ }
55
+ const MOJIBAKE_PATTERN = /[Â-ô][€-¿]/;
30
56
  /**
31
57
  * Safely parses query string parameters
32
58
  * Handles multi-value parameters
@@ -1 +1 @@
1
- {"version":3,"file":"body-parser.js","sourceRoot":"","sources":["../../src/http/body-parser.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAQH,sCAeC;AAQD,4CAcC;AAKD,gDAOC;AAvDD;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,IAA+B,EAAE,eAAyB;IACtF,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,IAAI,CAAC;QACH,IAAI,WAAW,GAAG,IAAI,CAAC;QAEvB,IAAI,eAAe,EAAE,CAAC;YACpB,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAwB,CAAC;QAC9D,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAC9B,MAA6D;IAE7D,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEvB,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAChC,KAAQ;IAER,OAAO;QACL,GAAG,KAAK;QACR,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,eAAe,CAAC;KAC7D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"body-parser.js","sourceRoot":"","sources":["../../src/http/body-parser.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAQH,sCAsBC;AA0BD,4CAcC;AAKD,gDAOC;AAhFD;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,IAA+B,EAAE,eAAyB;IACtF,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,IAAI,CAAC;QACH,IAAI,WAAW,GAAG,IAAI,CAAC;QAEvB,IAAI,eAAe,EAAE,CAAC;YACpB,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,oEAAoE;YACpE,+DAA+D;YAC/D,qEAAqE;YACrE,8DAA8D;YAC9D,4CAA4C;YAC5C,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAwB,CAAC;QAC9D,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAEtC;;;;;GAKG;AACH,SAAgB,gBAAgB,CAC9B,MAA6D;IAE7D,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEvB,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAChC,KAAQ;IAER,OAAO;QACL,GAAG,KAAK;QACR,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,eAAe,CAAC;KAC7D,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serverless-event-orchestrator",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "A lightweight, type-safe event dispatcher and middleware orchestrator for AWS Lambda. Designed for hexagonal architectures with support for segmented routing (public, private, backoffice), Cognito User Pool validation, and built-in infrastructure middlewares.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,14 +10,21 @@
10
10
  */
11
11
  export function parseJsonBody(body: string | null | undefined, isBase64Encoded?: boolean): Record<string, any> {
12
12
  if (!body) return {};
13
-
13
+
14
14
  try {
15
15
  let decodedBody = body;
16
-
16
+
17
17
  if (isBase64Encoded) {
18
18
  decodedBody = Buffer.from(body, 'base64').toString('utf-8');
19
+ } else {
20
+ // API Gateway puede entregar el body interpretando bytes UTF-8 como
21
+ // Latin-1 cuando el Content-Type no incluye `; charset=utf-8`,
22
+ // produciendo mojibake (`María` en lugar de `María`). Si detectamos
23
+ // el patrón típico (byte UTF-8 multibyte visto como Latin-1),
24
+ // revertimos re-codificando latin1 → utf-8.
25
+ decodedBody = fixUtf8Mojibake(decodedBody);
19
26
  }
20
-
27
+
21
28
  const parsed = JSON.parse(decodedBody) as Record<string, any>;
22
29
  return parsed ?? {};
23
30
  } catch {
@@ -25,6 +32,24 @@ export function parseJsonBody(body: string | null | undefined, isBase64Encoded?:
25
32
  }
26
33
  }
27
34
 
35
+ /**
36
+ * Detecta mojibake UTF-8-as-Latin-1 y lo revierte. La heurística busca un
37
+ * primer byte UTF-8 multibyte (0xC2-0xF4) seguido de un byte de continuación
38
+ * (0x80-0xBF). En texto natural casi siempre indica corrupción de encoding;
39
+ * si no hay match, el body se considera limpio y se devuelve intacto, así
40
+ * los bodies ASCII puros o UTF-8 ya correctos no se ven afectados.
41
+ */
42
+ function fixUtf8Mojibake(input: string): string {
43
+ if (!MOJIBAKE_PATTERN.test(input)) return input;
44
+ try {
45
+ return Buffer.from(input, 'latin1').toString('utf-8');
46
+ } catch {
47
+ return input;
48
+ }
49
+ }
50
+
51
+ const MOJIBAKE_PATTERN = /[Â-ô][€-¿]/;
52
+
28
53
  /**
29
54
  * Safely parses query string parameters
30
55
  * Handles multi-value parameters
@@ -35,15 +60,15 @@ export function parseQueryParams(
35
60
  params: Record<string, string | undefined> | null | undefined
36
61
  ): Record<string, string> {
37
62
  if (!params) return {};
38
-
63
+
39
64
  const result: Record<string, string> = {};
40
-
65
+
41
66
  for (const [key, value] of Object.entries(params)) {
42
67
  if (value !== undefined) {
43
68
  result[key] = value;
44
69
  }
45
70
  }
46
-
71
+
47
72
  return result;
48
73
  }
49
74