alepha 0.15.1 → 0.15.3

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 (523) hide show
  1. package/README.md +68 -80
  2. package/dist/api/audits/index.d.ts +10 -33
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +10 -33
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +10 -3
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +10 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +162 -155
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/jobs/index.js +10 -3
  13. package/dist/api/jobs/index.js.map +1 -1
  14. package/dist/api/keys/index.d.ts +413 -0
  15. package/dist/api/keys/index.d.ts.map +1 -0
  16. package/dist/api/keys/index.js +476 -0
  17. package/dist/api/keys/index.js.map +1 -0
  18. package/dist/api/notifications/index.d.ts +10 -4
  19. package/dist/api/notifications/index.d.ts.map +1 -1
  20. package/dist/api/notifications/index.js +10 -4
  21. package/dist/api/notifications/index.js.map +1 -1
  22. package/dist/api/parameters/index.d.ts +43 -50
  23. package/dist/api/parameters/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.js +30 -37
  25. package/dist/api/parameters/index.js.map +1 -1
  26. package/dist/api/users/index.d.ts +1081 -760
  27. package/dist/api/users/index.d.ts.map +1 -1
  28. package/dist/api/users/index.js +2539 -218
  29. package/dist/api/users/index.js.map +1 -1
  30. package/dist/api/verifications/index.d.ts +138 -132
  31. package/dist/api/verifications/index.d.ts.map +1 -1
  32. package/dist/api/verifications/index.js +12 -4
  33. package/dist/api/verifications/index.js.map +1 -1
  34. package/dist/batch/index.d.ts +20 -40
  35. package/dist/batch/index.d.ts.map +1 -1
  36. package/dist/batch/index.js +31 -44
  37. package/dist/batch/index.js.map +1 -1
  38. package/dist/bucket/index.d.ts +440 -8
  39. package/dist/bucket/index.d.ts.map +1 -1
  40. package/dist/bucket/index.js +1861 -12
  41. package/dist/bucket/index.js.map +1 -1
  42. package/dist/cache/core/index.d.ts +179 -7
  43. package/dist/cache/core/index.d.ts.map +1 -1
  44. package/dist/cache/core/index.js +213 -7
  45. package/dist/cache/core/index.js.map +1 -1
  46. package/dist/cache/redis/index.d.ts +1 -0
  47. package/dist/cache/redis/index.d.ts.map +1 -1
  48. package/dist/cache/redis/index.js +4 -0
  49. package/dist/cache/redis/index.js.map +1 -1
  50. package/dist/cli/index.d.ts +638 -5645
  51. package/dist/cli/index.d.ts.map +1 -1
  52. package/dist/cli/index.js +2550 -368
  53. package/dist/cli/index.js.map +1 -1
  54. package/dist/command/index.d.ts +203 -45
  55. package/dist/command/index.d.ts.map +1 -1
  56. package/dist/command/index.js +2060 -71
  57. package/dist/command/index.js.map +1 -1
  58. package/dist/core/index.browser.js +70 -40
  59. package/dist/core/index.browser.js.map +1 -1
  60. package/dist/core/index.d.ts +34 -13
  61. package/dist/core/index.d.ts.map +1 -1
  62. package/dist/core/index.js +90 -40
  63. package/dist/core/index.js.map +1 -1
  64. package/dist/core/index.native.js +70 -40
  65. package/dist/core/index.native.js.map +1 -1
  66. package/dist/datetime/index.d.ts +15 -0
  67. package/dist/datetime/index.d.ts.map +1 -1
  68. package/dist/datetime/index.js +15 -0
  69. package/dist/datetime/index.js.map +1 -1
  70. package/dist/email/index.d.ts +323 -20
  71. package/dist/email/index.d.ts.map +1 -1
  72. package/dist/email/index.js +1857 -7
  73. package/dist/email/index.js.map +1 -1
  74. package/dist/fake/index.d.ts +90 -8
  75. package/dist/fake/index.d.ts.map +1 -1
  76. package/dist/fake/index.js +91 -20
  77. package/dist/fake/index.js.map +1 -1
  78. package/dist/lock/core/index.d.ts +11 -4
  79. package/dist/lock/core/index.d.ts.map +1 -1
  80. package/dist/lock/core/index.js +11 -4
  81. package/dist/lock/core/index.js.map +1 -1
  82. package/dist/logger/index.d.ts +17 -66
  83. package/dist/logger/index.d.ts.map +1 -1
  84. package/dist/logger/index.js +14 -63
  85. package/dist/logger/index.js.map +1 -1
  86. package/dist/mcp/index.d.ts +10 -30
  87. package/dist/mcp/index.d.ts.map +1 -1
  88. package/dist/mcp/index.js +12 -35
  89. package/dist/mcp/index.js.map +1 -1
  90. package/dist/orm/index.browser.js +3 -3
  91. package/dist/orm/index.browser.js.map +1 -1
  92. package/dist/orm/index.bun.js +39 -20
  93. package/dist/orm/index.bun.js.map +1 -1
  94. package/dist/orm/index.d.ts +517 -540
  95. package/dist/orm/index.d.ts.map +1 -1
  96. package/dist/orm/index.js +58 -71
  97. package/dist/orm/index.js.map +1 -1
  98. package/dist/queue/core/index.d.ts +18 -10
  99. package/dist/queue/core/index.d.ts.map +1 -1
  100. package/dist/queue/core/index.js +14 -6
  101. package/dist/queue/core/index.js.map +1 -1
  102. package/dist/react/auth/index.browser.js +108 -0
  103. package/dist/react/auth/index.browser.js.map +1 -0
  104. package/dist/react/auth/index.d.ts +100 -0
  105. package/dist/react/auth/index.d.ts.map +1 -0
  106. package/dist/react/auth/index.js +145 -0
  107. package/dist/react/auth/index.js.map +1 -0
  108. package/dist/react/core/index.d.ts +469 -0
  109. package/dist/react/core/index.d.ts.map +1 -0
  110. package/dist/react/core/index.js +464 -0
  111. package/dist/react/core/index.js.map +1 -0
  112. package/dist/react/form/index.d.ts +232 -0
  113. package/dist/react/form/index.d.ts.map +1 -0
  114. package/dist/react/form/index.js +432 -0
  115. package/dist/react/form/index.js.map +1 -0
  116. package/dist/react/head/index.browser.js +423 -0
  117. package/dist/react/head/index.browser.js.map +1 -0
  118. package/dist/react/head/index.d.ts +288 -0
  119. package/dist/react/head/index.d.ts.map +1 -0
  120. package/dist/react/head/index.js +465 -0
  121. package/dist/react/head/index.js.map +1 -0
  122. package/dist/react/i18n/index.d.ts +175 -0
  123. package/dist/react/i18n/index.d.ts.map +1 -0
  124. package/dist/react/i18n/index.js +224 -0
  125. package/dist/react/i18n/index.js.map +1 -0
  126. package/dist/react/router/index.browser.js +1974 -0
  127. package/dist/react/router/index.browser.js.map +1 -0
  128. package/dist/react/router/index.d.ts +1956 -0
  129. package/dist/react/router/index.d.ts.map +1 -0
  130. package/dist/react/router/index.js +4722 -0
  131. package/dist/react/router/index.js.map +1 -0
  132. package/dist/react/websocket/index.d.ts +117 -0
  133. package/dist/react/websocket/index.d.ts.map +1 -0
  134. package/dist/react/websocket/index.js +107 -0
  135. package/dist/react/websocket/index.js.map +1 -0
  136. package/dist/redis/index.bun.js +4 -0
  137. package/dist/redis/index.bun.js.map +1 -1
  138. package/dist/redis/index.d.ts +41 -44
  139. package/dist/redis/index.d.ts.map +1 -1
  140. package/dist/redis/index.js +16 -25
  141. package/dist/redis/index.js.map +1 -1
  142. package/dist/retry/index.d.ts +11 -2
  143. package/dist/retry/index.d.ts.map +1 -1
  144. package/dist/retry/index.js +11 -2
  145. package/dist/retry/index.js.map +1 -1
  146. package/dist/scheduler/index.d.ts +11 -2
  147. package/dist/scheduler/index.d.ts.map +1 -1
  148. package/dist/scheduler/index.js +11 -2
  149. package/dist/scheduler/index.js.map +1 -1
  150. package/dist/security/index.d.ts +140 -49
  151. package/dist/security/index.d.ts.map +1 -1
  152. package/dist/security/index.js +164 -32
  153. package/dist/security/index.js.map +1 -1
  154. package/dist/server/auth/index.d.ts +12 -7
  155. package/dist/server/auth/index.d.ts.map +1 -1
  156. package/dist/server/auth/index.js +12 -7
  157. package/dist/server/auth/index.js.map +1 -1
  158. package/dist/server/cache/index.d.ts +7 -22
  159. package/dist/server/cache/index.d.ts.map +1 -1
  160. package/dist/server/cache/index.js +7 -22
  161. package/dist/server/cache/index.js.map +1 -1
  162. package/dist/server/compress/index.d.ts +10 -2
  163. package/dist/server/compress/index.d.ts.map +1 -1
  164. package/dist/server/compress/index.js +10 -2
  165. package/dist/server/compress/index.js.map +1 -1
  166. package/dist/server/cookies/index.d.ts +40 -16
  167. package/dist/server/cookies/index.d.ts.map +1 -1
  168. package/dist/server/cookies/index.js +7 -5
  169. package/dist/server/cookies/index.js.map +1 -1
  170. package/dist/server/core/index.d.ts +124 -23
  171. package/dist/server/core/index.d.ts.map +1 -1
  172. package/dist/server/core/index.js +231 -14
  173. package/dist/server/core/index.js.map +1 -1
  174. package/dist/server/cors/index.d.ts +13 -23
  175. package/dist/server/cors/index.d.ts.map +1 -1
  176. package/dist/server/cors/index.js +7 -21
  177. package/dist/server/cors/index.js.map +1 -1
  178. package/dist/server/health/index.d.ts +8 -2
  179. package/dist/server/health/index.d.ts.map +1 -1
  180. package/dist/server/health/index.js +8 -2
  181. package/dist/server/health/index.js.map +1 -1
  182. package/dist/server/helmet/index.d.ts +11 -3
  183. package/dist/server/helmet/index.d.ts.map +1 -1
  184. package/dist/server/helmet/index.js +11 -3
  185. package/dist/server/helmet/index.js.map +1 -1
  186. package/dist/server/links/index.d.ts +11 -6
  187. package/dist/server/links/index.d.ts.map +1 -1
  188. package/dist/server/links/index.js +11 -6
  189. package/dist/server/links/index.js.map +1 -1
  190. package/dist/server/metrics/index.d.ts +10 -3
  191. package/dist/server/metrics/index.d.ts.map +1 -1
  192. package/dist/server/metrics/index.js +10 -3
  193. package/dist/server/metrics/index.js.map +1 -1
  194. package/dist/server/multipart/index.d.ts +9 -3
  195. package/dist/server/multipart/index.d.ts.map +1 -1
  196. package/dist/server/multipart/index.js +9 -3
  197. package/dist/server/multipart/index.js.map +1 -1
  198. package/dist/server/proxy/index.d.ts +8 -2
  199. package/dist/server/proxy/index.d.ts.map +1 -1
  200. package/dist/server/proxy/index.js +8 -2
  201. package/dist/server/proxy/index.js.map +1 -1
  202. package/dist/server/rate-limit/index.d.ts +30 -35
  203. package/dist/server/rate-limit/index.d.ts.map +1 -1
  204. package/dist/server/rate-limit/index.js +18 -55
  205. package/dist/server/rate-limit/index.js.map +1 -1
  206. package/dist/server/static/index.d.ts +137 -4
  207. package/dist/server/static/index.d.ts.map +1 -1
  208. package/dist/server/static/index.js +1853 -5
  209. package/dist/server/static/index.js.map +1 -1
  210. package/dist/server/swagger/index.d.ts +309 -6
  211. package/dist/server/swagger/index.d.ts.map +1 -1
  212. package/dist/server/swagger/index.js +1854 -6
  213. package/dist/server/swagger/index.js.map +1 -1
  214. package/dist/sms/index.d.ts +309 -7
  215. package/dist/sms/index.d.ts.map +1 -1
  216. package/dist/sms/index.js +1856 -7
  217. package/dist/sms/index.js.map +1 -1
  218. package/dist/system/index.browser.js +1218 -0
  219. package/dist/system/index.browser.js.map +1 -0
  220. package/dist/{file → system}/index.d.ts +343 -16
  221. package/dist/system/index.d.ts.map +1 -0
  222. package/dist/{file → system}/index.js +419 -22
  223. package/dist/system/index.js.map +1 -0
  224. package/dist/thread/index.d.ts +11 -2
  225. package/dist/thread/index.d.ts.map +1 -1
  226. package/dist/thread/index.js +11 -2
  227. package/dist/thread/index.js.map +1 -1
  228. package/dist/topic/core/index.d.ts +12 -5
  229. package/dist/topic/core/index.d.ts.map +1 -1
  230. package/dist/topic/core/index.js +12 -5
  231. package/dist/topic/core/index.js.map +1 -1
  232. package/dist/vite/index.d.ts +5 -6272
  233. package/dist/vite/index.d.ts.map +1 -1
  234. package/dist/vite/index.js +23 -10
  235. package/dist/vite/index.js.map +1 -1
  236. package/dist/websocket/index.d.ts +12 -8
  237. package/dist/websocket/index.d.ts.map +1 -1
  238. package/dist/websocket/index.js +12 -8
  239. package/dist/websocket/index.js.map +1 -1
  240. package/package.json +82 -11
  241. package/src/api/audits/index.ts +10 -33
  242. package/src/api/files/__tests__/$bucket.spec.ts +1 -1
  243. package/src/api/files/controllers/AdminFileStatsController.spec.ts +1 -1
  244. package/src/api/files/controllers/FileController.spec.ts +1 -1
  245. package/src/api/files/index.ts +10 -3
  246. package/src/api/files/jobs/FileJobs.spec.ts +1 -1
  247. package/src/api/files/services/FileService.spec.ts +1 -1
  248. package/src/api/jobs/index.ts +10 -3
  249. package/src/api/keys/controllers/AdminApiKeyController.ts +75 -0
  250. package/src/api/keys/controllers/ApiKeyController.ts +103 -0
  251. package/src/api/keys/entities/apiKeyEntity.ts +41 -0
  252. package/src/api/keys/index.ts +49 -0
  253. package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +7 -0
  254. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +17 -0
  255. package/src/api/keys/schemas/createApiKeyBodySchema.ts +7 -0
  256. package/src/api/keys/schemas/createApiKeyResponseSchema.ts +11 -0
  257. package/src/api/keys/schemas/listApiKeyResponseSchema.ts +15 -0
  258. package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +5 -0
  259. package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +5 -0
  260. package/src/api/keys/services/ApiKeyService.spec.ts +553 -0
  261. package/src/api/keys/services/ApiKeyService.ts +306 -0
  262. package/src/api/logs/TODO.md +55 -0
  263. package/src/api/notifications/index.ts +10 -4
  264. package/src/api/parameters/index.ts +9 -30
  265. package/src/api/parameters/primitives/$config.ts +12 -4
  266. package/src/api/parameters/services/ConfigStore.ts +9 -3
  267. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1035 -0
  268. package/src/api/users/__tests__/ApiKeys.spec.ts +401 -0
  269. package/src/api/users/index.ts +14 -3
  270. package/src/api/users/primitives/$realm.ts +33 -5
  271. package/src/api/users/providers/RealmProvider.ts +1 -12
  272. package/src/api/users/services/SessionService.ts +1 -1
  273. package/src/api/verifications/controllers/VerificationController.ts +2 -0
  274. package/src/api/verifications/index.ts +10 -4
  275. package/src/batch/index.ts +9 -36
  276. package/src/batch/primitives/$batch.ts +0 -8
  277. package/src/batch/providers/BatchProvider.ts +29 -2
  278. package/src/bucket/__tests__/shared.ts +1 -1
  279. package/src/bucket/index.ts +13 -6
  280. package/src/bucket/primitives/$bucket.ts +1 -1
  281. package/src/bucket/providers/LocalFileStorageProvider.ts +1 -1
  282. package/src/bucket/providers/MemoryFileStorageProvider.ts +1 -1
  283. package/src/cache/core/__tests__/shared.ts +30 -0
  284. package/src/cache/core/index.ts +11 -6
  285. package/src/cache/core/primitives/$cache.spec.ts +5 -0
  286. package/src/cache/core/providers/CacheProvider.ts +17 -0
  287. package/src/cache/core/providers/MemoryCacheProvider.ts +300 -1
  288. package/src/cache/redis/__tests__/cache-redis.spec.ts +5 -0
  289. package/src/cache/redis/providers/RedisCacheProvider.ts +9 -0
  290. package/src/cli/apps/AlephaCli.ts +1 -14
  291. package/src/cli/apps/AlephaPackageBuilderCli.ts +10 -1
  292. package/src/cli/atoms/buildOptions.ts +99 -9
  293. package/src/cli/commands/build.ts +150 -37
  294. package/src/cli/commands/db.ts +22 -18
  295. package/src/cli/commands/deploy.ts +1 -1
  296. package/src/cli/commands/dev.ts +1 -20
  297. package/src/cli/commands/gen/env.ts +5 -2
  298. package/src/cli/commands/gen/openapi.ts +5 -2
  299. package/src/cli/commands/init.spec.ts +588 -0
  300. package/src/cli/commands/init.ts +115 -58
  301. package/src/cli/commands/lint.ts +7 -1
  302. package/src/cli/commands/typecheck.ts +11 -0
  303. package/src/cli/providers/AppEntryProvider.ts +1 -1
  304. package/src/cli/providers/ViteBuildProvider.ts +8 -50
  305. package/src/cli/providers/ViteDevServerProvider.ts +35 -16
  306. package/src/cli/services/AlephaCliUtils.ts +52 -121
  307. package/src/cli/services/PackageManagerUtils.ts +129 -11
  308. package/src/cli/services/ProjectScaffolder.spec.ts +97 -0
  309. package/src/cli/services/ProjectScaffolder.ts +148 -81
  310. package/src/cli/services/ViteUtils.ts +82 -0
  311. package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +37 -24
  312. package/src/cli/templates/apiAppSecurityTs.ts +11 -0
  313. package/src/cli/templates/apiIndexTs.ts +30 -0
  314. package/src/cli/templates/gitignore.ts +39 -0
  315. package/src/cli/{assets → templates}/mainCss.ts +11 -2
  316. package/src/cli/templates/mainServerTs.ts +33 -0
  317. package/src/cli/templates/webAppRouterTs.ts +74 -0
  318. package/src/cli/templates/webHelloComponentTsx.ts +30 -0
  319. package/src/command/helpers/Runner.spec.ts +139 -0
  320. package/src/command/helpers/Runner.ts +7 -22
  321. package/src/command/index.ts +12 -4
  322. package/src/command/providers/CliProvider.spec.ts +1392 -0
  323. package/src/command/providers/CliProvider.ts +320 -47
  324. package/src/core/Alepha.ts +34 -27
  325. package/src/core/__tests__/Alepha-start.spec.ts +4 -4
  326. package/src/core/helpers/jsonSchemaToTypeBox.spec.ts +771 -0
  327. package/src/core/helpers/jsonSchemaToTypeBox.ts +62 -10
  328. package/src/core/index.shared.ts +1 -0
  329. package/src/core/index.ts +20 -0
  330. package/src/core/providers/EventManager.spec.ts +0 -71
  331. package/src/core/providers/EventManager.ts +3 -15
  332. package/src/core/providers/Json.ts +2 -14
  333. package/src/datetime/index.ts +15 -0
  334. package/src/email/index.ts +10 -5
  335. package/src/email/providers/LocalEmailProvider.spec.ts +1 -1
  336. package/src/email/providers/LocalEmailProvider.ts +1 -1
  337. package/src/fake/__tests__/keyName.example.ts +1 -1
  338. package/src/fake/__tests__/keyName.spec.ts +5 -5
  339. package/src/fake/index.ts +9 -6
  340. package/src/fake/providers/FakeProvider.spec.ts +258 -40
  341. package/src/fake/providers/FakeProvider.ts +133 -19
  342. package/src/lock/core/index.ts +11 -4
  343. package/src/logger/index.ts +17 -66
  344. package/src/mcp/index.ts +10 -27
  345. package/src/mcp/transports/SseMcpTransport.ts +0 -11
  346. package/src/orm/__tests__/PostgresProvider.spec.ts +2 -2
  347. package/src/orm/index.browser.ts +2 -2
  348. package/src/orm/index.bun.ts +5 -3
  349. package/src/orm/index.ts +23 -53
  350. package/src/orm/providers/drivers/BunSqliteProvider.ts +5 -1
  351. package/src/orm/providers/drivers/CloudflareD1Provider.ts +57 -30
  352. package/src/orm/providers/drivers/DatabaseProvider.ts +9 -1
  353. package/src/orm/providers/drivers/NodeSqliteProvider.ts +4 -1
  354. package/src/orm/services/Repository.ts +7 -3
  355. package/src/queue/core/index.ts +14 -6
  356. package/src/react/auth/__tests__/$auth.spec.ts +202 -0
  357. package/src/react/auth/hooks/useAuth.ts +32 -0
  358. package/src/react/auth/index.browser.ts +13 -0
  359. package/src/react/auth/index.shared.ts +2 -0
  360. package/src/react/auth/index.ts +48 -0
  361. package/src/react/auth/providers/ReactAuthProvider.ts +16 -0
  362. package/src/react/auth/services/ReactAuth.ts +135 -0
  363. package/src/react/core/__tests__/Router.spec.tsx +169 -0
  364. package/src/react/core/components/ClientOnly.tsx +49 -0
  365. package/src/react/core/components/ErrorBoundary.tsx +73 -0
  366. package/src/react/core/contexts/AlephaContext.ts +7 -0
  367. package/src/react/core/contexts/AlephaProvider.tsx +42 -0
  368. package/src/react/core/hooks/useAction.browser.spec.tsx +569 -0
  369. package/src/react/core/hooks/useAction.ts +480 -0
  370. package/src/react/core/hooks/useAlepha.ts +26 -0
  371. package/src/react/core/hooks/useClient.ts +17 -0
  372. package/src/react/core/hooks/useEvents.ts +51 -0
  373. package/src/react/core/hooks/useInject.ts +12 -0
  374. package/src/react/core/hooks/useStore.ts +52 -0
  375. package/src/react/core/index.ts +90 -0
  376. package/src/react/form/components/FormState.tsx +17 -0
  377. package/src/react/form/errors/FormValidationError.ts +18 -0
  378. package/src/react/form/hooks/useForm.browser.spec.tsx +366 -0
  379. package/src/react/form/hooks/useForm.ts +47 -0
  380. package/src/react/form/hooks/useFormState.ts +130 -0
  381. package/src/react/form/index.ts +44 -0
  382. package/src/react/form/services/FormModel.ts +614 -0
  383. package/src/react/head/helpers/SeoExpander.spec.ts +203 -0
  384. package/src/react/head/helpers/SeoExpander.ts +142 -0
  385. package/src/react/head/hooks/useHead.spec.tsx +288 -0
  386. package/src/react/head/hooks/useHead.ts +62 -0
  387. package/src/react/head/index.browser.ts +26 -0
  388. package/src/react/head/index.ts +44 -0
  389. package/src/react/head/interfaces/Head.ts +105 -0
  390. package/src/react/head/primitives/$head.ts +25 -0
  391. package/src/react/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
  392. package/src/react/head/providers/BrowserHeadProvider.ts +212 -0
  393. package/src/react/head/providers/HeadProvider.ts +168 -0
  394. package/src/react/head/providers/ServerHeadProvider.ts +31 -0
  395. package/src/react/i18n/__tests__/integration.spec.tsx +239 -0
  396. package/src/react/i18n/components/Localize.spec.tsx +357 -0
  397. package/src/react/i18n/components/Localize.tsx +35 -0
  398. package/src/react/i18n/hooks/useI18n.browser.spec.tsx +438 -0
  399. package/src/react/i18n/hooks/useI18n.ts +18 -0
  400. package/src/react/i18n/index.ts +41 -0
  401. package/src/react/i18n/primitives/$dictionary.ts +69 -0
  402. package/src/react/i18n/providers/I18nProvider.spec.ts +389 -0
  403. package/src/react/i18n/providers/I18nProvider.ts +278 -0
  404. package/src/react/router/__tests__/page-head-browser.browser.spec.ts +95 -0
  405. package/src/react/router/__tests__/page-head.spec.ts +48 -0
  406. package/src/react/router/__tests__/seo-head.spec.ts +125 -0
  407. package/src/react/router/atoms/ssrManifestAtom.ts +58 -0
  408. package/src/react/router/components/ErrorViewer.tsx +872 -0
  409. package/src/react/router/components/Link.tsx +23 -0
  410. package/src/react/router/components/NestedView.tsx +223 -0
  411. package/src/react/router/components/NotFound.tsx +30 -0
  412. package/src/react/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
  413. package/src/react/router/contexts/RouterLayerContext.ts +12 -0
  414. package/src/react/router/errors/Redirection.ts +28 -0
  415. package/src/react/router/hooks/useActive.ts +52 -0
  416. package/src/react/router/hooks/useQueryParams.ts +63 -0
  417. package/src/react/router/hooks/useRouter.ts +20 -0
  418. package/src/react/router/hooks/useRouterState.ts +11 -0
  419. package/src/react/router/index.browser.ts +45 -0
  420. package/src/react/router/index.shared.ts +19 -0
  421. package/src/react/router/index.ts +146 -0
  422. package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
  423. package/src/react/router/primitives/$page.spec.tsx +676 -0
  424. package/src/react/router/primitives/$page.ts +489 -0
  425. package/src/react/router/providers/ReactBrowserProvider.ts +312 -0
  426. package/src/react/router/providers/ReactBrowserRendererProvider.ts +25 -0
  427. package/src/react/router/providers/ReactBrowserRouterProvider.ts +168 -0
  428. package/src/react/router/providers/ReactPageProvider.ts +726 -0
  429. package/src/react/router/providers/ReactPreloadProvider.spec.ts +142 -0
  430. package/src/react/router/providers/ReactPreloadProvider.ts +85 -0
  431. package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
  432. package/src/react/router/providers/ReactServerProvider.ts +487 -0
  433. package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
  434. package/src/react/router/providers/ReactServerTemplateProvider.ts +542 -0
  435. package/src/react/router/providers/SSRManifestProvider.ts +334 -0
  436. package/src/react/router/services/ReactPageServerService.ts +48 -0
  437. package/src/react/router/services/ReactPageService.ts +27 -0
  438. package/src/react/router/services/ReactRouter.ts +262 -0
  439. package/src/react/websocket/hooks/useRoom.tsx +242 -0
  440. package/src/react/websocket/index.ts +7 -0
  441. package/src/redis/__tests__/redis.spec.ts +13 -0
  442. package/src/redis/index.ts +9 -25
  443. package/src/redis/providers/BunRedisProvider.ts +9 -0
  444. package/src/redis/providers/NodeRedisProvider.ts +8 -0
  445. package/src/redis/providers/RedisProvider.ts +16 -0
  446. package/src/retry/index.ts +11 -2
  447. package/src/router/index.ts +15 -0
  448. package/src/scheduler/index.ts +11 -2
  449. package/src/security/__tests__/BasicAuth.spec.ts +2 -0
  450. package/src/security/__tests__/ServerSecurityProvider.spec.ts +90 -5
  451. package/src/security/index.ts +15 -10
  452. package/src/security/interfaces/IssuerResolver.ts +27 -0
  453. package/src/security/primitives/$issuer.ts +55 -0
  454. package/src/security/providers/SecurityProvider.ts +179 -0
  455. package/src/security/providers/ServerBasicAuthProvider.ts +6 -2
  456. package/src/security/providers/ServerSecurityProvider.ts +63 -41
  457. package/src/server/auth/index.ts +12 -7
  458. package/src/server/cache/index.ts +7 -22
  459. package/src/server/compress/index.ts +10 -2
  460. package/src/server/cookies/index.ts +7 -5
  461. package/src/server/cookies/primitives/$cookie.ts +33 -11
  462. package/src/server/core/index.ts +16 -6
  463. package/src/server/core/interfaces/ServerRequest.ts +83 -1
  464. package/src/server/core/primitives/$action.spec.ts +1 -1
  465. package/src/server/core/primitives/$action.ts +8 -3
  466. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +9 -3
  467. package/src/server/core/providers/NodeHttpServerProvider.ts +9 -3
  468. package/src/server/core/services/ServerRequestParser.spec.ts +520 -0
  469. package/src/server/core/services/ServerRequestParser.ts +306 -13
  470. package/src/server/cors/index.ts +7 -21
  471. package/src/server/cors/primitives/$cors.ts +6 -2
  472. package/src/server/health/index.ts +8 -2
  473. package/src/server/helmet/index.ts +11 -3
  474. package/src/server/links/index.ts +11 -6
  475. package/src/server/metrics/index.ts +10 -3
  476. package/src/server/multipart/index.ts +9 -3
  477. package/src/server/proxy/index.ts +8 -2
  478. package/src/server/rate-limit/index.ts +21 -25
  479. package/src/server/rate-limit/primitives/$rateLimit.ts +6 -2
  480. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +38 -14
  481. package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +22 -56
  482. package/src/server/static/index.ts +8 -2
  483. package/src/server/static/providers/ServerStaticProvider.ts +1 -1
  484. package/src/server/swagger/index.ts +9 -4
  485. package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
  486. package/src/sms/index.ts +9 -5
  487. package/src/sms/providers/LocalSmsProvider.spec.ts +1 -1
  488. package/src/sms/providers/LocalSmsProvider.ts +1 -1
  489. package/src/system/index.browser.ts +36 -0
  490. package/src/system/index.ts +62 -0
  491. package/src/system/index.workerd.ts +1 -0
  492. package/src/{file → system}/providers/FileSystemProvider.ts +24 -0
  493. package/src/{file → system}/providers/MemoryFileSystemProvider.ts +116 -3
  494. package/src/system/providers/MemoryShellProvider.ts +164 -0
  495. package/src/{file → system}/providers/NodeFileSystemProvider.spec.ts +2 -2
  496. package/src/{file → system}/providers/NodeFileSystemProvider.ts +47 -2
  497. package/src/system/providers/NodeShellProvider.ts +184 -0
  498. package/src/system/providers/ShellProvider.ts +74 -0
  499. package/src/{file → system}/services/FileDetector.spec.ts +2 -2
  500. package/src/thread/index.ts +11 -2
  501. package/src/topic/core/index.ts +12 -5
  502. package/src/vite/tasks/buildClient.ts +2 -7
  503. package/src/vite/tasks/buildServer.ts +19 -13
  504. package/src/vite/tasks/generateCloudflare.ts +10 -7
  505. package/src/vite/tasks/generateDocker.ts +4 -0
  506. package/src/websocket/index.ts +12 -8
  507. package/dist/file/index.d.ts.map +0 -1
  508. package/dist/file/index.js.map +0 -1
  509. package/src/cli/assets/apiIndexTs.ts +0 -16
  510. package/src/cli/assets/mainServerTs.ts +0 -24
  511. package/src/cli/assets/webAppRouterTs.ts +0 -16
  512. package/src/cli/assets/webHelloComponentTsx.ts +0 -20
  513. package/src/cli/providers/ViteTemplateProvider.ts +0 -27
  514. package/src/file/index.ts +0 -43
  515. /package/src/cli/{assets → templates}/apiHelloControllerTs.ts +0 -0
  516. /package/src/cli/{assets → templates}/biomeJson.ts +0 -0
  517. /package/src/cli/{assets → templates}/dummySpecTs.ts +0 -0
  518. /package/src/cli/{assets → templates}/editorconfig.ts +0 -0
  519. /package/src/cli/{assets → templates}/mainBrowserTs.ts +0 -0
  520. /package/src/cli/{assets → templates}/tsconfigJson.ts +0 -0
  521. /package/src/cli/{assets → templates}/webIndexTs.ts +0 -0
  522. /package/src/{file → system}/errors/FileError.ts +0 -0
  523. /package/src/{file → system}/services/FileDetector.ts +0 -0
@@ -5,8 +5,10 @@ import {
5
5
  type DurationLike,
6
6
  } from "alepha/datetime";
7
7
  import { $logger } from "alepha/logger";
8
+ import type { ServerRequest } from "alepha/server";
8
9
  import type { JSONWebKeySet, JWTPayload } from "jose";
9
10
  import { SecurityError } from "../errors/SecurityError.ts";
11
+ import type { IssuerResolver } from "../interfaces/IssuerResolver.ts";
10
12
  import { JwtProvider } from "../providers/JwtProvider.ts";
11
13
  import { SecurityProvider } from "../providers/SecurityProvider.ts";
12
14
  import type { Role } from "../schemas/roleSchema.ts";
@@ -50,6 +52,11 @@ export type IssuerPrimitiveOptions = {
50
52
  * Parse the JWT payload to create a user account info.
51
53
  */
52
54
  profile?: (jwtPayload: Record<string, any>) => UserAccount;
55
+
56
+ /**
57
+ * Custom resolvers (in addition to default JWT resolver).
58
+ */
59
+ resolvers?: IssuerResolver[];
53
60
  } & (IssuerInternal | IssuerExternal);
54
61
 
55
62
  export interface IssuerSettings {
@@ -147,7 +154,55 @@ export class IssuerPrimitive extends Primitive<IssuerPrimitiveOptions> {
147
154
  profile: this.options.profile,
148
155
  secret: "jwks" in this.options ? this.options.jwks : this.options.secret,
149
156
  roles,
157
+ resolvers: [],
150
158
  });
159
+
160
+ // Register custom resolvers first (they usually have lower priority)
161
+ for (const resolver of this.options.resolvers ?? []) {
162
+ this.registerResolver(resolver);
163
+ }
164
+
165
+ // Register default JWT resolver (priority 100)
166
+ this.registerResolver(this.createJwtResolver());
167
+ }
168
+
169
+ /**
170
+ * Creates the default JWT resolver.
171
+ */
172
+ protected createJwtResolver(): IssuerResolver {
173
+ return {
174
+ priority: 100,
175
+ onRequest: async (req: ServerRequest) => {
176
+ const auth = req.headers.authorization;
177
+ if (!auth?.startsWith("Bearer ")) {
178
+ return null;
179
+ }
180
+
181
+ const token = auth.slice(7);
182
+
183
+ // Check if it looks like a JWT (has dots)
184
+ if (!token.includes(".")) {
185
+ return null;
186
+ }
187
+
188
+ // Parse and validate JWT
189
+ const { result } = await this.jwt.parse(token, this.name);
190
+
191
+ // Extract user info from JWT payload
192
+ return this.securityProvider.createUserFromPayload(
193
+ result.payload,
194
+ this.name,
195
+ );
196
+ },
197
+ };
198
+ }
199
+
200
+ /**
201
+ * Register a resolver to this issuer.
202
+ * Resolvers are sorted by priority (lower = first).
203
+ */
204
+ public registerResolver(resolver: IssuerResolver): void {
205
+ this.securityProvider.registerResolver(resolver, this.name);
151
206
  }
152
207
 
153
208
  /**
@@ -15,6 +15,7 @@ import { InvalidPermissionError } from "../errors/InvalidPermissionError.ts";
15
15
  import { InvalidTokenError } from "../errors/InvalidTokenError.ts";
16
16
  import { RealmNotFoundError } from "../errors/RealmNotFoundError.ts";
17
17
  import { SecurityError } from "../errors/SecurityError.ts";
18
+ import type { IssuerResolver, UserInfo } from "../interfaces/IssuerResolver.ts";
18
19
  import type { UserAccountToken } from "../interfaces/UserAccountToken.ts";
19
20
  import type { Permission } from "../schemas/permissionSchema.ts";
20
21
  import type { Role } from "../schemas/roleSchema.ts";
@@ -90,10 +91,46 @@ export class SecurityProvider {
90
91
  typeof realm.secret === "function" ? realm.secret() : realm.secret;
91
92
  this.jwt.setKeyLoader(realm.name, secret);
92
93
  }
94
+
95
+ // Register default JWT resolver for realms without resolvers
96
+ if (!realm.resolvers || realm.resolvers.length === 0) {
97
+ this.registerResolver(
98
+ this.createDefaultJwtResolver(realm.name),
99
+ realm.name,
100
+ );
101
+ }
93
102
  }
94
103
  },
95
104
  });
96
105
 
106
+ /**
107
+ * Creates a default JWT resolver for a realm.
108
+ */
109
+ protected createDefaultJwtResolver(realmName: string): IssuerResolver {
110
+ return {
111
+ priority: 100,
112
+ onRequest: async (req) => {
113
+ const auth = req.headers.authorization;
114
+ if (!auth?.startsWith("Bearer ")) {
115
+ return null;
116
+ }
117
+
118
+ const token = auth.slice(7);
119
+
120
+ // Check if it looks like a JWT (has dots)
121
+ if (!token.includes(".")) {
122
+ return null;
123
+ }
124
+
125
+ // Parse and validate JWT
126
+ const { result } = await this.jwt.parse(token, realmName);
127
+
128
+ // Extract user info from JWT payload
129
+ return this.createUserFromPayload(result.payload, realmName);
130
+ },
131
+ };
132
+ }
133
+
97
134
  /**
98
135
  * Adds a role to one or more realms.
99
136
  *
@@ -305,6 +342,143 @@ export class SecurityProvider {
305
342
  };
306
343
  }
307
344
 
345
+ /**
346
+ * Generic user creation from any source (JWT, API key, etc.).
347
+ * Handles permission checking, ownership, default roles.
348
+ */
349
+ public createUser(
350
+ userInfo: UserInfo,
351
+ options: {
352
+ realm?: string;
353
+ permission?: Permission | string;
354
+ } = {},
355
+ ): UserAccountToken {
356
+ const realmRoles = this.getRoles(options.realm).filter((it) => it.default);
357
+ const roles = [...(userInfo.roles ?? [])];
358
+
359
+ // Add default roles
360
+ for (const role of realmRoles) {
361
+ if (!roles.includes(role.name)) {
362
+ roles.push(role.name);
363
+ }
364
+ }
365
+
366
+ let ownership: string | boolean | undefined;
367
+
368
+ // Permission check
369
+ if (options.permission) {
370
+ const check = this.checkPermission(options.permission, ...roles);
371
+ if (!check.isAuthorized) {
372
+ throw new SecurityError(
373
+ `User is not allowed to access '${this.permissionToString(options.permission)}'`,
374
+ );
375
+ }
376
+ ownership = check.ownership;
377
+ }
378
+
379
+ return {
380
+ ...userInfo,
381
+ roles,
382
+ ownership,
383
+ realm: options.realm,
384
+ };
385
+ }
386
+
387
+ /**
388
+ * Register a resolver to a realm.
389
+ * Resolvers are sorted by priority (lower = first).
390
+ */
391
+ public registerResolver(resolver: IssuerResolver, realmName?: string): void {
392
+ const realm = this.getRealm(realmName);
393
+ if (!realm.resolvers) {
394
+ realm.resolvers = [];
395
+ }
396
+
397
+ realm.resolvers.push(resolver);
398
+ realm.resolvers.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
399
+ }
400
+
401
+ /**
402
+ * Get a realm by name.
403
+ * Throws if realm not found.
404
+ */
405
+ public getRealm(realmName?: string): Realm {
406
+ const realm = realmName
407
+ ? this.realms.find((it) => it.name === realmName)
408
+ : this.realms[0];
409
+
410
+ if (!realm) {
411
+ throw new RealmNotFoundError(realmName ?? "default");
412
+ }
413
+
414
+ return realm;
415
+ }
416
+
417
+ /**
418
+ * Resolve user from request using registered resolvers.
419
+ * Returns undefined if no resolver could authenticate (no auth provided).
420
+ * Throws UnauthorizedError if auth was provided but invalid.
421
+ *
422
+ * Note: This method tries resolvers from ALL realms to find a match,
423
+ * regardless of the `realm` option. The `realm` option is only used for
424
+ * permission checking after the user is resolved.
425
+ */
426
+ public async resolveUserFromServerRequest(
427
+ req: { url: URL | string; headers: { authorization?: string } },
428
+ options: {
429
+ realm?: string;
430
+ permission?: Permission | string;
431
+ } = {},
432
+ ): Promise<UserAccountToken | undefined> {
433
+ // Collect all resolvers from all realms with their realm name
434
+ const allResolvers: Array<{
435
+ resolver: IssuerResolver;
436
+ realmName: string;
437
+ }> = [];
438
+
439
+ for (const realm of this.realms) {
440
+ for (const resolver of realm.resolvers ?? []) {
441
+ allResolvers.push({ resolver, realmName: realm.name });
442
+ }
443
+ }
444
+
445
+ // Sort by priority
446
+ allResolvers.sort(
447
+ (a, b) => (a.resolver.priority ?? 100) - (b.resolver.priority ?? 100),
448
+ );
449
+
450
+ // Try resolvers in priority order
451
+ for (const { resolver, realmName } of allResolvers) {
452
+ let userInfo: UserInfo | null;
453
+
454
+ try {
455
+ userInfo = await resolver.onRequest(req as any);
456
+ } catch {
457
+ // Resolver failed (e.g., wrong key), try next
458
+ continue;
459
+ }
460
+
461
+ if (userInfo) {
462
+ // User was resolved - now create user and check permissions
463
+ // (errors from createUser should propagate, not be caught)
464
+ const user = this.createUser(userInfo, {
465
+ realm: realmName,
466
+ permission: options.permission,
467
+ });
468
+
469
+ await this.alepha.events.emit("security:user:created", {
470
+ realm: realmName,
471
+ user,
472
+ });
473
+
474
+ return user;
475
+ }
476
+ }
477
+
478
+ // No resolver matched = no auth provided
479
+ return undefined;
480
+ }
481
+
308
482
  /**
309
483
  * Checks if the user has the specified permission.
310
484
  *
@@ -783,6 +957,11 @@ export interface Realm {
783
957
  * By default, SecurityProvider has his own implementation, but this method allow to override it.
784
958
  */
785
959
  profile?: (raw: Record<string, any>) => UserAccount;
960
+
961
+ /**
962
+ * Custom resolvers for this realm (sorted by priority).
963
+ */
964
+ resolvers?: IssuerResolver[];
786
965
  }
787
966
 
788
967
  export interface SecurityCheckResult {
@@ -15,9 +15,13 @@ export interface BasicAuthOptions {
15
15
  }
16
16
 
17
17
  export interface BasicAuthPrimitiveConfig extends BasicAuthOptions {
18
- /** Name identifier for this basic auth (default: property key) */
18
+ /**
19
+ * Name identifier for this basic auth (default: property key).
20
+ */
19
21
  name?: string;
20
- /** Path patterns to match (supports wildcards like /devtools/*) */
22
+ /**
23
+ * Path patterns to match (supports wildcards like /devtools/*).
24
+ */
21
25
  paths?: string[];
22
26
  }
23
27
 
@@ -7,6 +7,7 @@ import {
7
7
  type ServerRequest,
8
8
  UnauthorizedError,
9
9
  } from "alepha/server";
10
+ import { InvalidTokenError } from "../errors/InvalidTokenError.ts";
10
11
  import type { UserAccountToken } from "../interfaces/UserAccountToken.ts";
11
12
  import type { Permission } from "../schemas/permissionSchema.ts";
12
13
  import { userAccountInfoSchema } from "../schemas/userAccountInfoSchema.ts";
@@ -23,30 +24,30 @@ export class ServerSecurityProvider {
23
24
  protected readonly jwtProvider = $inject(JwtProvider);
24
25
  protected readonly alepha = $inject(Alepha);
25
26
 
27
+ protected readonly resolvers: Array<ServerSecurityUserResolver> = [];
28
+
26
29
  protected readonly onConfigure = $hook({
27
30
  on: "configure",
28
31
  handler: async () => {
29
32
  for (const action of this.alepha.primitives($action)) {
30
33
  // -------------------------------------------------------------------------------------------------------------
31
- // if the action is disabled or not secure, we do NOT create a permission for it
34
+ // Only create permission when secure is explicitly set to true
35
+ // Actions are public by default (like $route)
32
36
  // -------------------------------------------------------------------------------------------------------------
33
37
  if (
34
38
  action.options.disabled ||
35
- action.options.secure === false ||
39
+ action.options.secure !== true ||
36
40
  this.securityProvider.getRealms().length === 0
37
41
  ) {
38
42
  continue;
39
43
  }
40
44
 
41
- const secure = action.options.secure;
42
- if (typeof secure !== "object") {
43
- this.securityProvider.createPermission({
44
- name: action.name,
45
- group: action.group,
46
- method: action.route.method,
47
- path: action.route.path,
48
- });
49
- }
45
+ this.securityProvider.createPermission({
46
+ name: action.name,
47
+ group: action.group,
48
+ method: action.route.method,
49
+ path: action.route.path,
50
+ });
50
51
  }
51
52
  },
52
53
  });
@@ -56,10 +57,12 @@ export class ServerSecurityProvider {
56
57
  protected readonly onActionRequest = $hook({
57
58
  on: "action:onRequest",
58
59
  handler: async ({ action, request, options }) => {
59
- // if you set explicitly secure: false, we assume you don't want any security check
60
- // but only if no user is provided in options
61
- if (action.options.secure === false && !options.user) {
62
- this.log.trace("Skipping security check for route");
60
+ const secure = action.options.secure;
61
+
62
+ // Skip security if not explicitly enabled (secure: true or secure: { realm: ... })
63
+ // Actions are public by default (like $route)
64
+ if (secure !== true && typeof secure !== "object" && !options.user) {
65
+ this.log.trace("Skipping security check for action - not secured");
63
66
  return;
64
67
  }
65
68
 
@@ -90,7 +93,7 @@ export class ServerSecurityProvider {
90
93
  this.alepha.codec.decode(userAccountInfoSchema, request.user),
91
94
  );
92
95
  } catch (error) {
93
- if (action.options.secure || permission) {
96
+ if (secure === true || typeof secure === "object" || permission) {
94
97
  throw error;
95
98
  }
96
99
  // else, we skip the security check
@@ -103,7 +106,7 @@ export class ServerSecurityProvider {
103
106
  on: "server:onRequest",
104
107
  priority: "last",
105
108
  handler: async ({ request, route }) => {
106
- // if you set explicitly secure: false, we assume you don't want any security check
109
+ // Skip entirely only if explicitly disabled
107
110
  if (route.secure === false) {
108
111
  this.log.trace(
109
112
  "Skipping security check for route - explicitly disabled",
@@ -119,20 +122,39 @@ export class ServerSecurityProvider {
119
122
  .getPermissions()
120
123
  .find((it) => it.path === route.path && it.method === route.method);
121
124
 
122
- if (!request.headers.authorization && !route.secure && !permission) {
123
- this.log.trace(
124
- "Skipping security check for route - no authorization header and not secure",
125
- );
126
- return;
127
- }
125
+ const realm =
126
+ typeof route.secure === "object" ? route.secure.realm : undefined;
128
127
 
129
128
  try {
130
- // set user to request
131
- request.user = await this.securityProvider.createUserFromToken(
132
- request.headers.authorization,
133
- { permission },
129
+ // Try to resolve user (JWT, API key, etc.) - even for public routes (optional auth)
130
+ request.user = await this.securityProvider.resolveUserFromServerRequest(
131
+ request,
132
+ { permission, realm },
134
133
  );
135
134
 
135
+ // No user resolved?
136
+ if (!request.user) {
137
+ // Route requires auth → throw
138
+ if (
139
+ route.secure === true ||
140
+ typeof route.secure === "object" ||
141
+ permission
142
+ ) {
143
+ // Provide a more specific error message when no auth header was provided
144
+ if (!request.headers.authorization) {
145
+ throw new InvalidTokenError(
146
+ "Invalid authorization header, maybe token is missing ?",
147
+ );
148
+ }
149
+ throw new UnauthorizedError("Authentication required");
150
+ }
151
+ // Route is public → skip (but we tried to resolve user for optional auth)
152
+ this.log.trace(
153
+ "Skipping security check for route - no auth provided and not required",
154
+ );
155
+ return;
156
+ }
157
+
136
158
  if (typeof route.secure === "object") {
137
159
  this.check(request.user, route.secure);
138
160
  }
@@ -143,16 +165,20 @@ export class ServerSecurityProvider {
143
165
  this.alepha.codec.decode(userAccountInfoSchema, request.user),
144
166
  );
145
167
 
146
- this.log.trace("User set from request token", {
168
+ this.log.trace("User set from request", {
147
169
  user: request.user,
148
170
  permission,
149
171
  });
150
172
  } catch (error) {
151
- if (route.secure || permission) {
173
+ if (
174
+ route.secure === true ||
175
+ typeof route.secure === "object" ||
176
+ permission
177
+ ) {
152
178
  throw error;
153
179
  }
154
180
 
155
- // else, we skip the security check
181
+ // else, we skip the security check (route is public)
156
182
  this.log.trace(
157
183
  "Skipping security check for route - error occurred",
158
184
  error,
@@ -209,19 +235,10 @@ export class ServerSecurityProvider {
209
235
  }
210
236
 
211
237
  if (!user) {
212
- // in testing mode, we create a test user
213
- if (this.alepha.isTest() && !("user" in options)) {
214
- return this.createTestUser();
215
- }
216
-
217
238
  throw new UnauthorizedError("User is required for calling this action");
218
239
  }
219
240
 
220
- const roles =
221
- user.roles ??
222
- (this.alepha.isTest()
223
- ? this.securityProvider.getRoles().map((role) => role.name)
224
- : []);
241
+ const roles = user.roles ?? [];
225
242
  let ownership: boolean | string | undefined;
226
243
 
227
244
  if (permission) {
@@ -264,7 +281,8 @@ export class ServerSecurityProvider {
264
281
  }
265
282
 
266
283
  // skip helper if user is explicitly set to undefined
267
- if ("user" in options && options.user === undefined) {
284
+ //if ("user" in options && options.user === undefined) {
285
+ if (!options.user) {
268
286
  return;
269
287
  }
270
288
 
@@ -295,3 +313,7 @@ export type ServerRouteSecure = {
295
313
  realm?: string;
296
314
  basic?: BasicAuthOptions;
297
315
  };
316
+
317
+ export type ServerSecurityUserResolver = (
318
+ request: ServerRequest,
319
+ ) => Promise<UserAccountToken | undefined>;
@@ -29,16 +29,21 @@ declare module "alepha" {
29
29
  // ---------------------------------------------------------------------------------------------------------------------
30
30
 
31
31
  /**
32
- * Allow authentication services for server applications.
33
- * It provides login and logout functionalities.
32
+ * | type | quality | stability |
33
+ * |------|---------|-----------|
34
+ * | backend | rare | stable |
34
35
  *
35
- * There are multiple authentication providers available (e.g., Google, GitHub).
36
- * You can also delegate authentication to your own OIDC/OAuth2, for example using Keycloak or Auth0.
36
+ * OAuth2/OIDC authentication with social login providers.
37
37
  *
38
- * It's cookie-based and SSR friendly.
38
+ * **Features:**
39
+ * - OAuth authentication provider
40
+ * - Username/password authentication
41
+ * - Google OAuth integration
42
+ * - GitHub OAuth integration
43
+ * - Apple OAuth integration
44
+ * - Cookie-based, SSR-friendly authentication
45
+ * - Token management and refresh
39
46
  *
40
- * @see {@link $auth}
41
- * @see {@link ServerAuthProvider}
42
47
  * @module alepha.server.auth
43
48
  */
44
49
  export const AlephaServerAuth = $module({
@@ -9,31 +9,16 @@ export * from "./providers/ServerCacheProvider.ts";
9
9
  // ---------------------------------------------------------------------------------------------------------------------
10
10
 
11
11
  /**
12
- * Plugin for Alepha Server that provides server-side caching capabilities.
13
- * It uses the Alepha Cache module to cache responses from server actions ($action).
14
- * It also provides a ETag-based cache invalidation mechanism.
12
+ * | type | quality | stability |
13
+ * |------|---------|-----------|
14
+ * | backend | standard | stable |
15
15
  *
16
- * @example
17
- * ```ts
18
- * import { Alepha } from "alepha";
19
- * import { $action } from "alepha/server";
20
- * import { AlephaServerCache } from "alepha/server/cache";
16
+ * ETag-based response caching.
21
17
  *
22
- * class ApiServer {
23
- * hello = $action({
24
- * cache: true,
25
- * handler: () => "Hello, World!",
26
- * });
27
- * }
18
+ * **Features:**
19
+ * - ETag generation and validation
20
+ * - Conditional request handling
28
21
  *
29
- * const alepha = Alepha.create()
30
- * .with(AlephaServerCache)
31
- * .with(ApiServer);
32
- *
33
- * run(alepha);
34
- * ```
35
- *
36
- * @see {@link ServerCacheProvider}
37
22
  * @module alepha.server.cache
38
23
  */
39
24
  export const AlephaServerCache = $module({
@@ -9,9 +9,17 @@ export * from "./providers/ServerCompressProvider.ts";
9
9
  // ---------------------------------------------------------------------------------------------------------------------
10
10
 
11
11
  /**
12
- * Plugin for Alepha Server that provides server-side compression capabilities.
12
+ * | type | quality | stability |
13
+ * |------|---------|-----------|
14
+ * | backend | standard | stable |
13
15
  *
14
- * Compresses responses using gzip, brotli, or zstd based on the `Accept-Encoding` header.
16
+ * Response compression.
17
+ *
18
+ * **Features:**
19
+ * - Gzip compression
20
+ * - Brotli compression
21
+ *
22
+ * @module alepha.server.compress
15
23
  */
16
24
  export const AlephaServerCompress = $module({
17
25
  name: "alepha.server.compress",
@@ -18,13 +18,15 @@ declare module "alepha/server" {
18
18
  }
19
19
 
20
20
  /**
21
- * Provides HTTP cookie management capabilities for server requests and responses with type-safe cookie primitives.
21
+ * | type | quality | stability |
22
+ * |------|---------|-----------|
23
+ * | backend | standard | stable |
22
24
  *
23
- * The server-cookies module enables declarative cookie handling using the `$cookie` primitive on class properties.
24
- * It offers automatic cookie parsing, secure cookie configuration, and seamless integration with server routes
25
- * for managing user sessions, preferences, and authentication tokens.
25
+ * Server and browser-safe cookie handling.
26
+ *
27
+ * **Features:**
28
+ * - Cookie management on server and browser
26
29
  *
27
- * @see {@link $cookie}
28
30
  * @module alepha.server.cookies
29
31
  */
30
32
  export const AlephaServerCookies = $module({
@@ -23,37 +23,59 @@ export const $cookie = <T extends TSchema>(
23
23
  // ---------------------------------------------------------------------------------------------------------------------
24
24
 
25
25
  export interface CookiePrimitiveOptions<T extends TSchema> {
26
- /** The schema for the cookie's value, used for validation and type safety. */
26
+ /**
27
+ * The schema for the cookie's value, used for validation and type safety.
28
+ */
27
29
  schema: T;
28
30
 
29
- /** The name of the cookie. */
31
+ /**
32
+ * The name of the cookie.
33
+ */
30
34
  name?: string;
31
35
 
32
- /** The cookie's path. Defaults to "/". */
36
+ /**
37
+ * The cookie's path. Defaults to "/".
38
+ */
33
39
  path?: string;
34
40
 
35
- /** Time-to-live for the cookie. Maps to `Max-Age`. */
41
+ /**
42
+ * Time-to-live for the cookie. Maps to `Max-Age`.
43
+ */
36
44
  ttl?: DurationLike;
37
45
 
38
- /** If true, the cookie is only sent over HTTPS. Defaults to true in production. */
46
+ /**
47
+ * If true, the cookie is only sent over HTTPS. Defaults to true in production.
48
+ */
39
49
  secure?: boolean;
40
50
 
41
- /** If true, the cookie cannot be accessed by client-side scripts. */
51
+ /**
52
+ * If true, the cookie cannot be accessed by client-side scripts.
53
+ */
42
54
  httpOnly?: boolean;
43
55
 
44
- /** SameSite policy for the cookie. Defaults to "lax". */
56
+ /**
57
+ * SameSite policy for the cookie. Defaults to "lax".
58
+ */
45
59
  sameSite?: "strict" | "lax" | "none";
46
60
 
47
- /** The domain for the cookie. */
61
+ /**
62
+ * The domain for the cookie.
63
+ */
48
64
  domain?: string;
49
65
 
50
- /** If true, the cookie value will be compressed using zlib. */
66
+ /**
67
+ * If true, the cookie value will be compressed using zlib.
68
+ */
51
69
  compress?: boolean;
52
70
 
53
- /** If true, the cookie value will be encrypted. Requires `COOKIE_SECRET` env var. */
71
+ /**
72
+ * If true, the cookie value will be encrypted. Requires `COOKIE_SECRET` env var.
73
+ */
54
74
  encrypt?: boolean;
55
75
 
56
- /** If true, the cookie will be signed to prevent tampering. Requires `COOKIE_SECRET` env var. */
76
+ /**
77
+ * If true, the cookie will be signed to prevent tampering. Requires `COOKIE_SECRET` env var.
78
+ */
57
79
  sign?: boolean;
58
80
  }
59
81