alepha 0.15.1 → 0.15.2

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 (507) hide show
  1. package/dist/api/audits/index.d.ts +342 -365
  2. package/dist/api/audits/index.d.ts.map +1 -1
  3. package/dist/api/audits/index.js +10 -33
  4. package/dist/api/audits/index.js.map +1 -1
  5. package/dist/api/files/index.d.ts +180 -173
  6. package/dist/api/files/index.d.ts.map +1 -1
  7. package/dist/api/files/index.js +10 -3
  8. package/dist/api/files/index.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts +162 -155
  10. package/dist/api/jobs/index.d.ts.map +1 -1
  11. package/dist/api/jobs/index.js +10 -3
  12. package/dist/api/jobs/index.js.map +1 -1
  13. package/dist/api/keys/index.d.ts +413 -0
  14. package/dist/api/keys/index.d.ts.map +1 -0
  15. package/dist/api/keys/index.js +476 -0
  16. package/dist/api/keys/index.js.map +1 -0
  17. package/dist/api/notifications/index.d.ts +10 -4
  18. package/dist/api/notifications/index.d.ts.map +1 -1
  19. package/dist/api/notifications/index.js +10 -4
  20. package/dist/api/notifications/index.js.map +1 -1
  21. package/dist/api/parameters/index.d.ts +294 -301
  22. package/dist/api/parameters/index.d.ts.map +1 -1
  23. package/dist/api/parameters/index.js +30 -37
  24. package/dist/api/parameters/index.js.map +1 -1
  25. package/dist/api/users/index.d.ts +1079 -769
  26. package/dist/api/users/index.d.ts.map +1 -1
  27. package/dist/api/users/index.js +2534 -218
  28. package/dist/api/users/index.js.map +1 -1
  29. package/dist/api/verifications/index.d.ts +10 -4
  30. package/dist/api/verifications/index.d.ts.map +1 -1
  31. package/dist/api/verifications/index.js +12 -4
  32. package/dist/api/verifications/index.js.map +1 -1
  33. package/dist/batch/index.d.ts +20 -40
  34. package/dist/batch/index.d.ts.map +1 -1
  35. package/dist/batch/index.js +31 -44
  36. package/dist/batch/index.js.map +1 -1
  37. package/dist/bucket/index.d.ts +432 -8
  38. package/dist/bucket/index.d.ts.map +1 -1
  39. package/dist/bucket/index.js +1856 -12
  40. package/dist/bucket/index.js.map +1 -1
  41. package/dist/cache/core/index.d.ts +179 -7
  42. package/dist/cache/core/index.d.ts.map +1 -1
  43. package/dist/cache/core/index.js +213 -7
  44. package/dist/cache/core/index.js.map +1 -1
  45. package/dist/cache/redis/index.d.ts +1 -0
  46. package/dist/cache/redis/index.d.ts.map +1 -1
  47. package/dist/cache/redis/index.js +4 -0
  48. package/dist/cache/redis/index.js.map +1 -1
  49. package/dist/cli/index.d.ts +488 -5612
  50. package/dist/cli/index.d.ts.map +1 -1
  51. package/dist/cli/index.js +2326 -311
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/command/index.d.ts +194 -46
  54. package/dist/command/index.d.ts.map +1 -1
  55. package/dist/command/index.js +1995 -60
  56. package/dist/command/index.js.map +1 -1
  57. package/dist/core/index.browser.js +42 -19
  58. package/dist/core/index.browser.js.map +1 -1
  59. package/dist/core/index.d.ts +34 -13
  60. package/dist/core/index.d.ts.map +1 -1
  61. package/dist/core/index.js +62 -19
  62. package/dist/core/index.js.map +1 -1
  63. package/dist/core/index.native.js +42 -19
  64. package/dist/core/index.native.js.map +1 -1
  65. package/dist/datetime/index.d.ts +15 -0
  66. package/dist/datetime/index.d.ts.map +1 -1
  67. package/dist/datetime/index.js +15 -0
  68. package/dist/datetime/index.js.map +1 -1
  69. package/dist/email/index.d.ts +315 -20
  70. package/dist/email/index.d.ts.map +1 -1
  71. package/dist/email/index.js +1852 -7
  72. package/dist/email/index.js.map +1 -1
  73. package/dist/fake/index.d.ts +90 -8
  74. package/dist/fake/index.d.ts.map +1 -1
  75. package/dist/fake/index.js +91 -20
  76. package/dist/fake/index.js.map +1 -1
  77. package/dist/lock/core/index.d.ts +11 -4
  78. package/dist/lock/core/index.d.ts.map +1 -1
  79. package/dist/lock/core/index.js +11 -4
  80. package/dist/lock/core/index.js.map +1 -1
  81. package/dist/logger/index.d.ts +17 -66
  82. package/dist/logger/index.d.ts.map +1 -1
  83. package/dist/logger/index.js +14 -63
  84. package/dist/logger/index.js.map +1 -1
  85. package/dist/mcp/index.d.ts +15 -35
  86. package/dist/mcp/index.d.ts.map +1 -1
  87. package/dist/mcp/index.js +12 -35
  88. package/dist/mcp/index.js.map +1 -1
  89. package/dist/orm/index.browser.js +3 -3
  90. package/dist/orm/index.browser.js.map +1 -1
  91. package/dist/orm/index.bun.js +7 -4
  92. package/dist/orm/index.bun.js.map +1 -1
  93. package/dist/orm/index.d.ts +514 -540
  94. package/dist/orm/index.d.ts.map +1 -1
  95. package/dist/orm/index.js +24 -49
  96. package/dist/orm/index.js.map +1 -1
  97. package/dist/queue/core/index.d.ts +18 -10
  98. package/dist/queue/core/index.d.ts.map +1 -1
  99. package/dist/queue/core/index.js +14 -6
  100. package/dist/queue/core/index.js.map +1 -1
  101. package/dist/react/auth/index.browser.js +108 -0
  102. package/dist/react/auth/index.browser.js.map +1 -0
  103. package/dist/react/auth/index.d.ts +100 -0
  104. package/dist/react/auth/index.d.ts.map +1 -0
  105. package/dist/react/auth/index.js +145 -0
  106. package/dist/react/auth/index.js.map +1 -0
  107. package/dist/react/core/index.d.ts +469 -0
  108. package/dist/react/core/index.d.ts.map +1 -0
  109. package/dist/react/core/index.js +464 -0
  110. package/dist/react/core/index.js.map +1 -0
  111. package/dist/react/form/index.d.ts +232 -0
  112. package/dist/react/form/index.d.ts.map +1 -0
  113. package/dist/react/form/index.js +432 -0
  114. package/dist/react/form/index.js.map +1 -0
  115. package/dist/react/head/index.browser.js +423 -0
  116. package/dist/react/head/index.browser.js.map +1 -0
  117. package/dist/react/head/index.d.ts +288 -0
  118. package/dist/react/head/index.d.ts.map +1 -0
  119. package/dist/react/head/index.js +465 -0
  120. package/dist/react/head/index.js.map +1 -0
  121. package/dist/react/i18n/index.d.ts +175 -0
  122. package/dist/react/i18n/index.d.ts.map +1 -0
  123. package/dist/react/i18n/index.js +224 -0
  124. package/dist/react/i18n/index.js.map +1 -0
  125. package/dist/react/router/index.browser.js +1980 -0
  126. package/dist/react/router/index.browser.js.map +1 -0
  127. package/dist/react/router/index.d.ts +2068 -0
  128. package/dist/react/router/index.d.ts.map +1 -0
  129. package/dist/react/router/index.js +4932 -0
  130. package/dist/react/router/index.js.map +1 -0
  131. package/dist/react/websocket/index.d.ts +117 -0
  132. package/dist/react/websocket/index.d.ts.map +1 -0
  133. package/dist/react/websocket/index.js +107 -0
  134. package/dist/react/websocket/index.js.map +1 -0
  135. package/dist/redis/index.bun.js +4 -0
  136. package/dist/redis/index.bun.js.map +1 -1
  137. package/dist/redis/index.d.ts +22 -25
  138. package/dist/redis/index.d.ts.map +1 -1
  139. package/dist/redis/index.js +16 -25
  140. package/dist/redis/index.js.map +1 -1
  141. package/dist/retry/index.d.ts +11 -2
  142. package/dist/retry/index.d.ts.map +1 -1
  143. package/dist/retry/index.js +11 -2
  144. package/dist/retry/index.js.map +1 -1
  145. package/dist/scheduler/index.d.ts +11 -2
  146. package/dist/scheduler/index.d.ts.map +1 -1
  147. package/dist/scheduler/index.js +11 -2
  148. package/dist/scheduler/index.js.map +1 -1
  149. package/dist/security/index.d.ts +110 -19
  150. package/dist/security/index.d.ts.map +1 -1
  151. package/dist/security/index.js +157 -26
  152. package/dist/security/index.js.map +1 -1
  153. package/dist/server/auth/index.d.ts +179 -174
  154. package/dist/server/auth/index.d.ts.map +1 -1
  155. package/dist/server/auth/index.js +12 -7
  156. package/dist/server/auth/index.js.map +1 -1
  157. package/dist/server/cache/index.d.ts +7 -22
  158. package/dist/server/cache/index.d.ts.map +1 -1
  159. package/dist/server/cache/index.js +7 -22
  160. package/dist/server/cache/index.js.map +1 -1
  161. package/dist/server/compress/index.d.ts +10 -2
  162. package/dist/server/compress/index.d.ts.map +1 -1
  163. package/dist/server/compress/index.js +10 -2
  164. package/dist/server/compress/index.js.map +1 -1
  165. package/dist/server/cookies/index.d.ts +40 -16
  166. package/dist/server/cookies/index.d.ts.map +1 -1
  167. package/dist/server/cookies/index.js +7 -5
  168. package/dist/server/cookies/index.js.map +1 -1
  169. package/dist/server/core/index.d.ts +115 -14
  170. package/dist/server/core/index.d.ts.map +1 -1
  171. package/dist/server/core/index.js +231 -14
  172. package/dist/server/core/index.js.map +1 -1
  173. package/dist/server/cors/index.d.ts +13 -23
  174. package/dist/server/cors/index.d.ts.map +1 -1
  175. package/dist/server/cors/index.js +7 -21
  176. package/dist/server/cors/index.js.map +1 -1
  177. package/dist/server/health/index.d.ts +25 -19
  178. package/dist/server/health/index.d.ts.map +1 -1
  179. package/dist/server/health/index.js +8 -2
  180. package/dist/server/health/index.js.map +1 -1
  181. package/dist/server/helmet/index.d.ts +11 -3
  182. package/dist/server/helmet/index.d.ts.map +1 -1
  183. package/dist/server/helmet/index.js +11 -3
  184. package/dist/server/helmet/index.js.map +1 -1
  185. package/dist/server/links/index.d.ts +50 -45
  186. package/dist/server/links/index.d.ts.map +1 -1
  187. package/dist/server/links/index.js +11 -6
  188. package/dist/server/links/index.js.map +1 -1
  189. package/dist/server/metrics/index.d.ts +10 -3
  190. package/dist/server/metrics/index.d.ts.map +1 -1
  191. package/dist/server/metrics/index.js +10 -3
  192. package/dist/server/metrics/index.js.map +1 -1
  193. package/dist/server/multipart/index.d.ts +9 -3
  194. package/dist/server/multipart/index.d.ts.map +1 -1
  195. package/dist/server/multipart/index.js +9 -3
  196. package/dist/server/multipart/index.js.map +1 -1
  197. package/dist/server/proxy/index.d.ts +8 -2
  198. package/dist/server/proxy/index.d.ts.map +1 -1
  199. package/dist/server/proxy/index.js +8 -2
  200. package/dist/server/proxy/index.js.map +1 -1
  201. package/dist/server/rate-limit/index.d.ts +30 -35
  202. package/dist/server/rate-limit/index.d.ts.map +1 -1
  203. package/dist/server/rate-limit/index.js +18 -55
  204. package/dist/server/rate-limit/index.js.map +1 -1
  205. package/dist/server/static/index.d.ts +137 -4
  206. package/dist/server/static/index.d.ts.map +1 -1
  207. package/dist/server/static/index.js +1848 -5
  208. package/dist/server/static/index.js.map +1 -1
  209. package/dist/server/swagger/index.d.ts +301 -6
  210. package/dist/server/swagger/index.d.ts.map +1 -1
  211. package/dist/server/swagger/index.js +1849 -6
  212. package/dist/server/swagger/index.js.map +1 -1
  213. package/dist/sms/index.d.ts +301 -7
  214. package/dist/sms/index.d.ts.map +1 -1
  215. package/dist/sms/index.js +1851 -7
  216. package/dist/sms/index.js.map +1 -1
  217. package/dist/system/index.browser.js +496 -0
  218. package/dist/system/index.browser.js.map +1 -0
  219. package/dist/{file → system}/index.d.ts +335 -16
  220. package/dist/system/index.d.ts.map +1 -0
  221. package/dist/{file → system}/index.js +412 -20
  222. package/dist/system/index.js.map +1 -0
  223. package/dist/thread/index.d.ts +11 -2
  224. package/dist/thread/index.d.ts.map +1 -1
  225. package/dist/thread/index.js +11 -2
  226. package/dist/thread/index.js.map +1 -1
  227. package/dist/topic/core/index.d.ts +12 -5
  228. package/dist/topic/core/index.d.ts.map +1 -1
  229. package/dist/topic/core/index.js +12 -5
  230. package/dist/topic/core/index.js.map +1 -1
  231. package/dist/vite/index.d.ts +4 -6271
  232. package/dist/vite/index.d.ts.map +1 -1
  233. package/dist/vite/index.js +8 -3
  234. package/dist/vite/index.js.map +1 -1
  235. package/dist/websocket/index.d.ts +12 -8
  236. package/dist/websocket/index.d.ts.map +1 -1
  237. package/dist/websocket/index.js +12 -8
  238. package/dist/websocket/index.js.map +1 -1
  239. package/package.json +80 -11
  240. package/src/api/audits/index.ts +10 -33
  241. package/src/api/files/__tests__/$bucket.spec.ts +1 -1
  242. package/src/api/files/controllers/AdminFileStatsController.spec.ts +1 -1
  243. package/src/api/files/controllers/FileController.spec.ts +1 -1
  244. package/src/api/files/index.ts +10 -3
  245. package/src/api/files/jobs/FileJobs.spec.ts +1 -1
  246. package/src/api/files/services/FileService.spec.ts +1 -1
  247. package/src/api/jobs/index.ts +10 -3
  248. package/src/api/keys/controllers/AdminApiKeyController.ts +75 -0
  249. package/src/api/keys/controllers/ApiKeyController.ts +103 -0
  250. package/src/api/keys/entities/apiKeyEntity.ts +41 -0
  251. package/src/api/keys/index.ts +49 -0
  252. package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +7 -0
  253. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +17 -0
  254. package/src/api/keys/schemas/createApiKeyBodySchema.ts +7 -0
  255. package/src/api/keys/schemas/createApiKeyResponseSchema.ts +11 -0
  256. package/src/api/keys/schemas/listApiKeyResponseSchema.ts +15 -0
  257. package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +5 -0
  258. package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +5 -0
  259. package/src/api/keys/services/ApiKeyService.spec.ts +553 -0
  260. package/src/api/keys/services/ApiKeyService.ts +306 -0
  261. package/src/api/logs/TODO.md +52 -0
  262. package/src/api/notifications/index.ts +10 -4
  263. package/src/api/parameters/index.ts +9 -30
  264. package/src/api/parameters/primitives/$config.ts +12 -4
  265. package/src/api/parameters/services/ConfigStore.ts +9 -3
  266. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1035 -0
  267. package/src/api/users/__tests__/ApiKeys.spec.ts +401 -0
  268. package/src/api/users/index.ts +14 -3
  269. package/src/api/users/primitives/$realm.ts +33 -5
  270. package/src/api/users/providers/RealmProvider.ts +1 -12
  271. package/src/api/users/services/SessionService.ts +1 -1
  272. package/src/api/verifications/controllers/VerificationController.ts +2 -0
  273. package/src/api/verifications/index.ts +10 -4
  274. package/src/batch/index.ts +9 -36
  275. package/src/batch/primitives/$batch.ts +0 -8
  276. package/src/batch/providers/BatchProvider.ts +29 -2
  277. package/src/bucket/__tests__/shared.ts +1 -1
  278. package/src/bucket/index.ts +13 -6
  279. package/src/bucket/primitives/$bucket.ts +1 -1
  280. package/src/bucket/providers/LocalFileStorageProvider.ts +1 -1
  281. package/src/bucket/providers/MemoryFileStorageProvider.ts +1 -1
  282. package/src/cache/core/__tests__/shared.ts +30 -0
  283. package/src/cache/core/index.ts +11 -6
  284. package/src/cache/core/primitives/$cache.spec.ts +5 -0
  285. package/src/cache/core/providers/CacheProvider.ts +17 -0
  286. package/src/cache/core/providers/MemoryCacheProvider.ts +300 -1
  287. package/src/cache/redis/__tests__/cache-redis.spec.ts +5 -0
  288. package/src/cache/redis/providers/RedisCacheProvider.ts +9 -0
  289. package/src/cli/apps/AlephaCli.ts +1 -14
  290. package/src/cli/apps/AlephaPackageBuilderCli.ts +1 -1
  291. package/src/cli/commands/build.ts +1 -5
  292. package/src/cli/commands/db.ts +17 -11
  293. package/src/cli/commands/deploy.ts +1 -1
  294. package/src/cli/commands/dev.ts +1 -20
  295. package/src/cli/commands/gen/env.ts +5 -2
  296. package/src/cli/commands/gen/openapi.ts +5 -2
  297. package/src/cli/commands/init.spec.ts +544 -0
  298. package/src/cli/commands/init.ts +89 -55
  299. package/src/cli/commands/lint.ts +7 -1
  300. package/src/cli/commands/typecheck.ts +11 -0
  301. package/src/cli/providers/AppEntryProvider.ts +1 -1
  302. package/src/cli/providers/ViteBuildProvider.ts +8 -50
  303. package/src/cli/providers/ViteDevServerProvider.ts +36 -8
  304. package/src/cli/services/AlephaCliUtils.ts +37 -122
  305. package/src/cli/services/PackageManagerUtils.ts +127 -11
  306. package/src/cli/services/ProjectScaffolder.ts +122 -77
  307. package/src/cli/services/ViteUtils.ts +82 -0
  308. package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +32 -24
  309. package/src/cli/templates/gitignore.ts +39 -0
  310. package/src/cli/{assets → templates}/mainCss.ts +11 -2
  311. package/src/cli/templates/mainServerTs.ts +33 -0
  312. package/src/cli/templates/webAppRouterTs.ts +50 -0
  313. package/src/cli/{assets → templates}/webHelloComponentTsx.ts +2 -2
  314. package/src/command/helpers/Runner.spec.ts +4 -0
  315. package/src/command/helpers/Runner.ts +3 -21
  316. package/src/command/index.ts +12 -4
  317. package/src/command/providers/CliProvider.spec.ts +1067 -0
  318. package/src/command/providers/CliProvider.ts +203 -40
  319. package/src/core/Alepha.ts +2 -2
  320. package/src/core/__tests__/Alepha-start.spec.ts +4 -4
  321. package/src/core/helpers/jsonSchemaToTypeBox.spec.ts +771 -0
  322. package/src/core/helpers/jsonSchemaToTypeBox.ts +62 -10
  323. package/src/core/index.shared.ts +1 -0
  324. package/src/core/index.ts +20 -0
  325. package/src/core/providers/EventManager.spec.ts +0 -71
  326. package/src/core/providers/EventManager.ts +3 -15
  327. package/src/core/providers/Json.ts +2 -14
  328. package/src/datetime/index.ts +15 -0
  329. package/src/email/index.ts +10 -5
  330. package/src/email/providers/LocalEmailProvider.spec.ts +1 -1
  331. package/src/email/providers/LocalEmailProvider.ts +1 -1
  332. package/src/fake/__tests__/keyName.example.ts +1 -1
  333. package/src/fake/__tests__/keyName.spec.ts +5 -5
  334. package/src/fake/index.ts +9 -6
  335. package/src/fake/providers/FakeProvider.spec.ts +258 -40
  336. package/src/fake/providers/FakeProvider.ts +133 -19
  337. package/src/lock/core/index.ts +11 -4
  338. package/src/logger/index.ts +17 -66
  339. package/src/mcp/index.ts +10 -27
  340. package/src/mcp/transports/SseMcpTransport.ts +0 -11
  341. package/src/orm/__tests__/PostgresProvider.spec.ts +2 -2
  342. package/src/orm/index.browser.ts +2 -2
  343. package/src/orm/index.bun.ts +4 -2
  344. package/src/orm/index.ts +21 -47
  345. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -0
  346. package/src/orm/services/Repository.ts +7 -3
  347. package/src/queue/core/index.ts +14 -6
  348. package/src/react/auth/__tests__/$auth.spec.ts +202 -0
  349. package/src/react/auth/hooks/useAuth.ts +32 -0
  350. package/src/react/auth/index.browser.ts +13 -0
  351. package/src/react/auth/index.shared.ts +2 -0
  352. package/src/react/auth/index.ts +48 -0
  353. package/src/react/auth/providers/ReactAuthProvider.ts +16 -0
  354. package/src/react/auth/services/ReactAuth.ts +135 -0
  355. package/src/react/core/__tests__/Router.spec.tsx +169 -0
  356. package/src/react/core/components/ClientOnly.tsx +49 -0
  357. package/src/react/core/components/ErrorBoundary.tsx +73 -0
  358. package/src/react/core/contexts/AlephaContext.ts +7 -0
  359. package/src/react/core/contexts/AlephaProvider.tsx +42 -0
  360. package/src/react/core/hooks/useAction.browser.spec.tsx +569 -0
  361. package/src/react/core/hooks/useAction.ts +480 -0
  362. package/src/react/core/hooks/useAlepha.ts +26 -0
  363. package/src/react/core/hooks/useClient.ts +17 -0
  364. package/src/react/core/hooks/useEvents.ts +51 -0
  365. package/src/react/core/hooks/useInject.ts +12 -0
  366. package/src/react/core/hooks/useStore.ts +52 -0
  367. package/src/react/core/index.ts +90 -0
  368. package/src/react/form/components/FormState.tsx +17 -0
  369. package/src/react/form/errors/FormValidationError.ts +18 -0
  370. package/src/react/form/hooks/useForm.browser.spec.tsx +366 -0
  371. package/src/react/form/hooks/useForm.ts +47 -0
  372. package/src/react/form/hooks/useFormState.ts +130 -0
  373. package/src/react/form/index.ts +44 -0
  374. package/src/react/form/services/FormModel.ts +614 -0
  375. package/src/react/head/helpers/SeoExpander.spec.ts +203 -0
  376. package/src/react/head/helpers/SeoExpander.ts +142 -0
  377. package/src/react/head/hooks/useHead.spec.tsx +288 -0
  378. package/src/react/head/hooks/useHead.ts +62 -0
  379. package/src/react/head/index.browser.ts +26 -0
  380. package/src/react/head/index.ts +44 -0
  381. package/src/react/head/interfaces/Head.ts +105 -0
  382. package/src/react/head/primitives/$head.ts +25 -0
  383. package/src/react/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
  384. package/src/react/head/providers/BrowserHeadProvider.ts +212 -0
  385. package/src/react/head/providers/HeadProvider.ts +168 -0
  386. package/src/react/head/providers/ServerHeadProvider.ts +31 -0
  387. package/src/react/i18n/__tests__/integration.spec.tsx +239 -0
  388. package/src/react/i18n/components/Localize.spec.tsx +357 -0
  389. package/src/react/i18n/components/Localize.tsx +35 -0
  390. package/src/react/i18n/hooks/useI18n.browser.spec.tsx +438 -0
  391. package/src/react/i18n/hooks/useI18n.ts +18 -0
  392. package/src/react/i18n/index.ts +41 -0
  393. package/src/react/i18n/primitives/$dictionary.ts +69 -0
  394. package/src/react/i18n/providers/I18nProvider.spec.ts +389 -0
  395. package/src/react/i18n/providers/I18nProvider.ts +278 -0
  396. package/src/react/router/__tests__/page-head-browser.browser.spec.ts +95 -0
  397. package/src/react/router/__tests__/page-head.spec.ts +48 -0
  398. package/src/react/router/__tests__/seo-head.spec.ts +125 -0
  399. package/src/react/router/atoms/ssrManifestAtom.ts +58 -0
  400. package/src/react/router/components/ErrorViewer.tsx +872 -0
  401. package/src/react/router/components/Link.tsx +23 -0
  402. package/src/react/router/components/NestedView.tsx +223 -0
  403. package/src/react/router/components/NotFound.tsx +30 -0
  404. package/src/react/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
  405. package/src/react/router/contexts/RouterLayerContext.ts +12 -0
  406. package/src/react/router/errors/Redirection.ts +28 -0
  407. package/src/react/router/hooks/useActive.ts +52 -0
  408. package/src/react/router/hooks/useQueryParams.ts +63 -0
  409. package/src/react/router/hooks/useRouter.ts +20 -0
  410. package/src/react/router/hooks/useRouterState.ts +11 -0
  411. package/src/react/router/index.browser.ts +45 -0
  412. package/src/react/router/index.shared.ts +19 -0
  413. package/src/react/router/index.ts +142 -0
  414. package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
  415. package/src/react/router/primitives/$page.spec.tsx +708 -0
  416. package/src/react/router/primitives/$page.ts +497 -0
  417. package/src/react/router/providers/ReactBrowserProvider.ts +309 -0
  418. package/src/react/router/providers/ReactBrowserRendererProvider.ts +25 -0
  419. package/src/react/router/providers/ReactBrowserRouterProvider.ts +168 -0
  420. package/src/react/router/providers/ReactPageProvider.ts +726 -0
  421. package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
  422. package/src/react/router/providers/ReactServerProvider.ts +558 -0
  423. package/src/react/router/providers/ReactServerTemplateProvider.ts +979 -0
  424. package/src/react/router/providers/SSRManifestProvider.ts +334 -0
  425. package/src/react/router/services/ReactPageServerService.ts +48 -0
  426. package/src/react/router/services/ReactPageService.ts +27 -0
  427. package/src/react/router/services/ReactRouter.ts +262 -0
  428. package/src/react/websocket/hooks/useRoom.tsx +242 -0
  429. package/src/react/websocket/index.ts +7 -0
  430. package/src/redis/__tests__/redis.spec.ts +13 -0
  431. package/src/redis/index.ts +9 -25
  432. package/src/redis/providers/BunRedisProvider.ts +9 -0
  433. package/src/redis/providers/NodeRedisProvider.ts +8 -0
  434. package/src/redis/providers/RedisProvider.ts +16 -0
  435. package/src/retry/index.ts +11 -2
  436. package/src/router/index.ts +15 -0
  437. package/src/scheduler/index.ts +11 -2
  438. package/src/security/__tests__/BasicAuth.spec.ts +2 -0
  439. package/src/security/__tests__/ServerSecurityProvider.spec.ts +13 -5
  440. package/src/security/index.ts +15 -10
  441. package/src/security/interfaces/IssuerResolver.ts +27 -0
  442. package/src/security/primitives/$issuer.ts +55 -0
  443. package/src/security/providers/SecurityProvider.ts +179 -0
  444. package/src/security/providers/ServerBasicAuthProvider.ts +6 -2
  445. package/src/security/providers/ServerSecurityProvider.ts +36 -22
  446. package/src/server/auth/index.ts +12 -7
  447. package/src/server/cache/index.ts +7 -22
  448. package/src/server/compress/index.ts +10 -2
  449. package/src/server/cookies/index.ts +7 -5
  450. package/src/server/cookies/primitives/$cookie.ts +33 -11
  451. package/src/server/core/index.ts +16 -6
  452. package/src/server/core/interfaces/ServerRequest.ts +83 -1
  453. package/src/server/core/primitives/$action.spec.ts +1 -1
  454. package/src/server/core/primitives/$action.ts +8 -3
  455. package/src/server/core/providers/NodeHttpServerProvider.ts +9 -3
  456. package/src/server/core/services/ServerRequestParser.spec.ts +520 -0
  457. package/src/server/core/services/ServerRequestParser.ts +306 -13
  458. package/src/server/cors/index.ts +7 -21
  459. package/src/server/cors/primitives/$cors.ts +6 -2
  460. package/src/server/health/index.ts +8 -2
  461. package/src/server/helmet/index.ts +11 -3
  462. package/src/server/links/index.ts +11 -6
  463. package/src/server/metrics/index.ts +10 -3
  464. package/src/server/multipart/index.ts +9 -3
  465. package/src/server/proxy/index.ts +8 -2
  466. package/src/server/rate-limit/index.ts +21 -25
  467. package/src/server/rate-limit/primitives/$rateLimit.ts +6 -2
  468. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +38 -14
  469. package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +22 -56
  470. package/src/server/static/index.ts +8 -2
  471. package/src/server/static/providers/ServerStaticProvider.ts +1 -1
  472. package/src/server/swagger/index.ts +9 -4
  473. package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
  474. package/src/sms/index.ts +9 -5
  475. package/src/sms/providers/LocalSmsProvider.spec.ts +1 -1
  476. package/src/sms/providers/LocalSmsProvider.ts +1 -1
  477. package/src/system/index.browser.ts +11 -0
  478. package/src/system/index.ts +62 -0
  479. package/src/{file → system}/providers/FileSystemProvider.ts +16 -0
  480. package/src/{file → system}/providers/MemoryFileSystemProvider.ts +116 -3
  481. package/src/system/providers/MemoryShellProvider.ts +164 -0
  482. package/src/{file → system}/providers/NodeFileSystemProvider.spec.ts +2 -2
  483. package/src/{file → system}/providers/NodeFileSystemProvider.ts +36 -0
  484. package/src/system/providers/NodeShellProvider.ts +184 -0
  485. package/src/system/providers/ShellProvider.ts +74 -0
  486. package/src/{file → system}/services/FileDetector.spec.ts +2 -2
  487. package/src/thread/index.ts +11 -2
  488. package/src/topic/core/index.ts +12 -5
  489. package/src/vite/tasks/buildClient.ts +2 -7
  490. package/src/vite/tasks/buildServer.ts +17 -1
  491. package/src/websocket/index.ts +12 -8
  492. package/dist/file/index.d.ts.map +0 -1
  493. package/dist/file/index.js.map +0 -1
  494. package/src/cli/assets/mainServerTs.ts +0 -24
  495. package/src/cli/assets/webAppRouterTs.ts +0 -16
  496. package/src/cli/providers/ViteTemplateProvider.ts +0 -27
  497. package/src/file/index.ts +0 -43
  498. /package/src/cli/{assets → templates}/apiHelloControllerTs.ts +0 -0
  499. /package/src/cli/{assets → templates}/apiIndexTs.ts +0 -0
  500. /package/src/cli/{assets → templates}/biomeJson.ts +0 -0
  501. /package/src/cli/{assets → templates}/dummySpecTs.ts +0 -0
  502. /package/src/cli/{assets → templates}/editorconfig.ts +0 -0
  503. /package/src/cli/{assets → templates}/mainBrowserTs.ts +0 -0
  504. /package/src/cli/{assets → templates}/tsconfigJson.ts +0 -0
  505. /package/src/cli/{assets → templates}/webIndexTs.ts +0 -0
  506. /package/src/{file → system}/errors/FileError.ts +0 -0
  507. /package/src/{file → system}/services/FileDetector.ts +0 -0
@@ -20,6 +20,7 @@ import type {
20
20
  ServerRequest,
21
21
  ServerResponseBody,
22
22
  ServerRoute,
23
+ TRequestBody,
23
24
  } from "../interfaces/ServerRequest.ts";
24
25
  import { ServerProvider } from "../providers/ServerProvider.ts";
25
26
  import { ServerRouterProvider } from "../providers/ServerRouterProvider.ts";
@@ -445,7 +446,9 @@ export type ClientRequestEntry<
445
446
  };
446
447
 
447
448
  export type ClientRequestEntryContainer<TConfig extends RequestConfigSchema> = {
448
- body: TConfig["body"] extends TObject ? Static<TConfig["body"]> : undefined;
449
+ body: TConfig["body"] extends TRequestBody
450
+ ? Static<TConfig["body"]>
451
+ : undefined;
449
452
 
450
453
  params: TConfig["params"] extends TObject
451
454
  ? Static<TConfig["params"]>
@@ -453,11 +456,11 @@ export type ClientRequestEntryContainer<TConfig extends RequestConfigSchema> = {
453
456
 
454
457
  headers?: TConfig["headers"] extends TObject
455
458
  ? Static<TConfig["headers"]>
456
- : undefined;
459
+ : Record<string, string>;
457
460
 
458
461
  query?: TConfig["query"] extends TObject
459
462
  ? Partial<Static<TConfig["query"]>>
460
- : undefined;
463
+ : Record<string, string>;
461
464
  };
462
465
 
463
466
  export interface ClientRequestOptions extends FetchOptions {
@@ -465,6 +468,8 @@ export interface ClientRequestOptions extends FetchOptions {
465
468
  * Standard request fetch options.
466
469
  */
467
470
  request?: RequestInit;
471
+
472
+ query?: Record<string, string | number | boolean>;
468
473
  }
469
474
 
470
475
  export type ClientRequestResponse<TConfig extends RequestConfigSchema> =
@@ -35,15 +35,21 @@ export class NodeHttpServerProvider extends ServerProvider {
35
35
  protected readonly env = $env(envSchema);
36
36
  protected readonly router = $inject(ServerRouterProvider);
37
37
 
38
- /** Track active connections for fast shutdown */
38
+ /**
39
+ * Track active connections for fast shutdown.
40
+ */
39
41
  protected readonly connections = new Set<Socket>();
40
42
 
41
- /** Get number of active connections */
43
+ /**
44
+ * Get number of active connections.
45
+ */
42
46
  public getConnectionsCount(): number {
43
47
  return this.connections.size;
44
48
  }
45
49
 
46
- /** Server options */
50
+ /**
51
+ * Server options.
52
+ */
47
53
  public readonly options = {
48
54
  /**
49
55
  * Graceful shutdown timeout in ms.
@@ -0,0 +1,520 @@
1
+ import { Alepha } from "alepha";
2
+ import { describe, it } from "vitest";
3
+ import type { ServerRequestData } from "../interfaces/ServerRequest.ts";
4
+ import { ServerRequestParser } from "./ServerRequestParser.ts";
5
+
6
+ const createMockRequestData = (
7
+ headers: Record<string, string> = {},
8
+ ): ServerRequestData =>
9
+ ({
10
+ method: "GET",
11
+ url: new URL("https://example.com/test"),
12
+ headers,
13
+ query: {},
14
+ params: {},
15
+ raw: { node: undefined, web: undefined },
16
+ }) as ServerRequestData;
17
+
18
+ describe("ServerRequestParser", () => {
19
+ describe("getRequestIp", () => {
20
+ it("should use X-Forwarded-For when TRUST_PROXY is true", ({ expect }) => {
21
+ const alepha = Alepha.create({ env: { TRUST_PROXY: "true" } });
22
+ const parser = alepha.inject(ServerRequestParser);
23
+
24
+ const request = createMockRequestData({
25
+ "x-forwarded-for": "203.0.113.195, 70.41.3.18, 150.172.238.178",
26
+ });
27
+
28
+ expect(parser.getRequestIp(request)).toBe("203.0.113.195");
29
+ });
30
+
31
+ it("should use first IP from X-Forwarded-For chain", ({ expect }) => {
32
+ const alepha = Alepha.create({ env: { TRUST_PROXY: "true" } });
33
+ const parser = alepha.inject(ServerRequestParser);
34
+
35
+ const request = createMockRequestData({
36
+ "x-forwarded-for": "192.168.1.1, 10.0.0.1",
37
+ });
38
+
39
+ expect(parser.getRequestIp(request)).toBe("192.168.1.1");
40
+ });
41
+
42
+ it("should use X-Real-IP as fallback", ({ expect }) => {
43
+ const alepha = Alepha.create({ env: { TRUST_PROXY: "true" } });
44
+ const parser = alepha.inject(ServerRequestParser);
45
+
46
+ const request = createMockRequestData({
47
+ "x-real-ip": "192.168.1.100",
48
+ });
49
+
50
+ expect(parser.getRequestIp(request)).toBe("192.168.1.100");
51
+ });
52
+
53
+ it("should ignore proxy headers when TRUST_PROXY is false", ({
54
+ expect,
55
+ }) => {
56
+ const alepha = Alepha.create({ env: { TRUST_PROXY: "false" } });
57
+ const parser = alepha.inject(ServerRequestParser);
58
+
59
+ const request = createMockRequestData({
60
+ "x-forwarded-for": "203.0.113.195",
61
+ "x-real-ip": "192.168.1.100",
62
+ });
63
+
64
+ // Should return undefined since no raw connection IP
65
+ expect(parser.getRequestIp(request)).toBe(undefined);
66
+ });
67
+ });
68
+
69
+ describe("getRequestGeo", () => {
70
+ it("should parse Cloudflare geo headers", ({ expect }) => {
71
+ const alepha = Alepha.create();
72
+ const parser = alepha.inject(ServerRequestParser);
73
+
74
+ const request = createMockRequestData({
75
+ "cf-ipcountry": "US",
76
+ "cf-ipcity": "San Francisco",
77
+ "cf-region": "California",
78
+ "cf-iplatitude": "37.7749",
79
+ "cf-iplongitude": "-122.4194",
80
+ });
81
+
82
+ const geo = parser.getRequestGeo(request);
83
+ expect(geo.country).toBe("US");
84
+ expect(geo.city).toBe("San Francisco");
85
+ expect(geo.region).toBe("California");
86
+ expect(geo.latitude).toBe("37.7749");
87
+ expect(geo.longitude).toBe("-122.4194");
88
+ });
89
+
90
+ it("should parse Vercel geo headers", ({ expect }) => {
91
+ const alepha = Alepha.create();
92
+ const parser = alepha.inject(ServerRequestParser);
93
+
94
+ const request = createMockRequestData({
95
+ "x-vercel-ip-country": "FR",
96
+ "x-vercel-ip-city": "Paris",
97
+ "x-vercel-ip-country-region": "IDF",
98
+ "x-vercel-ip-latitude": "48.8566",
99
+ "x-vercel-ip-longitude": "2.3522",
100
+ });
101
+
102
+ const geo = parser.getRequestGeo(request);
103
+ expect(geo.country).toBe("FR");
104
+ expect(geo.city).toBe("Paris");
105
+ expect(geo.region).toBe("IDF");
106
+ expect(geo.latitude).toBe("48.8566");
107
+ expect(geo.longitude).toBe("2.3522");
108
+ });
109
+
110
+ it("should parse AWS CloudFront geo headers", ({ expect }) => {
111
+ const alepha = Alepha.create();
112
+ const parser = alepha.inject(ServerRequestParser);
113
+
114
+ const request = createMockRequestData({
115
+ "cloudfront-viewer-country": "JP",
116
+ });
117
+
118
+ const geo = parser.getRequestGeo(request);
119
+ expect(geo.country).toBe("JP");
120
+ });
121
+
122
+ it("should return empty geo for missing headers", ({ expect }) => {
123
+ const alepha = Alepha.create();
124
+ const parser = alepha.inject(ServerRequestParser);
125
+
126
+ const request = createMockRequestData({});
127
+
128
+ const geo = parser.getRequestGeo(request);
129
+ expect(geo.country).toBe(undefined);
130
+ expect(geo.city).toBe(undefined);
131
+ expect(geo.region).toBe(undefined);
132
+ expect(geo.latitude).toBe(undefined);
133
+ expect(geo.longitude).toBe(undefined);
134
+ });
135
+ });
136
+
137
+ describe("getIsBot", () => {
138
+ it("should detect Googlebot", ({ expect }) => {
139
+ const alepha = Alepha.create();
140
+ const parser = alepha.inject(ServerRequestParser);
141
+
142
+ const request = createMockRequestData({
143
+ "user-agent":
144
+ "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
145
+ });
146
+
147
+ expect(parser.getIsBot(request)).toBe(true);
148
+ });
149
+
150
+ it("should detect Bingbot", ({ expect }) => {
151
+ const alepha = Alepha.create();
152
+ const parser = alepha.inject(ServerRequestParser);
153
+
154
+ const request = createMockRequestData({
155
+ "user-agent":
156
+ "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)",
157
+ });
158
+
159
+ expect(parser.getIsBot(request)).toBe(true);
160
+ });
161
+
162
+ it("should detect curl", ({ expect }) => {
163
+ const alepha = Alepha.create();
164
+ const parser = alepha.inject(ServerRequestParser);
165
+
166
+ const request = createMockRequestData({
167
+ "user-agent": "curl/7.68.0",
168
+ });
169
+
170
+ expect(parser.getIsBot(request)).toBe(true);
171
+ });
172
+
173
+ it("should detect Python requests", ({ expect }) => {
174
+ const alepha = Alepha.create();
175
+ const parser = alepha.inject(ServerRequestParser);
176
+
177
+ const request = createMockRequestData({
178
+ "user-agent": "python-requests/2.25.1",
179
+ });
180
+
181
+ expect(parser.getIsBot(request)).toBe(true);
182
+ });
183
+
184
+ it("should detect HeadlessChrome", ({ expect }) => {
185
+ const alepha = Alepha.create();
186
+ const parser = alepha.inject(ServerRequestParser);
187
+
188
+ const request = createMockRequestData({
189
+ "user-agent":
190
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/91.0.4472.114 Safari/537.36",
191
+ });
192
+
193
+ expect(parser.getIsBot(request)).toBe(true);
194
+ });
195
+
196
+ it("should detect GPTBot", ({ expect }) => {
197
+ const alepha = Alepha.create();
198
+ const parser = alepha.inject(ServerRequestParser);
199
+
200
+ const request = createMockRequestData({
201
+ "user-agent":
202
+ "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.0; +https://openai.com/gptbot)",
203
+ });
204
+
205
+ expect(parser.getIsBot(request)).toBe(true);
206
+ });
207
+
208
+ it("should detect ClaudeBot", ({ expect }) => {
209
+ const alepha = Alepha.create();
210
+ const parser = alepha.inject(ServerRequestParser);
211
+
212
+ const request = createMockRequestData({
213
+ "user-agent": "ClaudeBot/1.0",
214
+ });
215
+
216
+ expect(parser.getIsBot(request)).toBe(true);
217
+ });
218
+
219
+ it("should not detect regular browser as bot", ({ expect }) => {
220
+ const alepha = Alepha.create();
221
+ const parser = alepha.inject(ServerRequestParser);
222
+
223
+ const request = createMockRequestData({
224
+ "user-agent":
225
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
226
+ });
227
+
228
+ expect(parser.getIsBot(request)).toBe(false);
229
+ });
230
+
231
+ it("should return false for missing user-agent", ({ expect }) => {
232
+ const alepha = Alepha.create();
233
+ const parser = alepha.inject(ServerRequestParser);
234
+
235
+ const request = createMockRequestData({});
236
+
237
+ expect(parser.getIsBot(request)).toBe(false);
238
+ });
239
+ });
240
+
241
+ describe("getIsMobile", () => {
242
+ it("should detect Android device", ({ expect }) => {
243
+ const alepha = Alepha.create();
244
+ const parser = alepha.inject(ServerRequestParser);
245
+
246
+ const request = createMockRequestData({
247
+ "user-agent":
248
+ "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36",
249
+ });
250
+
251
+ expect(parser.getIsMobile(request)).toBe(true);
252
+ });
253
+
254
+ it("should detect iPhone", ({ expect }) => {
255
+ const alepha = Alepha.create();
256
+ const parser = alepha.inject(ServerRequestParser);
257
+
258
+ const request = createMockRequestData({
259
+ "user-agent":
260
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1",
261
+ });
262
+
263
+ expect(parser.getIsMobile(request)).toBe(true);
264
+ });
265
+
266
+ it("should detect iPad", ({ expect }) => {
267
+ const alepha = Alepha.create();
268
+ const parser = alepha.inject(ServerRequestParser);
269
+
270
+ const request = createMockRequestData({
271
+ "user-agent":
272
+ "Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1",
273
+ });
274
+
275
+ expect(parser.getIsMobile(request)).toBe(true);
276
+ });
277
+
278
+ it("should detect Windows Phone", ({ expect }) => {
279
+ const alepha = Alepha.create();
280
+ const parser = alepha.inject(ServerRequestParser);
281
+
282
+ const request = createMockRequestData({
283
+ "user-agent":
284
+ "Mozilla/5.0 (Windows Phone 10.0; Android 6.0.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Mobile Safari/537.36 Edge/15.15254",
285
+ });
286
+
287
+ expect(parser.getIsMobile(request)).toBe(true);
288
+ });
289
+
290
+ it("should not detect desktop as mobile", ({ expect }) => {
291
+ const alepha = Alepha.create();
292
+ const parser = alepha.inject(ServerRequestParser);
293
+
294
+ const request = createMockRequestData({
295
+ "user-agent":
296
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
297
+ });
298
+
299
+ expect(parser.getIsMobile(request)).toBe(false);
300
+ });
301
+
302
+ it("should return false for missing user-agent", ({ expect }) => {
303
+ const alepha = Alepha.create();
304
+ const parser = alepha.inject(ServerRequestParser);
305
+
306
+ const request = createMockRequestData({});
307
+
308
+ expect(parser.getIsMobile(request)).toBe(false);
309
+ });
310
+ });
311
+
312
+ describe("getProtocol", () => {
313
+ it("should use X-Forwarded-Proto header", ({ expect }) => {
314
+ const alepha = Alepha.create();
315
+ const parser = alepha.inject(ServerRequestParser);
316
+
317
+ const request = createMockRequestData({
318
+ "x-forwarded-proto": "https",
319
+ });
320
+
321
+ expect(parser.getProtocol(request)).toBe("https");
322
+ });
323
+
324
+ it("should handle HTTP from X-Forwarded-Proto", ({ expect }) => {
325
+ const alepha = Alepha.create();
326
+ const parser = alepha.inject(ServerRequestParser);
327
+
328
+ const request = createMockRequestData({
329
+ "x-forwarded-proto": "http",
330
+ });
331
+
332
+ expect(parser.getProtocol(request)).toBe("http");
333
+ });
334
+
335
+ it("should parse Cloudflare CF-Visitor header", ({ expect }) => {
336
+ const alepha = Alepha.create();
337
+ const parser = alepha.inject(ServerRequestParser);
338
+
339
+ const request = createMockRequestData({
340
+ "cf-visitor": '{"scheme":"https"}',
341
+ });
342
+
343
+ expect(parser.getProtocol(request)).toBe("https");
344
+ });
345
+
346
+ it("should handle invalid CF-Visitor JSON gracefully", ({ expect }) => {
347
+ const alepha = Alepha.create();
348
+ const parser = alepha.inject(ServerRequestParser);
349
+
350
+ const request = createMockRequestData({
351
+ "cf-visitor": "invalid-json",
352
+ });
353
+
354
+ // Should fall back to URL scheme (http since mock URL is https)
355
+ expect(parser.getProtocol(request)).toBe("https");
356
+ });
357
+
358
+ it("should use URL scheme as fallback", ({ expect }) => {
359
+ const alepha = Alepha.create();
360
+ const parser = alepha.inject(ServerRequestParser);
361
+
362
+ const request = createMockRequestData({});
363
+
364
+ // Our mock URL is https://example.com/test
365
+ expect(parser.getProtocol(request)).toBe("https");
366
+ });
367
+
368
+ it("should default to http when URL is http", ({ expect }) => {
369
+ const alepha = Alepha.create();
370
+ const parser = alepha.inject(ServerRequestParser);
371
+
372
+ const request = {
373
+ ...createMockRequestData({}),
374
+ url: new URL("http://example.com/test"),
375
+ };
376
+
377
+ expect(parser.getProtocol(request)).toBe("http");
378
+ });
379
+ });
380
+
381
+ describe("getLanguage", () => {
382
+ it("should parse simple Accept-Language", ({ expect }) => {
383
+ const alepha = Alepha.create();
384
+ const parser = alepha.inject(ServerRequestParser);
385
+
386
+ const request = createMockRequestData({
387
+ "accept-language": "en-US",
388
+ });
389
+
390
+ expect(parser.getLanguage(request)).toBe("en-US");
391
+ });
392
+
393
+ it("should return first language from list", ({ expect }) => {
394
+ const alepha = Alepha.create();
395
+ const parser = alepha.inject(ServerRequestParser);
396
+
397
+ const request = createMockRequestData({
398
+ "accept-language": "en-US,en;q=0.9,fr;q=0.8",
399
+ });
400
+
401
+ expect(parser.getLanguage(request)).toBe("en-US");
402
+ });
403
+
404
+ it("should handle quality values", ({ expect }) => {
405
+ const alepha = Alepha.create();
406
+ const parser = alepha.inject(ServerRequestParser);
407
+
408
+ const request = createMockRequestData({
409
+ "accept-language": "fr;q=0.9,en;q=0.8",
410
+ });
411
+
412
+ expect(parser.getLanguage(request)).toBe("fr");
413
+ });
414
+
415
+ it("should return undefined for missing header", ({ expect }) => {
416
+ const alepha = Alepha.create();
417
+ const parser = alepha.inject(ServerRequestParser);
418
+
419
+ const request = createMockRequestData({});
420
+
421
+ expect(parser.getLanguage(request)).toBe(undefined);
422
+ });
423
+
424
+ it("should handle complex Accept-Language", ({ expect }) => {
425
+ const alepha = Alepha.create();
426
+ const parser = alepha.inject(ServerRequestParser);
427
+
428
+ const request = createMockRequestData({
429
+ "accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
430
+ });
431
+
432
+ expect(parser.getLanguage(request)).toBe("zh-CN");
433
+ });
434
+ });
435
+
436
+ describe("getReferer", () => {
437
+ it("should parse valid referer URL", ({ expect }) => {
438
+ const alepha = Alepha.create();
439
+ const parser = alepha.inject(ServerRequestParser);
440
+
441
+ const request = createMockRequestData({
442
+ referer: "https://google.com/search?q=test",
443
+ });
444
+
445
+ const referer = parser.getReferer(request);
446
+ expect(referer?.url).toBe("https://google.com/search?q=test");
447
+ expect(referer?.hostname).toBe("google.com");
448
+ expect(referer?.pathname).toBe("/search");
449
+ });
450
+
451
+ it("should handle referrer header (alternative spelling)", ({ expect }) => {
452
+ const alepha = Alepha.create();
453
+ const parser = alepha.inject(ServerRequestParser);
454
+
455
+ const request = createMockRequestData({
456
+ referrer: "https://example.org/page",
457
+ });
458
+
459
+ const referer = parser.getReferer(request);
460
+ expect(referer?.url).toBe("https://example.org/page");
461
+ expect(referer?.hostname).toBe("example.org");
462
+ expect(referer?.pathname).toBe("/page");
463
+ });
464
+
465
+ it("should prefer referer over referrer", ({ expect }) => {
466
+ const alepha = Alepha.create();
467
+ const parser = alepha.inject(ServerRequestParser);
468
+
469
+ const request = createMockRequestData({
470
+ referer: "https://first.com/",
471
+ referrer: "https://second.com/",
472
+ });
473
+
474
+ const referer = parser.getReferer(request);
475
+ expect(referer?.hostname).toBe("first.com");
476
+ });
477
+
478
+ it("should return undefined for missing header", ({ expect }) => {
479
+ const alepha = Alepha.create();
480
+ const parser = alepha.inject(ServerRequestParser);
481
+
482
+ const request = createMockRequestData({});
483
+
484
+ expect(parser.getReferer(request)).toBe(undefined);
485
+ });
486
+
487
+ it("should return undefined for invalid URL", ({ expect }) => {
488
+ const alepha = Alepha.create();
489
+ const parser = alepha.inject(ServerRequestParser);
490
+
491
+ const request = createMockRequestData({
492
+ referer: "not-a-valid-url",
493
+ });
494
+
495
+ expect(parser.getReferer(request)).toBe(undefined);
496
+ });
497
+ });
498
+
499
+ describe("getRequestId", () => {
500
+ it("should extract X-Request-ID header", ({ expect }) => {
501
+ const alepha = Alepha.create();
502
+ const parser = alepha.inject(ServerRequestParser);
503
+
504
+ const request = createMockRequestData({
505
+ "x-request-id": "abc-123-def",
506
+ });
507
+
508
+ expect(parser.getRequestId(request)).toBe("abc-123-def");
509
+ });
510
+
511
+ it("should return undefined for missing header", ({ expect }) => {
512
+ const alepha = Alepha.create();
513
+ const parser = alepha.inject(ServerRequestParser);
514
+
515
+ const request = createMockRequestData({});
516
+
517
+ expect(parser.getRequestId(request)).toBe(undefined);
518
+ });
519
+ });
520
+ });