@morojs/moro 1.0.0 → 1.0.1

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 (284) hide show
  1. package/README.md +1 -1
  2. package/dist/core/config/index.d.ts +5 -5
  3. package/dist/core/config/index.js +1 -1
  4. package/dist/core/config/index.js.map +1 -1
  5. package/dist/core/config/loader.d.ts +1 -1
  6. package/dist/core/config/loader.js +58 -82
  7. package/dist/core/config/loader.js.map +1 -1
  8. package/dist/core/config/schema.d.ts +1 -1
  9. package/dist/core/config/schema.js +52 -111
  10. package/dist/core/config/schema.js.map +1 -1
  11. package/dist/core/config/utils.d.ts +2 -2
  12. package/dist/core/config/utils.js +18 -18
  13. package/dist/core/config/utils.js.map +1 -1
  14. package/dist/core/database/adapters/drizzle.d.ts +1 -1
  15. package/dist/core/database/adapters/drizzle.js +39 -55
  16. package/dist/core/database/adapters/drizzle.js.map +1 -1
  17. package/dist/core/database/adapters/index.d.ts +7 -7
  18. package/dist/core/database/adapters/index.js +11 -11
  19. package/dist/core/database/adapters/index.js.map +1 -1
  20. package/dist/core/database/adapters/mongodb.d.ts +1 -1
  21. package/dist/core/database/adapters/mongodb.js +19 -23
  22. package/dist/core/database/adapters/mongodb.js.map +1 -1
  23. package/dist/core/database/adapters/mysql.d.ts +1 -1
  24. package/dist/core/database/adapters/mysql.js +31 -27
  25. package/dist/core/database/adapters/mysql.js.map +1 -1
  26. package/dist/core/database/adapters/postgresql.d.ts +1 -1
  27. package/dist/core/database/adapters/postgresql.js +27 -35
  28. package/dist/core/database/adapters/postgresql.js.map +1 -1
  29. package/dist/core/database/adapters/redis.d.ts +1 -1
  30. package/dist/core/database/adapters/redis.js +24 -24
  31. package/dist/core/database/adapters/redis.js.map +1 -1
  32. package/dist/core/database/adapters/sqlite.d.ts +1 -1
  33. package/dist/core/database/adapters/sqlite.js +36 -36
  34. package/dist/core/database/adapters/sqlite.js.map +1 -1
  35. package/dist/core/database/index.d.ts +2 -2
  36. package/dist/core/docs/index.d.ts +7 -7
  37. package/dist/core/docs/index.js +13 -15
  38. package/dist/core/docs/index.js.map +1 -1
  39. package/dist/core/docs/openapi-generator.d.ts +5 -5
  40. package/dist/core/docs/openapi-generator.js +93 -94
  41. package/dist/core/docs/openapi-generator.js.map +1 -1
  42. package/dist/core/docs/simple-docs.d.ts +1 -1
  43. package/dist/core/docs/simple-docs.js +25 -28
  44. package/dist/core/docs/simple-docs.js.map +1 -1
  45. package/dist/core/docs/swagger-ui.d.ts +2 -2
  46. package/dist/core/docs/swagger-ui.js +46 -51
  47. package/dist/core/docs/swagger-ui.js.map +1 -1
  48. package/dist/core/docs/zod-to-openapi.d.ts +1 -1
  49. package/dist/core/docs/zod-to-openapi.js +115 -125
  50. package/dist/core/docs/zod-to-openapi.js.map +1 -1
  51. package/dist/core/events/event-bus.d.ts +1 -1
  52. package/dist/core/events/event-bus.js +15 -21
  53. package/dist/core/events/event-bus.js.map +1 -1
  54. package/dist/core/events/index.d.ts +2 -2
  55. package/dist/core/framework.d.ts +5 -5
  56. package/dist/core/framework.js +55 -60
  57. package/dist/core/framework.js.map +1 -1
  58. package/dist/core/http/http-server.d.ts +2 -2
  59. package/dist/core/http/http-server.js +228 -261
  60. package/dist/core/http/http-server.js.map +1 -1
  61. package/dist/core/http/index.d.ts +3 -3
  62. package/dist/core/http/router.d.ts +1 -1
  63. package/dist/core/http/router.js +15 -17
  64. package/dist/core/http/router.js.map +1 -1
  65. package/dist/core/logger/filters.d.ts +1 -1
  66. package/dist/core/logger/filters.js +16 -16
  67. package/dist/core/logger/filters.js.map +1 -1
  68. package/dist/core/logger/index.d.ts +3 -3
  69. package/dist/core/logger/logger.d.ts +1 -1
  70. package/dist/core/logger/logger.js +48 -59
  71. package/dist/core/logger/logger.js.map +1 -1
  72. package/dist/core/logger/outputs.d.ts +4 -4
  73. package/dist/core/logger/outputs.js +16 -20
  74. package/dist/core/logger/outputs.js.map +1 -1
  75. package/dist/core/middleware/built-in/adapters/cache/file.d.ts +1 -1
  76. package/dist/core/middleware/built-in/adapters/cache/file.js +19 -19
  77. package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -1
  78. package/dist/core/middleware/built-in/adapters/cache/index.d.ts +4 -4
  79. package/dist/core/middleware/built-in/adapters/cache/index.js +3 -3
  80. package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -1
  81. package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +1 -1
  82. package/dist/core/middleware/built-in/adapters/cache/memory.js +5 -5
  83. package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -1
  84. package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +1 -1
  85. package/dist/core/middleware/built-in/adapters/cache/redis.js +18 -18
  86. package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -1
  87. package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +1 -1
  88. package/dist/core/middleware/built-in/adapters/cdn/azure.js +8 -8
  89. package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -1
  90. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +1 -1
  91. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +14 -14
  92. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -1
  93. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +1 -1
  94. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +13 -15
  95. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -1
  96. package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +4 -4
  97. package/dist/core/middleware/built-in/adapters/cdn/index.js +3 -3
  98. package/dist/core/middleware/built-in/adapters/index.d.ts +4 -4
  99. package/dist/core/middleware/built-in/auth.d.ts +1 -1
  100. package/dist/core/middleware/built-in/auth.js +14 -14
  101. package/dist/core/middleware/built-in/cache.d.ts +2 -2
  102. package/dist/core/middleware/built-in/cache.js +43 -45
  103. package/dist/core/middleware/built-in/cache.js.map +1 -1
  104. package/dist/core/middleware/built-in/cdn.d.ts +2 -2
  105. package/dist/core/middleware/built-in/cdn.js +27 -29
  106. package/dist/core/middleware/built-in/cdn.js.map +1 -1
  107. package/dist/core/middleware/built-in/cookie.d.ts +2 -2
  108. package/dist/core/middleware/built-in/cookie.js +17 -17
  109. package/dist/core/middleware/built-in/cookie.js.map +1 -1
  110. package/dist/core/middleware/built-in/cors.d.ts +1 -1
  111. package/dist/core/middleware/built-in/cors.js +13 -13
  112. package/dist/core/middleware/built-in/csp.d.ts +1 -1
  113. package/dist/core/middleware/built-in/csp.js +22 -25
  114. package/dist/core/middleware/built-in/csp.js.map +1 -1
  115. package/dist/core/middleware/built-in/csrf.d.ts +1 -1
  116. package/dist/core/middleware/built-in/csrf.js +21 -24
  117. package/dist/core/middleware/built-in/csrf.js.map +1 -1
  118. package/dist/core/middleware/built-in/error-tracker.js +2 -2
  119. package/dist/core/middleware/built-in/index.d.ts +14 -14
  120. package/dist/core/middleware/built-in/performance-monitor.js +2 -2
  121. package/dist/core/middleware/built-in/rate-limit.d.ts +1 -1
  122. package/dist/core/middleware/built-in/rate-limit.js +12 -12
  123. package/dist/core/middleware/built-in/request-logger.js.map +1 -1
  124. package/dist/core/middleware/built-in/session.d.ts +5 -5
  125. package/dist/core/middleware/built-in/session.js +35 -38
  126. package/dist/core/middleware/built-in/session.js.map +1 -1
  127. package/dist/core/middleware/built-in/sse.d.ts +1 -1
  128. package/dist/core/middleware/built-in/sse.js +20 -22
  129. package/dist/core/middleware/built-in/sse.js.map +1 -1
  130. package/dist/core/middleware/built-in/validation.d.ts +1 -1
  131. package/dist/core/middleware/built-in/validation.js +13 -13
  132. package/dist/core/middleware/index.d.ts +5 -5
  133. package/dist/core/middleware/index.js +16 -16
  134. package/dist/core/middleware/index.js.map +1 -1
  135. package/dist/core/modules/auto-discovery.d.ts +2 -2
  136. package/dist/core/modules/auto-discovery.js +12 -13
  137. package/dist/core/modules/auto-discovery.js.map +1 -1
  138. package/dist/core/modules/index.d.ts +2 -2
  139. package/dist/core/modules/index.js.map +1 -1
  140. package/dist/core/modules/modules.d.ts +3 -3
  141. package/dist/core/modules/modules.js +3 -6
  142. package/dist/core/modules/modules.js.map +1 -1
  143. package/dist/core/networking/index.d.ts +2 -2
  144. package/dist/core/networking/index.js.map +1 -1
  145. package/dist/core/networking/service-discovery.d.ts +2 -2
  146. package/dist/core/networking/service-discovery.js +27 -27
  147. package/dist/core/networking/service-discovery.js.map +1 -1
  148. package/dist/core/networking/websocket-manager.d.ts +3 -3
  149. package/dist/core/networking/websocket-manager.js +15 -16
  150. package/dist/core/networking/websocket-manager.js.map +1 -1
  151. package/dist/core/routing/app-integration.d.ts +2 -2
  152. package/dist/core/routing/app-integration.js +13 -13
  153. package/dist/core/routing/app-integration.js.map +1 -1
  154. package/dist/core/routing/index.d.ts +3 -3
  155. package/dist/core/routing/index.js +43 -52
  156. package/dist/core/routing/index.js.map +1 -1
  157. package/dist/core/runtime/aws-lambda-adapter.d.ts +3 -3
  158. package/dist/core/runtime/aws-lambda-adapter.js +14 -16
  159. package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
  160. package/dist/core/runtime/base-adapter.d.ts +2 -2
  161. package/dist/core/runtime/base-adapter.js +11 -12
  162. package/dist/core/runtime/base-adapter.js.map +1 -1
  163. package/dist/core/runtime/cloudflare-workers-adapter.d.ts +3 -3
  164. package/dist/core/runtime/cloudflare-workers-adapter.js +20 -21
  165. package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
  166. package/dist/core/runtime/index.d.ts +9 -9
  167. package/dist/core/runtime/index.js +4 -4
  168. package/dist/core/runtime/index.js.map +1 -1
  169. package/dist/core/runtime/node-adapter.d.ts +5 -5
  170. package/dist/core/runtime/node-adapter.js +35 -35
  171. package/dist/core/runtime/node-adapter.js.map +1 -1
  172. package/dist/core/runtime/vercel-edge-adapter.d.ts +3 -3
  173. package/dist/core/runtime/vercel-edge-adapter.js +12 -15
  174. package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
  175. package/dist/core/utilities/circuit-breaker.js +6 -6
  176. package/dist/core/utilities/container.d.ts +1 -1
  177. package/dist/core/utilities/container.js +17 -22
  178. package/dist/core/utilities/container.js.map +1 -1
  179. package/dist/core/utilities/hooks.d.ts +3 -3
  180. package/dist/core/utilities/hooks.js +11 -11
  181. package/dist/core/utilities/hooks.js.map +1 -1
  182. package/dist/core/utilities/index.d.ts +4 -4
  183. package/dist/core/validation/index.d.ts +3 -3
  184. package/dist/core/validation/index.js +15 -15
  185. package/dist/core/validation/index.js.map +1 -1
  186. package/dist/index.d.ts +31 -30
  187. package/dist/index.js +28 -1
  188. package/dist/index.js.map +1 -1
  189. package/dist/moro.d.ts +14 -14
  190. package/dist/moro.js +79 -88
  191. package/dist/moro.js.map +1 -1
  192. package/dist/types/cache.d.ts +1 -1
  193. package/dist/types/core.d.ts +2 -2
  194. package/dist/types/events.d.ts +19 -19
  195. package/dist/types/hooks.d.ts +1 -1
  196. package/dist/types/http.d.ts +2 -2
  197. package/dist/types/logger.d.ts +3 -3
  198. package/dist/types/module.d.ts +2 -2
  199. package/dist/types/runtime.d.ts +2 -2
  200. package/dist/types/session.d.ts +4 -4
  201. package/package.json +180 -164
  202. package/src/core/config/index.ts +7 -9
  203. package/src/core/config/loader.ts +86 -158
  204. package/src/core/config/schema.ts +59 -122
  205. package/src/core/config/utils.ts +27 -45
  206. package/src/core/database/adapters/drizzle.ts +53 -75
  207. package/src/core/database/adapters/index.ts +26 -29
  208. package/src/core/database/adapters/mongodb.ts +31 -54
  209. package/src/core/database/adapters/mysql.ts +40 -50
  210. package/src/core/database/adapters/postgresql.ts +32 -42
  211. package/src/core/database/adapters/redis.ts +31 -36
  212. package/src/core/database/adapters/sqlite.ts +43 -51
  213. package/src/core/database/index.ts +2 -2
  214. package/src/core/docs/index.ts +25 -39
  215. package/src/core/docs/openapi-generator.ts +104 -117
  216. package/src/core/docs/simple-docs.ts +29 -39
  217. package/src/core/docs/swagger-ui.ts +57 -76
  218. package/src/core/docs/zod-to-openapi.ts +121 -153
  219. package/src/core/events/event-bus.ts +22 -45
  220. package/src/core/events/index.ts +2 -2
  221. package/src/core/framework.ts +119 -197
  222. package/src/core/http/http-server.ts +260 -360
  223. package/src/core/http/index.ts +3 -8
  224. package/src/core/http/router.ts +19 -31
  225. package/src/core/logger/filters.ts +19 -22
  226. package/src/core/logger/index.ts +3 -3
  227. package/src/core/logger/logger.ts +59 -100
  228. package/src/core/logger/outputs.ts +23 -27
  229. package/src/core/middleware/built-in/adapters/cache/file.ts +21 -23
  230. package/src/core/middleware/built-in/adapters/cache/index.ts +11 -14
  231. package/src/core/middleware/built-in/adapters/cache/memory.ts +7 -7
  232. package/src/core/middleware/built-in/adapters/cache/redis.ts +21 -24
  233. package/src/core/middleware/built-in/adapters/cdn/azure.ts +10 -18
  234. package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +19 -36
  235. package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +17 -26
  236. package/src/core/middleware/built-in/adapters/cdn/index.ts +10 -10
  237. package/src/core/middleware/built-in/adapters/index.ts +4 -4
  238. package/src/core/middleware/built-in/auth.ts +16 -16
  239. package/src/core/middleware/built-in/cache.ts +50 -67
  240. package/src/core/middleware/built-in/cdn.ts +34 -61
  241. package/src/core/middleware/built-in/cookie.ts +23 -28
  242. package/src/core/middleware/built-in/cors.ts +17 -17
  243. package/src/core/middleware/built-in/csp.ts +25 -31
  244. package/src/core/middleware/built-in/csrf.ts +24 -29
  245. package/src/core/middleware/built-in/error-tracker.ts +3 -3
  246. package/src/core/middleware/built-in/index.ts +28 -28
  247. package/src/core/middleware/built-in/performance-monitor.ts +4 -4
  248. package/src/core/middleware/built-in/rate-limit.ts +15 -15
  249. package/src/core/middleware/built-in/request-logger.ts +1 -3
  250. package/src/core/middleware/built-in/session.ts +47 -70
  251. package/src/core/middleware/built-in/sse.ts +23 -28
  252. package/src/core/middleware/built-in/validation.ts +15 -15
  253. package/src/core/middleware/index.ts +26 -37
  254. package/src/core/modules/auto-discovery.ts +21 -31
  255. package/src/core/modules/index.ts +2 -5
  256. package/src/core/modules/modules.ts +11 -20
  257. package/src/core/networking/index.ts +2 -6
  258. package/src/core/networking/service-discovery.ts +41 -61
  259. package/src/core/networking/websocket-manager.ts +27 -36
  260. package/src/core/routing/app-integration.ts +19 -32
  261. package/src/core/routing/index.ts +57 -88
  262. package/src/core/runtime/aws-lambda-adapter.ts +20 -30
  263. package/src/core/runtime/base-adapter.ts +17 -27
  264. package/src/core/runtime/cloudflare-workers-adapter.ts +28 -42
  265. package/src/core/runtime/index.ts +21 -33
  266. package/src/core/runtime/node-adapter.ts +59 -73
  267. package/src/core/runtime/vercel-edge-adapter.ts +18 -29
  268. package/src/core/utilities/circuit-breaker.ts +7 -7
  269. package/src/core/utilities/container.ts +52 -89
  270. package/src/core/utilities/hooks.ts +17 -23
  271. package/src/core/utilities/index.ts +4 -4
  272. package/src/core/validation/index.ts +25 -51
  273. package/src/index.ts +58 -60
  274. package/src/moro.ts +119 -191
  275. package/src/types/cache.ts +1 -1
  276. package/src/types/core.ts +2 -2
  277. package/src/types/database.ts +2 -10
  278. package/src/types/events.ts +23 -31
  279. package/src/types/hooks.ts +1 -1
  280. package/src/types/http.ts +5 -8
  281. package/src/types/logger.ts +7 -23
  282. package/src/types/module.ts +2 -2
  283. package/src/types/runtime.ts +6 -21
  284. package/src/types/session.ts +4 -4
@@ -48,7 +48,7 @@ class MoroHttpServer {
48
48
  this.globalMiddleware = [];
49
49
  this.compressionEnabled = true;
50
50
  this.compressionThreshold = 1024;
51
- this.logger = (0, logger_1.createFrameworkLogger)("HttpServer");
51
+ this.logger = (0, logger_1.createFrameworkLogger)('HttpServer');
52
52
  this.server = (0, http_1.createServer)(this.handleRequest.bind(this));
53
53
  }
54
54
  // Middleware management
@@ -57,19 +57,19 @@ class MoroHttpServer {
57
57
  }
58
58
  // Routing methods
59
59
  get(path, ...handlers) {
60
- this.addRoute("GET", path, handlers);
60
+ this.addRoute('GET', path, handlers);
61
61
  }
62
62
  post(path, ...handlers) {
63
- this.addRoute("POST", path, handlers);
63
+ this.addRoute('POST', path, handlers);
64
64
  }
65
65
  put(path, ...handlers) {
66
- this.addRoute("PUT", path, handlers);
66
+ this.addRoute('PUT', path, handlers);
67
67
  }
68
68
  delete(path, ...handlers) {
69
- this.addRoute("DELETE", path, handlers);
69
+ this.addRoute('DELETE', path, handlers);
70
70
  }
71
71
  patch(path, ...handlers) {
72
- this.addRoute("PATCH", path, handlers);
72
+ this.addRoute('PATCH', path, handlers);
73
73
  }
74
74
  addRoute(method, path, handlers) {
75
75
  const { pattern, paramNames } = this.pathToRegex(path);
@@ -90,9 +90,9 @@ class MoroHttpServer {
90
90
  const regexPattern = path
91
91
  .replace(/\/:([^/]+)/g, (match, paramName) => {
92
92
  paramNames.push(paramName);
93
- return "/([^/]+)";
93
+ return '/([^/]+)';
94
94
  })
95
- .replace(/\//g, "\\/");
95
+ .replace(/\//g, '\\/');
96
96
  return {
97
97
  pattern: new RegExp(`^${regexPattern}$`),
98
98
  paramNames,
@@ -107,7 +107,7 @@ class MoroHttpServer {
107
107
  httpReq.path = url.pathname;
108
108
  httpReq.query = Object.fromEntries(url.searchParams);
109
109
  // Parse body for POST/PUT/PATCH requests
110
- if (["POST", "PUT", "PATCH"].includes(req.method)) {
110
+ if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
111
111
  httpReq.body = await this.parseBody(req);
112
112
  }
113
113
  // Execute global middleware first
@@ -119,7 +119,7 @@ class MoroHttpServer {
119
119
  // Find matching route
120
120
  const route = this.findRoute(req.method, httpReq.path);
121
121
  if (!route) {
122
- httpRes.status(404).json({ success: false, error: "Not found" });
122
+ httpRes.status(404).json({ success: false, error: 'Not found' });
123
123
  return;
124
124
  }
125
125
  // Extract path parameters
@@ -136,7 +136,7 @@ class MoroHttpServer {
136
136
  await route.handler(httpReq, httpRes);
137
137
  }
138
138
  catch (error) {
139
- this.logger.error("Request error", "RequestHandler", {
139
+ this.logger.error('Request error', 'RequestHandler', {
140
140
  error: error instanceof Error ? error.message : String(error),
141
141
  requestId: httpReq.requestId,
142
142
  method: req.method,
@@ -145,7 +145,7 @@ class MoroHttpServer {
145
145
  if (!httpRes.headersSent) {
146
146
  httpRes.status(500).json({
147
147
  success: false,
148
- error: "Internal server error",
148
+ error: 'Internal server error',
149
149
  requestId: httpReq.requestId,
150
150
  });
151
151
  }
@@ -156,20 +156,20 @@ class MoroHttpServer {
156
156
  httpReq.params = {};
157
157
  httpReq.query = {};
158
158
  httpReq.body = null;
159
- httpReq.path = "";
160
- httpReq.ip = req.socket.remoteAddress || "";
159
+ httpReq.path = '';
160
+ httpReq.ip = req.socket.remoteAddress || '';
161
161
  httpReq.requestId = Math.random().toString(36).substring(7);
162
162
  httpReq.headers = req.headers;
163
163
  // Parse cookies
164
- httpReq.cookies = this.parseCookies(req.headers.cookie || "");
164
+ httpReq.cookies = this.parseCookies(req.headers.cookie || '');
165
165
  return httpReq;
166
166
  }
167
167
  parseCookies(cookieHeader) {
168
168
  const cookies = {};
169
169
  if (!cookieHeader)
170
170
  return cookies;
171
- cookieHeader.split(";").forEach((cookie) => {
172
- const [name, value] = cookie.trim().split("=");
171
+ cookieHeader.split(';').forEach(cookie => {
172
+ const [name, value] = cookie.trim().split('=');
173
173
  if (name && value) {
174
174
  cookies[name] = decodeURIComponent(value);
175
175
  }
@@ -183,27 +183,26 @@ class MoroHttpServer {
183
183
  return;
184
184
  const jsonString = JSON.stringify(data);
185
185
  const buffer = Buffer.from(jsonString);
186
- httpRes.setHeader("Content-Type", "application/json; charset=utf-8");
186
+ httpRes.setHeader('Content-Type', 'application/json; charset=utf-8');
187
187
  // Compression
188
- if (this.compressionEnabled &&
189
- buffer.length > this.compressionThreshold) {
190
- const acceptEncoding = httpRes.req.headers["accept-encoding"] || "";
191
- if (acceptEncoding.includes("gzip")) {
188
+ if (this.compressionEnabled && buffer.length > this.compressionThreshold) {
189
+ const acceptEncoding = httpRes.req.headers['accept-encoding'] || '';
190
+ if (acceptEncoding.includes('gzip')) {
192
191
  const compressed = await gzip(buffer);
193
- httpRes.setHeader("Content-Encoding", "gzip");
194
- httpRes.setHeader("Content-Length", compressed.length);
192
+ httpRes.setHeader('Content-Encoding', 'gzip');
193
+ httpRes.setHeader('Content-Length', compressed.length);
195
194
  httpRes.end(compressed);
196
195
  return;
197
196
  }
198
- else if (acceptEncoding.includes("deflate")) {
197
+ else if (acceptEncoding.includes('deflate')) {
199
198
  const compressed = await deflate(buffer);
200
- httpRes.setHeader("Content-Encoding", "deflate");
201
- httpRes.setHeader("Content-Length", compressed.length);
199
+ httpRes.setHeader('Content-Encoding', 'deflate');
200
+ httpRes.setHeader('Content-Length', compressed.length);
202
201
  httpRes.end(compressed);
203
202
  return;
204
203
  }
205
204
  }
206
- httpRes.setHeader("Content-Length", buffer.length);
205
+ httpRes.setHeader('Content-Length', buffer.length);
207
206
  httpRes.end(buffer);
208
207
  };
209
208
  httpRes.status = (code) => {
@@ -214,21 +213,21 @@ class MoroHttpServer {
214
213
  if (httpRes.headersSent)
215
214
  return;
216
215
  // Auto-detect content type if not already set
217
- if (!httpRes.getHeader("Content-Type")) {
218
- if (typeof data === "string") {
216
+ if (!httpRes.getHeader('Content-Type')) {
217
+ if (typeof data === 'string') {
219
218
  // Check if it's JSON
220
219
  try {
221
220
  JSON.parse(data);
222
- httpRes.setHeader("Content-Type", "application/json; charset=utf-8");
221
+ httpRes.setHeader('Content-Type', 'application/json; charset=utf-8');
223
222
  }
224
223
  catch {
225
224
  // Default to plain text
226
- httpRes.setHeader("Content-Type", "text/plain; charset=utf-8");
225
+ httpRes.setHeader('Content-Type', 'text/plain; charset=utf-8');
227
226
  }
228
227
  }
229
228
  else {
230
229
  // Buffer data - default to octet-stream
231
- httpRes.setHeader("Content-Type", "application/octet-stream");
230
+ httpRes.setHeader('Content-Type', 'application/octet-stream');
232
231
  }
233
232
  }
234
233
  httpRes.end(data);
@@ -241,90 +240,90 @@ class MoroHttpServer {
241
240
  if (options.expires)
242
241
  cookieString += `; Expires=${options.expires.toUTCString()}`;
243
242
  if (options.httpOnly)
244
- cookieString += "; HttpOnly";
243
+ cookieString += '; HttpOnly';
245
244
  if (options.secure)
246
- cookieString += "; Secure";
245
+ cookieString += '; Secure';
247
246
  if (options.sameSite)
248
247
  cookieString += `; SameSite=${options.sameSite}`;
249
248
  if (options.domain)
250
249
  cookieString += `; Domain=${options.domain}`;
251
250
  if (options.path)
252
251
  cookieString += `; Path=${options.path}`;
253
- const existingCookies = httpRes.getHeader("Set-Cookie") || [];
252
+ const existingCookies = httpRes.getHeader('Set-Cookie') || [];
254
253
  const cookies = Array.isArray(existingCookies)
255
254
  ? [...existingCookies]
256
255
  : [existingCookies];
257
256
  cookies.push(cookieString);
258
- httpRes.setHeader("Set-Cookie", cookies);
257
+ httpRes.setHeader('Set-Cookie', cookies);
259
258
  return httpRes;
260
259
  };
261
260
  httpRes.clearCookie = (name, options = {}) => {
262
261
  const clearOptions = { ...options, expires: new Date(0), maxAge: 0 };
263
- return httpRes.cookie(name, "", clearOptions);
262
+ return httpRes.cookie(name, '', clearOptions);
264
263
  };
265
264
  httpRes.redirect = (url, status = 302) => {
266
265
  if (httpRes.headersSent)
267
266
  return;
268
267
  httpRes.statusCode = status;
269
- httpRes.setHeader("Location", url);
268
+ httpRes.setHeader('Location', url);
270
269
  httpRes.end();
271
270
  };
272
271
  httpRes.sendFile = async (filePath) => {
273
272
  if (httpRes.headersSent)
274
273
  return;
275
274
  try {
276
- const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
277
- const path = await Promise.resolve().then(() => __importStar(require("path")));
275
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
276
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
278
277
  const extension = path.extname(filePath);
279
278
  const mime = await this.getMimeType(extension);
280
279
  const stats = await fs.stat(filePath);
281
280
  const data = await fs.readFile(filePath);
282
281
  // Add charset for text-based files
283
282
  const contentType = this.addCharsetIfNeeded(mime);
284
- httpRes.setHeader("Content-Type", contentType);
285
- httpRes.setHeader("Content-Length", stats.size);
283
+ httpRes.setHeader('Content-Type', contentType);
284
+ httpRes.setHeader('Content-Length', stats.size);
286
285
  // Add security headers for file downloads
287
- httpRes.setHeader("X-Content-Type-Options", "nosniff");
286
+ httpRes.setHeader('X-Content-Type-Options', 'nosniff');
288
287
  // Add caching headers
289
- httpRes.setHeader("Last-Modified", stats.mtime.toUTCString());
290
- httpRes.setHeader("Cache-Control", "public, max-age=31536000"); // 1 year for static files
288
+ httpRes.setHeader('Last-Modified', stats.mtime.toUTCString());
289
+ httpRes.setHeader('Cache-Control', 'public, max-age=31536000'); // 1 year for static files
291
290
  httpRes.end(data);
292
291
  }
293
292
  catch (error) {
294
- httpRes.status(404).json({ success: false, error: "File not found" });
293
+ httpRes.status(404).json({ success: false, error: 'File not found' });
295
294
  }
296
295
  };
297
296
  return httpRes;
298
297
  }
299
298
  async getMimeType(ext) {
300
299
  const mimeTypes = {
301
- ".html": "text/html",
302
- ".css": "text/css",
303
- ".js": "application/javascript",
304
- ".json": "application/json",
305
- ".png": "image/png",
306
- ".jpg": "image/jpeg",
307
- ".jpeg": "image/jpeg",
308
- ".gif": "image/gif",
309
- ".svg": "image/svg+xml",
310
- ".ico": "image/x-icon",
311
- ".pdf": "application/pdf",
312
- ".txt": "text/plain",
313
- ".xml": "application/xml",
300
+ '.html': 'text/html',
301
+ '.css': 'text/css',
302
+ '.js': 'application/javascript',
303
+ '.json': 'application/json',
304
+ '.png': 'image/png',
305
+ '.jpg': 'image/jpeg',
306
+ '.jpeg': 'image/jpeg',
307
+ '.gif': 'image/gif',
308
+ '.svg': 'image/svg+xml',
309
+ '.ico': 'image/x-icon',
310
+ '.pdf': 'application/pdf',
311
+ '.txt': 'text/plain',
312
+ '.xml': 'application/xml',
314
313
  };
315
- return mimeTypes[ext.toLowerCase()] || "application/octet-stream";
314
+ return mimeTypes[ext.toLowerCase()] || 'application/octet-stream';
316
315
  }
317
316
  addCharsetIfNeeded(mimeType) {
318
317
  // Add charset for text-based content types
319
318
  const textTypes = [
320
- "text/",
321
- "application/json",
322
- "application/javascript",
323
- "application/xml",
324
- "image/svg+xml",
319
+ 'text/',
320
+ 'application/json',
321
+ 'application/javascript',
322
+ 'application/xml',
323
+ 'image/svg+xml',
325
324
  ];
326
- const needsCharset = textTypes.some((type) => mimeType.startsWith(type));
327
- if (needsCharset && !mimeType.includes("charset")) {
325
+ const needsCharset = textTypes.some(type => mimeType.startsWith(type));
326
+ if (needsCharset && !mimeType.includes('charset')) {
328
327
  return `${mimeType}; charset=utf-8`;
329
328
  }
330
329
  return mimeType;
@@ -334,25 +333,25 @@ class MoroHttpServer {
334
333
  const chunks = [];
335
334
  let totalLength = 0;
336
335
  const maxSize = 10 * 1024 * 1024; // 10MB limit
337
- req.on("data", (chunk) => {
336
+ req.on('data', (chunk) => {
338
337
  totalLength += chunk.length;
339
338
  if (totalLength > maxSize) {
340
- reject(new Error("Request body too large"));
339
+ reject(new Error('Request body too large'));
341
340
  return;
342
341
  }
343
342
  chunks.push(chunk);
344
343
  });
345
- req.on("end", () => {
344
+ req.on('end', () => {
346
345
  try {
347
346
  const body = Buffer.concat(chunks);
348
- const contentType = req.headers["content-type"] || "";
349
- if (contentType.includes("application/json")) {
347
+ const contentType = req.headers['content-type'] || '';
348
+ if (contentType.includes('application/json')) {
350
349
  resolve(JSON.parse(body.toString()));
351
350
  }
352
- else if (contentType.includes("application/x-www-form-urlencoded")) {
351
+ else if (contentType.includes('application/x-www-form-urlencoded')) {
353
352
  resolve(this.parseUrlEncoded(body.toString()));
354
353
  }
355
- else if (contentType.includes("multipart/form-data")) {
354
+ else if (contentType.includes('multipart/form-data')) {
356
355
  resolve(this.parseMultipart(body, contentType));
357
356
  }
358
357
  else {
@@ -363,20 +362,20 @@ class MoroHttpServer {
363
362
  reject(error);
364
363
  }
365
364
  });
366
- req.on("error", reject);
365
+ req.on('error', reject);
367
366
  });
368
367
  }
369
368
  parseMultipart(buffer, contentType) {
370
- const boundary = contentType.split("boundary=")[1];
369
+ const boundary = contentType.split('boundary=')[1];
371
370
  if (!boundary) {
372
- throw new Error("Invalid multipart boundary");
371
+ throw new Error('Invalid multipart boundary');
373
372
  }
374
- const parts = buffer.toString("binary").split("--" + boundary);
373
+ const parts = buffer.toString('binary').split('--' + boundary);
375
374
  const fields = {};
376
375
  const files = {};
377
376
  for (let i = 1; i < parts.length - 1; i++) {
378
377
  const part = parts[i];
379
- const [headers, content] = part.split("\r\n\r\n");
378
+ const [headers, content] = part.split('\r\n\r\n');
380
379
  if (!headers || content === undefined)
381
380
  continue;
382
381
  const nameMatch = headers.match(/name="([^"]+)"/);
@@ -387,15 +386,13 @@ class MoroHttpServer {
387
386
  if (filenameMatch) {
388
387
  // This is a file
389
388
  const filename = filenameMatch[1];
390
- const mimeType = contentTypeMatch
391
- ? contentTypeMatch[1]
392
- : "application/octet-stream";
389
+ const mimeType = contentTypeMatch ? contentTypeMatch[1] : 'application/octet-stream';
393
390
  const fileContent = content.substring(0, content.length - 2); // Remove trailing \r\n
394
391
  files[name] = {
395
392
  filename,
396
393
  mimetype: mimeType,
397
- data: Buffer.from(fileContent, "binary"),
398
- size: Buffer.byteLength(fileContent, "binary"),
394
+ data: Buffer.from(fileContent, 'binary'),
395
+ size: Buffer.byteLength(fileContent, 'binary'),
399
396
  };
400
397
  }
401
398
  else {
@@ -415,7 +412,7 @@ class MoroHttpServer {
415
412
  return result;
416
413
  }
417
414
  findRoute(method, path) {
418
- return (this.routes.find((route) => route.method === method && route.pattern.test(path)) || null);
415
+ return this.routes.find(route => route.method === method && route.pattern.test(path)) || null;
419
416
  }
420
417
  async executeMiddleware(middleware, req, res) {
421
418
  for (const mw of middleware) {
@@ -447,7 +444,7 @@ class MoroHttpServer {
447
444
  }
448
445
  listen(port, host, callback) {
449
446
  // Handle overloaded parameters (port, callback) or (port, host, callback)
450
- if (typeof host === "function") {
447
+ if (typeof host === 'function') {
451
448
  callback = host;
452
449
  host = undefined;
453
450
  }
@@ -459,7 +456,7 @@ class MoroHttpServer {
459
456
  }
460
457
  }
461
458
  close() {
462
- return new Promise((resolve) => {
459
+ return new Promise(resolve => {
463
460
  this.server.close(() => resolve());
464
461
  });
465
462
  }
@@ -472,14 +469,14 @@ exports.MoroHttpServer = MoroHttpServer;
472
469
  exports.middleware = {
473
470
  cors: (options = {}) => {
474
471
  return (req, res, next) => {
475
- res.setHeader("Access-Control-Allow-Origin", options.origin || "*");
476
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
477
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
472
+ res.setHeader('Access-Control-Allow-Origin', options.origin || '*');
473
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
474
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
478
475
  if (options.credentials) {
479
- res.setHeader("Access-Control-Allow-Credentials", "true");
476
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
480
477
  }
481
- if (req.method === "OPTIONS") {
482
- res.status(200).send("");
478
+ if (req.method === 'OPTIONS') {
479
+ res.status(200).send('');
483
480
  return;
484
481
  }
485
482
  next();
@@ -487,21 +484,21 @@ exports.middleware = {
487
484
  },
488
485
  helmet: () => {
489
486
  return (req, res, next) => {
490
- res.setHeader("X-Content-Type-Options", "nosniff");
491
- res.setHeader("X-Frame-Options", "DENY");
492
- res.setHeader("X-XSS-Protection", "1; mode=block");
493
- res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
494
- res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
495
- res.setHeader("Content-Security-Policy", "default-src 'self'");
487
+ res.setHeader('X-Content-Type-Options', 'nosniff');
488
+ res.setHeader('X-Frame-Options', 'DENY');
489
+ res.setHeader('X-XSS-Protection', '1; mode=block');
490
+ res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
491
+ res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
492
+ res.setHeader('Content-Security-Policy', "default-src 'self'");
496
493
  next();
497
494
  };
498
495
  },
499
496
  compression: (options = {}) => {
500
- const zlib = require("zlib");
497
+ const zlib = require('zlib');
501
498
  const threshold = options.threshold || 1024;
502
499
  const level = options.level || 6;
503
500
  return (req, res, next) => {
504
- const acceptEncoding = req.headers["accept-encoding"] || "";
501
+ const acceptEncoding = req.headers['accept-encoding'] || '';
505
502
  // Override res.json to compress responses
506
503
  const originalJson = res.json;
507
504
  const originalSend = res.send;
@@ -509,45 +506,37 @@ exports.middleware = {
509
506
  const content = isJson ? JSON.stringify(data) : data;
510
507
  const buffer = Buffer.from(content);
511
508
  if (buffer.length < threshold) {
512
- return isJson
513
- ? originalJson.call(res, data)
514
- : originalSend.call(res, data);
509
+ return isJson ? originalJson.call(res, data) : originalSend.call(res, data);
515
510
  }
516
- if (acceptEncoding.includes("gzip")) {
517
- res.setHeader("Content-Encoding", "gzip");
511
+ if (acceptEncoding.includes('gzip')) {
512
+ res.setHeader('Content-Encoding', 'gzip');
518
513
  zlib.gzip(buffer, { level }, (err, compressed) => {
519
514
  if (err) {
520
- return isJson
521
- ? originalJson.call(res, data)
522
- : originalSend.call(res, data);
515
+ return isJson ? originalJson.call(res, data) : originalSend.call(res, data);
523
516
  }
524
- res.setHeader("Content-Length", compressed.length);
517
+ res.setHeader('Content-Length', compressed.length);
525
518
  res.writeHead(res.statusCode || 200, res.getHeaders());
526
519
  res.end(compressed);
527
520
  });
528
521
  }
529
- else if (acceptEncoding.includes("deflate")) {
530
- res.setHeader("Content-Encoding", "deflate");
522
+ else if (acceptEncoding.includes('deflate')) {
523
+ res.setHeader('Content-Encoding', 'deflate');
531
524
  zlib.deflate(buffer, { level }, (err, compressed) => {
532
525
  if (err) {
533
- return isJson
534
- ? originalJson.call(res, data)
535
- : originalSend.call(res, data);
526
+ return isJson ? originalJson.call(res, data) : originalSend.call(res, data);
536
527
  }
537
- res.setHeader("Content-Length", compressed.length);
528
+ res.setHeader('Content-Length', compressed.length);
538
529
  res.writeHead(res.statusCode || 200, res.getHeaders());
539
530
  res.end(compressed);
540
531
  });
541
532
  }
542
533
  else {
543
- return isJson
544
- ? originalJson.call(res, data)
545
- : originalSend.call(res, data);
534
+ return isJson ? originalJson.call(res, data) : originalSend.call(res, data);
546
535
  }
547
536
  };
548
537
  res.json = function (data) {
549
538
  // Ensure charset is set for Safari compatibility
550
- this.setHeader("Content-Type", "application/json; charset=utf-8");
539
+ this.setHeader('Content-Type', 'application/json; charset=utf-8');
551
540
  compressResponse(data, true);
552
541
  return this;
553
542
  };
@@ -561,7 +550,7 @@ exports.middleware = {
561
550
  requestLogger: () => {
562
551
  return (req, res, next) => {
563
552
  const start = Date.now();
564
- res.on("finish", () => {
553
+ res.on('finish', () => {
565
554
  const duration = Date.now() - start;
566
555
  // Request completed - logged by framework
567
556
  });
@@ -569,14 +558,14 @@ exports.middleware = {
569
558
  };
570
559
  },
571
560
  bodySize: (options = {}) => {
572
- const limit = options.limit || "10mb";
561
+ const limit = options.limit || '10mb';
573
562
  const limitBytes = parseSize(limit);
574
563
  return (req, res, next) => {
575
- const contentLength = parseInt(req.headers["content-length"] || "0");
564
+ const contentLength = parseInt(req.headers['content-length'] || '0');
576
565
  if (contentLength > limitBytes) {
577
566
  res.status(413).json({
578
567
  success: false,
579
- error: "Request entity too large",
568
+ error: 'Request entity too large',
580
569
  limit: limit,
581
570
  });
582
571
  return;
@@ -587,28 +576,28 @@ exports.middleware = {
587
576
  static: (options) => {
588
577
  return async (req, res, next) => {
589
578
  // Only handle GET and HEAD requests
590
- if (req.method !== "GET" && req.method !== "HEAD") {
579
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
591
580
  next();
592
581
  return;
593
582
  }
594
583
  try {
595
- const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
596
- const path = await Promise.resolve().then(() => __importStar(require("path")));
597
- const crypto = await Promise.resolve().then(() => __importStar(require("crypto")));
584
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
585
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
586
+ const crypto = await Promise.resolve().then(() => __importStar(require('crypto')));
598
587
  let filePath = path.join(options.root, req.path);
599
588
  // Security: prevent directory traversal
600
589
  if (!filePath.startsWith(path.resolve(options.root))) {
601
- res.status(403).json({ success: false, error: "Forbidden" });
590
+ res.status(403).json({ success: false, error: 'Forbidden' });
602
591
  return;
603
592
  }
604
593
  // Handle dotfiles
605
594
  const basename = path.basename(filePath);
606
- if (basename.startsWith(".")) {
607
- if (options.dotfiles === "deny") {
608
- res.status(403).json({ success: false, error: "Forbidden" });
595
+ if (basename.startsWith('.')) {
596
+ if (options.dotfiles === 'deny') {
597
+ res.status(403).json({ success: false, error: 'Forbidden' });
609
598
  return;
610
599
  }
611
- else if (options.dotfiles === "ignore") {
600
+ else if (options.dotfiles === 'ignore') {
612
601
  next();
613
602
  return;
614
603
  }
@@ -623,7 +612,7 @@ exports.middleware = {
623
612
  }
624
613
  // Handle directories
625
614
  if (stats.isDirectory()) {
626
- const indexFiles = options.index || ["index.html", "index.htm"];
615
+ const indexFiles = options.index || ['index.html', 'index.htm'];
627
616
  let indexFound = false;
628
617
  for (const indexFile of indexFiles) {
629
618
  const indexPath = path.join(filePath, indexFile);
@@ -648,48 +637,46 @@ exports.middleware = {
648
637
  // Set headers with proper mime type and charset
649
638
  const ext = path.extname(filePath);
650
639
  const mimeTypes = {
651
- ".html": "text/html",
652
- ".css": "text/css",
653
- ".js": "application/javascript",
654
- ".json": "application/json",
655
- ".png": "image/png",
656
- ".jpg": "image/jpeg",
657
- ".jpeg": "image/jpeg",
658
- ".gif": "image/gif",
659
- ".svg": "image/svg+xml",
660
- ".ico": "image/x-icon",
661
- ".pdf": "application/pdf",
662
- ".txt": "text/plain",
663
- ".xml": "application/xml",
640
+ '.html': 'text/html',
641
+ '.css': 'text/css',
642
+ '.js': 'application/javascript',
643
+ '.json': 'application/json',
644
+ '.png': 'image/png',
645
+ '.jpg': 'image/jpeg',
646
+ '.jpeg': 'image/jpeg',
647
+ '.gif': 'image/gif',
648
+ '.svg': 'image/svg+xml',
649
+ '.ico': 'image/x-icon',
650
+ '.pdf': 'application/pdf',
651
+ '.txt': 'text/plain',
652
+ '.xml': 'application/xml',
664
653
  };
665
- const baseMimeType = mimeTypes[ext.toLowerCase()] || "application/octet-stream";
654
+ const baseMimeType = mimeTypes[ext.toLowerCase()] || 'application/octet-stream';
666
655
  // Add charset for text-based files
667
656
  const textTypes = [
668
- "text/",
669
- "application/json",
670
- "application/javascript",
671
- "application/xml",
672
- "image/svg+xml",
657
+ 'text/',
658
+ 'application/json',
659
+ 'application/javascript',
660
+ 'application/xml',
661
+ 'image/svg+xml',
673
662
  ];
674
- const needsCharset = textTypes.some((type) => baseMimeType.startsWith(type));
675
- const contentType = needsCharset
676
- ? `${baseMimeType}; charset=utf-8`
677
- : baseMimeType;
678
- res.setHeader("Content-Type", contentType);
679
- res.setHeader("Content-Length", stats.size);
663
+ const needsCharset = textTypes.some(type => baseMimeType.startsWith(type));
664
+ const contentType = needsCharset ? `${baseMimeType}; charset=utf-8` : baseMimeType;
665
+ res.setHeader('Content-Type', contentType);
666
+ res.setHeader('Content-Length', stats.size);
680
667
  // Cache headers
681
668
  if (options.maxAge) {
682
- res.setHeader("Cache-Control", `public, max-age=${options.maxAge}`);
669
+ res.setHeader('Cache-Control', `public, max-age=${options.maxAge}`);
683
670
  }
684
671
  // ETag support
685
672
  if (options.etag !== false) {
686
673
  const etag = crypto
687
- .createHash("md5")
674
+ .createHash('md5')
688
675
  .update(`${stats.mtime.getTime()}-${stats.size}`)
689
- .digest("hex");
690
- res.setHeader("ETag", `"${etag}"`);
676
+ .digest('hex');
677
+ res.setHeader('ETag', `"${etag}"`);
691
678
  // Handle conditional requests
692
- const ifNoneMatch = req.headers["if-none-match"];
679
+ const ifNoneMatch = req.headers['if-none-match'];
693
680
  if (ifNoneMatch === `"${etag}"`) {
694
681
  res.statusCode = 304;
695
682
  res.end();
@@ -697,7 +684,7 @@ exports.middleware = {
697
684
  }
698
685
  }
699
686
  // Handle HEAD requests
700
- if (req.method === "HEAD") {
687
+ if (req.method === 'HEAD') {
701
688
  res.end();
702
689
  return;
703
690
  }
@@ -706,16 +693,14 @@ exports.middleware = {
706
693
  res.end(data);
707
694
  }
708
695
  catch (error) {
709
- res
710
- .status(500)
711
- .json({ success: false, error: "Internal server error" });
696
+ res.status(500).json({ success: false, error: 'Internal server error' });
712
697
  }
713
698
  };
714
699
  },
715
700
  upload: (options = {}) => {
716
701
  return (req, res, next) => {
717
- const contentType = req.headers["content-type"] || "";
718
- if (!contentType.includes("multipart/form-data")) {
702
+ const contentType = req.headers['content-type'] || '';
703
+ if (!contentType.includes('multipart/form-data')) {
719
704
  next();
720
705
  return;
721
706
  }
@@ -766,8 +751,8 @@ exports.middleware = {
766
751
  // Add render method to response
767
752
  res.render = async (template, data = {}) => {
768
753
  try {
769
- const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
770
- const path = await Promise.resolve().then(() => __importStar(require("path")));
754
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
755
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
771
756
  const templatePath = path.join(options.views, `${template}.html`);
772
757
  let templateContent;
773
758
  // Check cache first
@@ -775,7 +760,7 @@ exports.middleware = {
775
760
  templateContent = templateCache.get(templatePath);
776
761
  }
777
762
  else {
778
- templateContent = await fs.readFile(templatePath, "utf-8");
763
+ templateContent = await fs.readFile(templatePath, 'utf-8');
779
764
  if (options.cache) {
780
765
  templateCache.set(templatePath, templateContent);
781
766
  }
@@ -788,44 +773,40 @@ exports.middleware = {
788
773
  });
789
774
  // Handle nested object properties like {{user.name}}
790
775
  rendered = rendered.replace(/\{\{([\w.]+)\}\}/g, (match, key) => {
791
- const value = key
792
- .split(".")
793
- .reduce((obj, prop) => obj?.[prop], data);
776
+ const value = key.split('.').reduce((obj, prop) => obj?.[prop], data);
794
777
  return value !== undefined ? String(value) : match;
795
778
  });
796
779
  // Handle loops: {{#each items}}{{name}}{{/each}}
797
780
  rendered = rendered.replace(/\{\{#each (\w+)\}\}(.*?)\{\{\/each\}\}/gs, (match, arrayKey, template) => {
798
781
  const array = data[arrayKey];
799
782
  if (!Array.isArray(array))
800
- return "";
783
+ return '';
801
784
  return array
802
- .map((item) => {
785
+ .map(item => {
803
786
  let itemTemplate = template;
804
787
  // Replace variables in the loop template
805
788
  itemTemplate = itemTemplate.replace(/\{\{(\w+)\}\}/g, (match, key) => {
806
- return item[key] !== undefined
807
- ? String(item[key])
808
- : match;
789
+ return item[key] !== undefined ? String(item[key]) : match;
809
790
  });
810
791
  return itemTemplate;
811
792
  })
812
- .join("");
793
+ .join('');
813
794
  });
814
795
  // Handle conditionals: {{#if condition}}content{{/if}}
815
796
  rendered = rendered.replace(/\{\{#if (\w+)\}\}(.*?)\{\{\/if\}\}/gs, (match, conditionKey, content) => {
816
797
  const condition = data[conditionKey];
817
- return condition ? content : "";
798
+ return condition ? content : '';
818
799
  });
819
800
  // Handle layout
820
801
  if (options.defaultLayout) {
821
- const layoutPath = path.join(options.views, "layouts", `${options.defaultLayout}.html`);
802
+ const layoutPath = path.join(options.views, 'layouts', `${options.defaultLayout}.html`);
822
803
  try {
823
804
  let layoutContent;
824
805
  if (options.cache && templateCache.has(layoutPath)) {
825
806
  layoutContent = templateCache.get(layoutPath);
826
807
  }
827
808
  else {
828
- layoutContent = await fs.readFile(layoutPath, "utf-8");
809
+ layoutContent = await fs.readFile(layoutPath, 'utf-8');
829
810
  if (options.cache) {
830
811
  templateCache.set(layoutPath, layoutContent);
831
812
  }
@@ -836,13 +817,11 @@ exports.middleware = {
836
817
  // Layout not found, use template as-is
837
818
  }
838
819
  }
839
- res.setHeader("Content-Type", "text/html");
820
+ res.setHeader('Content-Type', 'text/html');
840
821
  res.end(rendered);
841
822
  }
842
823
  catch (error) {
843
- res
844
- .status(500)
845
- .json({ success: false, error: "Template rendering failed" });
824
+ res.status(500).json({ success: false, error: 'Template rendering failed' });
846
825
  }
847
826
  };
848
827
  next();
@@ -854,13 +833,11 @@ exports.middleware = {
854
833
  // Add HTTP/2 push capability to response
855
834
  res.push = (path, options = {}) => {
856
835
  // Check if HTTP/2 is supported
857
- if (req.httpVersion === "2.0" &&
858
- res.stream &&
859
- res.stream.pushAllowed) {
836
+ if (req.httpVersion === '2.0' && res.stream && res.stream.pushAllowed) {
860
837
  try {
861
838
  const pushStream = res.stream.pushStream({
862
- ":method": "GET",
863
- ":path": path,
839
+ ':method': 'GET',
840
+ ':path': path,
864
841
  ...options.headers,
865
842
  });
866
843
  if (pushStream) {
@@ -879,7 +856,7 @@ exports.middleware = {
879
856
  for (const resource of options.resources) {
880
857
  res.push?.(resource.path, {
881
858
  headers: {
882
- "content-type": resource.type || "text/plain",
859
+ 'content-type': resource.type || 'text/plain',
883
860
  },
884
861
  });
885
862
  }
@@ -891,16 +868,14 @@ exports.middleware = {
891
868
  sse: (options = {}) => {
892
869
  return (req, res, next) => {
893
870
  // Only handle SSE requests
894
- if (req.headers.accept?.includes("text/event-stream")) {
871
+ if (req.headers.accept?.includes('text/event-stream')) {
895
872
  // Set SSE headers
896
873
  res.writeHead(200, {
897
- "Content-Type": "text/event-stream",
898
- "Cache-Control": "no-cache",
899
- Connection: "keep-alive",
900
- "Access-Control-Allow-Origin": options.cors ? "*" : undefined,
901
- "Access-Control-Allow-Headers": options.cors
902
- ? "Cache-Control"
903
- : undefined,
874
+ 'Content-Type': 'text/event-stream',
875
+ 'Cache-Control': 'no-cache',
876
+ Connection: 'keep-alive',
877
+ 'Access-Control-Allow-Origin': options.cors ? '*' : undefined,
878
+ 'Access-Control-Allow-Headers': options.cors ? 'Cache-Control' : undefined,
904
879
  });
905
880
  // Add SSE methods to response
906
881
  res.sendEvent = (data, event, id) => {
@@ -908,7 +883,7 @@ exports.middleware = {
908
883
  res.write(`id: ${id}\n`);
909
884
  if (event)
910
885
  res.write(`event: ${event}\n`);
911
- res.write(`data: ${typeof data === "string" ? data : JSON.stringify(data)}\n\n`);
886
+ res.write(`data: ${typeof data === 'string' ? data : JSON.stringify(data)}\n\n`);
912
887
  };
913
888
  res.sendComment = (comment) => {
914
889
  res.write(`: ${comment}\n\n`);
@@ -920,7 +895,7 @@ exports.middleware = {
920
895
  let heartbeatInterval = null;
921
896
  if (options.heartbeat) {
922
897
  heartbeatInterval = setInterval(() => {
923
- res.sendComment("heartbeat");
898
+ res.sendComment('heartbeat');
924
899
  }, options.heartbeat);
925
900
  }
926
901
  // Set retry if configured
@@ -928,7 +903,7 @@ exports.middleware = {
928
903
  res.sendRetry(options.retry);
929
904
  }
930
905
  // Clean up on close
931
- req.on("close", () => {
906
+ req.on('close', () => {
932
907
  if (heartbeatInterval) {
933
908
  clearInterval(heartbeatInterval);
934
909
  }
@@ -945,28 +920,28 @@ exports.middleware = {
945
920
  // Add range support to response
946
921
  res.sendRange = async (filePath, stats) => {
947
922
  try {
948
- const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
949
- const path = await Promise.resolve().then(() => __importStar(require("path")));
923
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
924
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
950
925
  if (!stats) {
951
926
  stats = await fs.stat(filePath);
952
927
  }
953
928
  const fileSize = stats.size;
954
929
  const range = req.headers.range;
955
930
  // Set Accept-Ranges header
956
- res.setHeader("Accept-Ranges", options.acceptRanges || "bytes");
931
+ res.setHeader('Accept-Ranges', options.acceptRanges || 'bytes');
957
932
  if (!range) {
958
933
  // No range requested, send entire file
959
- res.setHeader("Content-Length", fileSize);
934
+ res.setHeader('Content-Length', fileSize);
960
935
  const data = await fs.readFile(filePath);
961
936
  res.end(data);
962
937
  return;
963
938
  }
964
939
  // Parse range header
965
940
  const ranges = range
966
- .replace(/bytes=/, "")
967
- .split(",")
968
- .map((r) => {
969
- const [start, end] = r.split("-");
941
+ .replace(/bytes=/, '')
942
+ .split(',')
943
+ .map(r => {
944
+ const [start, end] = r.split('-');
970
945
  return {
971
946
  start: start ? parseInt(start) : 0,
972
947
  end: end ? parseInt(end) : fileSize - 1,
@@ -974,7 +949,7 @@ exports.middleware = {
974
949
  });
975
950
  // Validate ranges
976
951
  if (options.maxRanges && ranges.length > options.maxRanges) {
977
- res.status(416).json({ success: false, error: "Too many ranges" });
952
+ res.status(416).json({ success: false, error: 'Too many ranges' });
978
953
  return;
979
954
  }
980
955
  if (ranges.length === 1) {
@@ -982,15 +957,15 @@ exports.middleware = {
982
957
  const { start, end } = ranges[0];
983
958
  const chunkSize = end - start + 1;
984
959
  if (start >= fileSize || end >= fileSize) {
985
- res.status(416).setHeader("Content-Range", `bytes */${fileSize}`);
986
- res.json({ success: false, error: "Range not satisfiable" });
960
+ res.status(416).setHeader('Content-Range', `bytes */${fileSize}`);
961
+ res.json({ success: false, error: 'Range not satisfiable' });
987
962
  return;
988
963
  }
989
964
  res.status(206);
990
- res.setHeader("Content-Range", `bytes ${start}-${end}/${fileSize}`);
991
- res.setHeader("Content-Length", chunkSize);
965
+ res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);
966
+ res.setHeader('Content-Length', chunkSize);
992
967
  // Stream the range
993
- const stream = require("fs").createReadStream(filePath, {
968
+ const stream = require('fs').createReadStream(filePath, {
994
969
  start,
995
970
  end,
996
971
  });
@@ -998,21 +973,21 @@ exports.middleware = {
998
973
  }
999
974
  else {
1000
975
  // Multiple ranges - multipart response
1001
- const boundary = "MULTIPART_BYTERANGES";
976
+ const boundary = 'MULTIPART_BYTERANGES';
1002
977
  res.status(206);
1003
- res.setHeader("Content-Type", `multipart/byteranges; boundary=${boundary}`);
978
+ res.setHeader('Content-Type', `multipart/byteranges; boundary=${boundary}`);
1004
979
  for (const { start, end } of ranges) {
1005
980
  if (start >= fileSize || end >= fileSize)
1006
981
  continue;
1007
982
  const chunkSize = end - start + 1;
1008
983
  res.write(`\r\n--${boundary}\r\n`);
1009
984
  res.write(`Content-Range: bytes ${start}-${end}/${fileSize}\r\n\r\n`);
1010
- const stream = require("fs").createReadStream(filePath, {
985
+ const stream = require('fs').createReadStream(filePath, {
1011
986
  start,
1012
987
  end,
1013
988
  });
1014
- await new Promise((resolve) => {
1015
- stream.on("end", resolve);
989
+ await new Promise(resolve => {
990
+ stream.on('end', resolve);
1016
991
  stream.pipe(res, { end: false });
1017
992
  });
1018
993
  }
@@ -1021,9 +996,7 @@ exports.middleware = {
1021
996
  }
1022
997
  }
1023
998
  catch (error) {
1024
- res
1025
- .status(500)
1026
- .json({ success: false, error: "Range request failed" });
999
+ res.status(500).json({ success: false, error: 'Range request failed' });
1027
1000
  }
1028
1001
  };
1029
1002
  next();
@@ -1031,14 +1004,14 @@ exports.middleware = {
1031
1004
  },
1032
1005
  // CSRF Protection middleware
1033
1006
  csrf: (options = {}) => {
1034
- const secret = options.secret || "moro-csrf-secret";
1007
+ const secret = options.secret || 'moro-csrf-secret';
1035
1008
  const tokenLength = options.tokenLength || 32;
1036
- const cookieName = options.cookieName || "_csrf";
1037
- const headerName = options.headerName || "x-csrf-token";
1038
- const ignoreMethods = options.ignoreMethods || ["GET", "HEAD", "OPTIONS"];
1009
+ const cookieName = options.cookieName || '_csrf';
1010
+ const headerName = options.headerName || 'x-csrf-token';
1011
+ const ignoreMethods = options.ignoreMethods || ['GET', 'HEAD', 'OPTIONS'];
1039
1012
  const generateToken = () => {
1040
- const crypto = require("crypto");
1041
- return crypto.randomBytes(tokenLength).toString("hex");
1013
+ const crypto = require('crypto');
1014
+ return crypto.randomBytes(tokenLength).toString('hex');
1042
1015
  };
1043
1016
  const verifyToken = (token, sessionToken) => {
1044
1017
  return token && sessionToken && token === sessionToken;
@@ -1051,9 +1024,8 @@ exports.middleware = {
1051
1024
  // Set token in cookie
1052
1025
  res.cookie(cookieName, req._csrfToken, {
1053
1026
  httpOnly: true,
1054
- sameSite: options.sameSite !== false ? "strict" : undefined,
1055
- secure: req.headers["x-forwarded-proto"] === "https" ||
1056
- req.socket.encrypted,
1027
+ sameSite: options.sameSite !== false ? 'strict' : undefined,
1028
+ secure: req.headers['x-forwarded-proto'] === 'https' || req.socket.encrypted,
1057
1029
  });
1058
1030
  }
1059
1031
  return req._csrfToken;
@@ -1064,16 +1036,14 @@ exports.middleware = {
1064
1036
  return;
1065
1037
  }
1066
1038
  // Get token from header or body
1067
- const token = req.headers[headerName] ||
1068
- (req.body && req.body._csrf) ||
1069
- (req.query && req.query._csrf);
1039
+ const token = req.headers[headerName] || (req.body && req.body._csrf) || (req.query && req.query._csrf);
1070
1040
  // Get session token from cookie
1071
1041
  const sessionToken = req.cookies?.[cookieName];
1072
- if (!verifyToken(token, sessionToken || "")) {
1042
+ if (!verifyToken(token, sessionToken || '')) {
1073
1043
  res.status(403).json({
1074
1044
  success: false,
1075
- error: "Invalid CSRF token",
1076
- code: "CSRF_TOKEN_MISMATCH",
1045
+ error: 'Invalid CSRF token',
1046
+ code: 'CSRF_TOKEN_MISMATCH',
1077
1047
  });
1078
1048
  return;
1079
1049
  }
@@ -1087,7 +1057,7 @@ exports.middleware = {
1087
1057
  defaultSrc: ["'self'"],
1088
1058
  scriptSrc: ["'self'"],
1089
1059
  styleSrc: ["'self'", "'unsafe-inline'"],
1090
- imgSrc: ["'self'", "data:", "https:"],
1060
+ imgSrc: ["'self'", 'data:', 'https:'],
1091
1061
  connectSrc: ["'self'"],
1092
1062
  fontSrc: ["'self'"],
1093
1063
  objectSrc: ["'none'"],
@@ -1097,30 +1067,27 @@ exports.middleware = {
1097
1067
  // Generate nonce if requested
1098
1068
  let nonce;
1099
1069
  if (options.nonce) {
1100
- const crypto = require("crypto");
1101
- nonce = crypto.randomBytes(16).toString("base64");
1070
+ const crypto = require('crypto');
1071
+ nonce = crypto.randomBytes(16).toString('base64');
1102
1072
  req.cspNonce = nonce;
1103
1073
  }
1104
1074
  // Build CSP header value
1105
1075
  const cspParts = [];
1106
1076
  for (const [directive, sources] of Object.entries(directives)) {
1107
- if (directive === "upgradeInsecureRequests" && sources === true) {
1108
- cspParts.push("upgrade-insecure-requests");
1077
+ if (directive === 'upgradeInsecureRequests' && sources === true) {
1078
+ cspParts.push('upgrade-insecure-requests');
1109
1079
  }
1110
- else if (directive === "blockAllMixedContent" && sources === true) {
1111
- cspParts.push("block-all-mixed-content");
1080
+ else if (directive === 'blockAllMixedContent' && sources === true) {
1081
+ cspParts.push('block-all-mixed-content');
1112
1082
  }
1113
1083
  else if (Array.isArray(sources)) {
1114
- let sourceList = sources.join(" ");
1084
+ let sourceList = sources.join(' ');
1115
1085
  // Add nonce to script-src and style-src if enabled
1116
- if (nonce &&
1117
- (directive === "scriptSrc" || directive === "styleSrc")) {
1086
+ if (nonce && (directive === 'scriptSrc' || directive === 'styleSrc')) {
1118
1087
  sourceList += ` 'nonce-${nonce}'`;
1119
1088
  }
1120
1089
  // Convert camelCase to kebab-case
1121
- const kebabDirective = directive
1122
- .replace(/([A-Z])/g, "-$1")
1123
- .toLowerCase();
1090
+ const kebabDirective = directive.replace(/([A-Z])/g, '-$1').toLowerCase();
1124
1091
  cspParts.push(`${kebabDirective} ${sourceList}`);
1125
1092
  }
1126
1093
  }
@@ -1128,10 +1095,10 @@ exports.middleware = {
1128
1095
  if (options.reportUri) {
1129
1096
  cspParts.push(`report-uri ${options.reportUri}`);
1130
1097
  }
1131
- const cspValue = cspParts.join("; ");
1098
+ const cspValue = cspParts.join('; ');
1132
1099
  const headerName = options.reportOnly
1133
- ? "Content-Security-Policy-Report-Only"
1134
- : "Content-Security-Policy";
1100
+ ? 'Content-Security-Policy-Report-Only'
1101
+ : 'Content-Security-Policy';
1135
1102
  res.setHeader(headerName, cspValue);
1136
1103
  next();
1137
1104
  };
@@ -1148,7 +1115,7 @@ function parseSize(size) {
1148
1115
  if (!match)
1149
1116
  return 1024 * 1024; // Default 1MB
1150
1117
  const value = parseFloat(match[1]);
1151
- const unit = match[2] || "b";
1118
+ const unit = match[2] || 'b';
1152
1119
  return Math.round(value * units[unit]);
1153
1120
  }
1154
1121
  //# sourceMappingURL=http-server.js.map