@j3r3mcdev/oast-server 1.1.6 → 1.1.8
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/.github/workflows/ci.yml +29 -29
- package/.github/workflows/publish.yml +31 -31
- package/README.md +192 -192
- package/dist/core/router.d.ts +1 -0
- package/dist/core/router.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +16 -1
- package/jest.config.js +14 -14
- package/package.json +45 -45
- package/sadmin list shadows +9 -9
- package/src/api/controllers/__tests__/tasks.controller.test.ts +74 -74
- package/src/api/controllers/events.controller.ts +10 -10
- package/src/api/controllers/health.controller.ts +7 -7
- package/src/api/controllers/tasks.controller.ts +41 -41
- package/src/api/dto/__tests__/create-task.dto.test.ts +41 -41
- package/src/api/dto/__tests__/filter-tasks.dto.test.ts +35 -35
- package/src/api/dto/create-task.dto.ts +33 -33
- package/src/api/dto/filter-tasks.dto.ts +33 -33
- package/src/api/services/__tests__/events.service.test.ts +41 -41
- package/src/api/services/__tests__/tasks.service.test.ts +41 -41
- package/src/api/services/events.service.ts +17 -17
- package/src/api/services/tasks.service.ts +79 -79
- package/src/api/sse/events.stream.ts +90 -90
- package/src/bootstrap.ts +89 -89
- package/src/core/__tests__/core-router.test.ts +30 -30
- package/src/core/__tests__/core-server.test.ts +44 -44
- package/src/core/__tests__/event.normalizer.test.ts +56 -56
- package/src/core/__tests__/event.router.test.ts +89 -89
- package/src/core/__tests__/logger.test.ts +32 -32
- package/src/core/__tests__/storage-manager.test.ts +74 -74
- package/src/core/event.normalizer.ts +147 -147
- package/src/core/event.router.ts +13 -13
- package/src/core/http/__tests__/adapter-node.test.ts +52 -52
- package/src/core/http/__tests__/body-parser-multipart.test.ts +41 -41
- package/src/core/http/__tests__/body-parser-raw.test.ts +28 -28
- package/src/core/http/__tests__/body-parser-text.test.ts +28 -28
- package/src/core/http/__tests__/compile-path.test.ts +39 -39
- package/src/core/http/__tests__/middleware-pipeline.test.ts +51 -51
- package/src/core/http/__tests__/request.test.ts +34 -34
- package/src/core/http/__tests__/response.test.ts +35 -35
- package/src/core/http/__tests__/router-match.test.ts +171 -171
- package/src/core/http/adapter-node.ts +51 -51
- package/src/core/http/buildRequest.ts +18 -18
- package/src/core/http/compile-path.ts +32 -32
- package/src/core/http/errors.ts +37 -37
- package/src/core/http/http-server.ts +52 -52
- package/src/core/http/middleware.ts +160 -160
- package/src/core/http/request.ts +55 -55
- package/src/core/http/response.ts +93 -93
- package/src/core/http/router.ts +138 -138
- package/src/core/id-generator.ts +8 -8
- package/src/core/logger.ts +113 -113
- package/src/core/router.ts +44 -44
- package/src/core/server.ts +85 -85
- package/src/core/storage.ts +64 -64
- package/src/index.ts +14 -14
- package/src/listeners/api/__tests__/api.controller.test.ts +116 -116
- package/src/listeners/api/__tests__/api.extractor.test.ts +46 -46
- package/src/listeners/api/__tests__/api.listener.test.ts +82 -82
- package/src/listeners/api/__tests__/api.routes.test.ts +155 -155
- package/src/listeners/api/__tests__/api.sse.test.ts +105 -105
- package/src/listeners/api/api.controllers.ts +67 -67
- package/src/listeners/api/api.extractor.ts +43 -43
- package/src/listeners/api/api.listener.ts +50 -50
- package/src/listeners/api/api.routes.ts +76 -76
- package/src/listeners/api/api.sse.ts +38 -38
- package/src/listeners/dns/__tests__/dns.test.ts +118 -118
- package/src/listeners/dns/dns.extractor.ts +14 -14
- package/src/listeners/dns/dns.listener.ts +61 -61
- package/src/listeners/http/__tests__/http.extractor.test.ts +59 -59
- package/src/listeners/http/__tests__/http.listener.test.ts +133 -133
- package/src/listeners/http/http.extractor.ts +15 -15
- package/src/listeners/http/http.listener.ts +110 -110
- package/src/listeners/listener.interface.ts +4 -4
- package/src/listeners/smtp/__tests__/smtp.extractor.test.ts +69 -69
- package/src/listeners/smtp/__tests__/smtp.listener.test.ts +150 -150
- package/src/listeners/smtp/smtp.extractor.ts +18 -18
- package/src/listeners/smtp/smtp.listener.ts +60 -60
- package/src/listeners/ssrf/__tests__/ssrf.extractor.test.ts +41 -41
- package/src/listeners/ssrf/__tests__/ssrf.listener.test.ts +87 -87
- package/src/listeners/ssrf/ssrf.extractor.ts +14 -14
- package/src/listeners/ssrf/ssrf.listener.ts +37 -37
- package/src/listeners/tcp/tcp.extractor.ts +16 -16
- package/src/listeners/tcp/tcp.listener.ts +61 -61
- package/src/listeners/webhook/__tests__/webhook.extractor.test.ts +35 -35
- package/src/listeners/webhook/__tests__/webhook.listener.test.ts +122 -122
- package/src/listeners/webhook/webhook.extractor.ts +12 -12
- package/src/listeners/webhook/webhook.listener.ts +58 -58
- package/src/listeners/websocket/__tests__/websocket.extractor.test.ts +33 -33
- package/src/listeners/websocket/__tests__/websocket.listener.test.ts +90 -90
- package/src/listeners/websocket/websocket.extractor.ts +11 -11
- package/src/listeners/websocket/websocket.listener.ts +40 -40
- package/src/storage-adapters/adapters/__tests__/memory.storage.test.ts +75 -75
- package/src/storage-adapters/adapters/memory.storage.ts +64 -64
- package/src/storage-adapters/storage.interface.ts +26 -26
- package/src/types/event.types.ts +147 -147
- package/tsconfig.json +20 -21
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
import { Router } from "../router";
|
|
2
|
-
import { describe, it, expect } from "@jest/globals";
|
|
3
|
-
|
|
4
|
-
describe("Router.match", () => {
|
|
5
|
-
it("match une route statique", () => {
|
|
6
|
-
const router = new Router();
|
|
7
|
-
|
|
8
|
-
router.register("GET", "/tasks", () => "ok");
|
|
9
|
-
|
|
10
|
-
const result = router.match("GET", "/tasks");
|
|
11
|
-
|
|
12
|
-
expect(result).not.toBeNull();
|
|
13
|
-
expect(result?.handler()).toBe("ok");
|
|
14
|
-
expect(result?.params).toEqual({});
|
|
15
|
-
expect(result?.middlewares).toEqual([]);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("match une route avec paramètre", () => {
|
|
19
|
-
const router = new Router();
|
|
20
|
-
|
|
21
|
-
router.register("GET", "/tasks/:id", () => "task");
|
|
22
|
-
|
|
23
|
-
const result = router.match("GET", "/tasks/42");
|
|
24
|
-
|
|
25
|
-
expect(result).not.toBeNull();
|
|
26
|
-
expect(result?.handler()).toBe("task");
|
|
27
|
-
expect(result?.params).toEqual({ id: "42" });
|
|
28
|
-
expect(result?.middlewares).toEqual([]);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("match une route avec wildcard", () => {
|
|
32
|
-
const router = new Router();
|
|
33
|
-
|
|
34
|
-
router.register("GET", "/files/*", () => "wild");
|
|
35
|
-
|
|
36
|
-
const result = router.match("GET", "/files/any/path/here");
|
|
37
|
-
|
|
38
|
-
expect(result).not.toBeNull();
|
|
39
|
-
expect(result?.handler()).toBe("wild");
|
|
40
|
-
expect(result?.params).toEqual({});
|
|
41
|
-
expect(result?.middlewares).toEqual([]);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("match un chemin complexe avec static, param et wildcard", () => {
|
|
45
|
-
const router = new Router();
|
|
46
|
-
|
|
47
|
-
router.register("GET", "/a/:b/*/c", () => "complex");
|
|
48
|
-
|
|
49
|
-
const result = router.match("GET", "/a/hello/anything/here/c");
|
|
50
|
-
|
|
51
|
-
expect(result).not.toBeNull();
|
|
52
|
-
expect(result?.handler()).toBe("complex");
|
|
53
|
-
expect(result?.params).toEqual({ b: "hello" });
|
|
54
|
-
expect(result?.middlewares).toEqual([]);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("ne match pas quand le chemin ne correspond pas", () => {
|
|
58
|
-
const router = new Router();
|
|
59
|
-
|
|
60
|
-
router.register("GET", "/tasks/:id", () => "ok");
|
|
61
|
-
|
|
62
|
-
const result = router.match("GET", "/tasks");
|
|
63
|
-
|
|
64
|
-
expect(result).toBeNull();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("ne match pas quand le chemin est trop long", () => {
|
|
68
|
-
const router = new Router();
|
|
69
|
-
|
|
70
|
-
router.register("GET", "/tasks/:id", () => "ok");
|
|
71
|
-
|
|
72
|
-
const result = router.match("GET", "/tasks/42/extra");
|
|
73
|
-
|
|
74
|
-
expect(result).toBeNull();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("ne match pas quand la méthode HTTP ne correspond pas", () => {
|
|
78
|
-
const router = new Router();
|
|
79
|
-
|
|
80
|
-
router.register("GET", "/tasks", () => "ok");
|
|
81
|
-
|
|
82
|
-
const result = router.match("POST", "/tasks");
|
|
83
|
-
|
|
84
|
-
expect(result).toBeNull();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("match une route avec plusieurs paramètres", () => {
|
|
88
|
-
const router = new Router();
|
|
89
|
-
|
|
90
|
-
router.register("GET", "/users/:userId/tasks/:taskId", () => "multi");
|
|
91
|
-
|
|
92
|
-
const result = router.match("GET", "/users/12/tasks/99");
|
|
93
|
-
|
|
94
|
-
expect(result).not.toBeNull();
|
|
95
|
-
expect(result?.handler()).toBe("multi");
|
|
96
|
-
expect(result?.params).toEqual({
|
|
97
|
-
userId: "12",
|
|
98
|
-
taskId: "99",
|
|
99
|
-
});
|
|
100
|
-
expect(result?.middlewares).toEqual([]);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("match une route complexe avec plusieurs paramètres et un wildcard", () => {
|
|
104
|
-
const router = new Router();
|
|
105
|
-
|
|
106
|
-
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
107
|
-
|
|
108
|
-
const result = router.match("GET", "/users/12/any/path/here/tasks/99");
|
|
109
|
-
|
|
110
|
-
expect(result).not.toBeNull();
|
|
111
|
-
expect(result?.handler()).toBe("mw");
|
|
112
|
-
expect(result?.params).toEqual({
|
|
113
|
-
userId: "12",
|
|
114
|
-
taskId: "99",
|
|
115
|
-
});
|
|
116
|
-
expect(result?.middlewares).toEqual([]);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("ne match pas un chemin complexe si la fin ne correspond pas", () => {
|
|
120
|
-
const router = new Router();
|
|
121
|
-
|
|
122
|
-
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
123
|
-
|
|
124
|
-
const result = router.match("GET", "/users/12/any/path/here/taskz/99");
|
|
125
|
-
|
|
126
|
-
expect(result).toBeNull();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("ne match pas si le paramètre final est manquant", () => {
|
|
130
|
-
const router = new Router();
|
|
131
|
-
|
|
132
|
-
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
133
|
-
|
|
134
|
-
const result = router.match("GET", "/users/12/any/path/here/tasks/");
|
|
135
|
-
|
|
136
|
-
expect(result).toBeNull();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("ne match pas si le paramètre du début est manquant", () => {
|
|
140
|
-
const router = new Router();
|
|
141
|
-
|
|
142
|
-
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
143
|
-
|
|
144
|
-
const result = router.match("GET", "/users//any/path/tasks/99");
|
|
145
|
-
|
|
146
|
-
expect(result).toBeNull();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("ne match pas si le wildcard est vide", () => {
|
|
150
|
-
const router = new Router();
|
|
151
|
-
|
|
152
|
-
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
153
|
-
|
|
154
|
-
const result = router.match("GET", "/users/12//tasks/99");
|
|
155
|
-
|
|
156
|
-
expect(result).toBeNull();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it("match une route avec wildcard en fin de chemin", () => {
|
|
160
|
-
const router = new Router();
|
|
161
|
-
|
|
162
|
-
router.register("GET", "/files/*", () => "end");
|
|
163
|
-
|
|
164
|
-
const result = router.match("GET", "/files/path/to/something");
|
|
165
|
-
|
|
166
|
-
expect(result).not.toBeNull();
|
|
167
|
-
expect(result?.handler()).toBe("end");
|
|
168
|
-
expect(result?.params).toEqual({});
|
|
169
|
-
expect(result?.middlewares).toEqual([]);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
1
|
+
import { Router } from "../router";
|
|
2
|
+
import { describe, it, expect } from "@jest/globals";
|
|
3
|
+
|
|
4
|
+
describe("Router.match", () => {
|
|
5
|
+
it("match une route statique", () => {
|
|
6
|
+
const router = new Router();
|
|
7
|
+
|
|
8
|
+
router.register("GET", "/tasks", () => "ok");
|
|
9
|
+
|
|
10
|
+
const result = router.match("GET", "/tasks");
|
|
11
|
+
|
|
12
|
+
expect(result).not.toBeNull();
|
|
13
|
+
expect(result?.handler()).toBe("ok");
|
|
14
|
+
expect(result?.params).toEqual({});
|
|
15
|
+
expect(result?.middlewares).toEqual([]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("match une route avec paramètre", () => {
|
|
19
|
+
const router = new Router();
|
|
20
|
+
|
|
21
|
+
router.register("GET", "/tasks/:id", () => "task");
|
|
22
|
+
|
|
23
|
+
const result = router.match("GET", "/tasks/42");
|
|
24
|
+
|
|
25
|
+
expect(result).not.toBeNull();
|
|
26
|
+
expect(result?.handler()).toBe("task");
|
|
27
|
+
expect(result?.params).toEqual({ id: "42" });
|
|
28
|
+
expect(result?.middlewares).toEqual([]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("match une route avec wildcard", () => {
|
|
32
|
+
const router = new Router();
|
|
33
|
+
|
|
34
|
+
router.register("GET", "/files/*", () => "wild");
|
|
35
|
+
|
|
36
|
+
const result = router.match("GET", "/files/any/path/here");
|
|
37
|
+
|
|
38
|
+
expect(result).not.toBeNull();
|
|
39
|
+
expect(result?.handler()).toBe("wild");
|
|
40
|
+
expect(result?.params).toEqual({});
|
|
41
|
+
expect(result?.middlewares).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("match un chemin complexe avec static, param et wildcard", () => {
|
|
45
|
+
const router = new Router();
|
|
46
|
+
|
|
47
|
+
router.register("GET", "/a/:b/*/c", () => "complex");
|
|
48
|
+
|
|
49
|
+
const result = router.match("GET", "/a/hello/anything/here/c");
|
|
50
|
+
|
|
51
|
+
expect(result).not.toBeNull();
|
|
52
|
+
expect(result?.handler()).toBe("complex");
|
|
53
|
+
expect(result?.params).toEqual({ b: "hello" });
|
|
54
|
+
expect(result?.middlewares).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("ne match pas quand le chemin ne correspond pas", () => {
|
|
58
|
+
const router = new Router();
|
|
59
|
+
|
|
60
|
+
router.register("GET", "/tasks/:id", () => "ok");
|
|
61
|
+
|
|
62
|
+
const result = router.match("GET", "/tasks");
|
|
63
|
+
|
|
64
|
+
expect(result).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("ne match pas quand le chemin est trop long", () => {
|
|
68
|
+
const router = new Router();
|
|
69
|
+
|
|
70
|
+
router.register("GET", "/tasks/:id", () => "ok");
|
|
71
|
+
|
|
72
|
+
const result = router.match("GET", "/tasks/42/extra");
|
|
73
|
+
|
|
74
|
+
expect(result).toBeNull();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("ne match pas quand la méthode HTTP ne correspond pas", () => {
|
|
78
|
+
const router = new Router();
|
|
79
|
+
|
|
80
|
+
router.register("GET", "/tasks", () => "ok");
|
|
81
|
+
|
|
82
|
+
const result = router.match("POST", "/tasks");
|
|
83
|
+
|
|
84
|
+
expect(result).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("match une route avec plusieurs paramètres", () => {
|
|
88
|
+
const router = new Router();
|
|
89
|
+
|
|
90
|
+
router.register("GET", "/users/:userId/tasks/:taskId", () => "multi");
|
|
91
|
+
|
|
92
|
+
const result = router.match("GET", "/users/12/tasks/99");
|
|
93
|
+
|
|
94
|
+
expect(result).not.toBeNull();
|
|
95
|
+
expect(result?.handler()).toBe("multi");
|
|
96
|
+
expect(result?.params).toEqual({
|
|
97
|
+
userId: "12",
|
|
98
|
+
taskId: "99",
|
|
99
|
+
});
|
|
100
|
+
expect(result?.middlewares).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("match une route complexe avec plusieurs paramètres et un wildcard", () => {
|
|
104
|
+
const router = new Router();
|
|
105
|
+
|
|
106
|
+
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
107
|
+
|
|
108
|
+
const result = router.match("GET", "/users/12/any/path/here/tasks/99");
|
|
109
|
+
|
|
110
|
+
expect(result).not.toBeNull();
|
|
111
|
+
expect(result?.handler()).toBe("mw");
|
|
112
|
+
expect(result?.params).toEqual({
|
|
113
|
+
userId: "12",
|
|
114
|
+
taskId: "99",
|
|
115
|
+
});
|
|
116
|
+
expect(result?.middlewares).toEqual([]);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("ne match pas un chemin complexe si la fin ne correspond pas", () => {
|
|
120
|
+
const router = new Router();
|
|
121
|
+
|
|
122
|
+
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
123
|
+
|
|
124
|
+
const result = router.match("GET", "/users/12/any/path/here/taskz/99");
|
|
125
|
+
|
|
126
|
+
expect(result).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("ne match pas si le paramètre final est manquant", () => {
|
|
130
|
+
const router = new Router();
|
|
131
|
+
|
|
132
|
+
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
133
|
+
|
|
134
|
+
const result = router.match("GET", "/users/12/any/path/here/tasks/");
|
|
135
|
+
|
|
136
|
+
expect(result).toBeNull();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("ne match pas si le paramètre du début est manquant", () => {
|
|
140
|
+
const router = new Router();
|
|
141
|
+
|
|
142
|
+
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
143
|
+
|
|
144
|
+
const result = router.match("GET", "/users//any/path/tasks/99");
|
|
145
|
+
|
|
146
|
+
expect(result).toBeNull();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("ne match pas si le wildcard est vide", () => {
|
|
150
|
+
const router = new Router();
|
|
151
|
+
|
|
152
|
+
router.register("GET", "/users/:userId/*/tasks/:taskId", () => "mw");
|
|
153
|
+
|
|
154
|
+
const result = router.match("GET", "/users/12//tasks/99");
|
|
155
|
+
|
|
156
|
+
expect(result).toBeNull();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("match une route avec wildcard en fin de chemin", () => {
|
|
160
|
+
const router = new Router();
|
|
161
|
+
|
|
162
|
+
router.register("GET", "/files/*", () => "end");
|
|
163
|
+
|
|
164
|
+
const result = router.match("GET", "/files/path/to/something");
|
|
165
|
+
|
|
166
|
+
expect(result).not.toBeNull();
|
|
167
|
+
expect(result?.handler()).toBe("end");
|
|
168
|
+
expect(result?.params).toEqual({});
|
|
169
|
+
expect(result?.middlewares).toEqual([]);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
// src/http/adapter-node.ts
|
|
2
|
-
|
|
3
|
-
import { Request } from "./request";
|
|
4
|
-
import { Response } from "./response";
|
|
5
|
-
import { ErrorHandler } from "./errors";
|
|
6
|
-
import { MiddlewarePipeline } from "./middleware";
|
|
7
|
-
import { Router } from "./router";
|
|
8
|
-
import { buildRequest } from "./buildRequest";
|
|
9
|
-
|
|
10
|
-
export class NodeAdapter {
|
|
11
|
-
constructor(
|
|
12
|
-
private router: Router,
|
|
13
|
-
private pipeline: MiddlewarePipeline,
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
async handle(req: any, res: any) {
|
|
17
|
-
try {
|
|
18
|
-
// 1) Construire la Request SANS params
|
|
19
|
-
const baseRequest = buildRequest(req);
|
|
20
|
-
|
|
21
|
-
const response = new Response(res);
|
|
22
|
-
|
|
23
|
-
// 2) Résoudre la route
|
|
24
|
-
const match = this.router.match(baseRequest.method, baseRequest.path);
|
|
25
|
-
|
|
26
|
-
if (!match) {
|
|
27
|
-
response.status(404).json({ error: "Not Found" });
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 3) Construire la Request AVEC params
|
|
32
|
-
const request = buildRequest(req, match.params);
|
|
33
|
-
|
|
34
|
-
// 4) Middlewares par route
|
|
35
|
-
for (const mw of match.middlewares ?? []) {
|
|
36
|
-
if (res.writableEnded) return;
|
|
37
|
-
await mw(request, response, async () => {});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// 5) Pipeline global
|
|
41
|
-
await this.pipeline.run(request, response);
|
|
42
|
-
|
|
43
|
-
// 6) Handler final
|
|
44
|
-
if (!res.writableEnded) {
|
|
45
|
-
await match.handler(request, response);
|
|
46
|
-
}
|
|
47
|
-
} catch (err) {
|
|
48
|
-
ErrorHandler.handle(err, new Response(res));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
1
|
+
// src/http/adapter-node.ts
|
|
2
|
+
|
|
3
|
+
import { Request } from "./request";
|
|
4
|
+
import { Response } from "./response";
|
|
5
|
+
import { ErrorHandler } from "./errors";
|
|
6
|
+
import { MiddlewarePipeline } from "./middleware";
|
|
7
|
+
import { Router } from "./router";
|
|
8
|
+
import { buildRequest } from "./buildRequest";
|
|
9
|
+
|
|
10
|
+
export class NodeAdapter {
|
|
11
|
+
constructor(
|
|
12
|
+
private router: Router,
|
|
13
|
+
private pipeline: MiddlewarePipeline,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
async handle(req: any, res: any) {
|
|
17
|
+
try {
|
|
18
|
+
// 1) Construire la Request SANS params
|
|
19
|
+
const baseRequest = buildRequest(req);
|
|
20
|
+
|
|
21
|
+
const response = new Response(res);
|
|
22
|
+
|
|
23
|
+
// 2) Résoudre la route
|
|
24
|
+
const match = this.router.match(baseRequest.method, baseRequest.path);
|
|
25
|
+
|
|
26
|
+
if (!match) {
|
|
27
|
+
response.status(404).json({ error: "Not Found" });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 3) Construire la Request AVEC params
|
|
32
|
+
const request = buildRequest(req, match.params);
|
|
33
|
+
|
|
34
|
+
// 4) Middlewares par route
|
|
35
|
+
for (const mw of match.middlewares ?? []) {
|
|
36
|
+
if (res.writableEnded) return;
|
|
37
|
+
await mw(request, response, async () => {});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 5) Pipeline global
|
|
41
|
+
await this.pipeline.run(request, response);
|
|
42
|
+
|
|
43
|
+
// 6) Handler final
|
|
44
|
+
if (!res.writableEnded) {
|
|
45
|
+
await match.handler(request, response);
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
ErrorHandler.handle(err, new Response(res));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Request } from "./request";
|
|
2
|
-
|
|
3
|
-
export function buildRequest(
|
|
4
|
-
raw: any,
|
|
5
|
-
params: Record<string, string> = {},
|
|
6
|
-
): Request {
|
|
7
|
-
const url = new URL(raw.url, `http://${raw.headers.host}`);
|
|
8
|
-
|
|
9
|
-
return new Request({
|
|
10
|
-
method: raw.method,
|
|
11
|
-
path: url.pathname,
|
|
12
|
-
headers: raw.headers,
|
|
13
|
-
query: Object.fromEntries(url.searchParams.entries()),
|
|
14
|
-
params,
|
|
15
|
-
ip: raw.socket?.remoteAddress ?? null,
|
|
16
|
-
raw,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
1
|
+
import { Request } from "./request";
|
|
2
|
+
|
|
3
|
+
export function buildRequest(
|
|
4
|
+
raw: any,
|
|
5
|
+
params: Record<string, string> = {},
|
|
6
|
+
): Request {
|
|
7
|
+
const url = new URL(raw.url, `http://${raw.headers.host}`);
|
|
8
|
+
|
|
9
|
+
return new Request({
|
|
10
|
+
method: raw.method,
|
|
11
|
+
path: url.pathname,
|
|
12
|
+
headers: raw.headers,
|
|
13
|
+
query: Object.fromEntries(url.searchParams.entries()),
|
|
14
|
+
params,
|
|
15
|
+
ip: raw.socket?.remoteAddress ?? null,
|
|
16
|
+
raw,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
export function compilePath(path: string) {
|
|
2
|
-
const segments = path.replace(/^\//, "").split("/");
|
|
3
|
-
const compiled = [];
|
|
4
|
-
|
|
5
|
-
for (const segment of segments) {
|
|
6
|
-
// analyse ici
|
|
7
|
-
if (segment !== "*" && !segment.startsWith(":")) {
|
|
8
|
-
compiled.push({ type: "static", value: segment });
|
|
9
|
-
continue;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (segment.startsWith(":")) {
|
|
13
|
-
compiled.push({
|
|
14
|
-
type: "param",
|
|
15
|
-
name: segment.slice(1),
|
|
16
|
-
});
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (segment === "*") {
|
|
21
|
-
compiled.push({ type: "wildcard" });
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (segment === "*") {
|
|
26
|
-
compiled.push({ type: "wildcard" });
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return compiled;
|
|
32
|
-
}
|
|
1
|
+
export function compilePath(path: string) {
|
|
2
|
+
const segments = path.replace(/^\//, "").split("/");
|
|
3
|
+
const compiled = [];
|
|
4
|
+
|
|
5
|
+
for (const segment of segments) {
|
|
6
|
+
// analyse ici
|
|
7
|
+
if (segment !== "*" && !segment.startsWith(":")) {
|
|
8
|
+
compiled.push({ type: "static", value: segment });
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (segment.startsWith(":")) {
|
|
13
|
+
compiled.push({
|
|
14
|
+
type: "param",
|
|
15
|
+
name: segment.slice(1),
|
|
16
|
+
});
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (segment === "*") {
|
|
21
|
+
compiled.push({ type: "wildcard" });
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (segment === "*") {
|
|
26
|
+
compiled.push({ type: "wildcard" });
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return compiled;
|
|
32
|
+
}
|
package/src/core/http/errors.ts
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
// src/http/error.ts
|
|
2
|
-
|
|
3
|
-
export class HttpError extends Error {
|
|
4
|
-
readonly status: number;
|
|
5
|
-
readonly code: string;
|
|
6
|
-
readonly details?: any;
|
|
7
|
-
|
|
8
|
-
constructor(status: number, code: string, message: string, details?: any) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.status = status;
|
|
11
|
-
this.code = code;
|
|
12
|
-
this.details = details;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class ErrorHandler {
|
|
17
|
-
static handle(err: unknown, res: any) {
|
|
18
|
-
if (err instanceof HttpError) {
|
|
19
|
-
res.status(err.status).json({
|
|
20
|
-
error: {
|
|
21
|
-
code: err.code,
|
|
22
|
-
message: err.message,
|
|
23
|
-
details: err.details ?? null,
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Erreur inconnue → 500
|
|
30
|
-
res.status(500).json({
|
|
31
|
-
error: {
|
|
32
|
-
code: "INTERNAL_ERROR",
|
|
33
|
-
message: "An unexpected error occurred",
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
1
|
+
// src/http/error.ts
|
|
2
|
+
|
|
3
|
+
export class HttpError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
readonly code: string;
|
|
6
|
+
readonly details?: any;
|
|
7
|
+
|
|
8
|
+
constructor(status: number, code: string, message: string, details?: any) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.details = details;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class ErrorHandler {
|
|
17
|
+
static handle(err: unknown, res: any) {
|
|
18
|
+
if (err instanceof HttpError) {
|
|
19
|
+
res.status(err.status).json({
|
|
20
|
+
error: {
|
|
21
|
+
code: err.code,
|
|
22
|
+
message: err.message,
|
|
23
|
+
details: err.details ?? null,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Erreur inconnue → 500
|
|
30
|
+
res.status(500).json({
|
|
31
|
+
error: {
|
|
32
|
+
code: "INTERNAL_ERROR",
|
|
33
|
+
message: "An unexpected error occurred",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|