@j3r3mcdev/oast-server 1.1.13 → 1.1.14

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 (105) hide show
  1. package/package.json +4 -1
  2. package/.env.example +0 -0
  3. package/.github/workflows/ci.yml +0 -29
  4. package/.github/workflows/publish.yml +0 -31
  5. package/image.png +0 -0
  6. package/jest.config.js +0 -14
  7. package/sadmin list shadows +0 -9
  8. package/src/api/controllers/__tests__/tasks.controller.test.ts +0 -74
  9. package/src/api/controllers/events.controller.ts +0 -10
  10. package/src/api/controllers/health.controller.ts +0 -7
  11. package/src/api/controllers/index.ts +0 -0
  12. package/src/api/controllers/tasks.controller.ts +0 -41
  13. package/src/api/dto/__tests__/create-task.dto.test.ts +0 -41
  14. package/src/api/dto/__tests__/filter-tasks.dto.test.ts +0 -35
  15. package/src/api/dto/create-task.dto.ts +0 -33
  16. package/src/api/dto/filter-tasks.dto.ts +0 -33
  17. package/src/api/services/__tests__/events.service.test.ts +0 -41
  18. package/src/api/services/__tests__/tasks.service.test.ts +0 -41
  19. package/src/api/services/events.service.ts +0 -17
  20. package/src/api/services/tasks.service.ts +0 -79
  21. package/src/api/sse/events.stream.ts +0 -90
  22. package/src/bootstrap.ts +0 -89
  23. package/src/config/constants.ts +0 -0
  24. package/src/config/env.ts +0 -0
  25. package/src/core/__tests__/core-router.test.ts +0 -30
  26. package/src/core/__tests__/core-server.test.ts +0 -44
  27. package/src/core/__tests__/event.normalizer.test.ts +0 -56
  28. package/src/core/__tests__/event.router.test.ts +0 -89
  29. package/src/core/__tests__/logger.test.ts +0 -32
  30. package/src/core/__tests__/storage-manager.test.ts +0 -74
  31. package/src/core/event.normalizer.ts +0 -167
  32. package/src/core/event.router.ts +0 -13
  33. package/src/core/http/__tests__/adapter-node.test.ts +0 -52
  34. package/src/core/http/__tests__/body-parser-multipart.test.ts +0 -41
  35. package/src/core/http/__tests__/body-parser-raw.test.ts +0 -28
  36. package/src/core/http/__tests__/body-parser-text.test.ts +0 -28
  37. package/src/core/http/__tests__/compile-path.test.ts +0 -39
  38. package/src/core/http/__tests__/middleware-pipeline.test.ts +0 -51
  39. package/src/core/http/__tests__/request.test.ts +0 -34
  40. package/src/core/http/__tests__/response.test.ts +0 -35
  41. package/src/core/http/__tests__/router-match.test.ts +0 -171
  42. package/src/core/http/adapter-node.ts +0 -51
  43. package/src/core/http/buildRequest.ts +0 -18
  44. package/src/core/http/compile-path.ts +0 -32
  45. package/src/core/http/errors.ts +0 -37
  46. package/src/core/http/http-server.ts +0 -52
  47. package/src/core/http/index.ts +0 -0
  48. package/src/core/http/main.ts +0 -0
  49. package/src/core/http/middleware.ts +0 -160
  50. package/src/core/http/request.ts +0 -55
  51. package/src/core/http/response.ts +0 -93
  52. package/src/core/http/router.ts +0 -138
  53. package/src/core/http/utils.ts +0 -0
  54. package/src/core/id-generator.ts +0 -8
  55. package/src/core/logger.ts +0 -113
  56. package/src/core/router.ts +0 -44
  57. package/src/core/server.ts +0 -85
  58. package/src/core/storage.ts +0 -64
  59. package/src/index.ts +0 -14
  60. package/src/listeners/api/__tests__/api.controller.test.ts +0 -116
  61. package/src/listeners/api/__tests__/api.extractor.test.ts +0 -46
  62. package/src/listeners/api/__tests__/api.listener.test.ts +0 -82
  63. package/src/listeners/api/__tests__/api.routes.test.ts +0 -155
  64. package/src/listeners/api/__tests__/api.sse.test.ts +0 -105
  65. package/src/listeners/api/api.controllers.ts +0 -67
  66. package/src/listeners/api/api.extractor.ts +0 -43
  67. package/src/listeners/api/api.listener.ts +0 -50
  68. package/src/listeners/api/api.routes.ts +0 -104
  69. package/src/listeners/api/api.sse.ts +0 -38
  70. package/src/listeners/dns/__tests__/dns.test.ts +0 -118
  71. package/src/listeners/dns/dns.extractor.ts +0 -14
  72. package/src/listeners/dns/dns.listener.ts +0 -61
  73. package/src/listeners/http/__tests__/http.extractor.test.ts +0 -59
  74. package/src/listeners/http/__tests__/http.listener.test.ts +0 -133
  75. package/src/listeners/http/http.extractor.ts +0 -15
  76. package/src/listeners/http/http.listener.ts +0 -110
  77. package/src/listeners/listener.interface.ts +0 -4
  78. package/src/listeners/smtp/__tests__/smtp.extractor.test.ts +0 -69
  79. package/src/listeners/smtp/__tests__/smtp.listener.test.ts +0 -150
  80. package/src/listeners/smtp/smtp.extractor.ts +0 -18
  81. package/src/listeners/smtp/smtp.listener.ts +0 -78
  82. package/src/listeners/ssrf/__tests__/ssrf.extractor.test.ts +0 -41
  83. package/src/listeners/ssrf/__tests__/ssrf.listener.test.ts +0 -87
  84. package/src/listeners/ssrf/ssrf.extractor.ts +0 -14
  85. package/src/listeners/ssrf/ssrf.listener.ts +0 -37
  86. package/src/listeners/tcp/tcp.extractor.ts +0 -16
  87. package/src/listeners/tcp/tcp.listener.ts +0 -61
  88. package/src/listeners/webhook/__tests__/webhook.extractor.test.ts +0 -35
  89. package/src/listeners/webhook/__tests__/webhook.listener.test.ts +0 -122
  90. package/src/listeners/webhook/webhook.extractor.ts +0 -12
  91. package/src/listeners/webhook/webhook.listener.ts +0 -58
  92. package/src/listeners/websocket/__tests__/websocket.extractor.test.ts +0 -33
  93. package/src/listeners/websocket/__tests__/websocket.listener.test.ts +0 -90
  94. package/src/listeners/websocket/websocket.extractor.ts +0 -11
  95. package/src/listeners/websocket/websocket.listener.ts +0 -40
  96. package/src/storage-adapters/adapters/__tests__/memory.storage.test.ts +0 -75
  97. package/src/storage-adapters/adapters/memory.storage.ts +0 -64
  98. package/src/storage-adapters/adapters/redis.storage.ts +0 -0
  99. package/src/storage-adapters/adapters/sqlite.storage.ts +0 -0
  100. package/src/storage-adapters/storage.interface.ts +0 -26
  101. package/src/types/event.types.ts +0 -166
  102. package/src/utils/token.ts +0 -0
  103. package/src-api.txt +0 -0
  104. package/src-architecture.txt +0 -0
  105. package/tsconfig.json +0 -20
@@ -1,160 +0,0 @@
1
- // src/http/middleware.ts
2
-
3
- import { Request } from "./request";
4
- import { Response } from "./response";
5
-
6
- export type Middleware = (
7
- req: Request,
8
- res: Response,
9
- next: () => Promise<void>,
10
- ) => Promise<void> | void;
11
-
12
- export class MiddlewarePipeline {
13
- private middlewares: Middleware[] = [];
14
-
15
- use(mw: Middleware): this {
16
- this.middlewares.push(mw);
17
- return this;
18
- }
19
-
20
- async run(req: Request, res: Response): Promise<void> {
21
- let index = -1;
22
-
23
- const next = async (): Promise<void> => {
24
- index++;
25
-
26
- if (index >= this.middlewares.length) return;
27
-
28
- const mw = this.middlewares[index];
29
-
30
- await Promise.resolve(mw(req, res, next));
31
- };
32
-
33
- await next();
34
- }
35
- }
36
-
37
- /* ---------------------------------------------------------
38
- JSON PARSER
39
- --------------------------------------------------------- */
40
- export async function bodyParserJson(req: Request, res: Response) {
41
- const raw = req.raw;
42
- const contentType = raw.headers["content-type"] ?? "";
43
-
44
- if (!contentType.includes("application/json")) {
45
- return;
46
- }
47
-
48
- const chunks: Buffer[] = [];
49
- for await (const chunk of raw) chunks.push(chunk);
50
-
51
- const text = Buffer.concat(chunks).toString("utf8");
52
-
53
- try {
54
- req.body = text.length > 0 ? JSON.parse(text) : {};
55
- } catch {
56
- res.status(400).json({ error: "Invalid JSON" });
57
- }
58
- }
59
-
60
- /* ---------------------------------------------------------
61
- RAW PARSER
62
- --------------------------------------------------------- */
63
- export async function bodyParserRaw(req: Request, res: Response) {
64
- const raw = req.raw;
65
- const contentType = raw.headers["content-type"] ?? "";
66
-
67
- if (contentType.includes("application/json")) return;
68
-
69
- const chunks: Buffer[] = [];
70
- for await (const chunk of raw) chunks.push(chunk);
71
-
72
- req.bodyRaw = Buffer.concat(chunks);
73
- }
74
-
75
- /* ---------------------------------------------------------
76
- TEXT PARSER
77
- --------------------------------------------------------- */
78
- export async function bodyParserText(req: Request, res: Response) {
79
- const raw = req.raw;
80
- const contentType = raw.headers["content-type"] ?? "";
81
-
82
- const isText =
83
- contentType.startsWith("text/") ||
84
- contentType.includes("application/xml") ||
85
- contentType.includes("application/xhtml+xml");
86
-
87
- if (!isText) return;
88
-
89
- const chunks: Buffer[] = [];
90
- for await (const chunk of raw) chunks.push(chunk);
91
-
92
- req.bodyText = Buffer.concat(chunks).toString("utf8");
93
- }
94
-
95
- /* ---------------------------------------------------------
96
- MULTIPART PARSER
97
- --------------------------------------------------------- */
98
- export async function bodyParserMultipart(req: Request, res: Response) {
99
- const raw = req.raw;
100
- const contentType = raw.headers["content-type"] ?? "";
101
-
102
- if (!contentType.startsWith("multipart/form-data")) return;
103
-
104
- const boundaryMatch = contentType.match(/boundary=(.+)$/);
105
- if (!boundaryMatch) {
106
- res.status(400).json({ error: "Missing multipart boundary" });
107
- return;
108
- }
109
-
110
- const boundary = "--" + boundaryMatch[1];
111
-
112
- const chunks: Buffer[] = [];
113
- for await (const chunk of raw) chunks.push(chunk);
114
-
115
- const buffer = Buffer.concat(chunks);
116
- const parts = buffer.toString("binary").split(boundary);
117
-
118
- req.files = [];
119
- req.form = {};
120
-
121
- for (const part of parts) {
122
- if (part === "--\r\n" || part === "" || part === "\r\n") continue;
123
-
124
- const [rawHeaders, rawBody] = part.split("\r\n\r\n");
125
- if (!rawBody) continue;
126
-
127
- // Nettoyage du body brut
128
- const cleaned = rawBody.replace(/\r\n--$/, "");
129
- const body = Buffer.from(cleaned, "binary");
130
-
131
- const disposition = rawHeaders.match(/name="([^"]+)"/);
132
- if (!disposition) continue;
133
-
134
- const fieldname = disposition[1];
135
- const filenameMatch = rawHeaders.match(/filename="([^"]+)"/);
136
-
137
- if (filenameMatch) {
138
- // ----------- FICHIER -----------
139
- const filename = filenameMatch[1];
140
- const contentTypeMatch = rawHeaders.match(/Content-Type: (.+)/);
141
-
142
- req.files.push({
143
- fieldname,
144
- filename,
145
- contentType: contentTypeMatch
146
- ? contentTypeMatch[1]
147
- : "application/octet-stream",
148
-
149
- // 🔥 Correction : retirer le \r\n final
150
- data: Buffer.from(
151
- body.toString("binary").replace(/\r\n$/, ""),
152
- "binary",
153
- ),
154
- });
155
- } else {
156
- // ----------- CHAMP TEXTE -----------
157
- req.form[fieldname] = body.toString("utf8").replace(/\r\n$/, ""); // 🔥 Correction champ texte
158
- }
159
- }
160
- }
@@ -1,55 +0,0 @@
1
- // src/http/request.ts
2
-
3
- export interface RequestContext {
4
- // espace réservé pour les middlewares
5
- [key: string]: any;
6
- }
7
-
8
- export class Request {
9
- readonly method: string;
10
- readonly path: string;
11
- readonly headers: Record<string, string>;
12
- readonly query: Record<string, string | string[]>;
13
- readonly params: Record<string, string>;
14
- body: any;
15
- bodyRaw?: Buffer;
16
- bodyText?: string;
17
- files?: Array<{
18
- fieldname: string;
19
- filename: string;
20
- contentType: string;
21
- data: Buffer;
22
- }>;
23
- form?: Record<string, string>;
24
-
25
- readonly ip: string;
26
- readonly raw: any; // Node IncomingMessage ou autre selon l'adaptateur
27
- readonly context: RequestContext;
28
-
29
- constructor(options: {
30
- method: string;
31
- path: string;
32
- headers: Record<string, string>;
33
- query?: Record<string, string | string[]>;
34
- params?: Record<string, string>;
35
- body?: any;
36
- ip?: string;
37
- raw?: any;
38
- context?: RequestContext;
39
- }) {
40
- this.method = options.method;
41
- this.path = options.path;
42
- this.headers = options.headers;
43
- this.query = options.query ?? {};
44
- this.params = options.params ?? {};
45
- this.body = options.body ?? null;
46
- this.ip = options.ip ?? "";
47
- this.raw = options.raw ?? null;
48
- this.context = options.context ?? {};
49
- }
50
-
51
- // Exemple d'utilitaire PRO
52
- header(name: string): string | undefined {
53
- return this.headers[name.toLowerCase()];
54
- }
55
- }
@@ -1,93 +0,0 @@
1
- // src/http/response.ts
2
-
3
- export class Response {
4
- private _status = 200;
5
- private _headers: Record<string, string> = {};
6
- private _sent = false;
7
- private _raw: any; // Node ServerResponse ou autre selon l'adaptateur
8
-
9
- constructor(raw: any) {
10
- this._raw = raw;
11
- }
12
-
13
- status(code: number): this {
14
- this._status = code;
15
- return this;
16
- }
17
-
18
- header(name: string, value: string): this {
19
- this._headers[name.toLowerCase()] = value;
20
- return this;
21
- }
22
-
23
- json(data: any): void {
24
- this.ensureNotSent();
25
- this.header("content-type", "application/json");
26
- this.send(JSON.stringify(data));
27
- }
28
-
29
- text(data: string): void {
30
- this.ensureNotSent();
31
- this.header("content-type", "text/plain");
32
- this.send(data);
33
- }
34
-
35
- send(data: any): void {
36
- this.ensureNotSent();
37
-
38
- for (const [name, value] of Object.entries(this._headers)) {
39
- this._raw.setHeader(name, value);
40
- }
41
-
42
- this._raw.statusCode = this._status;
43
- this._raw.end(data);
44
-
45
- this._sent = true;
46
- }
47
-
48
- stream(readable: NodeJS.ReadableStream): void {
49
- this.ensureNotSent();
50
-
51
- for (const [name, value] of Object.entries(this._headers)) {
52
- this._raw.setHeader(name, value);
53
- }
54
-
55
- this._raw.statusCode = this._status;
56
- readable.pipe(this._raw);
57
-
58
- this._sent = true;
59
- }
60
-
61
- sse(): void {
62
- this.ensureNotSent();
63
-
64
- this.header("content-type", "text/event-stream");
65
- this.header("cache-control", "no-cache");
66
- this.header("connection", "keep-alive");
67
-
68
- for (const [name, value] of Object.entries(this._headers)) {
69
- this._raw.setHeader(name, value);
70
- }
71
-
72
- this._raw.flushHeaders?.();
73
-
74
- this._sent = false; // SSE reste ouvert
75
- }
76
-
77
- write(data: string): void {
78
- this._raw.write(data);
79
- }
80
-
81
- end(): void {
82
- if (!this._sent) {
83
- this._raw.end();
84
- this._sent = true;
85
- }
86
- }
87
-
88
- private ensureNotSent() {
89
- if (this._sent) {
90
- throw new Error("Response already sent");
91
- }
92
- }
93
- }
@@ -1,138 +0,0 @@
1
- // src/http/router.ts
2
-
3
- import { compilePath } from "./compile-path";
4
- import { Middleware } from "./middleware";
5
-
6
- export class Router {
7
- private routes: Array<{
8
- method: string;
9
- path: string;
10
- compiled: any[];
11
- middlewares: Middleware[];
12
- handler: Function;
13
- }> = [];
14
-
15
- /**
16
- * Enregistre une route avec middlewares optionnels :
17
- * router.get("/x", mw1, mw2, handler)
18
- */
19
- register(method: string, path: string, ...middlewaresAndHandler: any[]) {
20
- const compiled = compilePath(path);
21
-
22
- const handler = middlewaresAndHandler.pop();
23
- const middlewares = middlewaresAndHandler as Middleware[];
24
-
25
- this.routes.push({
26
- method,
27
- path,
28
- compiled,
29
- middlewares,
30
- handler,
31
- });
32
- }
33
-
34
- /**
35
- * Trouve la route et extrait les params
36
- */
37
- match(method: string, urlPath: string) {
38
- const urlSegments = urlPath.replace(/^\//, "").split("/");
39
-
40
- for (const route of this.routes) {
41
- if (route.method !== method) continue;
42
-
43
- const params: Record<string, string> = {};
44
- const compiled = route.compiled;
45
-
46
- if (this.matchSegments(compiled, urlSegments, params)) {
47
- return {
48
- handler: route.handler,
49
- middlewares: route.middlewares,
50
- params,
51
- };
52
- }
53
- }
54
-
55
- return null;
56
- }
57
-
58
- /**
59
- * Ton moteur de matching existant — inchangé
60
- */
61
- private matchSegments(
62
- compiled: any[],
63
- urlSegments: string[],
64
- params: Record<string, string>,
65
- ) {
66
- let i = 0;
67
-
68
- for (let j = 0; j < compiled.length; j++) {
69
- const segment = compiled[j];
70
- const part = urlSegments[i];
71
-
72
- if (!part && segment.type !== "wildcard") {
73
- return false;
74
- }
75
-
76
- if (segment.type === "static") {
77
- if (segment.value !== part) return false;
78
- i++;
79
- continue;
80
- }
81
-
82
- if (segment.type === "param") {
83
- if (!part) return false;
84
- params[segment.name] = part;
85
- i++;
86
- continue;
87
- }
88
-
89
- if (segment.type === "wildcard") {
90
- if (!part) return false;
91
-
92
- const next = compiled[j + 1];
93
- if (!next) return true;
94
-
95
- while (i < urlSegments.length) {
96
- if (next.type === "static" && urlSegments[i] === next.value) {
97
- break;
98
- }
99
- i++;
100
- }
101
-
102
- if (i >= urlSegments.length) return false;
103
-
104
- continue;
105
- }
106
- }
107
-
108
- return i === urlSegments.length;
109
- }
110
-
111
- get(path: string, ...middlewaresAndHandler: any[]) {
112
- this.register("GET", path, ...middlewaresAndHandler);
113
- }
114
-
115
- post(path: string, ...middlewaresAndHandler: any[]) {
116
- this.register("POST", path, ...middlewaresAndHandler);
117
- }
118
-
119
- put(path: string, ...middlewaresAndHandler: any[]) {
120
- this.register("PUT", path, ...middlewaresAndHandler);
121
- }
122
-
123
- delete(path: string, ...middlewaresAndHandler: any[]) {
124
- this.register("DELETE", path, ...middlewaresAndHandler);
125
- }
126
-
127
- patch(path: string, ...middlewaresAndHandler: any[]) {
128
- this.register("PATCH", path, ...middlewaresAndHandler);
129
- }
130
-
131
- options(path: string, ...middlewaresAndHandler: any[]) {
132
- this.register("OPTIONS", path, ...middlewaresAndHandler);
133
- }
134
-
135
- head(path: string, ...middlewaresAndHandler: any[]) {
136
- this.register("HEAD", path, ...middlewaresAndHandler);
137
- }
138
- }
File without changes
@@ -1,8 +0,0 @@
1
- import crypto from "crypto";
2
-
3
- export class IdGenerator {
4
- static generate(): string {
5
- // Token long, alphanumérique, très difficile à deviner
6
- return crypto.randomBytes(16).toString("hex");
7
- }
8
- }
@@ -1,113 +0,0 @@
1
- export type LogLevel = "debug" | "info" | "warn" | "error" | "fatal";
2
-
3
- export interface LoggerOptions {
4
- level?: LogLevel;
5
- context?: string;
6
- enabled?: boolean;
7
- hooks?: Array<(entry: LogEntry) => void>;
8
- }
9
-
10
- export interface LogEntry {
11
- timestamp: string;
12
- level: LogLevel;
13
- message: string;
14
- context?: string;
15
- data?: any;
16
- }
17
-
18
- const COLORS = {
19
- reset: "\x1b[0m",
20
- gray: "\x1b[90m",
21
- blue: "\x1b[34m",
22
- yellow: "\x1b[33m",
23
- red: "\x1b[31m",
24
- magenta: "\x1b[35m",
25
- };
26
-
27
- const LEVEL_COLORS: Record<LogLevel, string> = {
28
- debug: COLORS.gray,
29
- info: COLORS.blue,
30
- warn: COLORS.yellow,
31
- error: COLORS.red,
32
- fatal: COLORS.magenta,
33
- };
34
-
35
- const LEVEL_ORDER: Record<LogLevel, number> = {
36
- debug: 10,
37
- info: 20,
38
- warn: 30,
39
- error: 40,
40
- fatal: 50,
41
- };
42
-
43
- export class Logger {
44
- private level: LogLevel;
45
- private context?: string;
46
- private enabled: boolean;
47
- private hooks: Array<(entry: LogEntry) => void>;
48
-
49
- constructor(options: LoggerOptions = {}) {
50
- this.level = options.level ?? "info";
51
- this.context = options.context;
52
- this.enabled = options.enabled ?? true;
53
- this.hooks = options.hooks ?? [];
54
- }
55
-
56
- private shouldLog(level: LogLevel): boolean {
57
- return this.enabled && LEVEL_ORDER[level] >= LEVEL_ORDER[this.level];
58
- }
59
-
60
- private emit(level: LogLevel, message: string, data?: any) {
61
- if (!this.shouldLog(level)) return;
62
-
63
- const entry: LogEntry = {
64
- timestamp: new Date().toISOString(),
65
- level,
66
- message,
67
- context: this.context,
68
- data,
69
- };
70
-
71
- // Console output
72
- const color = LEVEL_COLORS[level];
73
- const ctx = this.context ? `[${this.context}] ` : "";
74
- const formatted = `${color}${entry.timestamp} ${level.toUpperCase()} ${ctx}${message}${COLORS.reset}`;
75
-
76
- console.log(formatted);
77
-
78
- // Hooks (dashboard, file, webhook…)
79
- for (const hook of this.hooks) {
80
- hook(entry);
81
- }
82
- }
83
-
84
- debug(msg: string, data?: any) {
85
- this.emit("debug", msg, data);
86
- }
87
-
88
- info(msg: string, data?: any) {
89
- this.emit("info", msg, data);
90
- }
91
-
92
- warn(msg: string, data?: any) {
93
- this.emit("warn", msg, data);
94
- }
95
-
96
- error(msg: string, data?: any) {
97
- this.emit("error", msg, data);
98
- }
99
-
100
- fatal(msg: string, data?: any) {
101
- this.emit("fatal", msg, data);
102
- }
103
-
104
- // Créer un logger enfant avec un contexte différent
105
- withContext(context: string): Logger {
106
- return new Logger({
107
- level: this.level,
108
- enabled: this.enabled,
109
- hooks: this.hooks,
110
- context,
111
- });
112
- }
113
- }
@@ -1,44 +0,0 @@
1
- import { Storage } from "../storage-adapters/storage.interface";
2
- import { Logger } from "./logger";
3
- import { AnyNormalizedEvent } from "../types/event.types";
4
-
5
- export type RouterHook = (event: AnyNormalizedEvent) => void | Promise<void>;
6
-
7
- export interface RouterOptions {
8
- logger?: Logger;
9
- hooks?: RouterHook[];
10
- }
11
-
12
- export class CoreRouter {
13
- private logger: Logger;
14
- private hooks: RouterHook[];
15
-
16
- constructor(
17
- private storage: Storage,
18
- options: RouterOptions = {},
19
- ) {
20
- this.logger = options.logger ?? new Logger({ context: "CoreRouter" });
21
- this.hooks = options.hooks ?? [];
22
- }
23
-
24
- async dispatch(event: AnyNormalizedEvent): Promise<void> {
25
- this.logger.info(`Event received (${event.type})`, { id: event.id });
26
- await this.storage.save(event);
27
-
28
- for (const hook of this.hooks) {
29
- try {
30
- await hook(event);
31
- } catch (err) {
32
- this.logger.error("Hook error", err);
33
- }
34
- }
35
- }
36
-
37
- async route(event: AnyNormalizedEvent): Promise<void> {
38
- return this.dispatch(event);
39
- }
40
-
41
- addHook(hook: RouterHook) {
42
- this.hooks.push(hook);
43
- }
44
- }
@@ -1,85 +0,0 @@
1
- import { Logger } from "./logger";
2
- import { CoreRouter } from "./router";
3
- import { StorageManager } from "./storage";
4
- import { Listener } from "../listeners/listener.interface";
5
- export interface CoreServerOptions {
6
- logger?: Logger;
7
- storage?: StorageManager;
8
- listeners?: Listener[];
9
- }
10
-
11
- export class CoreServer {
12
- private logger: Logger;
13
- private storage: StorageManager;
14
- private router: CoreRouter;
15
- private listeners: Listener[];
16
-
17
- constructor(options: CoreServerOptions = {}) {
18
- this.logger = options.logger ?? new Logger({ context: "CoreServer" });
19
- this.storage =
20
- options.storage ?? new StorageManager({ logger: this.logger });
21
- this.router = new CoreRouter(this.storage, { logger: this.logger });
22
- this.listeners = options.listeners ?? [];
23
- }
24
-
25
- getRouter() {
26
- return this.router;
27
- }
28
-
29
- getStorage() {
30
- return this.storage;
31
- }
32
-
33
- async start(): Promise<void> {
34
- this.logger.info("Starting OAST server...");
35
-
36
- // Démarrage des listeners
37
- for (const listener of this.listeners) {
38
- try {
39
- await listener.start();
40
- this.logger.info(`Listener started`, {
41
- listener: listener.constructor.name,
42
- });
43
- } catch (err: any) {
44
- this.logger.error("Listener failed to start", {
45
- listener: listener.constructor.name,
46
- error: err.message,
47
- });
48
- }
49
- }
50
-
51
- this.logger.info("OAST server started");
52
- }
53
-
54
- async stop(): Promise<void> {
55
- this.logger.info("Stopping OAST server...");
56
-
57
- for (const listener of this.listeners) {
58
- try {
59
- await listener.stop();
60
- this.logger.info(`Listener stopped`, {
61
- listener: listener.constructor.name,
62
- });
63
- } catch (err: any) {
64
- this.logger.error("Listener failed to stop", {
65
- listener: listener.constructor.name,
66
- error: err.message,
67
- });
68
- }
69
- }
70
-
71
- this.logger.info("OAST server stopped");
72
- }
73
-
74
- /**
75
- * Méthode appelée par CoreRouter après chaque event normalisé.
76
- * Permet de diffuser l’event aux listeners SSE (ApiListener).
77
- */
78
- broadcast(event: any) {
79
- for (const listener of this.listeners) {
80
- if (typeof (listener as any).broadcastEvent === "function") {
81
- (listener as any).broadcastEvent(event);
82
- }
83
- }
84
- }
85
- }