alepha 0.14.4 → 0.15.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 (322) hide show
  1. package/README.md +44 -102
  2. package/dist/api/audits/index.d.ts +331 -443
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +2 -2
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +0 -113
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +2 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +151 -262
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/notifications/index.browser.js +4 -4
  13. package/dist/api/notifications/index.browser.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +164 -276
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/notifications/index.js +4 -4
  17. package/dist/api/notifications/index.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +265 -377
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/users/index.browser.js +1 -2
  21. package/dist/api/users/index.browser.js.map +1 -1
  22. package/dist/api/users/index.d.ts +195 -301
  23. package/dist/api/users/index.d.ts.map +1 -1
  24. package/dist/api/users/index.js +203 -184
  25. package/dist/api/users/index.js.map +1 -1
  26. package/dist/api/verifications/index.d.ts.map +1 -1
  27. package/dist/batch/index.d.ts.map +1 -1
  28. package/dist/batch/index.js +1 -2
  29. package/dist/batch/index.js.map +1 -1
  30. package/dist/bucket/index.d.ts.map +1 -1
  31. package/dist/cache/core/index.d.ts.map +1 -1
  32. package/dist/cache/redis/index.d.ts.map +1 -1
  33. package/dist/cache/redis/index.js +2 -2
  34. package/dist/cache/redis/index.js.map +1 -1
  35. package/dist/cli/index.d.ts +5900 -165
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +1481 -639
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/command/index.d.ts +8 -4
  40. package/dist/command/index.d.ts.map +1 -1
  41. package/dist/command/index.js +29 -25
  42. package/dist/command/index.js.map +1 -1
  43. package/dist/core/index.browser.js +563 -54
  44. package/dist/core/index.browser.js.map +1 -1
  45. package/dist/core/index.d.ts +175 -8
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/index.js +564 -54
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/core/index.native.js +563 -54
  50. package/dist/core/index.native.js.map +1 -1
  51. package/dist/datetime/index.d.ts.map +1 -1
  52. package/dist/datetime/index.js +4 -4
  53. package/dist/datetime/index.js.map +1 -1
  54. package/dist/email/index.d.ts +89 -42
  55. package/dist/email/index.d.ts.map +1 -1
  56. package/dist/email/index.js +129 -33
  57. package/dist/email/index.js.map +1 -1
  58. package/dist/fake/index.d.ts +7969 -2
  59. package/dist/fake/index.d.ts.map +1 -1
  60. package/dist/fake/index.js +22 -22
  61. package/dist/fake/index.js.map +1 -1
  62. package/dist/file/index.d.ts +134 -1
  63. package/dist/file/index.d.ts.map +1 -1
  64. package/dist/file/index.js +253 -1
  65. package/dist/file/index.js.map +1 -1
  66. package/dist/lock/core/index.d.ts.map +1 -1
  67. package/dist/lock/redis/index.d.ts.map +1 -1
  68. package/dist/logger/index.d.ts +1 -2
  69. package/dist/logger/index.d.ts.map +1 -1
  70. package/dist/logger/index.js +1 -5
  71. package/dist/logger/index.js.map +1 -1
  72. package/dist/mcp/index.d.ts +19 -1
  73. package/dist/mcp/index.d.ts.map +1 -1
  74. package/dist/mcp/index.js +28 -4
  75. package/dist/mcp/index.js.map +1 -1
  76. package/dist/orm/chunk-DH6iiROE.js +38 -0
  77. package/dist/orm/index.browser.js +9 -9
  78. package/dist/orm/index.browser.js.map +1 -1
  79. package/dist/orm/index.bun.js +2821 -0
  80. package/dist/orm/index.bun.js.map +1 -0
  81. package/dist/orm/index.d.ts +318 -169
  82. package/dist/orm/index.d.ts.map +1 -1
  83. package/dist/orm/index.js +2086 -1776
  84. package/dist/orm/index.js.map +1 -1
  85. package/dist/queue/core/index.d.ts +4 -4
  86. package/dist/queue/core/index.d.ts.map +1 -1
  87. package/dist/queue/redis/index.d.ts.map +1 -1
  88. package/dist/redis/index.bun.js +285 -0
  89. package/dist/redis/index.bun.js.map +1 -0
  90. package/dist/redis/index.d.ts +13 -31
  91. package/dist/redis/index.d.ts.map +1 -1
  92. package/dist/redis/index.js +18 -38
  93. package/dist/redis/index.js.map +1 -1
  94. package/dist/retry/index.d.ts.map +1 -1
  95. package/dist/router/index.d.ts.map +1 -1
  96. package/dist/scheduler/index.d.ts +83 -1
  97. package/dist/scheduler/index.d.ts.map +1 -1
  98. package/dist/scheduler/index.js +393 -1
  99. package/dist/scheduler/index.js.map +1 -1
  100. package/dist/security/index.browser.js +5 -1
  101. package/dist/security/index.browser.js.map +1 -1
  102. package/dist/security/index.d.ts +598 -112
  103. package/dist/security/index.d.ts.map +1 -1
  104. package/dist/security/index.js +1808 -97
  105. package/dist/security/index.js.map +1 -1
  106. package/dist/server/auth/index.d.ts +1200 -175
  107. package/dist/server/auth/index.d.ts.map +1 -1
  108. package/dist/server/auth/index.js +1268 -37
  109. package/dist/server/auth/index.js.map +1 -1
  110. package/dist/server/cache/index.d.ts +6 -3
  111. package/dist/server/cache/index.d.ts.map +1 -1
  112. package/dist/server/cache/index.js +1 -1
  113. package/dist/server/cache/index.js.map +1 -1
  114. package/dist/server/compress/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.d.ts.map +1 -1
  116. package/dist/server/cookies/index.js +3 -3
  117. package/dist/server/cookies/index.js.map +1 -1
  118. package/dist/server/core/index.d.ts +115 -13
  119. package/dist/server/core/index.d.ts.map +1 -1
  120. package/dist/server/core/index.js +321 -139
  121. package/dist/server/core/index.js.map +1 -1
  122. package/dist/server/cors/index.d.ts +0 -1
  123. package/dist/server/cors/index.d.ts.map +1 -1
  124. package/dist/server/health/index.d.ts +0 -1
  125. package/dist/server/health/index.d.ts.map +1 -1
  126. package/dist/server/helmet/index.d.ts.map +1 -1
  127. package/dist/server/links/index.browser.js +9 -1
  128. package/dist/server/links/index.browser.js.map +1 -1
  129. package/dist/server/links/index.d.ts +1 -2
  130. package/dist/server/links/index.d.ts.map +1 -1
  131. package/dist/server/links/index.js +14 -7
  132. package/dist/server/links/index.js.map +1 -1
  133. package/dist/server/metrics/index.d.ts +514 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/metrics/index.js +4462 -4
  136. package/dist/server/metrics/index.js.map +1 -1
  137. package/dist/server/multipart/index.d.ts.map +1 -1
  138. package/dist/server/proxy/index.d.ts +0 -1
  139. package/dist/server/proxy/index.d.ts.map +1 -1
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts.map +1 -1
  142. package/dist/server/swagger/index.d.ts +1 -2
  143. package/dist/server/swagger/index.d.ts.map +1 -1
  144. package/dist/server/swagger/index.js +1 -2
  145. package/dist/server/swagger/index.js.map +1 -1
  146. package/dist/sms/index.d.ts +3 -1
  147. package/dist/sms/index.d.ts.map +1 -1
  148. package/dist/sms/index.js +10 -10
  149. package/dist/sms/index.js.map +1 -1
  150. package/dist/thread/index.d.ts +0 -1
  151. package/dist/thread/index.d.ts.map +1 -1
  152. package/dist/thread/index.js +2 -2
  153. package/dist/thread/index.js.map +1 -1
  154. package/dist/topic/core/index.d.ts.map +1 -1
  155. package/dist/topic/redis/index.d.ts.map +1 -1
  156. package/dist/vite/index.d.ts +6315 -149
  157. package/dist/vite/index.d.ts.map +1 -1
  158. package/dist/vite/index.js +140 -469
  159. package/dist/vite/index.js.map +1 -1
  160. package/dist/websocket/index.browser.js +9 -9
  161. package/dist/websocket/index.browser.js.map +1 -1
  162. package/dist/websocket/index.d.ts +28 -28
  163. package/dist/websocket/index.d.ts.map +1 -1
  164. package/dist/websocket/index.js +9 -9
  165. package/dist/websocket/index.js.map +1 -1
  166. package/package.json +13 -18
  167. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  168. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  169. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  170. package/src/api/users/entities/users.ts +1 -1
  171. package/src/api/users/index.ts +8 -8
  172. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  173. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  174. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  175. package/src/api/users/services/CredentialService.ts +7 -7
  176. package/src/api/users/services/IdentityService.ts +4 -4
  177. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  178. package/src/api/users/services/RegistrationService.ts +38 -27
  179. package/src/api/users/services/SessionCrudService.ts +3 -3
  180. package/src/api/users/services/SessionService.spec.ts +3 -3
  181. package/src/api/users/services/SessionService.ts +27 -18
  182. package/src/api/users/services/UserService.ts +7 -7
  183. package/src/batch/providers/BatchProvider.ts +1 -2
  184. package/src/cli/apps/AlephaCli.ts +2 -2
  185. package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
  186. package/src/cli/assets/apiHelloControllerTs.ts +19 -0
  187. package/src/cli/assets/apiIndexTs.ts +16 -0
  188. package/src/cli/assets/biomeJson.ts +2 -1
  189. package/src/cli/assets/claudeMd.ts +308 -0
  190. package/src/cli/assets/dummySpecTs.ts +2 -1
  191. package/src/cli/assets/editorconfig.ts +2 -1
  192. package/src/cli/assets/mainBrowserTs.ts +4 -3
  193. package/src/cli/assets/mainCss.ts +24 -0
  194. package/src/cli/assets/mainServerTs.ts +24 -0
  195. package/src/cli/assets/tsconfigJson.ts +2 -1
  196. package/src/cli/assets/webAppRouterTs.ts +16 -0
  197. package/src/cli/assets/webHelloComponentTsx.ts +20 -0
  198. package/src/cli/assets/webIndexTs.ts +16 -0
  199. package/src/cli/atoms/appEntryOptions.ts +13 -0
  200. package/src/cli/atoms/buildOptions.ts +1 -1
  201. package/src/cli/atoms/changelogOptions.ts +1 -1
  202. package/src/cli/commands/build.ts +97 -61
  203. package/src/cli/commands/db.ts +21 -18
  204. package/src/cli/commands/deploy.ts +17 -5
  205. package/src/cli/commands/dev.ts +26 -47
  206. package/src/cli/commands/gen/env.ts +1 -1
  207. package/src/cli/commands/init.ts +79 -25
  208. package/src/cli/commands/lint.ts +9 -3
  209. package/src/cli/commands/test.ts +8 -2
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +4 -2
  212. package/src/cli/defineConfig.ts +9 -0
  213. package/src/cli/index.ts +2 -1
  214. package/src/cli/providers/AppEntryProvider.ts +131 -0
  215. package/src/cli/providers/ViteBuildProvider.ts +82 -0
  216. package/src/cli/providers/ViteDevServerProvider.ts +350 -0
  217. package/src/cli/providers/ViteTemplateProvider.ts +27 -0
  218. package/src/cli/services/AlephaCliUtils.ts +72 -602
  219. package/src/cli/services/PackageManagerUtils.ts +308 -0
  220. package/src/cli/services/ProjectScaffolder.ts +329 -0
  221. package/src/command/helpers/Runner.ts +15 -3
  222. package/src/core/Alepha.ts +2 -8
  223. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  224. package/src/core/index.shared.ts +1 -0
  225. package/src/core/index.ts +2 -0
  226. package/src/core/primitives/$hook.ts +6 -2
  227. package/src/core/primitives/$module.spec.ts +4 -0
  228. package/src/core/primitives/$module.ts +12 -0
  229. package/src/core/providers/AlsProvider.ts +1 -1
  230. package/src/core/providers/CodecManager.spec.ts +12 -6
  231. package/src/core/providers/CodecManager.ts +26 -6
  232. package/src/core/providers/EventManager.ts +169 -13
  233. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
  234. package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
  235. package/src/core/providers/SchemaValidator.spec.ts +236 -0
  236. package/src/core/providers/StateManager.spec.ts +27 -16
  237. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  238. package/src/email/providers/LocalEmailProvider.ts +52 -15
  239. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  240. package/src/file/errors/FileError.ts +7 -0
  241. package/src/file/index.ts +9 -1
  242. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  243. package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
  244. package/src/mcp/errors/McpError.ts +30 -0
  245. package/src/mcp/index.ts +3 -0
  246. package/src/mcp/transports/SseMcpTransport.ts +16 -6
  247. package/src/orm/index.browser.ts +1 -19
  248. package/src/orm/index.bun.ts +77 -0
  249. package/src/orm/index.shared-server.ts +22 -0
  250. package/src/orm/index.shared.ts +15 -0
  251. package/src/orm/index.ts +19 -39
  252. package/src/orm/providers/DrizzleKitProvider.ts +3 -5
  253. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  254. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  255. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  256. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  257. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  258. package/src/orm/services/Repository.ts +19 -0
  259. package/src/redis/index.bun.ts +35 -0
  260. package/src/redis/providers/BunRedisProvider.ts +12 -43
  261. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  262. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  263. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  264. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  265. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  266. package/src/security/index.browser.ts +5 -0
  267. package/src/security/index.ts +90 -7
  268. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  269. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  270. package/src/security/primitives/$role.ts +5 -5
  271. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  272. package/src/security/primitives/$serviceAccount.ts +3 -3
  273. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  274. package/src/server/auth/primitives/$auth.ts +10 -10
  275. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  276. package/src/server/auth/primitives/$authGithub.ts +3 -3
  277. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  278. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  279. package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
  280. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  281. package/src/server/core/index.ts +1 -1
  282. package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
  283. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
  284. package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
  285. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  286. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  287. package/src/server/core/providers/ServerProvider.ts +144 -24
  288. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  289. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  290. package/src/server/links/atoms/apiLinksAtom.ts +7 -0
  291. package/src/server/links/index.browser.ts +2 -0
  292. package/src/server/links/index.ts +3 -1
  293. package/src/server/links/providers/LinkProvider.ts +1 -1
  294. package/src/server/swagger/index.ts +1 -1
  295. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  296. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  297. package/src/vite/index.ts +3 -2
  298. package/src/vite/tasks/buildClient.ts +0 -1
  299. package/src/vite/tasks/buildServer.ts +80 -22
  300. package/src/vite/tasks/copyAssets.ts +5 -4
  301. package/src/vite/tasks/generateCloudflare.ts +7 -0
  302. package/src/vite/tasks/generateSitemap.ts +64 -23
  303. package/src/vite/tasks/index.ts +0 -2
  304. package/src/vite/tasks/prerenderPages.ts +49 -24
  305. package/dist/server/security/index.browser.js +0 -13
  306. package/dist/server/security/index.browser.js.map +0 -1
  307. package/dist/server/security/index.d.ts +0 -173
  308. package/dist/server/security/index.d.ts.map +0 -1
  309. package/dist/server/security/index.js +0 -311
  310. package/dist/server/security/index.js.map +0 -1
  311. package/src/cli/assets/appRouterTs.ts +0 -9
  312. package/src/cli/assets/indexHtml.ts +0 -15
  313. package/src/cli/assets/mainTs.ts +0 -13
  314. package/src/cli/commands/format.ts +0 -17
  315. package/src/server/security/index.browser.ts +0 -10
  316. package/src/server/security/index.ts +0 -94
  317. package/src/vite/helpers/boot.ts +0 -106
  318. package/src/vite/plugins/viteAlephaDev.ts +0 -177
  319. package/src/vite/tasks/devServer.ts +0 -69
  320. package/src/vite/tasks/runAlepha.ts +0 -270
  321. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  322. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -1,7 +1,8 @@
1
- import { $env, $hook, $inject, $module, Alepha, AlephaError, KIND, Primitive, createPrimitive, isFileLike, isTypeFile, isUUID, t } from "alepha";
1
+ import { $env, $hook, $inject, $module, Alepha, AlephaError, KIND, Primitive, createPrimitive, isFileLike, isTypeFile, t } from "alepha";
2
2
  import { $logger } from "alepha/logger";
3
3
  import { Readable } from "node:stream";
4
4
  import { DateTimeProvider } from "alepha/datetime";
5
+ import { randomUUID } from "node:crypto";
5
6
  import { ReadableStream as ReadableStream$1 } from "node:stream/web";
6
7
  import { RouterProvider } from "alepha/router";
7
8
  import { $cache } from "alepha/cache";
@@ -256,7 +257,7 @@ var ServerTimingProvider = class {
256
257
  onRequest = $hook({
257
258
  priority: "first",
258
259
  on: "server:onRequest",
259
- handler: async ({ request }) => {
260
+ handler: ({ request }) => {
260
261
  if (this.options.disabled) return;
261
262
  request.metadata.timing = {};
262
263
  request.metadata.timing[this.handlerName] = [Date.now()];
@@ -265,7 +266,7 @@ var ServerTimingProvider = class {
265
266
  onResponse = $hook({
266
267
  priority: "last",
267
268
  on: "server:onResponse",
268
- handler: async ({ request }) => {
269
+ handler: ({ request }) => {
269
270
  if (this.options.disabled) return;
270
271
  if (request.metadata.timing) {
271
272
  this.setDuration(this.handlerName, request.metadata.timing);
@@ -317,11 +318,12 @@ var ServerTimingProvider = class {
317
318
  //#endregion
318
319
  //#region ../../src/server/core/providers/ServerRouterProvider.ts
319
320
  /**
320
- * Main router for all routes on the server side.
321
+ * Main router for all routes server side.
321
322
  *
323
+ * Reminder:
322
324
  * - $route => generic route
323
325
  * - $action => action route (for API calls)
324
- * - $page => React route (for SSR)
326
+ * - $page => React route (for React SSR)
325
327
  */
326
328
  var ServerRouterProvider = class extends RouterProvider {
327
329
  log = $logger();
@@ -329,6 +331,43 @@ var ServerRouterProvider = class extends RouterProvider {
329
331
  routes = [];
330
332
  serverTimingProvider = $inject(ServerTimingProvider);
331
333
  serverRequestParser = $inject(ServerRequestParser);
334
+ compiledOnRequest;
335
+ compiledOnSend;
336
+ compiledOnResponse;
337
+ compiledOnError;
338
+ contextRunOptions = {
339
+ context: "",
340
+ _request: null,
341
+ _route: null,
342
+ _responseKind: "any"
343
+ };
344
+ processRequestBound = () => {
345
+ const opts = this.contextRunOptions;
346
+ return this.processRequest(opts._request, opts._route, opts._responseKind);
347
+ };
348
+ queryKeysCache = /* @__PURE__ */ new WeakMap();
349
+ /**
350
+ * Get cached keys for a query schema, computing them lazily on first access.
351
+ */
352
+ getQuerySchemaKeys(schema) {
353
+ let keys = this.queryKeysCache.get(schema.properties);
354
+ if (!keys) {
355
+ keys = Object.keys(schema.properties);
356
+ this.queryKeysCache.set(schema.properties, keys);
357
+ }
358
+ return keys;
359
+ }
360
+ /**
361
+ * Compile event executors for optimal performance.
362
+ * Called lazily on first request after all hooks are registered.
363
+ */
364
+ compileEvents() {
365
+ if (this.compiledOnRequest) return;
366
+ this.compiledOnRequest = this.alepha.events.compile("server:onRequest");
367
+ this.compiledOnSend = this.alepha.events.compile("server:onSend", { catch: true });
368
+ this.compiledOnResponse = this.alepha.events.compile("server:onResponse", { catch: true });
369
+ this.compiledOnError = this.alepha.events.compile("server:onError");
370
+ }
332
371
  /**
333
372
  * Get all registered routes, optionally filtered by a pattern.
334
373
  *
@@ -342,6 +381,9 @@ var ServerRouterProvider = class extends RouterProvider {
342
381
  } else return this.routes.filter((route) => route.path === pattern);
343
382
  return this.routes;
344
383
  }
384
+ /**
385
+ * Create a new server route.
386
+ */
345
387
  createRoute(route) {
346
388
  route.method ??= "GET";
347
389
  route.method = route.method.toUpperCase();
@@ -353,100 +395,135 @@ var ServerRouterProvider = class extends RouterProvider {
353
395
  path,
354
396
  handler: (rawRequest) => {
355
397
  const request = this.serverRequestParser.createServerRequest(rawRequest);
356
- return this.alepha.context.run(() => this.processRequest(request, route, responseKind), { context: this.getContextId(rawRequest.headers) });
398
+ const opts = this.contextRunOptions;
399
+ opts.context = this.getContextId(rawRequest.headers);
400
+ opts._request = request;
401
+ opts._route = route;
402
+ opts._responseKind = responseKind;
403
+ return this.alepha.context.run(this.processRequestBound, opts);
357
404
  }
358
405
  });
359
406
  }
407
+ /**
408
+ * Get or generate a context ID from request headers.
409
+ */
360
410
  getContextId(headers) {
361
- const contextId = headers["x-request-id"] || headers["x-correlation-id"];
362
- if (isUUID(contextId)) return contextId;
363
- return crypto.randomUUID();
411
+ const contextId = headers[HEADER_REQUEST_ID] || headers[HEADER_CORRELATION_ID];
412
+ if (contextId) return contextId;
413
+ return randomUUID();
364
414
  }
415
+ /**
416
+ * Process an incoming request through the full lifecycle:
417
+ * - onRequest hooks
418
+ * - route handler
419
+ * - onSend hooks
420
+ * - response serialization
421
+ * - onResponse hooks
422
+ */
365
423
  async processRequest(request, route, responseKind) {
366
- await this.runRouteHandler(route, request, responseKind).catch((error) => {
367
- return this.errorHandler(route, request, error);
368
- });
369
- await this.alepha.events.emit("server:onSend", {
424
+ this.compileEvents();
425
+ try {
426
+ await this.runRouteHandler(route, request, responseKind);
427
+ } catch (error) {
428
+ await this.errorHandler(route, request, error);
429
+ }
430
+ const reply = request.reply;
431
+ const payload = {
370
432
  request,
371
- route
372
- }, { catch: true });
433
+ route,
434
+ response: void 0
435
+ };
436
+ const onSendResult = this.compiledOnSend(payload);
437
+ if (onSendResult) await onSendResult;
373
438
  const response = {
374
- status: request.reply.status ?? (request.reply.body ? 200 : 204),
375
- headers: request.reply.headers,
376
- body: request.reply.body
439
+ status: reply.status ?? (reply.body ? 200 : 204),
440
+ headers: reply.headers,
441
+ body: reply.body
377
442
  };
378
- await this.alepha.events.emit("server:onResponse", {
379
- request,
380
- route,
381
- response
382
- }, { catch: true });
443
+ payload.response = response;
444
+ const onResponseResult = this.compiledOnResponse(payload);
445
+ if (onResponseResult) await onResponseResult;
383
446
  return response;
384
447
  }
448
+ /**
449
+ * Run the route handler with request validation and response serialization.
450
+ */
385
451
  async runRouteHandler(route, request, responseKind) {
386
- await this.alepha.events.emit("server:onRequest", {
452
+ const timing = this.serverTimingProvider;
453
+ const payload = {
387
454
  request,
388
455
  route
389
- }, { log: false });
390
- if (request.reply.body || request.reply.status && request.reply.status >= 200) return;
391
- this.alepha.context.set("request", request);
392
- this.serverTimingProvider.beginTiming("validateRequest");
456
+ };
457
+ const onRequestResult = this.compiledOnRequest(payload);
458
+ if (onRequestResult) await onRequestResult;
459
+ const reply = request.reply;
460
+ if (reply.body || reply.status && reply.status >= 200) return;
461
+ this.alepha.context.set(CTX_REQUEST, request);
462
+ timing.beginTiming(TIMING_VALIDATE);
393
463
  try {
394
464
  this.validateRequest(route, request);
395
465
  } finally {
396
- this.serverTimingProvider.endTiming("validateRequest");
466
+ timing.endTiming(TIMING_VALIDATE);
397
467
  }
398
- this.serverTimingProvider.beginTiming("runHandler");
468
+ timing.beginTiming(TIMING_HANDLER);
399
469
  try {
400
470
  const result = await route.handler(request);
401
471
  if (result) request.reply.body = result;
402
472
  } finally {
403
- this.serverTimingProvider.endTiming("runHandler");
473
+ timing.endTiming(TIMING_HANDLER);
404
474
  }
405
- this.serverTimingProvider.beginTiming("serializeResponse");
475
+ timing.beginTiming(TIMING_SERIALIZE);
406
476
  try {
407
477
  this.serializeResponse(route, request.reply, responseKind);
408
478
  } finally {
409
- this.serverTimingProvider.endTiming("serializeResponse");
479
+ timing.endTiming(TIMING_SERIALIZE);
410
480
  }
411
481
  }
482
+ /**
483
+ * Transform reply body based on response kind and route schema.
484
+ */
412
485
  serializeResponse(route, reply, responseKind) {
486
+ const headers = reply.headers;
413
487
  if (responseKind === "json" && route.schema?.response) {
414
- reply.headers["content-type"] = "application/json";
415
- reply.body = this.alepha.codec.encode(route.schema.response, reply.body, { as: "string" });
488
+ headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
489
+ reply.body = this.alepha.codec.encode(route.schema.response, reply.body, ENCODE_OPTIONS_STRING);
416
490
  return;
417
491
  }
418
492
  if (responseKind === "file") {
419
493
  if (!isFileLike(reply.body)) throw new HttpError({
420
494
  status: 500,
421
- message: "Invalid response body - not a file"
495
+ message: ERROR_NOT_FILE
422
496
  });
423
- reply.headers["content-type"] = reply.body.type;
424
- reply.headers["content-disposition"] = `attachment; filename="${reply.body.name.replaceAll("\"", "")}"`;
497
+ headers[HEADER_CONTENT_TYPE] = reply.body.type;
498
+ headers[HEADER_CONTENT_DISPOSITION] = `attachment; filename="${reply.body.name.replaceAll("\"", "")}"`;
425
499
  reply.body = reply.body.stream();
426
500
  return;
427
501
  }
428
502
  if (responseKind === "text") {
429
503
  reply.body = String(reply.body);
430
- if (reply.body.startsWith("<!DOCTYPE html>")) reply.headers["content-type"] ??= "text/html; charset=UTF-8";
431
- else reply.headers["content-type"] ??= "text/plain";
504
+ if (reply.body.length > 15 && reply.body.charCodeAt(0) === 60 && reply.body.startsWith("<!DOCTYPE html>")) headers[HEADER_CONTENT_TYPE] ??= CONTENT_TYPE_HTML;
505
+ else headers[HEADER_CONTENT_TYPE] ??= CONTENT_TYPE_TEXT;
432
506
  return;
433
507
  }
434
508
  if (reply.body == null || responseKind === "void") {
435
- delete reply.headers["content-type"];
509
+ delete headers[HEADER_CONTENT_TYPE];
436
510
  reply.body = void 0;
437
511
  return;
438
512
  }
439
513
  if (Buffer.isBuffer(reply.body)) {
440
- reply.headers["content-type"] ??= "application/octet-stream";
514
+ headers[HEADER_CONTENT_TYPE] ??= CONTENT_TYPE_OCTET;
441
515
  return;
442
516
  }
443
517
  if (reply.body instanceof ReadableStream$1 || reply.body instanceof Readable) {
444
- reply.headers["content-type"] ??= "application/octet-stream";
518
+ headers[HEADER_CONTENT_TYPE] ??= CONTENT_TYPE_OCTET;
445
519
  return;
446
520
  }
447
- reply.headers["content-type"] ??= "text/plain";
521
+ headers[HEADER_CONTENT_TYPE] ??= CONTENT_TYPE_TEXT;
448
522
  reply.body = String(reply.body);
449
523
  }
524
+ /**
525
+ * Determine response type based on route schema.
526
+ */
450
527
  getResponseType(schema) {
451
528
  if (schema?.response) {
452
529
  if (t.schema.isObject(schema.response) || t.schema.isRecord(schema.response) || t.schema.isArray(schema.response)) return "json";
@@ -456,42 +533,52 @@ var ServerRouterProvider = class extends RouterProvider {
456
533
  }
457
534
  return "any";
458
535
  }
536
+ /**
537
+ * When an error occurs during request processing, this method is called.
538
+ */
459
539
  async errorHandler(route, request, error) {
460
- request.reply.body = null;
461
- await this.alepha.events.emit("server:onError", {
540
+ const reply = request.reply;
541
+ const headers = reply.headers;
542
+ const requestId = request.requestId;
543
+ reply.body = null;
544
+ const onErrorResult = this.compiledOnError({
462
545
  request,
463
546
  route,
464
547
  error
465
- }, { log: false });
466
- if (!request.reply.body && !request.reply.status) if (error instanceof HttpError) {
467
- request.reply.status = error.status;
468
- request.reply.headers["content-type"] = "application/json";
469
- request.reply.body = JSON.stringify({
470
- ...HttpError.toJSON(error),
471
- requestId: request.requestId
472
- });
548
+ });
549
+ if (onErrorResult) await onErrorResult;
550
+ if (!reply.body && !reply.status) if (error instanceof HttpError) {
551
+ reply.status = error.status;
552
+ headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
553
+ const errorJson = HttpError.toJSON(error);
554
+ errorJson.requestId = requestId;
555
+ reply.body = JSON.stringify(errorJson);
473
556
  } else {
474
557
  if ("status" in error && typeof error.status === "number" && !!errorNameByStatus[error.status]) {
475
- request.reply.status = error.status;
476
- request.reply.headers["content-type"] = "application/json";
477
- request.reply.body = JSON.stringify({
478
- status: error.status,
479
- error: errorNameByStatus[error.status],
558
+ const status = error.status;
559
+ reply.status = status;
560
+ headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
561
+ reply.body = JSON.stringify({
562
+ status,
563
+ error: errorNameByStatus[status],
480
564
  message: error.message,
481
- requestId: request.requestId
565
+ requestId
482
566
  });
483
567
  return;
484
568
  }
485
- request.reply.status = 500;
486
- request.reply.headers["content-type"] = "application/json";
487
- request.reply.body = JSON.stringify({
569
+ reply.status = 500;
570
+ headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
571
+ reply.body = JSON.stringify({
488
572
  status: 500,
489
- error: "InternalServerError",
573
+ error: ERROR_INTERNAL,
490
574
  message: error.message,
491
- requestId: request.requestId
575
+ requestId
492
576
  });
493
577
  }
494
578
  }
579
+ /**
580
+ * Validate incoming request against route schema.
581
+ */
495
582
  validateRequest(route, request) {
496
583
  if (route.schema?.params) try {
497
584
  request.params = this.alepha.codec.validate(route.schema.params, request.params);
@@ -499,8 +586,13 @@ var ServerRouterProvider = class extends RouterProvider {
499
586
  throw new ValidationError("Invalid request params", error);
500
587
  }
501
588
  if (route.schema?.query) try {
589
+ const schemaQuery = route.schema.query;
590
+ const keys = this.getQuerySchemaKeys(schemaQuery);
502
591
  const query = {};
503
- for (const key in route.schema.query.properties) if (request.query[key] != null) query[key] = this.alepha.codec.decode(route.schema.query.properties[key], request.query[key]);
592
+ for (let i = 0; i < keys.length; i++) {
593
+ const key = keys[i];
594
+ if (request.query[key] != null) query[key] = this.alepha.codec.decode(schemaQuery.properties[key], request.query[key]);
595
+ }
504
596
  request.query = query;
505
597
  } catch (error) {
506
598
  throw new ValidationError("Invalid request query", error);
@@ -519,9 +611,28 @@ var ServerRouterProvider = class extends RouterProvider {
519
611
  }
520
612
  }
521
613
  };
614
+ const ENCODE_OPTIONS_STRING = Object.freeze({ as: "string" });
615
+ const HEADER_CONTENT_TYPE = "content-type";
616
+ const HEADER_CONTENT_DISPOSITION = "content-disposition";
617
+ const HEADER_REQUEST_ID = "x-request-id";
618
+ const HEADER_CORRELATION_ID = "x-correlation-id";
619
+ const CONTENT_TYPE_JSON = "application/json";
620
+ const CONTENT_TYPE_TEXT = "text/plain";
621
+ const CONTENT_TYPE_HTML = "text/html; charset=UTF-8";
622
+ const CONTENT_TYPE_OCTET = "application/octet-stream";
623
+ const TIMING_VALIDATE = "validateRequest";
624
+ const TIMING_HANDLER = "runHandler";
625
+ const TIMING_SERIALIZE = "serializeResponse";
626
+ const CTX_REQUEST = "request";
627
+ const ERROR_INTERNAL = "InternalServerError";
628
+ const ERROR_NOT_FILE = "Invalid response body - not a file";
522
629
 
523
630
  //#endregion
524
631
  //#region ../../src/server/core/providers/ServerProvider.ts
632
+ const HEADER_X_FORWARDED_PROTO = "x-forwarded-proto";
633
+ const HEADER_HOST = "host";
634
+ const PROTO_HTTPS = "https://";
635
+ const PROTO_HTTP = "http://";
525
636
  /**
526
637
  * Base server provider to handle incoming requests and route them.
527
638
  *
@@ -535,6 +646,64 @@ var ServerProvider = class {
535
646
  dateTimeProvider = $inject(DateTimeProvider);
536
647
  router = $inject(ServerRouterProvider);
537
648
  internalServerErrorMessage = "Internal Server Error";
649
+ internalErrorResponse = Object.freeze({
650
+ status: 500,
651
+ headers: Object.freeze({ "content-type": "text/plain" }),
652
+ body: this.internalServerErrorMessage
653
+ });
654
+ handleInternalError = () => this.internalErrorResponse;
655
+ urlBaseCache = /* @__PURE__ */ new Map();
656
+ /**
657
+ * Get cached URL base (protocol + host) for a given host header.
658
+ * Caches the result to avoid repeated string concatenation.
659
+ */
660
+ getUrlBase(headers) {
661
+ const host = headers[HEADER_HOST];
662
+ let base = this.urlBaseCache.get(host);
663
+ if (!base) {
664
+ base = (headers[HEADER_X_FORWARDED_PROTO] === "https" ? PROTO_HTTPS : PROTO_HTTP) + host;
665
+ if (this.urlBaseCache.size < 100) this.urlBaseCache.set(host, base);
666
+ }
667
+ return base;
668
+ }
669
+ /**
670
+ * Parse query string manually - faster than new URL() + URLSearchParams.
671
+ * Returns empty object if no query string.
672
+ */
673
+ parseQueryString(rawUrl) {
674
+ const qIndex = rawUrl.indexOf("?");
675
+ if (qIndex === -1) return {};
676
+ const qs = rawUrl.slice(qIndex + 1);
677
+ if (!qs) return {};
678
+ const query = {};
679
+ let start = 0;
680
+ let eqIdx = -1;
681
+ for (let i = 0; i <= qs.length; i++) {
682
+ const char = i < qs.length ? qs.charCodeAt(i) : 38;
683
+ if (char === 61) eqIdx = i;
684
+ else if (char === 38) {
685
+ if (eqIdx !== -1 && eqIdx > start) {
686
+ const key = qs.slice(start, eqIdx);
687
+ const value = qs.slice(eqIdx + 1, i);
688
+ query[this.fastDecode(key)] = this.fastDecode(value);
689
+ }
690
+ start = i + 1;
691
+ eqIdx = -1;
692
+ }
693
+ }
694
+ return query;
695
+ }
696
+ /**
697
+ * Fast decode - only calls decodeURIComponent if needed.
698
+ */
699
+ fastDecode(str) {
700
+ if (str.indexOf("%") === -1 && str.indexOf("+") === -1) return str;
701
+ try {
702
+ return decodeURIComponent(str.replace(/\+/g, " "));
703
+ } catch {
704
+ return str;
705
+ }
706
+ }
538
707
  get hostname() {
539
708
  if (this.alepha.isViteDev()) return `http://localhost:${this.alepha.env.SERVER_PORT}`;
540
709
  return "";
@@ -558,36 +727,32 @@ var ServerProvider = class {
558
727
  /**
559
728
  * Handle Node.js HTTP request event.
560
729
  *
561
- * Technically, we just convert Node.js request to Web Standard Request.
730
+ * Optimized to avoid expensive URL parsing when possible.
562
731
  */
563
732
  async handleNodeRequest(nodeRequestEvent) {
564
733
  const { req, res } = nodeRequestEvent;
565
- const { route, params } = this.router.match(`/${req.method}${req.url}`);
566
- if (this.isViteNotFound(req.url, route, params)) return;
734
+ const rawUrl = req.url;
735
+ const { route, params } = this.router.match(`/${req.method}${rawUrl}`);
567
736
  if (!route) {
737
+ if (res.headersSent) return;
568
738
  res.writeHead(404, { "content-type": "text/plain" });
569
739
  res.end("Not Found");
570
740
  return;
571
741
  }
572
742
  const headers = req.headers ?? {};
573
- const proto = headers["x-forwarded-proto"] === "https" ? "https" : "http";
574
- const url = new URL(`${proto}://${headers.host}${req.url}`);
575
- const query = Object.fromEntries(url.searchParams.entries());
743
+ const method = req.method?.toUpperCase() ?? "GET";
744
+ const query = this.parseQueryString(rawUrl);
745
+ const urlBase = this.getUrlBase(headers);
576
746
  const request = {
577
- method: req.method?.toUpperCase() ?? "GET",
578
- url,
747
+ method,
748
+ url: new URL(rawUrl, urlBase),
579
749
  headers,
580
750
  params: params ?? {},
581
751
  query,
582
752
  raw: { node: nodeRequestEvent }
583
753
  };
584
- const response = await route.handler(request).catch(() => {
585
- return {
586
- status: 500,
587
- headers: { "content-type": "text/plain" },
588
- body: this.internalServerErrorMessage
589
- };
590
- });
754
+ const response = await route.handler(request).catch(this.handleInternalError);
755
+ if (res.headersSent) return;
591
756
  if (!response.body) {
592
757
  res.writeHead(response.status, response.headers).end();
593
758
  return;
@@ -637,7 +802,7 @@ var ServerProvider = class {
637
802
  req.headers.forEach((value, key) => {
638
803
  headers[key] = value;
639
804
  });
640
- const query = Object.fromEntries(url.searchParams.entries());
805
+ const query = url.search ? Object.fromEntries(url.searchParams.entries()) : {};
641
806
  const request = {
642
807
  method: req.method.toUpperCase() ?? "GET",
643
808
  url,
@@ -646,13 +811,7 @@ var ServerProvider = class {
646
811
  query,
647
812
  raw: { web: ev }
648
813
  };
649
- const response = await route.handler(request).catch(() => {
650
- return {
651
- status: 500,
652
- headers: { "content-type": "text/plain" },
653
- body: this.internalServerErrorMessage
654
- };
655
- });
814
+ const response = await route.handler(request).catch(this.handleInternalError);
656
815
  if (!response.body) {
657
816
  ev.res = new Response(null, {
658
817
  status: response.status,
@@ -1023,8 +1182,8 @@ var HttpClient = class {
1023
1182
  */
1024
1183
  const $action = (options) => {
1025
1184
  const instance = createPrimitive(ActionPrimitive, options);
1026
- const fn = (config, options$1) => {
1027
- return instance.run(config, options$1);
1185
+ const fn = (config, options) => {
1186
+ return instance.run(config, options);
1028
1187
  };
1029
1188
  Object.defineProperty(fn, "name", { get() {
1030
1189
  return instance.options.name || instance.config.propertyKey;
@@ -1248,7 +1407,7 @@ var BunHttpServerProvider = class extends ServerProvider {
1248
1407
  });
1249
1408
  }
1250
1409
  });
1251
- this.log.info(`Server listening on ${this.hostname}`);
1410
+ this.log.info(`Server listening on ${this.hostname}/`);
1252
1411
  } catch (err) {
1253
1412
  this.log.error("Failed to start Bun server", err);
1254
1413
  throw err;
@@ -1288,6 +1447,14 @@ var NodeHttpServerProvider = class extends ServerProvider {
1288
1447
  log = $logger();
1289
1448
  env = $env(envSchema$1);
1290
1449
  router = $inject(ServerRouterProvider);
1450
+ /** Track active connections for fast shutdown */
1451
+ connections = /* @__PURE__ */ new Set();
1452
+ /** Get number of active connections */
1453
+ getConnectionsCount() {
1454
+ return this.connections.size;
1455
+ }
1456
+ /** Server options */
1457
+ options = { shutdownTimeout: 1e4 };
1291
1458
  get hostname() {
1292
1459
  if (this.server.listening) {
1293
1460
  const address = this.server.address();
@@ -1295,16 +1462,20 @@ var NodeHttpServerProvider = class extends ServerProvider {
1295
1462
  }
1296
1463
  return `http://${this.env.SERVER_HOST}:${this.env.SERVER_PORT}`;
1297
1464
  }
1465
+ handleRequestError = (res, err) => {
1466
+ this.log.error("Error handling request", err);
1467
+ res.statusCode = 500;
1468
+ res.end("Internal Server Error");
1469
+ };
1470
+ nodeRequestEvent = {
1471
+ req: null,
1472
+ res: null
1473
+ };
1298
1474
  server = this.createHttpServer((req, res) => {
1299
- this.log.trace(`Incoming Node.js message -> ${req.url}`);
1300
- this.handleNodeRequest({
1301
- req,
1302
- res
1303
- }).catch((err) => {
1304
- this.log.error("Error handling request", err);
1305
- res.statusCode = 500;
1306
- res.end("Internal Server Error");
1307
- });
1475
+ const ev = this.nodeRequestEvent;
1476
+ ev.req = req;
1477
+ ev.res = res;
1478
+ this.handleNodeRequest(ev).catch((err) => this.handleRequestError(res, err));
1308
1479
  });
1309
1480
  start = $hook({
1310
1481
  on: "start",
@@ -1314,16 +1485,17 @@ var NodeHttpServerProvider = class extends ServerProvider {
1314
1485
  }
1315
1486
  });
1316
1487
  createHttpServer(func) {
1317
- return createServer({ keepAlive: this.alepha.isProduction() }, func);
1488
+ const server = createServer({ keepAlive: this.alepha.isProduction() }, func);
1489
+ server.on("connection", (socket) => {
1490
+ this.connections.add(socket);
1491
+ socket.on("close", () => this.connections.delete(socket));
1492
+ });
1493
+ return server;
1318
1494
  }
1319
1495
  stop = $hook({
1320
1496
  on: "stop",
1321
1497
  handler: async () => {
1322
- if (this.alepha.isProduction()) {
1323
- await this.close();
1324
- return;
1325
- }
1326
- this.close().catch(() => {});
1498
+ await this.close();
1327
1499
  }
1328
1500
  });
1329
1501
  async listen() {
@@ -1331,7 +1503,7 @@ var NodeHttpServerProvider = class extends ServerProvider {
1331
1503
  if (this.alepha.isTest() && port === 3e3) port = 0;
1332
1504
  await new Promise((resolve, reject) => {
1333
1505
  this.server?.listen(port, this.env.SERVER_HOST, () => {
1334
- this.log.info(`Server listening on ${this.hostname}`);
1506
+ this.log.info(`Server listening on ${this.hostname}/`);
1335
1507
  resolve();
1336
1508
  });
1337
1509
  this.server?.on("error", (err) => {
@@ -1340,15 +1512,28 @@ var NodeHttpServerProvider = class extends ServerProvider {
1340
1512
  });
1341
1513
  }
1342
1514
  async close() {
1343
- const promise = new Promise((resolve, reject) => {
1344
- this.server?.close((err) => {
1345
- if (err) reject(err);
1346
- else resolve();
1347
- });
1515
+ if (!this.alepha.isProduction()) this.destroyAllConnections();
1516
+ const closePromise = new Promise((resolve, reject) => {
1517
+ this.server?.close((err) => err ? reject(err) : resolve());
1348
1518
  });
1349
- await Promise.race([this.dateTimeProvider.wait(2e3), promise]);
1519
+ if (this.alepha.isProduction() && this.connections.size > 0) {
1520
+ const timeout = this.options.shutdownTimeout;
1521
+ const timeoutId = setTimeout(() => {
1522
+ if (this.connections.size > 0) {
1523
+ this.log.warn(`Shutdown timeout (${timeout}ms) reached, forcing ${this.connections.size} connections to close`);
1524
+ for (const socket of this.connections) socket.destroy();
1525
+ }
1526
+ }, timeout);
1527
+ await closePromise;
1528
+ clearTimeout(timeoutId);
1529
+ this.connections.clear();
1530
+ } else await closePromise;
1350
1531
  this.log.info("Server closed");
1351
1532
  }
1533
+ destroyAllConnections() {
1534
+ for (const socket of this.connections) socket.destroy();
1535
+ this.connections.clear();
1536
+ }
1352
1537
  };
1353
1538
 
1354
1539
  //#endregion
@@ -1370,22 +1555,21 @@ var ServerBodyParserProvider = class {
1370
1555
  log = $logger();
1371
1556
  onRequest = $hook({
1372
1557
  on: "server:onRequest",
1373
- handler: async ({ route, request }) => {
1558
+ handler: ({ route, request }) => {
1374
1559
  if (request.body) return;
1375
1560
  let stream;
1376
1561
  if (request.raw.web?.req.body) stream = request.raw.web.req.body;
1377
1562
  else if (request.raw.node?.req) stream = ReadableStream$1.from(request.raw.node.req);
1378
1563
  if (!stream) return;
1379
- if (route.schema?.body) try {
1380
- const body = await this.parse(stream, request.headers, route.schema.body);
1564
+ if (route.schema?.body) return this.parse(stream, request.headers, route.schema.body).then((body) => {
1381
1565
  if (body) request.body = body;
1382
- } catch (error) {
1566
+ }).catch((error) => {
1383
1567
  if (error instanceof HttpError) throw error;
1384
1568
  throw new HttpError({
1385
1569
  status: 400,
1386
1570
  message: "Failed to parse request body"
1387
1571
  }, error);
1388
- }
1572
+ });
1389
1573
  }
1390
1574
  });
1391
1575
  async parse(stream, headers, schema) {
@@ -1475,19 +1659,18 @@ var ServerLoggerProvider = class {
1475
1659
  on: "server:onRequest",
1476
1660
  priority: "first",
1477
1661
  handler: ({ route, request }) => {
1478
- if (!route.silent) {
1479
- request.metadata.now = Date.now();
1480
- const data = {
1481
- method: request.method,
1482
- path: request.url.pathname
1483
- };
1484
- if (this.alepha.isProduction()) {
1485
- data.agent = request.headers["user-agent"];
1486
- const ip = request.ip;
1487
- if (ip) data.ip = ip;
1488
- }
1489
- this.log.info("Incoming request", data);
1662
+ if (route.silent || request.metadata.vite) return;
1663
+ request.metadata.now = Date.now();
1664
+ const data = {
1665
+ method: request.method,
1666
+ path: request.url.pathname
1667
+ };
1668
+ if (this.alepha.isProduction()) {
1669
+ data.agent = request.headers["user-agent"];
1670
+ const ip = request.ip;
1671
+ if (ip) data.ip = ip;
1490
1672
  }
1673
+ this.log.info("Incoming request", data);
1491
1674
  }
1492
1675
  });
1493
1676
  onError = $hook({
@@ -1501,13 +1684,12 @@ var ServerLoggerProvider = class {
1501
1684
  on: "server:onResponse",
1502
1685
  priority: "last",
1503
1686
  handler: ({ route, request, response }) => {
1504
- if (!route.silent) {
1505
- const ms = Date.now() - request.metadata.now;
1506
- this.log.info("Request completed", {
1507
- status: response.status,
1508
- ms
1509
- });
1510
- }
1687
+ if (route.silent || request.metadata.vite) return;
1688
+ const ms = Date.now() - request.metadata.now;
1689
+ this.log.info("Request completed", {
1690
+ status: response.status,
1691
+ ms
1692
+ });
1511
1693
  }
1512
1694
  });
1513
1695
  };
@@ -1648,7 +1830,7 @@ const AlephaServer = $module({
1648
1830
  ServerRouterProvider
1649
1831
  ],
1650
1832
  register: (alepha) => {
1651
- if (!alepha.isServerless() && !alepha.isViteDev()) if (alepha.isBun()) alepha.with({
1833
+ if (!alepha.isServerless()) if (alepha.isBun()) alepha.with({
1652
1834
  optional: true,
1653
1835
  provide: ServerProvider,
1654
1836
  use: BunHttpServerProvider