@scpxl/nodejs-framework 1.0.19 → 1.0.22

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 (276) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +530 -67
  3. package/dist/application/base-application.js +1 -1
  4. package/dist/application/base-application.js.map +2 -2
  5. package/dist/application/command-application.js.map +2 -2
  6. package/dist/application/web-application.js +1 -0
  7. package/dist/application/web-application.js.map +2 -2
  8. package/dist/command/command.js.map +1 -1
  9. package/dist/config/schema.js +16 -6
  10. package/dist/config/schema.js.map +2 -2
  11. package/dist/event/manager.js.map +2 -2
  12. package/dist/lifecycle/lifecycle-manager.js.map +2 -2
  13. package/dist/logger/logger.js +21 -1
  14. package/dist/logger/logger.js.map +2 -2
  15. package/dist/queue/index.js.map +1 -1
  16. package/dist/queue/manager.js +24 -12
  17. package/dist/queue/manager.js.map +2 -2
  18. package/dist/queue/processor/base.js.map +2 -2
  19. package/dist/services/aws/s3.js.map +2 -2
  20. package/dist/util/helper.js +1 -1
  21. package/dist/util/helper.js.map +2 -2
  22. package/dist/util/loader.js.map +2 -2
  23. package/dist/webserver/controller/base.js.map +2 -2
  24. package/dist/webserver/define-route.js +22 -0
  25. package/dist/webserver/define-route.js.map +7 -0
  26. package/dist/webserver/index.js +2 -0
  27. package/dist/webserver/index.js.map +2 -2
  28. package/dist/webserver/webserver.interface.js.map +2 -2
  29. package/dist/webserver/webserver.js +211 -56
  30. package/dist/webserver/webserver.js.map +2 -2
  31. package/dist/websocket/websocket-base.js.map +2 -2
  32. package/dist/websocket/websocket-client.js.map +1 -1
  33. package/dist/websocket/websocket-server.js +5 -5
  34. package/dist/websocket/websocket-server.js.map +2 -2
  35. package/dist/websocket/websocket.interface.js.map +2 -2
  36. package/package.json +3 -2
  37. package/dist/api-requester/api-requester.d.ts +0 -32
  38. package/dist/api-requester/api-requester.d.ts.map +0 -1
  39. package/dist/api-requester/index.d.ts +0 -3
  40. package/dist/api-requester/index.d.ts.map +0 -1
  41. package/dist/application/base-application.d.ts +0 -106
  42. package/dist/application/base-application.d.ts.map +0 -1
  43. package/dist/application/base-application.interface.d.ts +0 -161
  44. package/dist/application/base-application.interface.d.ts.map +0 -1
  45. package/dist/application/command-application.d.ts +0 -18
  46. package/dist/application/command-application.d.ts.map +0 -1
  47. package/dist/application/command-application.interface.d.ts +0 -26
  48. package/dist/application/command-application.interface.d.ts.map +0 -1
  49. package/dist/application/index.d.ts +0 -5
  50. package/dist/application/index.d.ts.map +0 -1
  51. package/dist/application/web-application.d.ts +0 -43
  52. package/dist/application/web-application.d.ts.map +0 -1
  53. package/dist/application/web-application.interface.d.ts +0 -21
  54. package/dist/application/web-application.interface.d.ts.map +0 -1
  55. package/dist/auth/index.d.ts +0 -2
  56. package/dist/auth/index.d.ts.map +0 -1
  57. package/dist/auth/jwt.d.ts +0 -25
  58. package/dist/auth/jwt.d.ts.map +0 -1
  59. package/dist/cache/index.d.ts +0 -2
  60. package/dist/cache/index.d.ts.map +0 -1
  61. package/dist/cache/manager.d.ts +0 -107
  62. package/dist/cache/manager.d.ts.map +0 -1
  63. package/dist/cluster/cluster-manager.d.ts +0 -15
  64. package/dist/cluster/cluster-manager.d.ts.map +0 -1
  65. package/dist/cluster/cluster-manager.interface.d.ts +0 -23
  66. package/dist/cluster/cluster-manager.interface.d.ts.map +0 -1
  67. package/dist/cluster/index.d.ts +0 -2
  68. package/dist/cluster/index.d.ts.map +0 -1
  69. package/dist/command/command-manager.d.ts +0 -19
  70. package/dist/command/command-manager.d.ts.map +0 -1
  71. package/dist/command/command.d.ts +0 -27
  72. package/dist/command/command.d.ts.map +0 -1
  73. package/dist/command/command.interface.d.ts +0 -11
  74. package/dist/command/command.interface.d.ts.map +0 -1
  75. package/dist/command/index.d.ts +0 -3
  76. package/dist/command/index.d.ts.map +0 -1
  77. package/dist/config/env.d.ts +0 -11
  78. package/dist/config/env.d.ts.map +0 -1
  79. package/dist/config/index.d.ts +0 -3
  80. package/dist/config/index.d.ts.map +0 -1
  81. package/dist/config/schema.d.ts +0 -408
  82. package/dist/config/schema.d.ts.map +0 -1
  83. package/dist/database/dynamic-entity-form-decorators.d.ts +0 -31
  84. package/dist/database/dynamic-entity-form-decorators.d.ts.map +0 -1
  85. package/dist/database/dynamic-entity.d.ts +0 -15
  86. package/dist/database/dynamic-entity.d.ts.map +0 -1
  87. package/dist/database/index.d.ts +0 -5
  88. package/dist/database/index.d.ts.map +0 -1
  89. package/dist/database/instance.d.ts +0 -36
  90. package/dist/database/instance.d.ts.map +0 -1
  91. package/dist/database/instance.interface.d.ts +0 -5
  92. package/dist/database/instance.interface.d.ts.map +0 -1
  93. package/dist/database/manager.d.ts +0 -27
  94. package/dist/database/manager.d.ts.map +0 -1
  95. package/dist/database/manager.interface.d.ts +0 -18
  96. package/dist/database/manager.interface.d.ts.map +0 -1
  97. package/dist/error/error-reporter.d.ts +0 -96
  98. package/dist/error/error-reporter.d.ts.map +0 -1
  99. package/dist/error/error.interface.d.ts +0 -126
  100. package/dist/error/error.interface.d.ts.map +0 -1
  101. package/dist/error/framework-errors.d.ts +0 -113
  102. package/dist/error/framework-errors.d.ts.map +0 -1
  103. package/dist/error/index.d.ts +0 -6
  104. package/dist/error/index.d.ts.map +0 -1
  105. package/dist/event/controller/base.d.ts +0 -23
  106. package/dist/event/controller/base.d.ts.map +0 -1
  107. package/dist/event/controller/base.interface.d.ts +0 -11
  108. package/dist/event/controller/base.interface.d.ts.map +0 -1
  109. package/dist/event/index.d.ts +0 -5
  110. package/dist/event/index.d.ts.map +0 -1
  111. package/dist/event/manager.d.ts +0 -21
  112. package/dist/event/manager.d.ts.map +0 -1
  113. package/dist/event/manager.interface.d.ts +0 -134
  114. package/dist/event/manager.interface.d.ts.map +0 -1
  115. package/dist/index.d.ts +0 -22
  116. package/dist/index.d.ts.map +0 -1
  117. package/dist/lifecycle/exit.d.ts +0 -11
  118. package/dist/lifecycle/exit.d.ts.map +0 -1
  119. package/dist/lifecycle/index.d.ts +0 -7
  120. package/dist/lifecycle/index.d.ts.map +0 -1
  121. package/dist/lifecycle/lifecycle-manager.d.ts +0 -66
  122. package/dist/lifecycle/lifecycle-manager.d.ts.map +0 -1
  123. package/dist/lifecycle/shutdown-controller.d.ts +0 -15
  124. package/dist/lifecycle/shutdown-controller.d.ts.map +0 -1
  125. package/dist/lifecycle/types.d.ts +0 -28
  126. package/dist/lifecycle/types.d.ts.map +0 -1
  127. package/dist/logger/index.d.ts +0 -2
  128. package/dist/logger/index.d.ts.map +0 -1
  129. package/dist/logger/logger.d.ts +0 -55
  130. package/dist/logger/logger.d.ts.map +0 -1
  131. package/dist/logger/logger.interface.d.ts +0 -2
  132. package/dist/logger/logger.interface.d.ts.map +0 -1
  133. package/dist/performance/cache-performance.d.ts +0 -64
  134. package/dist/performance/cache-performance.d.ts.map +0 -1
  135. package/dist/performance/database-performance.d.ts +0 -40
  136. package/dist/performance/database-performance.d.ts.map +0 -1
  137. package/dist/performance/index.d.ts +0 -8
  138. package/dist/performance/index.d.ts.map +0 -1
  139. package/dist/performance/performance-monitor.d.ts +0 -68
  140. package/dist/performance/performance-monitor.d.ts.map +0 -1
  141. package/dist/performance/performance-monitor.plugin.d.ts +0 -24
  142. package/dist/performance/performance-monitor.plugin.d.ts.map +0 -1
  143. package/dist/performance/queue-performance.d.ts +0 -46
  144. package/dist/performance/queue-performance.d.ts.map +0 -1
  145. package/dist/performance/webserver-performance.d.ts +0 -69
  146. package/dist/performance/webserver-performance.d.ts.map +0 -1
  147. package/dist/performance/websocket-performance.d.ts +0 -44
  148. package/dist/performance/websocket-performance.d.ts.map +0 -1
  149. package/dist/queue/index.d.ts +0 -6
  150. package/dist/queue/index.d.ts.map +0 -1
  151. package/dist/queue/index.interface.d.ts +0 -10
  152. package/dist/queue/index.interface.d.ts.map +0 -1
  153. package/dist/queue/job.interface.d.ts +0 -42
  154. package/dist/queue/job.interface.d.ts.map +0 -1
  155. package/dist/queue/manager.d.ts +0 -36
  156. package/dist/queue/manager.d.ts.map +0 -1
  157. package/dist/queue/manager.interface.d.ts +0 -18
  158. package/dist/queue/manager.interface.d.ts.map +0 -1
  159. package/dist/queue/processor/base.d.ts +0 -28
  160. package/dist/queue/processor/base.d.ts.map +0 -1
  161. package/dist/queue/processor/processor.interface.d.ts +0 -15
  162. package/dist/queue/processor/processor.interface.d.ts.map +0 -1
  163. package/dist/queue/worker.d.ts +0 -14
  164. package/dist/queue/worker.d.ts.map +0 -1
  165. package/dist/queue/worker.interface.d.ts +0 -13
  166. package/dist/queue/worker.interface.d.ts.map +0 -1
  167. package/dist/redis/index.d.ts +0 -3
  168. package/dist/redis/index.d.ts.map +0 -1
  169. package/dist/redis/instance.d.ts +0 -32
  170. package/dist/redis/instance.d.ts.map +0 -1
  171. package/dist/redis/instance.interface.d.ts +0 -9
  172. package/dist/redis/instance.interface.d.ts.map +0 -1
  173. package/dist/redis/manager.d.ts +0 -15
  174. package/dist/redis/manager.d.ts.map +0 -1
  175. package/dist/redis/manager.interface.d.ts +0 -8
  176. package/dist/redis/manager.interface.d.ts.map +0 -1
  177. package/dist/request-context/index.d.ts +0 -3
  178. package/dist/request-context/index.d.ts.map +0 -1
  179. package/dist/request-context/request-context.d.ts +0 -108
  180. package/dist/request-context/request-context.d.ts.map +0 -1
  181. package/dist/request-context/request-context.interface.d.ts +0 -46
  182. package/dist/request-context/request-context.interface.d.ts.map +0 -1
  183. package/dist/services/aws/index.d.ts +0 -2
  184. package/dist/services/aws/index.d.ts.map +0 -1
  185. package/dist/services/aws/s3.d.ts +0 -54
  186. package/dist/services/aws/s3.d.ts.map +0 -1
  187. package/dist/services/aws/s3.interface.d.ts +0 -14
  188. package/dist/services/aws/s3.interface.d.ts.map +0 -1
  189. package/dist/services/index.d.ts +0 -2
  190. package/dist/services/index.d.ts.map +0 -1
  191. package/dist/util/file.d.ts +0 -58
  192. package/dist/util/file.d.ts.map +0 -1
  193. package/dist/util/helper.d.ts +0 -52
  194. package/dist/util/helper.d.ts.map +0 -1
  195. package/dist/util/image.d.ts +0 -12
  196. package/dist/util/image.d.ts.map +0 -1
  197. package/dist/util/index.d.ts +0 -11
  198. package/dist/util/index.d.ts.map +0 -1
  199. package/dist/util/loader.d.ts +0 -19
  200. package/dist/util/loader.d.ts.map +0 -1
  201. package/dist/util/num.d.ts +0 -13
  202. package/dist/util/num.d.ts.map +0 -1
  203. package/dist/util/os.d.ts +0 -6
  204. package/dist/util/os.d.ts.map +0 -1
  205. package/dist/util/str.d.ts +0 -39
  206. package/dist/util/str.d.ts.map +0 -1
  207. package/dist/util/time.d.ts +0 -19
  208. package/dist/util/time.d.ts.map +0 -1
  209. package/dist/util/time.interface.d.ts +0 -12
  210. package/dist/util/time.interface.d.ts.map +0 -1
  211. package/dist/util/timing.d.ts +0 -36
  212. package/dist/util/timing.d.ts.map +0 -1
  213. package/dist/util/timing.interface.d.ts +0 -47
  214. package/dist/util/timing.interface.d.ts.map +0 -1
  215. package/dist/util/url.d.ts +0 -7
  216. package/dist/util/url.d.ts.map +0 -1
  217. package/dist/webserver/controller/auth-middleware.d.ts +0 -21
  218. package/dist/webserver/controller/auth-middleware.d.ts.map +0 -1
  219. package/dist/webserver/controller/base.d.ts +0 -41
  220. package/dist/webserver/controller/base.d.ts.map +0 -1
  221. package/dist/webserver/controller/base.interface.d.ts +0 -47
  222. package/dist/webserver/controller/base.interface.d.ts.map +0 -1
  223. package/dist/webserver/controller/entity.d.ts +0 -94
  224. package/dist/webserver/controller/entity.d.ts.map +0 -1
  225. package/dist/webserver/controller/example-auth.d.ts +0 -12
  226. package/dist/webserver/controller/example-auth.d.ts.map +0 -1
  227. package/dist/webserver/controller/health.d.ts +0 -15
  228. package/dist/webserver/controller/health.d.ts.map +0 -1
  229. package/dist/webserver/index.d.ts +0 -12
  230. package/dist/webserver/index.d.ts.map +0 -1
  231. package/dist/webserver/util.d.ts +0 -10
  232. package/dist/webserver/util.d.ts.map +0 -1
  233. package/dist/webserver/webserver.d.ts +0 -79
  234. package/dist/webserver/webserver.d.ts.map +0 -1
  235. package/dist/webserver/webserver.interface.d.ts +0 -155
  236. package/dist/webserver/webserver.interface.d.ts.map +0 -1
  237. package/dist/websocket/controller/client/base.d.ts +0 -12
  238. package/dist/websocket/controller/client/base.d.ts.map +0 -1
  239. package/dist/websocket/controller/client/base.interface.d.ts +0 -12
  240. package/dist/websocket/controller/client/base.interface.d.ts.map +0 -1
  241. package/dist/websocket/controller/server/base.d.ts +0 -13
  242. package/dist/websocket/controller/server/base.d.ts.map +0 -1
  243. package/dist/websocket/controller/server/base.interface.d.ts +0 -13
  244. package/dist/websocket/controller/server/base.interface.d.ts.map +0 -1
  245. package/dist/websocket/controllers/client/system.d.ts +0 -6
  246. package/dist/websocket/controllers/client/system.d.ts.map +0 -1
  247. package/dist/websocket/controllers/server/system.d.ts +0 -7
  248. package/dist/websocket/controllers/server/system.d.ts.map +0 -1
  249. package/dist/websocket/index.d.ts +0 -7
  250. package/dist/websocket/index.d.ts.map +0 -1
  251. package/dist/websocket/routes/client/system.d.ts +0 -3
  252. package/dist/websocket/routes/client/system.d.ts.map +0 -1
  253. package/dist/websocket/routes/server/system.d.ts +0 -3
  254. package/dist/websocket/routes/server/system.d.ts.map +0 -1
  255. package/dist/websocket/utils.d.ts +0 -9
  256. package/dist/websocket/utils.d.ts.map +0 -1
  257. package/dist/websocket/websocket-base.d.ts +0 -15
  258. package/dist/websocket/websocket-base.d.ts.map +0 -1
  259. package/dist/websocket/websocket-client-manager.d.ts +0 -53
  260. package/dist/websocket/websocket-client-manager.d.ts.map +0 -1
  261. package/dist/websocket/websocket-client-manager.interface.d.ts +0 -8
  262. package/dist/websocket/websocket-client-manager.interface.d.ts.map +0 -1
  263. package/dist/websocket/websocket-client.d.ts +0 -35
  264. package/dist/websocket/websocket-client.d.ts.map +0 -1
  265. package/dist/websocket/websocket-client.interface.d.ts +0 -14
  266. package/dist/websocket/websocket-client.interface.d.ts.map +0 -1
  267. package/dist/websocket/websocket-room-manager.d.ts +0 -32
  268. package/dist/websocket/websocket-room-manager.d.ts.map +0 -1
  269. package/dist/websocket/websocket-server.d.ts +0 -92
  270. package/dist/websocket/websocket-server.d.ts.map +0 -1
  271. package/dist/websocket/websocket-server.interface.d.ts +0 -16
  272. package/dist/websocket/websocket-server.interface.d.ts.map +0 -1
  273. package/dist/websocket/websocket-service.d.ts +0 -44
  274. package/dist/websocket/websocket-service.d.ts.map +0 -1
  275. package/dist/websocket/websocket.interface.d.ts +0 -119
  276. package/dist/websocket/websocket.interface.d.ts.map +0 -1
@@ -14,6 +14,7 @@ import { File, Helper, Loader, Time } from "../util/index.js";
14
14
  import WebServerUtil from "./util.js";
15
15
  import { WebServerHealthController } from "../index.js";
16
16
  import { enterRequestContext } from "../request-context/index.js";
17
+ import { toJSONSchema } from "zod";
17
18
  class WebServer {
18
19
  static {
19
20
  __name(this, "WebServer");
@@ -53,7 +54,7 @@ class WebServer {
53
54
  const mergedOptions = Helper.defaultsDeep(params.options, defaultOptions);
54
55
  this.applicationConfig = params.applicationConfig;
55
56
  this.options = mergedOptions;
56
- this.routes = params.routes;
57
+ this.routes = [...params.routes ?? []];
57
58
  this.redisInstance = params.redisInstance;
58
59
  this.queueManager = params.queueManager;
59
60
  this.eventManager = params.eventManager;
@@ -223,20 +224,24 @@ class WebServer {
223
224
  * Configure routes.
224
225
  */
225
226
  async configureRoutes() {
226
- const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory);
227
+ await this.loadRoutesFromDirectory();
228
+ const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory ?? "");
227
229
  if (!controllersDirectoryExists) {
228
- Logger.warn({
229
- message: "Web server controllers directory not found",
230
- meta: {
231
- Directory: this.options.controllersDirectory
232
- }
233
- });
234
- return;
230
+ const routesRequiringControllers = this.routes.length === 0 || this.routes.some((route) => !route.handler);
231
+ if (routesRequiringControllers) {
232
+ Logger.warn({
233
+ message: "Web server controllers directory not found",
234
+ meta: {
235
+ Directory: this.options.controllersDirectory
236
+ }
237
+ });
238
+ return;
239
+ }
235
240
  }
236
- const controllers = await Loader.loadModulesInDirectory({
241
+ const controllers = controllersDirectoryExists ? await Loader.loadModulesInDirectory({
237
242
  directory: this.options.controllersDirectory,
238
243
  extensions: [".ts", ".js"]
239
- });
244
+ }) : {};
240
245
  this.routes.push(
241
246
  {
242
247
  type: WebServerRouteType.Default,
@@ -256,6 +261,22 @@ class WebServer {
256
261
  for (const route of this.routes) {
257
262
  let ControllerClass;
258
263
  let controllerName;
264
+ if (route.handler && !route.controller && !route.controllerName) {
265
+ if (route.type && route.type !== WebServerRouteType.Default) {
266
+ throw new Error("Handler-only routes are only supported for default route type");
267
+ }
268
+ if (!("method" in route)) {
269
+ throw new Error("Handler-only routes require an HTTP method");
270
+ }
271
+ const schema = this.buildFastifySchema(route.schema) ?? this.buildLegacySchema(route.validation);
272
+ this.fastifyServer.route({
273
+ method: route.method,
274
+ url: route.path,
275
+ handler: route.handler,
276
+ ...schema ? { schema } : {}
277
+ });
278
+ continue;
279
+ }
259
280
  if (route.controller) {
260
281
  ControllerClass = route.controller;
261
282
  controllerName = ControllerClass.name;
@@ -300,7 +321,9 @@ class WebServer {
300
321
  routeMethod,
301
322
  routePath,
302
323
  routeAction,
303
- routeValidation: route.validation
324
+ routeSchema: route.schema,
325
+ handlerOverride: route.handler?.bind(controllerInstance),
326
+ legacyValidation: route.validation
304
327
  });
305
328
  break;
306
329
  }
@@ -314,10 +337,7 @@ class WebServer {
314
337
  const formattedEntityValidationSchema = entityValidationSchema ? {
315
338
  type: "object",
316
339
  properties: Object.fromEntries(
317
- Object.entries(entityValidationSchema.keys).map(([key, value]) => [
318
- key,
319
- { type: value.type }
320
- ])
340
+ Object.entries(entityValidationSchema.keys).map(([key, value]) => [key, { type: value.type }])
321
341
  ),
322
342
  required: Object.keys(entityValidationSchema.keys).filter(
323
343
  // Dynamic schema inspection of joi describe output; keys are from trusted entity definitions
@@ -336,7 +356,9 @@ class WebServer {
336
356
  routeMethod: entityRouteDefinition.method,
337
357
  routePath: entityRouteDefinition.path,
338
358
  routeAction: entityRouteDefinition.action,
339
- routeValidation: entityRouteDefinition.validationSchema
359
+ routeSchema: route.schema,
360
+ handlerOverride: route.handler?.bind(controllerInstance),
361
+ legacyValidation: entityRouteDefinition.validationSchema
340
362
  });
341
363
  }
342
364
  }
@@ -349,57 +371,138 @@ class WebServer {
349
371
  console.log(this.fastifyServer.printRoutes());
350
372
  }
351
373
  }
374
+ async loadRoutesFromDirectory() {
375
+ const { routesDirectory } = this.options;
376
+ if (!routesDirectory) {
377
+ return;
378
+ }
379
+ const directoryExists = await File.pathExists(routesDirectory);
380
+ if (!directoryExists) {
381
+ this.logger.warn({
382
+ message: "Web server routes directory not found",
383
+ meta: {
384
+ Directory: routesDirectory
385
+ }
386
+ });
387
+ return;
388
+ }
389
+ const routeModules = await Loader.loadModulesInDirectory({
390
+ directory: routesDirectory,
391
+ extensions: [".ts", ".js"]
392
+ });
393
+ const loadedRoutes = [];
394
+ for (const [moduleName, exportedRoutes] of Object.entries(routeModules)) {
395
+ const normalizedRoutes = this.normalizeRouteExport(exportedRoutes, moduleName);
396
+ if (normalizedRoutes.length === 0) {
397
+ continue;
398
+ }
399
+ loadedRoutes.push(...normalizedRoutes);
400
+ }
401
+ if (loadedRoutes.length > 0) {
402
+ this.routes.push(...loadedRoutes);
403
+ }
404
+ }
405
+ normalizeRouteExport(exportedValue, moduleName) {
406
+ const ensureRouteArray = /* @__PURE__ */ __name((value) => {
407
+ if (Array.isArray(value)) {
408
+ return value;
409
+ }
410
+ if (value && typeof value === "object") {
411
+ const maybeRoute = value;
412
+ if (Array.isArray(maybeRoute.routes)) {
413
+ return maybeRoute.routes;
414
+ }
415
+ }
416
+ return value ? [value] : [];
417
+ }, "ensureRouteArray");
418
+ const routeCandidates = ensureRouteArray(exportedValue);
419
+ const validRoutes = [];
420
+ for (const [index, candidate] of routeCandidates.entries()) {
421
+ if (this.isValidRoute(candidate)) {
422
+ validRoutes.push(candidate);
423
+ } else {
424
+ this.logger.warn({
425
+ message: "Invalid web server route definition skipped",
426
+ meta: {
427
+ Module: moduleName,
428
+ Index: index
429
+ }
430
+ });
431
+ }
432
+ }
433
+ if (validRoutes.length === 0 && routeCandidates.length > 0) {
434
+ this.logger.warn({
435
+ message: "No valid routes exported from module",
436
+ meta: {
437
+ Module: moduleName
438
+ }
439
+ });
440
+ }
441
+ return validRoutes;
442
+ }
443
+ isValidRoute(route) {
444
+ if (!route || typeof route !== "object") {
445
+ return false;
446
+ }
447
+ const candidate = route;
448
+ const routePath = candidate.path;
449
+ if (typeof routePath !== "string" || routePath.length === 0) {
450
+ return false;
451
+ }
452
+ const routeType = candidate.type ?? WebServerRouteType.Default;
453
+ const controllerProvided = typeof candidate.controller === "function" || typeof candidate.controllerName === "string";
454
+ if (routeType === WebServerRouteType.Entity || routeType === "entity") {
455
+ return controllerProvided && typeof candidate.entityName === "string" && candidate.entityName.length > 0;
456
+ }
457
+ if (!controllerProvided) {
458
+ return false;
459
+ }
460
+ const method = candidate.method;
461
+ const action = candidate.action;
462
+ const isValidMethod = typeof method === "string" || Array.isArray(method) && method.length > 0 && method.every((m) => typeof m === "string");
463
+ const isValidAction = typeof action === "string" && action.length > 0;
464
+ return isValidMethod && isValidAction;
465
+ }
352
466
  async defineRoute({
353
467
  controllerInstance,
354
468
  controllerName,
355
469
  routeMethod,
356
470
  routePath,
357
471
  routeAction,
358
- routeValidation
472
+ routeSchema,
473
+ handlerOverride,
474
+ legacyValidation
359
475
  }) {
360
- if (!/^[A-Za-z0-9_]+$/.test(routeAction) || ["__proto__", "prototype", "constructor"].includes(routeAction)) {
361
- throw new Error("Invalid controller action name");
476
+ let handler = handlerOverride;
477
+ if (!handler) {
478
+ if (!routeAction) {
479
+ throw new Error("Route action is required when handler override is not provided");
480
+ }
481
+ if (!/^[A-Za-z0-9_]+$/.test(routeAction) || ["__proto__", "prototype", "constructor"].includes(routeAction)) {
482
+ throw new Error("Invalid controller action name");
483
+ }
484
+ const controllerHandler = controllerInstance[routeAction];
485
+ if (!controllerHandler) {
486
+ Logger.warn({
487
+ message: "Web server controller action not found",
488
+ meta: {
489
+ Controller: controllerName,
490
+ Action: routeAction
491
+ }
492
+ });
493
+ throw new Error("Web server controller action not found");
494
+ }
495
+ handler = controllerHandler.bind(controllerInstance);
362
496
  }
363
- const controllerHandler = controllerInstance[routeAction];
364
- if (!controllerHandler) {
365
- Logger.warn({
366
- message: "Web server controller action not found",
367
- meta: {
368
- Controller: controllerName,
369
- Action: routeAction
370
- }
371
- });
372
- throw new Error("Web server controller action not found");
497
+ const fastifySchema = this.buildFastifySchema(routeSchema) ?? this.buildLegacySchema(legacyValidation);
498
+ if (!handler) {
499
+ throw new Error("Route handler could not be resolved");
373
500
  }
374
501
  this.fastifyServer.route({
375
502
  method: routeMethod,
376
503
  url: routePath,
377
- handler: controllerHandler,
378
- preValidation: /* @__PURE__ */ __name(async (request, reply) => {
379
- if (!routeValidation?.schema) {
380
- return;
381
- }
382
- const validate = request.compileValidationSchema(routeValidation.schema);
383
- let dataToValidate;
384
- switch (routeValidation.type) {
385
- case "body":
386
- dataToValidate = request.body;
387
- break;
388
- case "query":
389
- dataToValidate = request.query;
390
- break;
391
- case "params":
392
- dataToValidate = request.params;
393
- break;
394
- default:
395
- dataToValidate = void 0;
396
- }
397
- if (!validate(dataToValidate)) {
398
- return reply.code(400).send({
399
- error: validate.errors
400
- });
401
- }
402
- }, "preValidation")
504
+ handler,
505
+ ...fastifySchema ? { schema: fastifySchema } : {}
403
506
  });
404
507
  }
405
508
  /**
@@ -424,6 +527,58 @@ class WebServer {
424
527
  this._isReady = false;
425
528
  await this.fastifyServer.close();
426
529
  }
530
+ buildFastifySchema(routeSchema) {
531
+ if (!routeSchema) {
532
+ return void 0;
533
+ }
534
+ const schema = {};
535
+ if (routeSchema.params) {
536
+ schema.params = this.convertZodSchema(routeSchema.params);
537
+ }
538
+ if (routeSchema.querystring) {
539
+ schema.querystring = this.convertZodSchema(routeSchema.querystring);
540
+ }
541
+ if (routeSchema.body) {
542
+ schema.body = this.convertZodSchema(routeSchema.body);
543
+ }
544
+ if (routeSchema.headers) {
545
+ schema.headers = this.convertZodSchema(routeSchema.headers);
546
+ }
547
+ if (routeSchema.response) {
548
+ const responses = routeSchema.response;
549
+ const responseEntries = Object.entries(responses).filter(([statusCode]) => /^[1-5][0-9]{2}$/.test(statusCode)).map(([statusCode, responseSchema]) => [statusCode, this.convertZodSchema(responseSchema)]);
550
+ if (responseEntries.length > 0) {
551
+ schema.response = Object.fromEntries(responseEntries);
552
+ }
553
+ }
554
+ return schema;
555
+ }
556
+ buildLegacySchema(legacyValidation) {
557
+ if (!legacyValidation) {
558
+ return void 0;
559
+ }
560
+ const schema = {};
561
+ switch (legacyValidation.type) {
562
+ case "body":
563
+ schema.body = legacyValidation.schema;
564
+ break;
565
+ case "query":
566
+ schema.querystring = legacyValidation.schema;
567
+ break;
568
+ case "params":
569
+ schema.params = legacyValidation.schema;
570
+ break;
571
+ }
572
+ return schema;
573
+ }
574
+ convertZodSchema(zodSchema) {
575
+ const jsonSchema = toJSONSchema(zodSchema);
576
+ if (jsonSchema && typeof jsonSchema === "object" && "$schema" in jsonSchema) {
577
+ const { $schema: _jsonSchemaVersion, ...rest } = jsonSchema;
578
+ return rest;
579
+ }
580
+ return jsonSchema;
581
+ }
427
582
  /**
428
583
  * Check if web server is ready to accept traffic.
429
584
  */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/webserver/webserver.ts"],
4
- "sourcesContent": ["import crypto from 'node:crypto';\nimport Fastify, { type FastifyInstance, type FastifyReply, type FastifyRequest, type HTTPMethods } from 'fastify';\nimport cors from '@fastify/cors';\nimport helmet from '@fastify/helmet';\nimport rateLimit from '@fastify/rate-limit';\nimport multipart from '@fastify/multipart';\nimport {\n type WebServerConstructorParams,\n type WebServerOptions,\n type WebServerRoute,\n WebServerRouteType,\n} from './webserver.interface.js';\nimport { Logger } from '../logger/index.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport WebServerUtil from './util.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport type { WebServerBaseControllerType } from './controller/base.interface.js';\nimport type { QueueManager } from '../queue/index.js';\nimport { WebServerHealthController } from '../index.js';\nimport type { LifecycleManager } from '../lifecycle/lifecycle-manager.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\nimport { enterRequestContext } from '../request-context/index.js';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n startTime?: number;\n requestId?: string;\n }\n}\n\nclass WebServer {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: WebServerOptions;\n private routes: WebServerRoute[];\n\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private eventManager: EventManager;\n private databaseInstance: DatabaseInstance;\n\n public fastifyServer: FastifyInstance;\n\n private lifecycleManager: LifecycleManager;\n private _isReady = false;\n\n constructor(params: WebServerConstructorParams & { lifecycleManager: LifecycleManager }) {\n // Define default options\n const defaultOptions: Partial<WebServerOptions> = {\n host: '0.0.0.0',\n port: 3001,\n cors: {\n enabled: false,\n },\n errors: {\n verbose: false,\n },\n debug: {\n printRoutes: false,\n simulateSlowConnection: {\n enabled: false,\n delay: 250,\n },\n },\n log: {\n startUp: true,\n },\n };\n\n // Merge default options\n const mergedOptions = Helper.defaultsDeep(params.options, defaultOptions);\n\n this.applicationConfig = params.applicationConfig;\n\n this.options = mergedOptions;\n this.routes = params.routes;\n\n this.redisInstance = params.redisInstance;\n this.queueManager = params.queueManager;\n this.eventManager = params.eventManager;\n this.databaseInstance = params.databaseInstance;\n this.lifecycleManager = params.lifecycleManager;\n\n // Create Fastify server\n const defaultBodyLimit = 25 * 1024 * 1024; // 25MB (safer default)\n const defaultConnectionTimeout = 10 * 1000; // 10 seconds (safer default)\n\n this.fastifyServer = Fastify({\n logger: false,\n bodyLimit: this.options.bodyLimit ?? defaultBodyLimit,\n connectionTimeout: this.options.connectionTimeout ?? defaultConnectionTimeout,\n });\n }\n\n /**\n * Load web server.\n */\n public async load(): Promise<void> {\n // Configure security (helmet, rate limiting)\n await this.configureSecurity();\n\n // Configure hooks\n this.configureHooks();\n\n // Configure CORS\n this.configureCORS();\n\n // Configure multipart uploads\n this.configureMultipartUploads();\n\n // Configure routes\n await this.configureRoutes();\n }\n\n /**\n * Configure security features (Helmet, Rate Limiting)\n */\n private async configureSecurity(): Promise<void> {\n const security = this.options.security ?? {};\n\n // Configure Helmet for security headers\n const helmetConfig = security.helmet ?? { enabled: true };\n if (helmetConfig.enabled !== false) {\n await this.fastifyServer.register(helmet, {\n contentSecurityPolicy: helmetConfig.contentSecurityPolicy !== false,\n crossOriginEmbedderPolicy: helmetConfig.crossOriginEmbedderPolicy !== false,\n crossOriginOpenerPolicy: helmetConfig.crossOriginOpenerPolicy !== false,\n crossOriginResourcePolicy: helmetConfig.crossOriginResourcePolicy !== false,\n dnsPrefetchControl: helmetConfig.dnsPrefetchControl !== false,\n frameguard: helmetConfig.frameguard !== false,\n hidePoweredBy: helmetConfig.hidePoweredBy !== false,\n hsts: helmetConfig.hsts !== false,\n ieNoOpen: helmetConfig.ieNoOpen !== false,\n noSniff: helmetConfig.noSniff !== false,\n originAgentCluster: helmetConfig.originAgentCluster !== false,\n permittedCrossDomainPolicies: helmetConfig.permittedCrossDomainPolicies !== false,\n referrerPolicy: helmetConfig.referrerPolicy !== false,\n xssFilter: helmetConfig.xssFilter !== false,\n });\n }\n\n // Configure rate limiting\n const rateLimitConfig = security.rateLimit ?? { enabled: true };\n if (rateLimitConfig.enabled !== false) {\n await this.fastifyServer.register(rateLimit, {\n max: rateLimitConfig.max ?? 1000,\n timeWindow: rateLimitConfig.timeWindow ?? '1 minute',\n ban: rateLimitConfig.ban,\n cache: rateLimitConfig.cache ?? 5000,\n });\n }\n\n // Warn about wildcard CORS in production\n if (process.env.NODE_ENV === 'production' && this.options.cors?.enabled) {\n const corsConfig = this.options.cors as { enabled: true; urls: string[] };\n if (corsConfig.urls?.includes('*')) {\n this.logger.warn({\n message: 'Wildcard CORS (*) is enabled in production - this is a security risk',\n meta: {\n recommendation: 'Specify allowed origins explicitly',\n },\n });\n }\n }\n }\n\n /**\n * Configure hooks.\n */\n private configureHooks(): void {\n this.fastifyServer.addHook('onListen', async () => this.onListen());\n this.fastifyServer.addHook('onRequest', async request => this.onRequest(request));\n this.fastifyServer.addHook('onResponse', async (request, reply) => this.onResponse(request, reply));\n this.fastifyServer.addHook('onError', async (request, reply, error) => this.onError(request, reply, error));\n this.fastifyServer.addHook('onClose', async () => this.onClose());\n\n // if (process.env.NODE_ENV === 'local') {\n // this.fastifyServer.addHook('onSend', (request, reply, payload, done) => {\n // reply.header('Cache-Control', 'no-store');\n // done();\n // });\n // }\n }\n\n private async onListen(): Promise<void> {\n const address = this.fastifyServer.server.address();\n const port = typeof address === 'string' ? address : address?.port;\n\n if (this.options.log?.startUp) {\n this.log('Started', {\n Host: this.options.host,\n Port: port,\n // CORS: this.options.cors?.enabled && this.options.cors?..length > 0 ? this.options.corsUrls.join(', ') : 'Disabled',\n CORS: this.options.cors?.enabled ? this.options.cors.urls.join(', ') : 'Disabled',\n 'Fastify Version': this.fastifyServer.version,\n });\n }\n }\n\n private async onRequest(request: FastifyRequest): Promise<void> {\n if (\n this.options.debug?.simulateSlowConnection?.enabled &&\n this.options.debug?.simulateSlowConnection?.delay &&\n this.options.debug?.simulateSlowConnection?.delay > 0\n ) {\n await new Promise(resolve => setTimeout(resolve, this.options.debug?.simulateSlowConnection?.delay));\n }\n\n // Generate or use existing request ID for correlation\n const requestId = (request.headers['x-request-id'] as string | undefined) ?? crypto.randomUUID();\n request.requestId = requestId;\n\n const pathsToIgnore = ['/health/live', '/health/ready'];\n\n if (pathsToIgnore.includes(request.url) || request.method === 'OPTIONS') {\n // ...\n } else {\n const startTime = Time.now();\n request.startTime = startTime;\n\n // Initialize AsyncLocalStorage context for this request\n // Using enterWith() to set context for the current async execution\n enterRequestContext({ requestId, startTime });\n }\n }\n\n private async onResponse(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n // Add request ID to response headers for client-side correlation\n if (request.requestId) {\n reply.header('X-Request-ID', request.requestId);\n }\n\n if (!request.startTime) {\n return;\n }\n\n const executionTime = Time.calculateElapsedTimeMs({\n startTime: request.startTime,\n });\n const formattedExecutionTime = Time.formatTime({\n time: executionTime,\n numDecimals: 3,\n });\n\n const ip = request.headers['x-forwarded-for'] ?? request.ip;\n\n const logParams: Record<string, unknown> = {\n Method: request.method,\n Path: request.url,\n Status: reply.statusCode,\n };\n\n if (process.env.NODE_ENV !== 'development') {\n logParams.IP = ip.toString();\n }\n\n logParams.Time = formattedExecutionTime;\n\n // if (cluster.isWorker && cluster.worker) {\n // logParams.Worker = cluster.worker.id;\n // }\n\n this.log('API Request', logParams);\n }\n\n private async onError(request: FastifyRequest, reply: FastifyReply, error: Error): Promise<void> {\n // Adjusted for Fastify types\n Logger.error({ error });\n // Implement any additional logic here\n }\n\n private async onClose(): Promise<void> {\n this.log('Stopped');\n }\n\n private configureCORS(): void {\n if (!this.options.cors?.enabled) {\n return;\n }\n\n // Handle wildcard origin for development\n const origin = this.options.cors.urls.includes('*') ? true : this.options.cors.urls;\n\n this.fastifyServer.register(cors, {\n origin,\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization'],\n preflightContinue: false,\n optionsSuccessStatus: 204,\n // credentials: true,\n });\n }\n\n private configureMultipartUploads(): void {\n this.fastifyServer.register(multipart, {\n // attachFieldsToBody: true,\n limits: {\n fieldNameSize: 100,\n fieldSize: 1024 * 1024 * 10,\n fields: 10,\n fileSize: 1024 * 1024 * 1024 * 10, // 10GB file size limit\n files: 1,\n headerPairs: 2000,\n },\n });\n }\n\n /**\n * Configure routes.\n */\n private async configureRoutes(): Promise<void> {\n // Check if controllers directory exists\n const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory);\n\n if (!controllersDirectoryExists) {\n Logger.warn({\n message: 'Web server controllers directory not found',\n meta: {\n Directory: this.options.controllersDirectory,\n },\n });\n\n return;\n }\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: this.options.controllersDirectory,\n extensions: ['.ts', '.js'],\n });\n\n // Add health check routes\n this.routes.push(\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/live',\n controller: WebServerHealthController,\n action: 'live',\n },\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/ready',\n controller: WebServerHealthController,\n action: 'ready',\n },\n );\n\n // Go through each route\n for (const route of this.routes) {\n let ControllerClass: WebServerBaseControllerType;\n\n let controllerName;\n\n if (route.controller) {\n ControllerClass = route.controller;\n\n controllerName = ControllerClass.name;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName];\n\n controllerName = route.controllerName;\n } else {\n throw new Error('Web server controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n const controllerPath = `${this.options.controllersDirectory}/${route.controllerName}.ts`;\n\n Logger.warn({\n message: 'Web server controller not found',\n meta: {\n Controller: route.controllerName,\n Path: controllerPath,\n Route: `${route.path}`,\n },\n });\n\n continue;\n }\n\n // Initialize controller instance\n const controllerInstance = new ControllerClass({\n applicationConfig: this.applicationConfig,\n webServerOptions: this.options,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n eventManager: this.eventManager,\n databaseInstance: this.databaseInstance,\n lifecycleManager: this.lifecycleManager,\n });\n\n let routeMethod;\n let routeAction;\n let routePath;\n\n switch (route.type) {\n case WebServerRouteType.Default: {\n routeMethod = route.method;\n routeAction = route.action;\n routePath = route.path;\n\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeValidation: route.validation,\n });\n\n break;\n }\n case WebServerRouteType.Entity: {\n if (this.applicationConfig.database && this.applicationConfig.database.enabled === true) {\n const entityModel = await Loader.loadEntityModule({\n entitiesDirectory: this.applicationConfig.database.entitiesDirectory,\n entityName: route.entityName,\n });\n\n const entityValidationSchema = entityModel.schema?.describe();\n\n const formattedEntityValidationSchema = entityValidationSchema\n ? {\n type: 'object',\n properties: Object.fromEntries(\n Object.entries(entityValidationSchema.keys).map(([key, value]) => [\n key,\n { type: (value as any).type },\n ]),\n ),\n required: Object.keys(entityValidationSchema.keys).filter(\n // Dynamic schema inspection of joi describe output; keys are from trusted entity definitions\n // eslint-disable-next-line security/detect-object-injection\n key => entityValidationSchema.keys[key].flags?.presence === 'required',\n ),\n }\n : {};\n\n const entityRouteDefinitions = WebServerUtil.getEntityRouteDefinitions({\n basePath: route.path,\n entityValidationSchema: formattedEntityValidationSchema,\n });\n\n for (const entityRouteDefinition of entityRouteDefinitions) {\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod: entityRouteDefinition.method,\n routePath: entityRouteDefinition.path,\n routeAction: entityRouteDefinition.action,\n routeValidation: entityRouteDefinition.validationSchema,\n });\n }\n }\n\n break;\n }\n }\n }\n\n if (this.options.debug?.printRoutes) {\n this.log('Routes:');\n\n console.log(this.fastifyServer.printRoutes());\n }\n }\n\n public async defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeValidation,\n }: {\n controllerInstance: any;\n controllerName: string;\n routeMethod: HTTPMethods | HTTPMethods[];\n routePath: string;\n routeAction: string;\n routeValidation?: {\n type: 'body' | 'query' | 'params';\n schema: { [key: string]: any };\n };\n }): Promise<void> {\n // Get controller action handler\n // Validate action name to avoid prototype access\n if (!/^[A-Za-z0-9_]+$/.test(routeAction) || ['__proto__', 'prototype', 'constructor'].includes(routeAction)) {\n throw new Error('Invalid controller action name');\n }\n // Dynamic access guarded by regex + deny list (keys validated above)\n const controllerHandler = controllerInstance[routeAction as keyof typeof controllerInstance];\n\n if (!controllerHandler) {\n Logger.warn({\n message: 'Web server controller action not found',\n meta: {\n Controller: controllerName,\n Action: routeAction,\n },\n });\n\n throw new Error('Web server controller action not found');\n }\n\n // Add route\n this.fastifyServer.route({\n method: routeMethod,\n url: routePath,\n handler: controllerHandler,\n preValidation: async (request, reply) => {\n if (!routeValidation?.schema) {\n // Logger.warn('Web server route validation schema not found', {\n // Controller: controllerName,\n // Action: routeAction,\n // });\n\n return;\n }\n\n const validate = request.compileValidationSchema(routeValidation.schema);\n\n // Avoid dynamic request[...] access for security lint; map explicitly\n let dataToValidate: any;\n switch (routeValidation.type) {\n case 'body':\n dataToValidate = request.body;\n break;\n case 'query':\n dataToValidate = request.query;\n break;\n case 'params':\n dataToValidate = request.params;\n break;\n default:\n dataToValidate = undefined;\n }\n\n if (!validate(dataToValidate)) {\n return reply.code(400).send({\n error: validate.errors,\n });\n }\n },\n });\n }\n\n /**\n * Start web server.\n */\n public async start(): Promise<void> {\n try {\n await this.fastifyServer.listen({\n host: this.options.host,\n port: this.options.port,\n });\n this._isReady = true;\n } catch (error) {\n Logger.error({ error });\n throw error;\n }\n }\n\n /**\n * Stop web server.\n */\n public async stop(): Promise<void> {\n this._isReady = false;\n // Close Fastify server\n await this.fastifyServer.close();\n }\n\n /**\n * Check if web server is ready to accept traffic.\n */\n public isReady(): boolean {\n return this._isReady && this.fastifyServer.server?.listening === true;\n }\n\n /**\n * Log web server message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'webServer', message, meta });\n }\n}\n\nexport default WebServer;\n"],
5
- "mappings": ";;AAAA,OAAO,YAAY;AACnB,OAAO,aAAiG;AACxG,OAAO,UAAU;AACjB,OAAO,YAAY;AACnB,OAAO,eAAe;AACtB,OAAO,eAAe;AACtB;AAAA,EAIE;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,MAAM,QAAQ,QAAQ,YAAY;AAC3C,OAAO,mBAAmB;AAK1B,SAAS,iCAAiC;AAI1C,SAAS,2BAA2B;AASpC,MAAM,UAAU;AAAA,EAhChB,OAgCgB;AAAA;AAAA;AAAA,EACN,SAAwB;AAAA,EAExB;AAAA,EAEA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAED;AAAA,EAEC;AAAA,EACA,WAAW;AAAA,EAEnB,YAAY,QAA6E;AAEvF,UAAM,iBAA4C;AAAA,MAChD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,OAAO;AAAA,QACL,aAAa;AAAA,QACb,wBAAwB;AAAA,UACtB,SAAS;AAAA,UACT,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,KAAK;AAAA,QACH,SAAS;AAAA,MACX;AAAA,IACF;AAGA,UAAM,gBAAgB,OAAO,aAAa,OAAO,SAAS,cAAc;AAExE,SAAK,oBAAoB,OAAO;AAEhC,SAAK,UAAU;AACf,SAAK,SAAS,OAAO;AAErB,SAAK,gBAAgB,OAAO;AAC5B,SAAK,eAAe,OAAO;AAC3B,SAAK,eAAe,OAAO;AAC3B,SAAK,mBAAmB,OAAO;AAC/B,SAAK,mBAAmB,OAAO;AAG/B,UAAM,mBAAmB,KAAK,OAAO;AACrC,UAAM,2BAA2B,KAAK;AAEtC,SAAK,gBAAgB,QAAQ;AAAA,MAC3B,QAAQ;AAAA,MACR,WAAW,KAAK,QAAQ,aAAa;AAAA,MACrC,mBAAmB,KAAK,QAAQ,qBAAqB;AAAA,IACvD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,OAAsB;AAEjC,UAAM,KAAK,kBAAkB;AAG7B,SAAK,eAAe;AAGpB,SAAK,cAAc;AAGnB,SAAK,0BAA0B;AAG/B,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAmC;AAC/C,UAAM,WAAW,KAAK,QAAQ,YAAY,CAAC;AAG3C,UAAM,eAAe,SAAS,UAAU,EAAE,SAAS,KAAK;AACxD,QAAI,aAAa,YAAY,OAAO;AAClC,YAAM,KAAK,cAAc,SAAS,QAAQ;AAAA,QACxC,uBAAuB,aAAa,0BAA0B;AAAA,QAC9D,2BAA2B,aAAa,8BAA8B;AAAA,QACtE,yBAAyB,aAAa,4BAA4B;AAAA,QAClE,2BAA2B,aAAa,8BAA8B;AAAA,QACtE,oBAAoB,aAAa,uBAAuB;AAAA,QACxD,YAAY,aAAa,eAAe;AAAA,QACxC,eAAe,aAAa,kBAAkB;AAAA,QAC9C,MAAM,aAAa,SAAS;AAAA,QAC5B,UAAU,aAAa,aAAa;AAAA,QACpC,SAAS,aAAa,YAAY;AAAA,QAClC,oBAAoB,aAAa,uBAAuB;AAAA,QACxD,8BAA8B,aAAa,iCAAiC;AAAA,QAC5E,gBAAgB,aAAa,mBAAmB;AAAA,QAChD,WAAW,aAAa,cAAc;AAAA,MACxC,CAAC;AAAA,IACH;AAGA,UAAM,kBAAkB,SAAS,aAAa,EAAE,SAAS,KAAK;AAC9D,QAAI,gBAAgB,YAAY,OAAO;AACrC,YAAM,KAAK,cAAc,SAAS,WAAW;AAAA,QAC3C,KAAK,gBAAgB,OAAO;AAAA,QAC5B,YAAY,gBAAgB,cAAc;AAAA,QAC1C,KAAK,gBAAgB;AAAA,QACrB,OAAO,gBAAgB,SAAS;AAAA,MAClC,CAAC;AAAA,IACH;AAGA,QAAI,QAAQ,IAAI,aAAa,gBAAgB,KAAK,QAAQ,MAAM,SAAS;AACvE,YAAM,aAAa,KAAK,QAAQ;AAChC,UAAI,WAAW,MAAM,SAAS,GAAG,GAAG;AAClC,aAAK,OAAO,KAAK;AAAA,UACf,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,gBAAgB;AAAA,UAClB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAuB;AAC7B,SAAK,cAAc,QAAQ,YAAY,YAAY,KAAK,SAAS,CAAC;AAClE,SAAK,cAAc,QAAQ,aAAa,OAAM,YAAW,KAAK,UAAU,OAAO,CAAC;AAChF,SAAK,cAAc,QAAQ,cAAc,OAAO,SAAS,UAAU,KAAK,WAAW,SAAS,KAAK,CAAC;AAClG,SAAK,cAAc,QAAQ,WAAW,OAAO,SAAS,OAAO,UAAU,KAAK,QAAQ,SAAS,OAAO,KAAK,CAAC;AAC1G,SAAK,cAAc,QAAQ,WAAW,YAAY,KAAK,QAAQ,CAAC;AAAA,EAQlE;AAAA,EAEA,MAAc,WAA0B;AACtC,UAAM,UAAU,KAAK,cAAc,OAAO,QAAQ;AAClD,UAAM,OAAO,OAAO,YAAY,WAAW,UAAU,SAAS;AAE9D,QAAI,KAAK,QAAQ,KAAK,SAAS;AAC7B,WAAK,IAAI,WAAW;AAAA,QAClB,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM;AAAA;AAAA,QAEN,MAAM,KAAK,QAAQ,MAAM,UAAU,KAAK,QAAQ,KAAK,KAAK,KAAK,IAAI,IAAI;AAAA,QACvE,mBAAmB,KAAK,cAAc;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,UAAU,SAAwC;AAC9D,QACE,KAAK,QAAQ,OAAO,wBAAwB,WAC5C,KAAK,QAAQ,OAAO,wBAAwB,SAC5C,KAAK,QAAQ,OAAO,wBAAwB,QAAQ,GACpD;AACA,YAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,KAAK,QAAQ,OAAO,wBAAwB,KAAK,CAAC;AAAA,IACrG;AAGA,UAAM,YAAa,QAAQ,QAAQ,cAAc,KAA4B,OAAO,WAAW;AAC/F,YAAQ,YAAY;AAEpB,UAAM,gBAAgB,CAAC,gBAAgB,eAAe;AAEtD,QAAI,cAAc,SAAS,QAAQ,GAAG,KAAK,QAAQ,WAAW,WAAW;AAAA,IAEzE,OAAO;AACL,YAAM,YAAY,KAAK,IAAI;AAC3B,cAAQ,YAAY;AAIpB,0BAAoB,EAAE,WAAW,UAAU,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,SAAyB,OAAoC;AAEpF,QAAI,QAAQ,WAAW;AACrB,YAAM,OAAO,gBAAgB,QAAQ,SAAS;AAAA,IAChD;AAEA,QAAI,CAAC,QAAQ,WAAW;AACtB;AAAA,IACF;AAEA,UAAM,gBAAgB,KAAK,uBAAuB;AAAA,MAChD,WAAW,QAAQ;AAAA,IACrB,CAAC;AACD,UAAM,yBAAyB,KAAK,WAAW;AAAA,MAC7C,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAED,UAAM,KAAK,QAAQ,QAAQ,iBAAiB,KAAK,QAAQ;AAEzD,UAAM,YAAqC;AAAA,MACzC,QAAQ,QAAQ;AAAA,MAChB,MAAM,QAAQ;AAAA,MACd,QAAQ,MAAM;AAAA,IAChB;AAEA,QAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,gBAAU,KAAK,GAAG,SAAS;AAAA,IAC7B;AAEA,cAAU,OAAO;AAMjB,SAAK,IAAI,eAAe,SAAS;AAAA,EACnC;AAAA,EAEA,MAAc,QAAQ,SAAyB,OAAqB,OAA6B;AAE/F,WAAO,MAAM,EAAE,MAAM,CAAC;AAAA,EAExB;AAAA,EAEA,MAAc,UAAyB;AACrC,SAAK,IAAI,SAAS;AAAA,EACpB;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,CAAC,KAAK,QAAQ,MAAM,SAAS;AAC/B;AAAA,IACF;AAGA,UAAM,SAAS,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG,IAAI,OAAO,KAAK,QAAQ,KAAK;AAE/E,SAAK,cAAc,SAAS,MAAM;AAAA,MAChC;AAAA,MACA,SAAS,CAAC,OAAO,QAAQ,OAAO,UAAU,SAAS;AAAA,MACnD,gBAAgB,CAAC,gBAAgB,eAAe;AAAA,MAChD,mBAAmB;AAAA,MACnB,sBAAsB;AAAA;AAAA,IAExB,CAAC;AAAA,EACH;AAAA,EAEQ,4BAAkC;AACxC,SAAK,cAAc,SAAS,WAAW;AAAA;AAAA,MAErC,QAAQ;AAAA,QACN,eAAe;AAAA,QACf,WAAW,OAAO,OAAO;AAAA,QACzB,QAAQ;AAAA,QACR,UAAU,OAAO,OAAO,OAAO;AAAA;AAAA,QAC/B,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,kBAAiC;AAE7C,UAAM,6BAA6B,MAAM,KAAK,WAAW,KAAK,QAAQ,oBAAoB;AAE1F,QAAI,CAAC,4BAA4B;AAC/B,aAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,WAAW,KAAK,QAAQ;AAAA,QAC1B;AAAA,MACF,CAAC;AAED;AAAA,IACF;AAGA,UAAM,cAAc,MAAM,OAAO,uBAAuB;AAAA,MACtD,WAAW,KAAK,QAAQ;AAAA,MACxB,YAAY,CAAC,OAAO,KAAK;AAAA,IAC3B,CAAC;AAGD,SAAK,OAAO;AAAA,MACV;AAAA,QACE,MAAM,mBAAmB;AAAA,QACzB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,MACA;AAAA,QACE,MAAM,mBAAmB;AAAA,QACzB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,IACF;AAGA,eAAW,SAAS,KAAK,QAAQ;AAC/B,UAAI;AAEJ,UAAI;AAEJ,UAAI,MAAM,YAAY;AACpB,0BAAkB,MAAM;AAExB,yBAAiB,gBAAgB;AAAA,MACnC,WAAW,MAAM,gBAAgB;AAC/B,0BAAkB,YAAY,MAAM,cAAc;AAElD,yBAAiB,MAAM;AAAA,MACzB,OAAO;AACL,cAAM,IAAI,MAAM,wCAAwC;AAAA,MAC1D;AAEA,UAAI,OAAO,oBAAoB,YAAY;AACzC,cAAM,iBAAiB,GAAG,KAAK,QAAQ,oBAAoB,IAAI,MAAM,cAAc;AAEnF,eAAO,KAAK;AAAA,UACV,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,YAAY,MAAM;AAAA,YAClB,MAAM;AAAA,YACN,OAAO,GAAG,MAAM,IAAI;AAAA,UACtB;AAAA,QACF,CAAC;AAED;AAAA,MACF;AAGA,YAAM,qBAAqB,IAAI,gBAAgB;AAAA,QAC7C,mBAAmB,KAAK;AAAA,QACxB,kBAAkB,KAAK;AAAA,QACvB,eAAe,KAAK;AAAA,QACpB,cAAc,KAAK;AAAA,QACnB,cAAc,KAAK;AAAA,QACnB,kBAAkB,KAAK;AAAA,QACvB,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAED,UAAI;AACJ,UAAI;AACJ,UAAI;AAEJ,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK,mBAAmB,SAAS;AAC/B,wBAAc,MAAM;AACpB,wBAAc,MAAM;AACpB,sBAAY,MAAM;AAElB,eAAK,YAAY;AAAA,YACf;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,iBAAiB,MAAM;AAAA,UACzB,CAAC;AAED;AAAA,QACF;AAAA,QACA,KAAK,mBAAmB,QAAQ;AAC9B,cAAI,KAAK,kBAAkB,YAAY,KAAK,kBAAkB,SAAS,YAAY,MAAM;AACvF,kBAAM,cAAc,MAAM,OAAO,iBAAiB;AAAA,cAChD,mBAAmB,KAAK,kBAAkB,SAAS;AAAA,cACnD,YAAY,MAAM;AAAA,YACpB,CAAC;AAED,kBAAM,yBAAyB,YAAY,QAAQ,SAAS;AAE5D,kBAAM,kCAAkC,yBACpC;AAAA,cACE,MAAM;AAAA,cACN,YAAY,OAAO;AAAA,gBACjB,OAAO,QAAQ,uBAAuB,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,kBAChE;AAAA,kBACA,EAAE,MAAO,MAAc,KAAK;AAAA,gBAC9B,CAAC;AAAA,cACH;AAAA,cACA,UAAU,OAAO,KAAK,uBAAuB,IAAI,EAAE;AAAA;AAAA;AAAA,gBAGjD,SAAO,uBAAuB,KAAK,GAAG,EAAE,OAAO,aAAa;AAAA,cAC9D;AAAA,YACF,IACA,CAAC;AAEL,kBAAM,yBAAyB,cAAc,0BAA0B;AAAA,cACrE,UAAU,MAAM;AAAA,cAChB,wBAAwB;AAAA,YAC1B,CAAC;AAED,uBAAW,yBAAyB,wBAAwB;AAC1D,mBAAK,YAAY;AAAA,gBACf;AAAA,gBACA;AAAA,gBACA,aAAa,sBAAsB;AAAA,gBACnC,WAAW,sBAAsB;AAAA,gBACjC,aAAa,sBAAsB;AAAA,gBACnC,iBAAiB,sBAAsB;AAAA,cACzC,CAAC;AAAA,YACH;AAAA,UACF;AAEA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ,OAAO,aAAa;AACnC,WAAK,IAAI,SAAS;AAElB,cAAQ,IAAI,KAAK,cAAc,YAAY,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAa,YAAY;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAUkB;AAGhB,QAAI,CAAC,kBAAkB,KAAK,WAAW,KAAK,CAAC,aAAa,aAAa,aAAa,EAAE,SAAS,WAAW,GAAG;AAC3G,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,UAAM,oBAAoB,mBAAmB,WAA8C;AAE3F,QAAI,CAAC,mBAAmB;AACtB,aAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,YAAY;AAAA,UACZ,QAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAED,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAGA,SAAK,cAAc,MAAM;AAAA,MACvB,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,SAAS;AAAA,MACT,eAAe,8BAAO,SAAS,UAAU;AACvC,YAAI,CAAC,iBAAiB,QAAQ;AAM5B;AAAA,QACF;AAEA,cAAM,WAAW,QAAQ,wBAAwB,gBAAgB,MAAM;AAGvE,YAAI;AACJ,gBAAQ,gBAAgB,MAAM;AAAA,UAC5B,KAAK;AACH,6BAAiB,QAAQ;AACzB;AAAA,UACF,KAAK;AACH,6BAAiB,QAAQ;AACzB;AAAA,UACF,KAAK;AACH,6BAAiB,QAAQ;AACzB;AAAA,UACF;AACE,6BAAiB;AAAA,QACrB;AAEA,YAAI,CAAC,SAAS,cAAc,GAAG;AAC7B,iBAAO,MAAM,KAAK,GAAG,EAAE,KAAK;AAAA,YAC1B,OAAO,SAAS;AAAA,UAClB,CAAC;AAAA,QACH;AAAA,MACF,GAjCe;AAAA,IAkCjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,QAAuB;AAClC,QAAI;AACF,YAAM,KAAK,cAAc,OAAO;AAAA,QAC9B,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,QAAQ;AAAA,MACrB,CAAC;AACD,WAAK,WAAW;AAAA,IAClB,SAAS,OAAO;AACd,aAAO,MAAM,EAAE,MAAM,CAAC;AACtB,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,OAAsB;AACjC,SAAK,WAAW;AAEhB,UAAM,KAAK,cAAc,MAAM;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKO,UAAmB;AACxB,WAAO,KAAK,YAAY,KAAK,cAAc,QAAQ,cAAc;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKO,IAAI,SAAiB,MAAsC;AAChE,SAAK,OAAO,OAAO,EAAE,OAAO,aAAa,SAAS,KAAK,CAAC;AAAA,EAC1D;AACF;AAEA,IAAO,oBAAQ;",
4
+ "sourcesContent": ["import crypto from 'node:crypto';\nimport Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n type FastifySchema,\n type HTTPMethods,\n} from 'fastify';\nimport cors from '@fastify/cors';\nimport helmet from '@fastify/helmet';\nimport rateLimit from '@fastify/rate-limit';\nimport multipart from '@fastify/multipart';\nimport {\n type AnyRouteSchemaDefinition,\n type WebServerConstructorParams,\n type WebServerOptions,\n type WebServerRoute,\n WebServerRouteType,\n} from './webserver.interface.js';\nimport { Logger } from '../logger/index.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport WebServerUtil from './util.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport type { ControllerAction, WebServerBaseControllerType } from './controller/base.interface.js';\nimport type { QueueManager } from '../queue/index.js';\nimport { WebServerHealthController } from '../index.js';\nimport type { LifecycleManager } from '../lifecycle/lifecycle-manager.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\nimport { enterRequestContext } from '../request-context/index.js';\nimport { toJSONSchema, type z } from 'zod';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n startTime?: number;\n requestId?: string;\n }\n}\n\nclass WebServer {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: WebServerOptions;\n private routes: WebServerRoute[];\n\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private eventManager: EventManager;\n private databaseInstance: DatabaseInstance;\n\n public fastifyServer: FastifyInstance;\n\n private lifecycleManager: LifecycleManager;\n private _isReady = false;\n\n constructor(params: WebServerConstructorParams & { lifecycleManager: LifecycleManager }) {\n // Define default options\n const defaultOptions: Partial<WebServerOptions> = {\n host: '0.0.0.0',\n port: 3001,\n cors: {\n enabled: false,\n },\n errors: {\n verbose: false,\n },\n debug: {\n printRoutes: false,\n simulateSlowConnection: {\n enabled: false,\n delay: 250,\n },\n },\n log: {\n startUp: true,\n },\n };\n\n // Merge default options\n const mergedOptions = Helper.defaultsDeep(params.options, defaultOptions);\n\n this.applicationConfig = params.applicationConfig;\n\n this.options = mergedOptions;\n this.routes = [...(params.routes ?? [])];\n\n this.redisInstance = params.redisInstance;\n this.queueManager = params.queueManager;\n this.eventManager = params.eventManager;\n this.databaseInstance = params.databaseInstance;\n this.lifecycleManager = params.lifecycleManager;\n\n // Create Fastify server\n const defaultBodyLimit = 25 * 1024 * 1024; // 25MB (safer default)\n const defaultConnectionTimeout = 10 * 1000; // 10 seconds (safer default)\n\n this.fastifyServer = Fastify({\n logger: false,\n bodyLimit: this.options.bodyLimit ?? defaultBodyLimit,\n connectionTimeout: this.options.connectionTimeout ?? defaultConnectionTimeout,\n });\n }\n\n /**\n * Load web server.\n */\n public async load(): Promise<void> {\n // Configure security (helmet, rate limiting)\n await this.configureSecurity();\n\n // Configure hooks\n this.configureHooks();\n\n // Configure CORS\n this.configureCORS();\n\n // Configure multipart uploads\n this.configureMultipartUploads();\n\n // Configure routes\n await this.configureRoutes();\n }\n\n /**\n * Configure security features (Helmet, Rate Limiting)\n */\n private async configureSecurity(): Promise<void> {\n const security = this.options.security ?? {};\n\n // Configure Helmet for security headers\n const helmetConfig = security.helmet ?? { enabled: true };\n if (helmetConfig.enabled !== false) {\n await this.fastifyServer.register(helmet, {\n contentSecurityPolicy: helmetConfig.contentSecurityPolicy !== false,\n crossOriginEmbedderPolicy: helmetConfig.crossOriginEmbedderPolicy !== false,\n crossOriginOpenerPolicy: helmetConfig.crossOriginOpenerPolicy !== false,\n crossOriginResourcePolicy: helmetConfig.crossOriginResourcePolicy !== false,\n dnsPrefetchControl: helmetConfig.dnsPrefetchControl !== false,\n frameguard: helmetConfig.frameguard !== false,\n hidePoweredBy: helmetConfig.hidePoweredBy !== false,\n hsts: helmetConfig.hsts !== false,\n ieNoOpen: helmetConfig.ieNoOpen !== false,\n noSniff: helmetConfig.noSniff !== false,\n originAgentCluster: helmetConfig.originAgentCluster !== false,\n permittedCrossDomainPolicies: helmetConfig.permittedCrossDomainPolicies !== false,\n referrerPolicy: helmetConfig.referrerPolicy !== false,\n xssFilter: helmetConfig.xssFilter !== false,\n });\n }\n\n // Configure rate limiting\n const rateLimitConfig = security.rateLimit ?? { enabled: true };\n if (rateLimitConfig.enabled !== false) {\n await this.fastifyServer.register(rateLimit, {\n max: rateLimitConfig.max ?? 1000,\n timeWindow: rateLimitConfig.timeWindow ?? '1 minute',\n ban: rateLimitConfig.ban,\n cache: rateLimitConfig.cache ?? 5000,\n });\n }\n\n // Warn about wildcard CORS in production\n if (process.env.NODE_ENV === 'production' && this.options.cors?.enabled) {\n const corsConfig = this.options.cors as { enabled: true; urls: string[] };\n if (corsConfig.urls?.includes('*')) {\n this.logger.warn({\n message: 'Wildcard CORS (*) is enabled in production - this is a security risk',\n meta: {\n recommendation: 'Specify allowed origins explicitly',\n },\n });\n }\n }\n }\n\n /**\n * Configure hooks.\n */\n private configureHooks(): void {\n this.fastifyServer.addHook('onListen', async () => this.onListen());\n this.fastifyServer.addHook('onRequest', async request => this.onRequest(request));\n this.fastifyServer.addHook('onResponse', async (request, reply) => this.onResponse(request, reply));\n this.fastifyServer.addHook('onError', async (request, reply, error) => this.onError(request, reply, error));\n this.fastifyServer.addHook('onClose', async () => this.onClose());\n\n // if (process.env.NODE_ENV === 'local') {\n // this.fastifyServer.addHook('onSend', (request, reply, payload, done) => {\n // reply.header('Cache-Control', 'no-store');\n // done();\n // });\n // }\n }\n\n private async onListen(): Promise<void> {\n const address = this.fastifyServer.server.address();\n const port = typeof address === 'string' ? address : address?.port;\n\n if (this.options.log?.startUp) {\n this.log('Started', {\n Host: this.options.host,\n Port: port,\n // CORS: this.options.cors?.enabled && this.options.cors?..length > 0 ? this.options.corsUrls.join(', ') : 'Disabled',\n CORS: this.options.cors?.enabled ? this.options.cors.urls.join(', ') : 'Disabled',\n 'Fastify Version': this.fastifyServer.version,\n });\n }\n }\n\n private async onRequest(request: FastifyRequest): Promise<void> {\n if (\n this.options.debug?.simulateSlowConnection?.enabled &&\n this.options.debug?.simulateSlowConnection?.delay &&\n this.options.debug?.simulateSlowConnection?.delay > 0\n ) {\n await new Promise(resolve => setTimeout(resolve, this.options.debug?.simulateSlowConnection?.delay));\n }\n\n // Generate or use existing request ID for correlation\n const requestId = (request.headers['x-request-id'] as string | undefined) ?? crypto.randomUUID();\n request.requestId = requestId;\n\n const pathsToIgnore = ['/health/live', '/health/ready'];\n\n if (pathsToIgnore.includes(request.url) || request.method === 'OPTIONS') {\n // ...\n } else {\n const startTime = Time.now();\n request.startTime = startTime;\n\n // Initialize AsyncLocalStorage context for this request\n // Using enterWith() to set context for the current async execution\n enterRequestContext({ requestId, startTime });\n }\n }\n\n private async onResponse(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n // Add request ID to response headers for client-side correlation\n if (request.requestId) {\n reply.header('X-Request-ID', request.requestId);\n }\n\n if (!request.startTime) {\n return;\n }\n\n const executionTime = Time.calculateElapsedTimeMs({\n startTime: request.startTime,\n });\n const formattedExecutionTime = Time.formatTime({\n time: executionTime,\n numDecimals: 3,\n });\n\n const ip = request.headers['x-forwarded-for'] ?? request.ip;\n\n const logParams: Record<string, unknown> = {\n Method: request.method,\n Path: request.url,\n Status: reply.statusCode,\n };\n\n if (process.env.NODE_ENV !== 'development') {\n logParams.IP = ip.toString();\n }\n\n logParams.Time = formattedExecutionTime;\n\n // if (cluster.isWorker && cluster.worker) {\n // logParams.Worker = cluster.worker.id;\n // }\n\n this.log('API Request', logParams);\n }\n\n private async onError(request: FastifyRequest, reply: FastifyReply, error: Error): Promise<void> {\n // Adjusted for Fastify types\n Logger.error({ error });\n // Implement any additional logic here\n }\n\n private async onClose(): Promise<void> {\n this.log('Stopped');\n }\n\n private configureCORS(): void {\n if (!this.options.cors?.enabled) {\n return;\n }\n\n // Handle wildcard origin for development\n const origin = this.options.cors.urls.includes('*') ? true : this.options.cors.urls;\n\n this.fastifyServer.register(cors, {\n origin,\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization'],\n preflightContinue: false,\n optionsSuccessStatus: 204,\n // credentials: true,\n });\n }\n\n private configureMultipartUploads(): void {\n this.fastifyServer.register(multipart, {\n // attachFieldsToBody: true,\n limits: {\n fieldNameSize: 100,\n fieldSize: 1024 * 1024 * 10,\n fields: 10,\n fileSize: 1024 * 1024 * 1024 * 10, // 10GB file size limit\n files: 1,\n headerPairs: 2000,\n },\n });\n }\n\n /**\n * Configure routes.\n */\n private async configureRoutes(): Promise<void> {\n await this.loadRoutesFromDirectory();\n\n // Check if controllers directory exists\n const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory ?? '');\n\n if (!controllersDirectoryExists) {\n const routesRequiringControllers = this.routes.length === 0 || this.routes.some(route => !route.handler);\n\n if (routesRequiringControllers) {\n Logger.warn({\n message: 'Web server controllers directory not found',\n meta: {\n Directory: this.options.controllersDirectory,\n },\n });\n\n return;\n }\n }\n\n // Load controllers\n const controllers = controllersDirectoryExists\n ? await Loader.loadModulesInDirectory({\n directory: this.options.controllersDirectory,\n extensions: ['.ts', '.js'],\n })\n : {};\n\n // Add health check routes\n this.routes.push(\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/live',\n controller: WebServerHealthController,\n action: 'live',\n },\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/ready',\n controller: WebServerHealthController,\n action: 'ready',\n },\n );\n\n // Go through each route\n for (const route of this.routes) {\n let ControllerClass: WebServerBaseControllerType;\n\n let controllerName;\n\n if (route.handler && !route.controller && !route.controllerName) {\n if (route.type && route.type !== WebServerRouteType.Default) {\n throw new Error('Handler-only routes are only supported for default route type');\n }\n\n if (!('method' in route)) {\n throw new Error('Handler-only routes require an HTTP method');\n }\n\n const schema = this.buildFastifySchema(route.schema) ?? this.buildLegacySchema(route.validation);\n\n this.fastifyServer.route({\n method: route.method,\n url: route.path,\n handler: route.handler,\n ...(schema ? { schema } : {}),\n });\n\n continue;\n }\n\n if (route.controller) {\n ControllerClass = route.controller;\n\n controllerName = ControllerClass.name;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName] as WebServerBaseControllerType;\n\n controllerName = route.controllerName;\n } else {\n throw new Error('Web server controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n const controllerPath = `${this.options.controllersDirectory}/${route.controllerName}.ts`;\n\n Logger.warn({\n message: 'Web server controller not found',\n meta: {\n Controller: route.controllerName,\n Path: controllerPath,\n Route: `${route.path}`,\n },\n });\n\n continue;\n }\n\n // Initialize controller instance\n const controllerInstance = new ControllerClass({\n applicationConfig: this.applicationConfig,\n webServerOptions: this.options,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n eventManager: this.eventManager,\n databaseInstance: this.databaseInstance,\n lifecycleManager: this.lifecycleManager,\n });\n\n let routeMethod;\n let routeAction;\n let routePath;\n\n switch (route.type) {\n case WebServerRouteType.Default: {\n routeMethod = route.method;\n routeAction = route.action;\n routePath = route.path;\n\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeSchema: route.schema,\n handlerOverride: route.handler?.bind(controllerInstance),\n legacyValidation: route.validation,\n });\n\n break;\n }\n case WebServerRouteType.Entity: {\n if (this.applicationConfig.database && this.applicationConfig.database.enabled === true) {\n const entityModel = await Loader.loadEntityModule({\n entitiesDirectory: this.applicationConfig.database.entitiesDirectory,\n entityName: route.entityName,\n });\n\n const entityValidationSchema = (\n entityModel as { schema?: { describe: () => unknown } }\n ).schema?.describe() as\n | {\n keys: Record<string, { type: string; flags?: { presence?: string }; [key: string]: unknown }>;\n [key: string]: unknown;\n }\n | undefined;\n\n const formattedEntityValidationSchema = entityValidationSchema\n ? {\n type: 'object',\n properties: Object.fromEntries(\n Object.entries(entityValidationSchema.keys).map(([key, value]) => [key, { type: value.type }]),\n ),\n required: Object.keys(entityValidationSchema.keys).filter(\n // Dynamic schema inspection of joi describe output; keys are from trusted entity definitions\n // eslint-disable-next-line security/detect-object-injection\n key => entityValidationSchema.keys[key].flags?.presence === 'required',\n ),\n }\n : {};\n\n const entityRouteDefinitions = WebServerUtil.getEntityRouteDefinitions({\n basePath: route.path,\n entityValidationSchema: formattedEntityValidationSchema,\n });\n\n for (const entityRouteDefinition of entityRouteDefinitions) {\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod: entityRouteDefinition.method,\n routePath: entityRouteDefinition.path,\n routeAction: entityRouteDefinition.action,\n routeSchema: route.schema,\n handlerOverride: route.handler?.bind(controllerInstance),\n legacyValidation: entityRouteDefinition.validationSchema,\n });\n }\n }\n\n break;\n }\n }\n }\n\n if (this.options.debug?.printRoutes) {\n this.log('Routes:');\n\n console.log(this.fastifyServer.printRoutes());\n }\n }\n\n private async loadRoutesFromDirectory(): Promise<void> {\n const { routesDirectory } = this.options;\n\n if (!routesDirectory) {\n return;\n }\n\n const directoryExists = await File.pathExists(routesDirectory);\n\n if (!directoryExists) {\n this.logger.warn({\n message: 'Web server routes directory not found',\n meta: {\n Directory: routesDirectory,\n },\n });\n\n return;\n }\n\n const routeModules = await Loader.loadModulesInDirectory<\n WebServerRoute | WebServerRoute[] | { routes?: WebServerRoute[] }\n >({\n directory: routesDirectory,\n extensions: ['.ts', '.js'],\n });\n\n const loadedRoutes: WebServerRoute[] = [];\n\n for (const [moduleName, exportedRoutes] of Object.entries(routeModules)) {\n const normalizedRoutes = this.normalizeRouteExport(exportedRoutes, moduleName);\n\n if (normalizedRoutes.length === 0) {\n continue;\n }\n\n loadedRoutes.push(...normalizedRoutes);\n }\n\n if (loadedRoutes.length > 0) {\n this.routes.push(...loadedRoutes);\n }\n }\n\n private normalizeRouteExport(exportedValue: unknown, moduleName: string): WebServerRoute[] {\n const ensureRouteArray = (value: unknown): WebServerRoute[] => {\n if (Array.isArray(value)) {\n return value;\n }\n\n if (value && typeof value === 'object') {\n const maybeRoute = value as { routes?: unknown };\n\n if (Array.isArray(maybeRoute.routes)) {\n return maybeRoute.routes as WebServerRoute[];\n }\n }\n\n return value ? [value as WebServerRoute] : [];\n };\n\n const routeCandidates = ensureRouteArray(exportedValue);\n const validRoutes: WebServerRoute[] = [];\n\n for (const [index, candidate] of routeCandidates.entries()) {\n if (this.isValidRoute(candidate)) {\n validRoutes.push(candidate);\n } else {\n this.logger.warn({\n message: 'Invalid web server route definition skipped',\n meta: {\n Module: moduleName,\n Index: index,\n },\n });\n }\n }\n\n if (validRoutes.length === 0 && routeCandidates.length > 0) {\n this.logger.warn({\n message: 'No valid routes exported from module',\n meta: {\n Module: moduleName,\n },\n });\n }\n\n return validRoutes;\n }\n\n private isValidRoute(route: unknown): route is WebServerRoute {\n if (!route || typeof route !== 'object') {\n return false;\n }\n\n const candidate = route as Record<string, unknown>;\n const routePath = candidate.path;\n\n if (typeof routePath !== 'string' || routePath.length === 0) {\n return false;\n }\n\n const routeType = candidate.type ?? WebServerRouteType.Default;\n\n const controllerProvided =\n typeof candidate.controller === 'function' || typeof candidate.controllerName === 'string';\n\n if (routeType === WebServerRouteType.Entity || routeType === 'entity') {\n return controllerProvided && typeof candidate.entityName === 'string' && candidate.entityName.length > 0;\n }\n\n if (!controllerProvided) {\n return false;\n }\n\n const method = candidate.method;\n const action = candidate.action;\n\n const isValidMethod =\n typeof method === 'string' ||\n (Array.isArray(method) && method.length > 0 && method.every(m => typeof m === 'string'));\n\n const isValidAction = typeof action === 'string' && action.length > 0;\n\n return isValidMethod && isValidAction;\n }\n\n public async defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeSchema,\n handlerOverride,\n legacyValidation,\n }: {\n controllerInstance: any;\n controllerName: string;\n routeMethod: HTTPMethods | HTTPMethods[];\n routePath: string;\n routeAction?: string;\n routeSchema?: AnyRouteSchemaDefinition;\n handlerOverride?: ControllerAction<any>;\n legacyValidation?: {\n type: 'body' | 'query' | 'params';\n schema: { [key: string]: any };\n };\n }): Promise<void> {\n let handler = handlerOverride;\n\n if (!handler) {\n if (!routeAction) {\n throw new Error('Route action is required when handler override is not provided');\n }\n\n if (!/^[A-Za-z0-9_]+$/.test(routeAction) || ['__proto__', 'prototype', 'constructor'].includes(routeAction)) {\n throw new Error('Invalid controller action name');\n }\n\n const controllerHandler = controllerInstance[routeAction as keyof typeof controllerInstance];\n\n if (!controllerHandler) {\n Logger.warn({\n message: 'Web server controller action not found',\n meta: {\n Controller: controllerName,\n Action: routeAction,\n },\n });\n\n throw new Error('Web server controller action not found');\n }\n\n handler = controllerHandler.bind(controllerInstance) as ControllerAction<any>;\n }\n\n const fastifySchema = this.buildFastifySchema(routeSchema) ?? this.buildLegacySchema(legacyValidation);\n\n if (!handler) {\n throw new Error('Route handler could not be resolved');\n }\n\n this.fastifyServer.route({\n method: routeMethod,\n url: routePath,\n handler: handler as unknown as (request: FastifyRequest, reply: FastifyReply) => unknown,\n ...(fastifySchema ? { schema: fastifySchema } : {}),\n });\n }\n\n /**\n * Start web server.\n */\n public async start(): Promise<void> {\n try {\n await this.fastifyServer.listen({\n host: this.options.host,\n port: this.options.port,\n });\n this._isReady = true;\n } catch (error) {\n Logger.error({ error });\n throw error;\n }\n }\n\n /**\n * Stop web server.\n */\n public async stop(): Promise<void> {\n this._isReady = false;\n // Close Fastify server\n await this.fastifyServer.close();\n }\n\n private buildFastifySchema(routeSchema?: AnyRouteSchemaDefinition): FastifySchema | undefined {\n if (!routeSchema) {\n return undefined;\n }\n\n const schema: FastifySchema = {};\n\n if (routeSchema.params) {\n schema.params = this.convertZodSchema(routeSchema.params);\n }\n\n if (routeSchema.querystring) {\n schema.querystring = this.convertZodSchema(routeSchema.querystring);\n }\n\n if (routeSchema.body) {\n schema.body = this.convertZodSchema(routeSchema.body);\n }\n\n if (routeSchema.headers) {\n schema.headers = this.convertZodSchema(routeSchema.headers);\n }\n\n if (routeSchema.response) {\n const responses = routeSchema.response as Record<string, z.ZodTypeAny>;\n const responseEntries = Object.entries(responses)\n .filter(([statusCode]) => /^[1-5][0-9]{2}$/.test(statusCode))\n .map(([statusCode, responseSchema]) => [statusCode, this.convertZodSchema(responseSchema)] as const);\n\n if (responseEntries.length > 0) {\n schema.response = Object.fromEntries(responseEntries);\n }\n }\n\n return schema;\n }\n\n private buildLegacySchema(legacyValidation?: {\n type: 'body' | 'query' | 'params';\n schema: { [key: string]: any };\n }): FastifySchema | undefined {\n if (!legacyValidation) {\n return undefined;\n }\n\n const schema: FastifySchema = {};\n\n switch (legacyValidation.type) {\n case 'body':\n schema.body = legacyValidation.schema;\n break;\n case 'query':\n schema.querystring = legacyValidation.schema;\n break;\n case 'params':\n schema.params = legacyValidation.schema;\n break;\n }\n\n return schema;\n }\n\n private convertZodSchema(zodSchema: z.ZodTypeAny) {\n const jsonSchema = toJSONSchema(zodSchema);\n\n if (jsonSchema && typeof jsonSchema === 'object' && '$schema' in jsonSchema) {\n const { $schema: _jsonSchemaVersion, ...rest } = jsonSchema as Record<string, unknown>;\n return rest;\n }\n\n return jsonSchema as Record<string, unknown>;\n }\n\n /**\n * Check if web server is ready to accept traffic.\n */\n public isReady(): boolean {\n return this._isReady && this.fastifyServer.server?.listening === true;\n }\n\n /**\n * Log web server message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'webServer', message, meta });\n }\n}\n\nexport default WebServer;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/websocket-base.ts"],
4
- "sourcesContent": ["import type { WebSocketMessageHandler, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport { getRouteKey, log, parseServerMessage } from './utils.js';\nimport type { WebSocketServerBaseControllerType } from './controller/server/base.interface.js';\nimport type { WebSocketClientBaseControllerType } from './controller/client/base.interface.js';\nimport type WebSocket from 'ws';\nimport { File, Helper, Loader } from '../util/index.js';\n\nexport default abstract class WebSocketBase {\n protected routes: WebSocketRoute[] = [];\n protected routeHandlers: Map<string, WebSocketMessageHandler> = new Map();\n\n protected defaultRoutes: WebSocketRoute[] = [];\n\n public abstract get type(): WebSocketType;\n\n protected abstract getControllerDependencies(): any;\n protected abstract shouldPrintRoutes(): boolean;\n protected abstract handleMessageError(clientId: string, error: string): void;\n\n protected async configureRoutes(routes: WebSocketRoute[], controllersDirectory: string): Promise<void> {\n // log ('Configuring routes', { Type: this.type, 'Controllers Directory': controllersDirectory });\n\n const controllersDirectoryExists = await File.pathExists(controllersDirectory);\n\n if (!controllersDirectoryExists) {\n log('Controllers directory not found', {\n Directory: controllersDirectory,\n });\n\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: controllersDirectory,\n // NOTE:\n // When getting \"system\", it gets /app/node_modules/@scpxl/nodejs-framework/dist/websocket/controllers/server\n // Therefor .js is needed also\n // Fix so only .ts vs .js is needed\n extensions: ['.ts', '.js'],\n });\n\n for (const route of routes) {\n let ControllerClass: WebSocketServerBaseControllerType | WebSocketClientBaseControllerType;\n\n // log('Registering route', {\n // Type: route.type,\n // Controller: route.controller ? route.controller.toString() : route.controllerName,\n // Action: route.action,\n // });\n\n if (route.controller) {\n ControllerClass = route.controller;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName];\n } else {\n throw new Error('WebSocket controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n log('Controller not found', {\n Controller: route.controllerName,\n Path: `${controllersDirectory}/${route.controllerName}.${scriptFileExtension}`,\n });\n\n continue;\n }\n\n const controllerDependencies = this.getControllerDependencies();\n\n const controllerInstance = new ControllerClass(controllerDependencies);\n\n const controllerHandler = controllerInstance[\n route.action as keyof typeof controllerInstance\n ] as WebSocketMessageHandler;\n const routeKey = getRouteKey(route.type, route.action);\n\n this.routeHandlers.set(routeKey, controllerHandler);\n }\n\n if (this.shouldPrintRoutes()) {\n log('Routes:', { Type: this.type });\n\n this.printRoutes();\n }\n }\n\n protected async handleServerMessage(ws: WebSocket, message: WebSocket.Data, clientId: string): Promise<void | any> {\n try {\n const parsedMessage = parseServerMessage(message);\n const type = parsedMessage.type;\n const action = parsedMessage.action;\n\n log('Incoming message', {\n 'Client ID': clientId,\n Type: type ?? '-',\n Action: action ?? '-',\n });\n\n const routeKey = getRouteKey(parsedMessage.type as string, parsedMessage.action as string);\n\n const messageHandler = this.routeHandlers.get(routeKey);\n\n if (messageHandler) {\n const messageResponse = await messageHandler(ws, clientId, parsedMessage.data);\n\n return {\n type,\n action,\n response: messageResponse,\n };\n }\n // throw new Error(`Route handler not found (Route Key: ${routeKey} | Type: ${type} | Action: ${action})`);\n\n log('Route handler not found', {\n RouteKey: routeKey,\n Type: type,\n Action: action,\n });\n\n // if (\n // typeof this.applicationConfig.webSocket\n // ?.serverMessageHandler === 'function'\n // ) {\n // // Execute custom application subscriber event handler\n // this.applicationConfig.webSocket.serverMessageHandler(\n // {\n // ws,\n // clientId,\n // parsedMessage,\n // },\n // );\n // }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n\n log(errorMessage);\n\n this.handleMessageError(clientId, errorMessage);\n }\n }\n\n protected printRoutes(): void {\n let routesString = '';\n\n const routeKeys = Array.from(this.routeHandlers.keys());\n\n routeKeys.forEach((routeKey, index) => {\n const [type, action] = routeKey.split(':');\n\n routesString += `Type: ${type} -> Action: ${action}`;\n\n if (index !== routeKeys.length - 1) {\n routesString += '\\n';\n }\n });\n\n log(routesString);\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { WebSocketMessageHandler, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport { getRouteKey, log, parseServerMessage } from './utils.js';\nimport type { WebSocketServerBaseControllerType } from './controller/server/base.interface.js';\nimport type { WebSocketClientBaseControllerType } from './controller/client/base.interface.js';\nimport type WebSocket from 'ws';\nimport { File, Helper, Loader } from '../util/index.js';\n\nexport default abstract class WebSocketBase {\n protected routes: WebSocketRoute[] = [];\n protected routeHandlers: Map<string, WebSocketMessageHandler> = new Map();\n\n protected defaultRoutes: WebSocketRoute[] = [];\n\n public abstract get type(): WebSocketType;\n\n protected abstract getControllerDependencies(): Record<string, unknown>;\n protected abstract shouldPrintRoutes(): boolean;\n protected abstract handleMessageError(clientId: string, error: string): void;\n\n protected async configureRoutes(routes: WebSocketRoute[], controllersDirectory: string): Promise<void> {\n // log ('Configuring routes', { Type: this.type, 'Controllers Directory': controllersDirectory });\n\n const controllersDirectoryExists = await File.pathExists(controllersDirectory);\n\n if (!controllersDirectoryExists) {\n log('Controllers directory not found', {\n Directory: controllersDirectory,\n });\n\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: controllersDirectory,\n // NOTE:\n // When getting \"system\", it gets /app/node_modules/@scpxl/nodejs-framework/dist/websocket/controllers/server\n // Therefor .js is needed also\n // Fix so only .ts vs .js is needed\n extensions: ['.ts', '.js'],\n });\n\n for (const route of routes) {\n let ControllerClass: WebSocketServerBaseControllerType | WebSocketClientBaseControllerType;\n\n // log('Registering route', {\n // Type: route.type,\n // Controller: route.controller ? route.controller.toString() : route.controllerName,\n // Action: route.action,\n // });\n\n if (route.controller) {\n ControllerClass = route.controller;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName] as\n | WebSocketServerBaseControllerType\n | WebSocketClientBaseControllerType;\n } else {\n throw new Error('WebSocket controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n log('Controller not found', {\n Controller: route.controllerName,\n Path: `${controllersDirectory}/${route.controllerName}.${scriptFileExtension}`,\n });\n\n continue;\n }\n\n const controllerDependencies = this.getControllerDependencies();\n\n const controllerInstance = new ControllerClass(controllerDependencies as any);\n\n const controllerHandler = controllerInstance[\n route.action as keyof typeof controllerInstance\n ] as WebSocketMessageHandler;\n const routeKey = getRouteKey(route.type, route.action);\n\n this.routeHandlers.set(routeKey, controllerHandler);\n }\n\n if (this.shouldPrintRoutes()) {\n log('Routes:', { Type: this.type });\n\n this.printRoutes();\n }\n }\n\n protected async handleServerMessage(\n ws: WebSocket,\n message: WebSocket.Data,\n clientId: string,\n ): Promise<{ type: unknown; action: unknown; response: unknown } | void> {\n try {\n const parsedMessage = parseServerMessage(message);\n const type = parsedMessage.type;\n const action = parsedMessage.action;\n\n log('Incoming message', {\n 'Client ID': clientId,\n Type: type ?? '-',\n Action: action ?? '-',\n });\n\n const routeKey = getRouteKey(parsedMessage.type as string, parsedMessage.action as string);\n\n const messageHandler = this.routeHandlers.get(routeKey);\n\n if (messageHandler) {\n const messageResponse = await messageHandler(ws, clientId, parsedMessage.data);\n\n return {\n type,\n action,\n response: messageResponse,\n };\n }\n // throw new Error(`Route handler not found (Route Key: ${routeKey} | Type: ${type} | Action: ${action})`);\n\n log('Route handler not found', {\n RouteKey: routeKey,\n Type: type,\n Action: action,\n });\n\n // if (\n // typeof this.applicationConfig.webSocket\n // ?.serverMessageHandler === 'function'\n // ) {\n // // Execute custom application subscriber event handler\n // this.applicationConfig.webSocket.serverMessageHandler(\n // {\n // ws,\n // clientId,\n // parsedMessage,\n // },\n // );\n // }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n\n log(errorMessage);\n\n this.handleMessageError(clientId, errorMessage);\n }\n }\n\n protected printRoutes(): void {\n let routesString = '';\n\n const routeKeys = Array.from(this.routeHandlers.keys());\n\n routeKeys.forEach((routeKey, index) => {\n const [type, action] = routeKey.split(':');\n\n routesString += `Type: ${type} -> Action: ${action}`;\n\n if (index !== routeKeys.length - 1) {\n routesString += '\\n';\n }\n });\n\n log(routesString);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/websocket-client.ts"],
4
- "sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n\n constructor(props: WebSocketClientProps) {\n super();\n\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close', () => {\n this.isConnected = false;\n log('Connection to server closed');\n\n if (this.options.events?.onDisconnected) {\n this.options.events.onDisconnected({ clientId: this.clientId });\n }\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n this.ws = undefined;\n this.clientId = undefined;\n });\n\n ws.on('error', error => {\n log('WebSocket error', { error: error.message });\n\n if (this.options.events?.onError) {\n this.options.events.onError({ error });\n }\n });\n\n this.ws = ws;\n });\n }\n\n protected getControllerDependencies(): {\n sendMessage: (data: unknown) => void;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n sendMessage: this.sendMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleIncomingMessage = async (message: RawData): Promise<void> => {\n if (!this.ws || !this.clientId) {\n log('WebSocket not initialized or client ID not set');\n\n return;\n }\n\n if (this.options.events?.onMessage) {\n const parsedMessage = parseServerMessage(message);\n\n this.options.events.onMessage({\n ws: this.ws,\n clientId: this.clientId,\n data: parsedMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n }\n\n await this.handleServerMessage(this.ws, message, this.clientId);\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n log(error);\n }\n\n public sendClientMessage = (data: unknown, binary: boolean = false): void => {\n if (!this.ws) {\n log('WebSocket not initialized');\n\n return;\n }\n\n const webSocketMessage = JSON.stringify(data);\n\n console.log('SENDING LCIENT MESSAGE: ', webSocketMessage);\n\n this.ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = (data: unknown): void => {\n this.sendClientMessage(data);\n };\n\n public disconnect(): void {\n if (this.ws && this.isConnected) {\n this.ws.removeAllListeners();\n this.ws.close();\n this.ws = undefined;\n this.clientId = undefined;\n this.isConnected = false;\n log('WebSocket client disconnected');\n }\n }\n\n public isClientConnected(): boolean {\n return this.isConnected && this.ws?.readyState === WebSocket.OPEN;\n }\n}\n"],
4
+ "sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n\n constructor(props: WebSocketClientProps) {\n super();\n\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close', () => {\n this.isConnected = false;\n log('Connection to server closed');\n\n if (this.options.events?.onDisconnected) {\n this.options.events.onDisconnected({ clientId: this.clientId });\n }\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n this.ws = undefined;\n this.clientId = undefined;\n });\n\n ws.on('error', error => {\n log('WebSocket error', { error: error.message });\n\n if (this.options.events?.onError) {\n this.options.events.onError({ error });\n }\n });\n\n this.ws = ws;\n });\n }\n\n protected getControllerDependencies(): {\n sendMessage: (data: unknown) => void;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n sendMessage: this.sendMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleIncomingMessage = async (message: RawData): Promise<void> => {\n if (!this.ws || !this.clientId) {\n log('WebSocket not initialized or client ID not set');\n\n return;\n }\n\n if (this.options.events?.onMessage) {\n const parsedMessage = parseServerMessage(message);\n\n this.options.events.onMessage({\n ws: this.ws,\n clientId: this.clientId,\n data: parsedMessage as { type: string; action: string; data: unknown },\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n }\n\n await this.handleServerMessage(this.ws, message, this.clientId);\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n log(error);\n }\n\n public sendClientMessage = (data: unknown, binary: boolean = false): void => {\n if (!this.ws) {\n log('WebSocket not initialized');\n\n return;\n }\n\n const webSocketMessage = JSON.stringify(data);\n\n console.log('SENDING LCIENT MESSAGE: ', webSocketMessage);\n\n this.ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = (data: unknown): void => {\n this.sendClientMessage(data);\n };\n\n public disconnect(): void {\n if (this.ws && this.isConnected) {\n this.ws.removeAllListeners();\n this.ws.close();\n this.ws = undefined;\n this.clientId = undefined;\n this.isConnected = false;\n log('WebSocket client disconnected');\n }\n }\n\n public isClientConnected(): boolean {\n return this.isConnected && this.ws?.readyState === WebSocket.OPEN;\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -211,14 +211,14 @@ class WebSocketServer extends WebSocketBase {
211
211
  });
212
212
  return;
213
213
  }
214
- const runSameWorker = parsedMessage.runSameWorker === true;
214
+ const includeSender = parsedMessage.includeSender === true;
215
215
  const isSameWorker = parsedMessage.workerId === this.workerId;
216
- if (runSameWorker !== true && isSameWorker) {
216
+ if (includeSender !== true && isSameWorker) {
217
217
  return;
218
218
  }
219
219
  log("Incoming subscriber message", {
220
220
  Channel: channel,
221
- // 'Run Same Worker': parsedMessage.runSameWorker ? 'Yes' : 'No',
221
+ // 'Run Same Worker': parsedMessage.includeSender ? 'Yes' : 'No',
222
222
  "Client ID": parsedMessage.clientId ?? "-"
223
223
  });
224
224
  switch (channel) {
@@ -440,7 +440,7 @@ class WebSocketServer extends WebSocketBase {
440
440
  action: serverMessageResponse.action,
441
441
  response: serverMessageResponse?.response
442
442
  });
443
- if (serverMessageResponse?.response?.error) {
443
+ if (serverMessageResponse?.response && typeof serverMessageResponse.response === "object" && "error" in serverMessageResponse.response) {
444
444
  Logger.error({ error: serverMessageResponse.response.error });
445
445
  }
446
446
  }
@@ -455,7 +455,7 @@ class WebSocketServer extends WebSocketBase {
455
455
  this.redisInstance.publisherClient.publish(
456
456
  WebSocketRedisSubscriberEvent.MessageError,
457
457
  JSON.stringify({
458
- runSameWorker: true,
458
+ includeSender: true,
459
459
  clientId,
460
460
  error
461
461
  })