@j3r3mcdev/oast-server 1.1.1 → 1.1.3

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.
Files changed (191) hide show
  1. package/.github/workflows/ci.yml +29 -29
  2. package/.github/workflows/publish.yml +31 -31
  3. package/README.md +192 -192
  4. package/dist/api/controllers/__tests__/tasks.controller.test.d.ts +1 -0
  5. package/dist/api/controllers/events.controller.d.ts +6 -0
  6. package/dist/api/controllers/health.controller.d.ts +4 -0
  7. package/dist/api/controllers/index.d.ts +0 -0
  8. package/dist/api/controllers/tasks.controller.d.ts +40 -0
  9. package/dist/api/dto/__tests__/create-task.dto.test.d.ts +1 -0
  10. package/dist/api/dto/__tests__/filter-tasks.dto.test.d.ts +1 -0
  11. package/dist/api/dto/create-task.dto.d.ts +9 -0
  12. package/dist/api/dto/filter-tasks.dto.d.ts +8 -0
  13. package/dist/api/services/__tests__/events.service.test.d.ts +1 -0
  14. package/dist/api/services/__tests__/tasks.service.test.d.ts +1 -0
  15. package/dist/api/services/events.service.d.ts +8 -0
  16. package/dist/api/services/tasks.service.d.ts +22 -0
  17. package/dist/api/sse/events.stream.d.ts +25 -0
  18. package/dist/bootstrap.d.ts +1 -0
  19. package/dist/bootstrap.js +76 -0
  20. package/dist/config/constants.d.ts +0 -0
  21. package/dist/config/env.d.ts +0 -0
  22. package/dist/core/__tests__/core-router.test.d.ts +1 -0
  23. package/dist/core/__tests__/core-server.test.d.ts +1 -0
  24. package/dist/core/__tests__/event.normalizer.test.d.ts +1 -0
  25. package/dist/core/__tests__/event.router.test.d.ts +1 -0
  26. package/dist/core/__tests__/logger.test.d.ts +1 -0
  27. package/dist/core/__tests__/storage-manager.test.d.ts +1 -0
  28. package/dist/core/event.normalizer.d.ts +10 -0
  29. package/dist/core/event.router.d.ts +7 -0
  30. package/dist/core/http/__tests__/adapter-node.test.d.ts +1 -0
  31. package/dist/core/http/__tests__/body-parser-multipart.test.d.ts +1 -0
  32. package/dist/core/http/__tests__/body-parser-raw.test.d.ts +1 -0
  33. package/dist/core/http/__tests__/body-parser-text.test.d.ts +1 -0
  34. package/dist/core/http/__tests__/compile-path.test.d.ts +1 -0
  35. package/dist/core/http/__tests__/middleware-pipeline.test.d.ts +1 -0
  36. package/dist/core/http/__tests__/request.test.d.ts +1 -0
  37. package/dist/core/http/__tests__/response.test.d.ts +1 -0
  38. package/dist/core/http/__tests__/router-match.test.d.ts +1 -0
  39. package/dist/core/http/adapter-node.d.ts +8 -0
  40. package/dist/core/http/buildRequest.d.ts +2 -0
  41. package/dist/core/http/compile-path.d.ts +13 -0
  42. package/dist/core/http/errors.d.ts +9 -0
  43. package/dist/core/http/http-server.d.ts +7 -0
  44. package/dist/core/http/index.d.ts +0 -0
  45. package/dist/core/http/main.d.ts +0 -0
  46. package/dist/core/http/middleware.d.ts +12 -0
  47. package/dist/core/http/request.d.ts +35 -0
  48. package/dist/core/http/response.d.ts +17 -0
  49. package/dist/core/http/router.d.ts +28 -0
  50. package/dist/core/http/utils.d.ts +0 -0
  51. package/dist/core/id-generator.d.ts +3 -0
  52. package/dist/core/logger.d.ts +29 -0
  53. package/dist/core/router.d.ts +16 -0
  54. package/dist/core/server.d.ts +25 -0
  55. package/dist/core/storage.d.ts +24 -0
  56. package/dist/index.d.ts +9 -0
  57. package/dist/index.js +19 -74
  58. package/dist/listeners/api/__tests__/api.controller.test.d.ts +1 -0
  59. package/dist/listeners/api/__tests__/api.extractor.test.d.ts +1 -0
  60. package/dist/listeners/api/__tests__/api.listener.test.d.ts +1 -0
  61. package/dist/listeners/api/__tests__/api.routes.test.d.ts +1 -0
  62. package/dist/listeners/api/__tests__/api.sse.test.d.ts +1 -0
  63. package/dist/listeners/api/api.controllers.d.ts +9 -0
  64. package/dist/listeners/api/api.extractor.d.ts +5 -0
  65. package/dist/listeners/api/api.listener.d.ts +17 -0
  66. package/dist/listeners/api/api.routes.d.ts +5 -0
  67. package/dist/listeners/api/api.sse.d.ts +10 -0
  68. package/dist/listeners/dns/__tests__/dns.test.d.ts +1 -0
  69. package/dist/listeners/dns/dns.extractor.d.ts +8 -0
  70. package/dist/listeners/dns/dns.listener.d.ts +15 -0
  71. package/dist/listeners/http/__tests__/http.extractor.test.d.ts +1 -0
  72. package/dist/listeners/http/__tests__/http.listener.test.d.ts +1 -0
  73. package/dist/listeners/http/http.extractor.d.ts +11 -0
  74. package/dist/listeners/http/http.listener.d.ts +17 -0
  75. package/dist/listeners/listener.interface.d.ts +4 -0
  76. package/dist/listeners/smtp/__tests__/smtp.extractor.test.d.ts +1 -0
  77. package/dist/listeners/smtp/__tests__/smtp.listener.test.d.ts +1 -0
  78. package/dist/listeners/smtp/smtp.extractor.d.ts +12 -0
  79. package/dist/listeners/smtp/smtp.listener.d.ts +13 -0
  80. package/dist/listeners/ssrf/__tests__/ssrf.extractor.test.d.ts +1 -0
  81. package/dist/listeners/ssrf/__tests__/ssrf.listener.test.d.ts +1 -0
  82. package/dist/listeners/ssrf/__tests__/ssrf.listener.test.js +4 -16
  83. package/dist/listeners/ssrf/ssrf.extractor.d.ts +10 -0
  84. package/dist/listeners/ssrf/ssrf.listener.d.ts +8 -0
  85. package/dist/listeners/tcp/tcp.extractor.d.ts +4 -0
  86. package/dist/listeners/tcp/tcp.listener.d.ts +18 -0
  87. package/dist/listeners/webhook/__tests__/webhook.extractor.test.d.ts +1 -0
  88. package/dist/listeners/webhook/__tests__/webhook.listener.test.d.ts +1 -0
  89. package/dist/listeners/webhook/webhook.extractor.d.ts +8 -0
  90. package/dist/listeners/webhook/webhook.listener.d.ts +8 -0
  91. package/dist/listeners/websocket/__tests__/websocket.extractor.test.d.ts +1 -0
  92. package/dist/listeners/websocket/__tests__/websocket.listener.test.d.ts +1 -0
  93. package/dist/listeners/websocket/websocket.extractor.d.ts +10 -0
  94. package/dist/listeners/websocket/websocket.listener.d.ts +8 -0
  95. package/dist/storage-adapters/adapters/__tests__/memory.storage.test.d.ts +1 -0
  96. package/dist/storage-adapters/adapters/memory.storage.d.ts +21 -0
  97. package/dist/storage-adapters/adapters/redis.storage.d.ts +0 -0
  98. package/dist/storage-adapters/adapters/sqlite.storage.d.ts +0 -0
  99. package/dist/storage-adapters/storage.interface.d.ts +18 -0
  100. package/dist/types/event.types.d.ts +118 -0
  101. package/dist/utils/token.d.ts +0 -0
  102. package/jest.config.js +14 -14
  103. package/package.json +45 -45
  104. package/sadmin list shadows +9 -9
  105. package/src/api/controllers/__tests__/tasks.controller.test.ts +74 -74
  106. package/src/api/controllers/events.controller.ts +10 -10
  107. package/src/api/controllers/health.controller.ts +7 -7
  108. package/src/api/controllers/tasks.controller.ts +41 -41
  109. package/src/api/dto/__tests__/create-task.dto.test.ts +41 -41
  110. package/src/api/dto/__tests__/filter-tasks.dto.test.ts +35 -35
  111. package/src/api/dto/create-task.dto.ts +33 -33
  112. package/src/api/dto/filter-tasks.dto.ts +33 -33
  113. package/src/api/services/__tests__/events.service.test.ts +41 -41
  114. package/src/api/services/__tests__/tasks.service.test.ts +41 -41
  115. package/src/api/services/events.service.ts +17 -17
  116. package/src/api/services/tasks.service.ts +79 -79
  117. package/src/api/sse/events.stream.ts +90 -90
  118. package/src/bootstrap.ts +89 -0
  119. package/src/core/__tests__/core-router.test.ts +30 -30
  120. package/src/core/__tests__/core-server.test.ts +44 -44
  121. package/src/core/__tests__/event.normalizer.test.ts +56 -56
  122. package/src/core/__tests__/event.router.test.ts +89 -89
  123. package/src/core/__tests__/logger.test.ts +32 -32
  124. package/src/core/__tests__/storage-manager.test.ts +74 -74
  125. package/src/core/event.normalizer.ts +147 -147
  126. package/src/core/event.router.ts +13 -13
  127. package/src/core/http/__tests__/adapter-node.test.ts +52 -52
  128. package/src/core/http/__tests__/body-parser-multipart.test.ts +41 -41
  129. package/src/core/http/__tests__/body-parser-raw.test.ts +28 -28
  130. package/src/core/http/__tests__/body-parser-text.test.ts +28 -28
  131. package/src/core/http/__tests__/compile-path.test.ts +39 -39
  132. package/src/core/http/__tests__/middleware-pipeline.test.ts +51 -51
  133. package/src/core/http/__tests__/request.test.ts +34 -34
  134. package/src/core/http/__tests__/response.test.ts +35 -35
  135. package/src/core/http/__tests__/router-match.test.ts +171 -171
  136. package/src/core/http/adapter-node.ts +51 -51
  137. package/src/core/http/buildRequest.ts +18 -18
  138. package/src/core/http/compile-path.ts +32 -32
  139. package/src/core/http/errors.ts +37 -37
  140. package/src/core/http/http-server.ts +52 -52
  141. package/src/core/http/middleware.ts +160 -160
  142. package/src/core/http/request.ts +55 -55
  143. package/src/core/http/response.ts +93 -93
  144. package/src/core/http/router.ts +138 -138
  145. package/src/core/id-generator.ts +8 -8
  146. package/src/core/logger.ts +113 -113
  147. package/src/core/router.ts +44 -44
  148. package/src/core/server.ts +85 -85
  149. package/src/core/storage.ts +64 -64
  150. package/src/index.ts +10 -89
  151. package/src/listeners/api/__tests__/api.controller.test.ts +116 -116
  152. package/src/listeners/api/__tests__/api.extractor.test.ts +46 -46
  153. package/src/listeners/api/__tests__/api.listener.test.ts +82 -82
  154. package/src/listeners/api/__tests__/api.routes.test.ts +155 -155
  155. package/src/listeners/api/__tests__/api.sse.test.ts +105 -105
  156. package/src/listeners/api/api.controllers.ts +67 -67
  157. package/src/listeners/api/api.extractor.ts +43 -43
  158. package/src/listeners/api/api.listener.ts +50 -50
  159. package/src/listeners/api/api.routes.ts +76 -76
  160. package/src/listeners/api/api.sse.ts +38 -38
  161. package/src/listeners/dns/__tests__/dns.test.ts +118 -118
  162. package/src/listeners/dns/dns.extractor.ts +14 -14
  163. package/src/listeners/dns/dns.listener.ts +61 -61
  164. package/src/listeners/http/__tests__/http.extractor.test.ts +59 -59
  165. package/src/listeners/http/__tests__/http.listener.test.ts +133 -133
  166. package/src/listeners/http/http.extractor.ts +15 -15
  167. package/src/listeners/http/http.listener.ts +110 -110
  168. package/src/listeners/listener.interface.ts +4 -4
  169. package/src/listeners/smtp/__tests__/smtp.extractor.test.ts +69 -69
  170. package/src/listeners/smtp/__tests__/smtp.listener.test.ts +150 -150
  171. package/src/listeners/smtp/smtp.extractor.ts +18 -18
  172. package/src/listeners/smtp/smtp.listener.ts +60 -60
  173. package/src/listeners/ssrf/__tests__/ssrf.extractor.test.ts +41 -41
  174. package/src/listeners/ssrf/__tests__/ssrf.listener.test.ts +87 -87
  175. package/src/listeners/ssrf/ssrf.extractor.ts +14 -14
  176. package/src/listeners/ssrf/ssrf.listener.ts +37 -37
  177. package/src/listeners/tcp/tcp.extractor.ts +16 -16
  178. package/src/listeners/tcp/tcp.listener.ts +61 -61
  179. package/src/listeners/webhook/__tests__/webhook.extractor.test.ts +35 -35
  180. package/src/listeners/webhook/__tests__/webhook.listener.test.ts +122 -122
  181. package/src/listeners/webhook/webhook.extractor.ts +12 -12
  182. package/src/listeners/webhook/webhook.listener.ts +58 -58
  183. package/src/listeners/websocket/__tests__/websocket.extractor.test.ts +33 -33
  184. package/src/listeners/websocket/__tests__/websocket.listener.test.ts +90 -90
  185. package/src/listeners/websocket/websocket.extractor.ts +11 -11
  186. package/src/listeners/websocket/websocket.listener.ts +40 -40
  187. package/src/storage-adapters/adapters/__tests__/memory.storage.test.ts +75 -75
  188. package/src/storage-adapters/adapters/memory.storage.ts +64 -64
  189. package/src/storage-adapters/storage.interface.ts +26 -26
  190. package/src/types/event.types.ts +147 -147
  191. package/tsconfig.json +21 -21
@@ -1,59 +1,59 @@
1
- import { describe, it, expect } from "@jest/globals";
2
- import { HttpExtractor } from "../http.extractor";
3
-
4
- describe("HttpExtractor", () => {
5
- it("extrait correctement un RawEvent complet", () => {
6
- const req: any = {
7
- ip: "1.1.1.1",
8
- method: "POST",
9
- path: "/login",
10
- url: "/login",
11
- headers: {
12
- "x-forwarded-for": "2.2.2.2",
13
- host: "localhost",
14
- },
15
- query: { a: 1 },
16
- body: { user: "admin" },
17
- };
18
-
19
- const extracted = HttpExtractor.extract(req);
20
-
21
- expect(extracted).toEqual({
22
- ip: "1.1.1.1", // priorité à req.ip
23
- method: "POST",
24
- path: "/login",
25
- headers: req.headers,
26
- query: { a: 1 },
27
- body: { user: "admin" },
28
- raw: req,
29
- });
30
- });
31
-
32
- it("utilise x-forwarded-for si req.ip est absent", () => {
33
- const req: any = {
34
- method: "GET",
35
- url: "/",
36
- headers: { "x-forwarded-for": "9.9.9.9" },
37
- };
38
-
39
- const extracted = HttpExtractor.extract(req);
40
-
41
- expect(extracted.ip).toBe("9.9.9.9");
42
- });
43
-
44
- it("retourne une structure complète même si des champs manquent", () => {
45
- const req: any = {};
46
-
47
- const extracted = HttpExtractor.extract(req);
48
-
49
- expect(extracted).toEqual({
50
- ip: "",
51
- method: undefined,
52
- path: undefined,
53
- headers: {},
54
- query: {},
55
- body: null,
56
- raw: req,
57
- });
58
- });
59
- });
1
+ import { describe, it, expect } from "@jest/globals";
2
+ import { HttpExtractor } from "../http.extractor";
3
+
4
+ describe("HttpExtractor", () => {
5
+ it("extrait correctement un RawEvent complet", () => {
6
+ const req: any = {
7
+ ip: "1.1.1.1",
8
+ method: "POST",
9
+ path: "/login",
10
+ url: "/login",
11
+ headers: {
12
+ "x-forwarded-for": "2.2.2.2",
13
+ host: "localhost",
14
+ },
15
+ query: { a: 1 },
16
+ body: { user: "admin" },
17
+ };
18
+
19
+ const extracted = HttpExtractor.extract(req);
20
+
21
+ expect(extracted).toEqual({
22
+ ip: "1.1.1.1", // priorité à req.ip
23
+ method: "POST",
24
+ path: "/login",
25
+ headers: req.headers,
26
+ query: { a: 1 },
27
+ body: { user: "admin" },
28
+ raw: req,
29
+ });
30
+ });
31
+
32
+ it("utilise x-forwarded-for si req.ip est absent", () => {
33
+ const req: any = {
34
+ method: "GET",
35
+ url: "/",
36
+ headers: { "x-forwarded-for": "9.9.9.9" },
37
+ };
38
+
39
+ const extracted = HttpExtractor.extract(req);
40
+
41
+ expect(extracted.ip).toBe("9.9.9.9");
42
+ });
43
+
44
+ it("retourne une structure complète même si des champs manquent", () => {
45
+ const req: any = {};
46
+
47
+ const extracted = HttpExtractor.extract(req);
48
+
49
+ expect(extracted).toEqual({
50
+ ip: "",
51
+ method: undefined,
52
+ path: undefined,
53
+ headers: {},
54
+ query: {},
55
+ body: null,
56
+ raw: req,
57
+ });
58
+ });
59
+ });
@@ -1,133 +1,133 @@
1
- import {
2
- describe,
3
- it,
4
- expect,
5
- jest,
6
- beforeEach,
7
- afterEach,
8
- } from "@jest/globals";
9
- import http from "http";
10
- import { HttpListener } from "../http.listener";
11
- import { EventNormalizer } from "../../../core/event.normalizer";
12
-
13
- // Mock EventNormalizer
14
- jest.mock("../../../core/event.normalizer", () => ({
15
- EventNormalizer: {
16
- normalizeHttp: jest.fn(),
17
- },
18
- }));
19
-
20
- // Helper pour requêtes HTTP
21
- async function makeRequest(port: number, path: string): Promise<string> {
22
- return new Promise((resolve) => {
23
- const req = http.request(
24
- {
25
- hostname: "localhost",
26
- port,
27
- path,
28
- method: "GET",
29
- },
30
- (res) => {
31
- let data = "";
32
- res.on("data", (chunk) => (data += chunk));
33
- res.on("end", () => resolve(data));
34
- },
35
- );
36
-
37
- req.end();
38
- });
39
- }
40
-
41
- describe("HttpListener (PRO)", () => {
42
- let listener: HttpListener;
43
- let router: { dispatch: jest.Mock };
44
- let port: number;
45
-
46
- beforeEach(() => {
47
- router = {
48
- dispatch: jest.fn(),
49
- };
50
-
51
- port = 10000 + Math.floor(Math.random() * 5000);
52
- });
53
-
54
- afterEach(async () => {
55
- if (listener) {
56
- await listener.stop();
57
- }
58
- });
59
-
60
- it("normalise, dispatch et renvoie un eventId", async () => {
61
- listener = new HttpListener(router as any, { port });
62
- await listener.start();
63
-
64
- // NormalizedHttpEvent VALIDE
65
- (EventNormalizer.normalizeHttp as jest.Mock).mockReturnValue({
66
- id: "evt-123",
67
- type: "http",
68
- timestamp: Date.now(),
69
- sourceIp: "127.0.0.1",
70
- request: {
71
- method: "GET",
72
- path: "/test",
73
- headers: {},
74
- query: {},
75
- body: "",
76
- },
77
- });
78
-
79
- const response = await makeRequest(port, "/test");
80
- const json = JSON.parse(response);
81
-
82
- expect(EventNormalizer.normalizeHttp).toHaveBeenCalled();
83
- expect(router.dispatch).toHaveBeenCalled();
84
- expect(json).toEqual({
85
- success: true,
86
- eventId: "evt-123",
87
- });
88
- });
89
-
90
- it("renvoie 500 si normalizeHttp lance une erreur", async () => {
91
- listener = new HttpListener(router as any, { port });
92
- await listener.start();
93
-
94
- (EventNormalizer.normalizeHttp as jest.Mock).mockImplementation(() => {
95
- throw new Error("bad request");
96
- });
97
-
98
- const response = await makeRequest(port, "/err");
99
- const json = JSON.parse(response);
100
-
101
- expect(json.success).toBe(false);
102
- expect(json.error).toBe("bad request");
103
- });
104
-
105
- it("renvoie 500 si router.dispatch rejette une erreur", async () => {
106
- listener = new HttpListener(router as any, { port });
107
- await listener.start();
108
-
109
- (EventNormalizer.normalizeHttp as jest.Mock).mockReturnValue({
110
- id: "evt-999",
111
- type: "http",
112
- timestamp: Date.now(),
113
- sourceIp: "127.0.0.1",
114
- request: {
115
- method: "GET",
116
- path: "/dispatch-error",
117
- headers: {},
118
- query: {},
119
- body: "",
120
- },
121
- });
122
-
123
- (router.dispatch as any).mockRejectedValueOnce(
124
- new Error("dispatch failed"),
125
- );
126
-
127
- const response = await makeRequest(port, "/dispatch-error");
128
- const json = JSON.parse(response);
129
-
130
- expect(json.success).toBe(false);
131
- expect(json.error).toBe("dispatch failed");
132
- });
133
- });
1
+ import {
2
+ describe,
3
+ it,
4
+ expect,
5
+ jest,
6
+ beforeEach,
7
+ afterEach,
8
+ } from "@jest/globals";
9
+ import http from "http";
10
+ import { HttpListener } from "../http.listener";
11
+ import { EventNormalizer } from "../../../core/event.normalizer";
12
+
13
+ // Mock EventNormalizer
14
+ jest.mock("../../../core/event.normalizer", () => ({
15
+ EventNormalizer: {
16
+ normalizeHttp: jest.fn(),
17
+ },
18
+ }));
19
+
20
+ // Helper pour requêtes HTTP
21
+ async function makeRequest(port: number, path: string): Promise<string> {
22
+ return new Promise((resolve) => {
23
+ const req = http.request(
24
+ {
25
+ hostname: "localhost",
26
+ port,
27
+ path,
28
+ method: "GET",
29
+ },
30
+ (res) => {
31
+ let data = "";
32
+ res.on("data", (chunk) => (data += chunk));
33
+ res.on("end", () => resolve(data));
34
+ },
35
+ );
36
+
37
+ req.end();
38
+ });
39
+ }
40
+
41
+ describe("HttpListener (PRO)", () => {
42
+ let listener: HttpListener;
43
+ let router: { dispatch: jest.Mock };
44
+ let port: number;
45
+
46
+ beforeEach(() => {
47
+ router = {
48
+ dispatch: jest.fn(),
49
+ };
50
+
51
+ port = 10000 + Math.floor(Math.random() * 5000);
52
+ });
53
+
54
+ afterEach(async () => {
55
+ if (listener) {
56
+ await listener.stop();
57
+ }
58
+ });
59
+
60
+ it("normalise, dispatch et renvoie un eventId", async () => {
61
+ listener = new HttpListener(router as any, { port });
62
+ await listener.start();
63
+
64
+ // NormalizedHttpEvent VALIDE
65
+ (EventNormalizer.normalizeHttp as jest.Mock).mockReturnValue({
66
+ id: "evt-123",
67
+ type: "http",
68
+ timestamp: Date.now(),
69
+ sourceIp: "127.0.0.1",
70
+ request: {
71
+ method: "GET",
72
+ path: "/test",
73
+ headers: {},
74
+ query: {},
75
+ body: "",
76
+ },
77
+ });
78
+
79
+ const response = await makeRequest(port, "/test");
80
+ const json = JSON.parse(response);
81
+
82
+ expect(EventNormalizer.normalizeHttp).toHaveBeenCalled();
83
+ expect(router.dispatch).toHaveBeenCalled();
84
+ expect(json).toEqual({
85
+ success: true,
86
+ eventId: "evt-123",
87
+ });
88
+ });
89
+
90
+ it("renvoie 500 si normalizeHttp lance une erreur", async () => {
91
+ listener = new HttpListener(router as any, { port });
92
+ await listener.start();
93
+
94
+ (EventNormalizer.normalizeHttp as jest.Mock).mockImplementation(() => {
95
+ throw new Error("bad request");
96
+ });
97
+
98
+ const response = await makeRequest(port, "/err");
99
+ const json = JSON.parse(response);
100
+
101
+ expect(json.success).toBe(false);
102
+ expect(json.error).toBe("bad request");
103
+ });
104
+
105
+ it("renvoie 500 si router.dispatch rejette une erreur", async () => {
106
+ listener = new HttpListener(router as any, { port });
107
+ await listener.start();
108
+
109
+ (EventNormalizer.normalizeHttp as jest.Mock).mockReturnValue({
110
+ id: "evt-999",
111
+ type: "http",
112
+ timestamp: Date.now(),
113
+ sourceIp: "127.0.0.1",
114
+ request: {
115
+ method: "GET",
116
+ path: "/dispatch-error",
117
+ headers: {},
118
+ query: {},
119
+ body: "",
120
+ },
121
+ });
122
+
123
+ (router.dispatch as any).mockRejectedValueOnce(
124
+ new Error("dispatch failed"),
125
+ );
126
+
127
+ const response = await makeRequest(port, "/dispatch-error");
128
+ const json = JSON.parse(response);
129
+
130
+ expect(json.success).toBe(false);
131
+ expect(json.error).toBe("dispatch failed");
132
+ });
133
+ });
@@ -1,15 +1,15 @@
1
- export class HttpExtractor {
2
- static extract(req: any) {
3
- const headers = req.headers ?? {};
4
-
5
- return {
6
- ip: req.ip ?? headers["x-forwarded-for"] ?? "",
7
- method: req.method, // ← PAS de fallback ""
8
- path: req.path ?? req.url, // ← PAS de fallback ""
9
- headers,
10
- query: req.query ?? {},
11
- body: req.body ?? null,
12
- raw: req,
13
- };
14
- }
15
- }
1
+ export class HttpExtractor {
2
+ static extract(req: any) {
3
+ const headers = req.headers ?? {};
4
+
5
+ return {
6
+ ip: req.ip ?? headers["x-forwarded-for"] ?? "",
7
+ method: req.method, // ← PAS de fallback ""
8
+ path: req.path ?? req.url, // ← PAS de fallback ""
9
+ headers,
10
+ query: req.query ?? {},
11
+ body: req.body ?? null,
12
+ raw: req,
13
+ };
14
+ }
15
+ }
@@ -1,110 +1,110 @@
1
- import http, { IncomingMessage, ServerResponse } from "http";
2
- import { Logger } from "../../core/logger";
3
- import { CoreRouter } from "../../core/router";
4
- import { EventNormalizer } from "../../core/event.normalizer";
5
-
6
- export interface HttpListenerOptions {
7
- port: number;
8
- logger?: Logger;
9
- }
10
-
11
- export class HttpListener {
12
- private server?: http.Server;
13
- private logger: Logger;
14
-
15
- constructor(
16
- private router: CoreRouter,
17
- private options: HttpListenerOptions,
18
- ) {
19
- this.logger = options.logger ?? new Logger({ context: "HttpListener" });
20
- }
21
-
22
- async start(): Promise<void> {
23
- return new Promise((resolve) => {
24
- this.server = http.createServer(async (req, res) => {
25
- await this.handleRequest(req, res);
26
- });
27
-
28
- this.server.listen(this.options.port, () => {
29
- this.logger.info(`HTTP Listener started on port ${this.options.port}`);
30
- resolve();
31
- });
32
- });
33
- }
34
-
35
- async stop(): Promise<void> {
36
- return new Promise((resolve, reject) => {
37
- if (!this.server) return resolve();
38
-
39
- this.server.close((err) => {
40
- if (err) return reject(err);
41
- this.logger.info("HTTP Listener stopped");
42
- resolve();
43
- });
44
- });
45
- }
46
-
47
- private async handleRequest(req: IncomingMessage, res: ServerResponse) {
48
- try {
49
- const body = await this.readBody(req);
50
-
51
- const ipHeader = req.headers["x-forwarded-for"];
52
- const ip =
53
- typeof ipHeader === "string"
54
- ? ipHeader
55
- : Array.isArray(ipHeader)
56
- ? ipHeader[0]
57
- : (req.socket.remoteAddress ?? "");
58
-
59
- const rawEvent = {
60
- ip,
61
- method: req.method ?? "",
62
- path: req.url ?? "",
63
- headers: req.headers,
64
- query: {}, // parsing optionnel
65
- body,
66
- raw: req,
67
- };
68
-
69
- const normalized = EventNormalizer.normalizeHttp(rawEvent);
70
-
71
- await this.router.dispatch(normalized);
72
-
73
- res.writeHead(200, { "Content-Type": "application/json" });
74
- res.end(
75
- JSON.stringify({
76
- success: true,
77
- eventId: normalized.id,
78
- }),
79
- );
80
- } catch (err: any) {
81
- this.logger.error("HTTP Listener error", err);
82
-
83
- res.writeHead(500, { "Content-Type": "application/json" });
84
- res.end(
85
- JSON.stringify({
86
- success: false,
87
- error: err.message,
88
- }),
89
- );
90
- }
91
- }
92
-
93
- private readBody(req: IncomingMessage): Promise<any> {
94
- return new Promise((resolve) => {
95
- let data = "";
96
-
97
- req.on("data", (chunk) => {
98
- data += chunk;
99
- });
100
-
101
- req.on("end", () => {
102
- try {
103
- resolve(JSON.parse(data || "{}"));
104
- } catch {
105
- resolve(data);
106
- }
107
- });
108
- });
109
- }
110
- }
1
+ import http, { IncomingMessage, ServerResponse } from "http";
2
+ import { Logger } from "../../core/logger";
3
+ import { CoreRouter } from "../../core/router";
4
+ import { EventNormalizer } from "../../core/event.normalizer";
5
+
6
+ export interface HttpListenerOptions {
7
+ port: number;
8
+ logger?: Logger;
9
+ }
10
+
11
+ export class HttpListener {
12
+ private server?: http.Server;
13
+ private logger: Logger;
14
+
15
+ constructor(
16
+ private router: CoreRouter,
17
+ private options: HttpListenerOptions,
18
+ ) {
19
+ this.logger = options.logger ?? new Logger({ context: "HttpListener" });
20
+ }
21
+
22
+ async start(): Promise<void> {
23
+ return new Promise((resolve) => {
24
+ this.server = http.createServer(async (req, res) => {
25
+ await this.handleRequest(req, res);
26
+ });
27
+
28
+ this.server.listen(this.options.port, () => {
29
+ this.logger.info(`HTTP Listener started on port ${this.options.port}`);
30
+ resolve();
31
+ });
32
+ });
33
+ }
34
+
35
+ async stop(): Promise<void> {
36
+ return new Promise((resolve, reject) => {
37
+ if (!this.server) return resolve();
38
+
39
+ this.server.close((err) => {
40
+ if (err) return reject(err);
41
+ this.logger.info("HTTP Listener stopped");
42
+ resolve();
43
+ });
44
+ });
45
+ }
46
+
47
+ private async handleRequest(req: IncomingMessage, res: ServerResponse) {
48
+ try {
49
+ const body = await this.readBody(req);
50
+
51
+ const ipHeader = req.headers["x-forwarded-for"];
52
+ const ip =
53
+ typeof ipHeader === "string"
54
+ ? ipHeader
55
+ : Array.isArray(ipHeader)
56
+ ? ipHeader[0]
57
+ : (req.socket.remoteAddress ?? "");
58
+
59
+ const rawEvent = {
60
+ ip,
61
+ method: req.method ?? "",
62
+ path: req.url ?? "",
63
+ headers: req.headers,
64
+ query: {}, // parsing optionnel
65
+ body,
66
+ raw: req,
67
+ };
68
+
69
+ const normalized = EventNormalizer.normalizeHttp(rawEvent);
70
+
71
+ await this.router.dispatch(normalized);
72
+
73
+ res.writeHead(200, { "Content-Type": "application/json" });
74
+ res.end(
75
+ JSON.stringify({
76
+ success: true,
77
+ eventId: normalized.id,
78
+ }),
79
+ );
80
+ } catch (err: any) {
81
+ this.logger.error("HTTP Listener error", err);
82
+
83
+ res.writeHead(500, { "Content-Type": "application/json" });
84
+ res.end(
85
+ JSON.stringify({
86
+ success: false,
87
+ error: err.message,
88
+ }),
89
+ );
90
+ }
91
+ }
92
+
93
+ private readBody(req: IncomingMessage): Promise<any> {
94
+ return new Promise((resolve) => {
95
+ let data = "";
96
+
97
+ req.on("data", (chunk) => {
98
+ data += chunk;
99
+ });
100
+
101
+ req.on("end", () => {
102
+ try {
103
+ resolve(JSON.parse(data || "{}"));
104
+ } catch {
105
+ resolve(data);
106
+ }
107
+ });
108
+ });
109
+ }
110
+ }
@@ -1,4 +1,4 @@
1
- export interface Listener {
2
- start(): Promise<void>;
3
- stop(): Promise<void>;
4
- }
1
+ export interface Listener {
2
+ start(): Promise<void>;
3
+ stop(): Promise<void>;
4
+ }