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
@@ -0,0 +1,242 @@
1
+ import type { Static } from "alepha";
2
+ import { useAlepha, useInject } from "alepha/react";
3
+ import type { ChannelPrimitive, TWSObject } from "alepha/websocket";
4
+ import { WebSocketClient } from "alepha/websocket";
5
+ import { useEffect, useRef, useState } from "react";
6
+
7
+ /**
8
+ * UseRoom options
9
+ */
10
+ export interface UseRoomOptions<
11
+ TClient extends TWSObject,
12
+ TServer extends TWSObject,
13
+ > {
14
+ /**
15
+ * Room ID to connect to
16
+ */
17
+ roomId: string;
18
+
19
+ /**
20
+ * Channel primitive defining the schemas
21
+ */
22
+ channel: ChannelPrimitive<TClient, TServer>;
23
+
24
+ /**
25
+ * Handler for incoming messages from the server
26
+ */
27
+ handler: (message: Static<TClient>) => void;
28
+
29
+ /**
30
+ * Optional WebSocket URL override
31
+ * Defaults to auto-detected URL based on window.location
32
+ */
33
+ url?: string;
34
+
35
+ /**
36
+ * Enable automatic reconnection on disconnect
37
+ * @default true
38
+ */
39
+ autoReconnect?: boolean;
40
+
41
+ /**
42
+ * Reconnection interval in milliseconds
43
+ * @default 3000
44
+ */
45
+ reconnectInterval?: number;
46
+
47
+ /**
48
+ * Maximum reconnection attempts (-1 for infinite)
49
+ * @default 10
50
+ */
51
+ maxReconnectAttempts?: number;
52
+
53
+ /**
54
+ * Called when connection is established
55
+ */
56
+ onConnect?: () => void;
57
+
58
+ /**
59
+ * Called when connection is closed
60
+ */
61
+ onDisconnect?: () => void;
62
+
63
+ /**
64
+ * Called on connection error
65
+ */
66
+ onError?: (error: Error) => void;
67
+ }
68
+
69
+ /**
70
+ * UseRoom return value
71
+ */
72
+ export interface UseRoomReturn<TServer extends TWSObject> {
73
+ /**
74
+ * Send a message to the server
75
+ */
76
+ send: (message: Static<TServer>) => Promise<void>;
77
+
78
+ /**
79
+ * Whether the connection is established
80
+ */
81
+ isConnected: boolean;
82
+
83
+ /**
84
+ * Whether the connection is in progress
85
+ */
86
+ isConnecting: boolean;
87
+
88
+ /**
89
+ * Whether there was an error
90
+ */
91
+ isError: boolean;
92
+
93
+ /**
94
+ * The error object if any
95
+ */
96
+ error?: Error;
97
+
98
+ /**
99
+ * Manually reconnect
100
+ */
101
+ reconnect: () => void;
102
+
103
+ /**
104
+ * Manually disconnect
105
+ */
106
+ disconnect: () => void;
107
+ }
108
+
109
+ /**
110
+ * React hook for WebSocket room communication
111
+ *
112
+ * Provides automatic connection management, reconnection, and type-safe messaging
113
+ * for WebSocket rooms using the injected WebSocketClient service.
114
+ *
115
+ * Multiple useRoom hooks on the same channel will share a single WebSocket connection.
116
+ *
117
+ * @example
118
+ * ```tsx
119
+ * const chat = useRoom({
120
+ * roomId: "room-123",
121
+ * channel: chatChannel,
122
+ * handler: (message) => {
123
+ * if (message.type === "append") {
124
+ * setMessages(prev => [...prev, message]);
125
+ * }
126
+ * }
127
+ * }, [roomId]);
128
+ *
129
+ * const sendMessage = async () => {
130
+ * await chat.send({
131
+ * content: "Hello, world!"
132
+ * });
133
+ * };
134
+ * ```
135
+ */
136
+ export const useRoom = <TClient extends TWSObject, TServer extends TWSObject>(
137
+ options: UseRoomOptions<TClient, TServer>,
138
+ deps: unknown[],
139
+ ): UseRoomReturn<TServer> => {
140
+ const webSocketClient = useInject(WebSocketClient);
141
+ const unsubscribeRef = useRef<(() => void) | null>(null);
142
+
143
+ const [isConnected, setIsConnected] = useState(false);
144
+ const [isConnecting, setIsConnecting] = useState(false);
145
+ const [isError, setIsError] = useState(false);
146
+ const [error, setError] = useState<Error | undefined>(undefined);
147
+
148
+ const {
149
+ roomId,
150
+ channel,
151
+ handler,
152
+ url,
153
+ autoReconnect,
154
+ reconnectInterval,
155
+ maxReconnectAttempts,
156
+ onConnect,
157
+ onDisconnect,
158
+ onError,
159
+ } = options;
160
+
161
+ useEffect(() => {
162
+ // Subscribe to room
163
+ const unsubscribe = webSocketClient.subscribe(roomId, channel, handler, {
164
+ url,
165
+ autoReconnect,
166
+ reconnectInterval,
167
+ maxReconnectAttempts,
168
+ onConnect: () => {
169
+ setIsConnected(true);
170
+ setIsConnecting(false);
171
+ setIsError(false);
172
+ setError(undefined);
173
+ onConnect?.();
174
+ },
175
+ onDisconnect: () => {
176
+ setIsConnected(false);
177
+ setIsConnecting(false);
178
+ onDisconnect?.();
179
+ },
180
+ onError: (err) => {
181
+ setIsError(true);
182
+ setError(err);
183
+ setIsConnecting(false);
184
+ onError?.(err);
185
+ },
186
+ });
187
+
188
+ unsubscribeRef.current = unsubscribe;
189
+
190
+ // Get initial state from connection
191
+ const connection = webSocketClient.getConnection(channel);
192
+ if (connection) {
193
+ setIsConnected(connection.isConnected);
194
+ setIsConnecting(connection.isConnecting);
195
+ setIsError(connection.isError);
196
+ setError(connection.error);
197
+ }
198
+
199
+ // Cleanup on unmount or deps change
200
+ return () => {
201
+ unsubscribe();
202
+ unsubscribeRef.current = null;
203
+ };
204
+ }, deps);
205
+
206
+ const alepha = useAlepha();
207
+
208
+ if (!alepha.isBrowser()) {
209
+ return {
210
+ send: async (_message: Static<TServer>) => {
211
+ // No-op on server
212
+ },
213
+ isConnected: false,
214
+ isConnecting: false,
215
+ isError: false,
216
+ error: undefined,
217
+ reconnect: () => {
218
+ // No-op on server
219
+ },
220
+ disconnect: () => {
221
+ // No-op on server
222
+ },
223
+ };
224
+ }
225
+
226
+ return {
227
+ send: async (message: Static<TServer>) => {
228
+ await webSocketClient.send(roomId, channel, message);
229
+ },
230
+ isConnected,
231
+ isConnecting,
232
+ isError,
233
+ error,
234
+ reconnect: () => {
235
+ const connection = webSocketClient.getConnection(channel);
236
+ connection?.reconnect();
237
+ },
238
+ disconnect: () => {
239
+ unsubscribeRef.current?.();
240
+ },
241
+ };
242
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * alepha/react/websocket
3
+ *
4
+ * React hooks for real-time WebSocket communication
5
+ */
6
+
7
+ export * from "./hooks/useRoom.tsx";
@@ -55,4 +55,17 @@ describe("Redis", () => {
55
55
  await redis.lpush("test:b", "b");
56
56
  await alepha.stop();
57
57
  });
58
+
59
+ it("should increment values atomically", async ({ expect }) => {
60
+ const key = `test:incr:${randomUUID()}`;
61
+
62
+ const val1 = await redis.incr(key, 1);
63
+ expect(val1).toBe(1);
64
+
65
+ const val2 = await redis.incr(key, 5);
66
+ expect(val2).toBe(6);
67
+
68
+ const val3 = await redis.incr(key, -2);
69
+ expect(val3).toBe(4);
70
+ });
58
71
  });
@@ -18,34 +18,18 @@ export * from "./providers/RedisSubscriberProvider.ts";
18
18
  // ---------------------------------------------------------------------------------------------------------------------
19
19
 
20
20
  /**
21
- * Redis client provider for Alepha applications.
21
+ * | type | quality | stability |
22
+ * |------|---------|-----------|
23
+ * | backend | standard | stable |
22
24
  *
23
- * Automatically selects the appropriate provider based on runtime:
24
- * - Bun: Uses `BunRedisProvider` with Bun's native Redis client (7.9x faster than ioredis)
25
- * - Node.js: Uses `NodeRedisProvider` with `@redis/client`
25
+ * Redis client wrapper.
26
26
  *
27
- * @example
28
- * ```ts
29
- * // Inject the abstract provider - runtime selects the implementation
30
- * const redis = alepha.inject(RedisProvider);
27
+ * **Features:**
28
+ * - Connection pooling
29
+ * - Automatic reconnection
30
+ * - Command pipelining
31
+ * - Pub/sub support
31
32
  *
32
- * // Use common operations
33
- * await redis.set("key", "value");
34
- * const value = await redis.get("key");
35
- *
36
- * // For pub/sub
37
- * const subscriber = alepha.inject(RedisSubscriberProvider);
38
- * await subscriber.subscribe("channel", (message, channel) => {
39
- * console.log(`Received: ${message} on ${channel}`);
40
- * });
41
- * ```
42
- *
43
- * @see {@link RedisProvider} - Abstract base class
44
- * @see {@link NodeRedisProvider} - Node.js implementation
45
- * @see {@link BunRedisProvider} - Bun implementation
46
- * @see {@link RedisSubscriberProvider} - Abstract subscriber base class
47
- * @see {@link NodeRedisSubscriberProvider} - Node.js subscriber implementation
48
- * @see {@link BunRedisSubscriberProvider} - Bun subscriber implementation
49
33
  * @module alepha.redis
50
34
  */
51
35
  export const AlephaRedis = $module({
@@ -264,6 +264,15 @@ export class BunRedisProvider extends RedisProvider {
264
264
  await this.publisher.publish(channel, message);
265
265
  }
266
266
 
267
+ // ---------------------------------------------------------
268
+ // Counter operations
269
+ // ---------------------------------------------------------
270
+
271
+ public override async incr(key: string, amount: number): Promise<number> {
272
+ const result = await this.publisher.send("INCRBY", [key, String(amount)]);
273
+ return Number(result);
274
+ }
275
+
267
276
  /**
268
277
  * Get the Redis connection URL.
269
278
  */
@@ -233,6 +233,14 @@ export class NodeRedisProvider extends RedisProvider {
233
233
  await this.publisher.publish(channel, message);
234
234
  }
235
235
 
236
+ // ---------------------------------------------------------
237
+ // Counter operations
238
+ // ---------------------------------------------------------
239
+
240
+ public override async incr(key: string, amount: number): Promise<number> {
241
+ return this.publisher.INCRBY(key, amount);
242
+ }
243
+
236
244
  /**
237
245
  * Get the Redis connection URL.
238
246
  */
@@ -108,6 +108,22 @@ export abstract class RedisProvider {
108
108
  * @param message The message to publish.
109
109
  */
110
110
  public abstract publish(channel: string, message: string): Promise<void>;
111
+
112
+ // ---------------------------------------------------------
113
+ // Counter operations
114
+ // ---------------------------------------------------------
115
+
116
+ /**
117
+ * Increment the integer value of a key by the given amount.
118
+ *
119
+ * If the key does not exist, it is set to 0 before performing the operation.
120
+ * This operation is atomic.
121
+ *
122
+ * @param key The key to increment.
123
+ * @param amount The amount to increment by.
124
+ * @returns The new value after incrementing.
125
+ */
126
+ public abstract incr(key: string, amount: number): Promise<number>;
111
127
  }
112
128
 
113
129
  /**
@@ -12,9 +12,18 @@ export * from "./providers/RetryProvider.ts";
12
12
  // ---------------------------------------------------------------------------------------------------------------------
13
13
 
14
14
  /**
15
- * Retry mechanism provider for Alepha applications.
15
+ * | type | quality | stability |
16
+ * |------|---------|-----------|
17
+ * | backend | standard | stable |
18
+ *
19
+ * Automatic retry with backoff.
20
+ *
21
+ * **Features:**
22
+ * - Retry configuration
23
+ * - Exponential backoff
24
+ * - Max retry limits
25
+ * - Custom retry predicates
16
26
  *
17
- * @see {@link RetryProvider}
18
27
  * @module alepha.retry
19
28
  */
20
29
  export const AlephaRetry = $module({
@@ -1 +1,16 @@
1
+ /**
2
+ * | type | quality | stability |
3
+ * |------|---------|-----------|
4
+ * | frontend | standard | stable |
5
+ *
6
+ * Frontend routing infrastructure.
7
+ *
8
+ * **Features:**
9
+ * - Route state management
10
+ * - Navigation methods
11
+ * - Route matching
12
+ *
13
+ * @module alepha.router
14
+ */
15
+
1
16
  export * from "./providers/RouterProvider.ts";
@@ -35,9 +35,18 @@ declare module "alepha" {
35
35
  // ---------------------------------------------------------------------------------------------------------------------
36
36
 
37
37
  /**
38
- * Generic interface for scheduling tasks.
38
+ * | type | quality | stability |
39
+ * |------|---------|-----------|
40
+ * | backend | rare | stable |
41
+ *
42
+ * Cron and interval-based task execution.
43
+ *
44
+ * **Features:**
45
+ * - Scheduled tasks with cron expressions (e.g., `0 0 * * *`)
46
+ * - Interval-based scheduling
47
+ * - Distributed locking to prevent duplicate execution
48
+ * - Lifecycle hooks: `begin`, `success`, `error`, `end`
39
49
  *
40
- * @see {@link $scheduler}
41
50
  * @module alepha.scheduler
42
51
  */
43
52
  export const AlephaScheduler = $module({
@@ -24,6 +24,7 @@ describe("Basic Authentication", () => {
24
24
 
25
25
  // Action without basic auth
26
26
  publicAction = $action({
27
+ secure: false,
27
28
  handler: () => "public success",
28
29
  });
29
30
 
@@ -48,6 +49,7 @@ describe("Basic Authentication", () => {
48
49
  });
49
50
 
50
51
  customAuthAction = $action({
52
+ secure: false,
51
53
  handler: async (request) => {
52
54
  this.customAuth.check(request);
53
55
  return "custom auth success";
@@ -23,16 +23,24 @@ describe("ServerSecurityProvider", () => {
23
23
  const app = alepha.inject(TestApp);
24
24
  await alepha.start();
25
25
 
26
- // in testing environment, .run() a dummy user is created
27
- expect(await app.ok.run({})).toBe("OK");
28
-
29
- // but you can force empty user
26
+ await expect(app.ok.run({})).rejects.toThrowError(UnauthorizedError);
30
27
  await expect(app.ok.run({}, { user: undefined })).rejects.toThrowError(
31
28
  UnauthorizedError,
32
29
  );
33
30
 
34
31
  // .fetch() will also generates a dummy user in testing environment
35
- expect(await app.ok.fetch({}).then((it) => it.data)).toBe("OK");
32
+ expect(
33
+ await app.ok
34
+ .fetch(
35
+ {},
36
+ {
37
+ user: {
38
+ id: randomUUID(),
39
+ },
40
+ },
41
+ )
42
+ .then((it) => it.data),
43
+ ).toBe("OK");
36
44
 
37
45
  // but you can also force empty user
38
46
  await expect(app.ok.fetch({}, { user: undefined })).rejects.toThrowError(
@@ -15,6 +15,7 @@ import type { UserAccount } from "./schemas/userAccountInfoSchema.ts";
15
15
  export * from "./errors/InvalidCredentialsError.ts";
16
16
  export * from "./errors/InvalidPermissionError.ts";
17
17
  export * from "./errors/SecurityError.ts";
18
+ export * from "./interfaces/IssuerResolver.ts";
18
19
  export * from "./interfaces/UserAccountToken.ts";
19
20
  export * from "./primitives/$basicAuth.ts";
20
21
  export * from "./primitives/$issuer.ts";
@@ -88,19 +89,23 @@ declare module "alepha/server" {
88
89
  }
89
90
 
90
91
  /**
91
- * Provides comprehensive authentication and authorization capabilities with JWT tokens, role-based access control, and user management.
92
+ * | type | quality | stability |
93
+ * |------|---------|-----------|
94
+ * | backend | epic | stable |
92
95
  *
93
- * The security module enables building secure applications using primitives like `$issuer`, `$role`, and `$permission`
94
- * on class properties. It offers JWT-based authentication, fine-grained permissions, service accounts, and seamless
95
- * integration with various authentication providers and user management systems.
96
+ * Complete authentication and authorization system with JWT, RBAC, and multi-issuer support.
96
97
  *
97
- * When used with `AlephaServer`, this module automatically registers `ServerSecurityProvider` and `ServerBasicAuthProvider`
98
- * to protect HTTP routes and actions with JWT and Basic Auth.
98
+ * **Features:**
99
+ * - JWT token issuer with role definitions
100
+ * - Role-based access control (RBAC)
101
+ * - Fine-grained permissions
102
+ * - HTTP Basic Authentication
103
+ * - Service-to-service authentication
104
+ * - Multi-issuer support for federated auth
105
+ * - JWKS (JSON Web Key Set) for external issuers
106
+ * - Token refresh logic
107
+ * - User profile extraction from JWT
99
108
  *
100
- * @see {@link $issuer}
101
- * @see {@link $role}
102
- * @see {@link $permission}
103
- * @see {@link $basicAuth}
104
109
  * @module alepha.security
105
110
  */
106
111
  export const AlephaSecurity = $module({
@@ -0,0 +1,27 @@
1
+ import type { ServerRequest } from "alepha/server";
2
+ import type { UserAccount } from "../schemas/userAccountInfoSchema.ts";
3
+
4
+ /**
5
+ * User info that a resolver returns.
6
+ * This is the input to `SecurityProvider.createUser()`.
7
+ */
8
+ export type UserInfo = Omit<UserAccount, "sessionId"> & {
9
+ sessionId?: string;
10
+ };
11
+
12
+ /**
13
+ * Resolver definition for authenticating users from requests.
14
+ */
15
+ export interface IssuerResolver {
16
+ /**
17
+ * Priority (lower = first). Default: 100
18
+ */
19
+ priority?: number;
20
+
21
+ /**
22
+ * Resolve user from HTTP request.
23
+ * Return UserInfo if authenticated, null to try next resolver.
24
+ * Throw UnauthorizedError to stop chain.
25
+ */
26
+ onRequest: (req: ServerRequest) => Promise<UserInfo | null>;
27
+ }
@@ -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
  /**