alepha 0.22.0 → 0.24.0

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 (869) hide show
  1. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  2. package/assets/swagger-ui/swagger-ui-standalone-preset.js +1 -1
  3. package/dist/api/audits/index.browser.js +49 -52
  4. package/dist/api/audits/index.browser.js.map +1 -1
  5. package/dist/api/audits/index.d.ts +629 -565
  6. package/dist/api/audits/index.d.ts.map +1 -1
  7. package/dist/api/audits/index.js +206 -98
  8. package/dist/api/audits/index.js.map +1 -1
  9. package/dist/api/files/index.browser.js +44 -44
  10. package/dist/api/files/index.browser.js.map +1 -1
  11. package/dist/api/files/index.d.ts +292 -293
  12. package/dist/api/files/index.d.ts.map +1 -1
  13. package/dist/api/files/index.js +61 -64
  14. package/dist/api/files/index.js.map +1 -1
  15. package/dist/api/jobs/index.browser.js +61 -59
  16. package/dist/api/jobs/index.browser.js.map +1 -1
  17. package/dist/api/jobs/index.d.ts +546 -347
  18. package/dist/api/jobs/index.d.ts.map +1 -1
  19. package/dist/api/jobs/index.js +165 -86
  20. package/dist/api/jobs/index.js.map +1 -1
  21. package/dist/api/keys/index.d.ts +242 -230
  22. package/dist/api/keys/index.d.ts.map +1 -1
  23. package/dist/api/keys/index.js +63 -66
  24. package/dist/api/keys/index.js.map +1 -1
  25. package/dist/api/notifications/index.browser.js +40 -38
  26. package/dist/api/notifications/index.browser.js.map +1 -1
  27. package/dist/api/notifications/index.d.ts +339 -209
  28. package/dist/api/notifications/index.d.ts.map +1 -1
  29. package/dist/api/notifications/index.js +108 -60
  30. package/dist/api/notifications/index.js.map +1 -1
  31. package/dist/api/oauth/index.d.ts +190 -78
  32. package/dist/api/oauth/index.d.ts.map +1 -1
  33. package/dist/api/oauth/index.js +290 -68
  34. package/dist/api/oauth/index.js.map +1 -1
  35. package/dist/api/organizations/index.browser.js +14 -14
  36. package/dist/api/organizations/index.browser.js.map +1 -1
  37. package/dist/api/organizations/index.d.ts +158 -134
  38. package/dist/api/organizations/index.d.ts.map +1 -1
  39. package/dist/api/organizations/index.js +18 -18
  40. package/dist/api/organizations/index.js.map +1 -1
  41. package/dist/api/parameters/index.browser.js +74 -53
  42. package/dist/api/parameters/index.browser.js.map +1 -1
  43. package/dist/api/parameters/index.d.ts +607 -513
  44. package/dist/api/parameters/index.d.ts.map +1 -1
  45. package/dist/api/parameters/index.js +205 -127
  46. package/dist/api/parameters/index.js.map +1 -1
  47. package/dist/api/payments/index.d.ts +652 -449
  48. package/dist/api/payments/index.d.ts.map +1 -1
  49. package/dist/api/payments/index.js +159 -93
  50. package/dist/api/payments/index.js.map +1 -1
  51. package/dist/api/subscriptions/index.d.ts +1032 -762
  52. package/dist/api/subscriptions/index.d.ts.map +1 -1
  53. package/dist/api/subscriptions/index.js +166 -185
  54. package/dist/api/subscriptions/index.js.map +1 -1
  55. package/dist/api/users/index.browser.js +48 -71
  56. package/dist/api/users/index.browser.js.map +1 -1
  57. package/dist/api/users/index.d.ts +1297 -1109
  58. package/dist/api/users/index.d.ts.map +1 -1
  59. package/dist/api/users/index.js +454 -369
  60. package/dist/api/users/index.js.map +1 -1
  61. package/dist/api/verifications/index.browser.js +17 -17
  62. package/dist/api/verifications/index.browser.js.map +1 -1
  63. package/dist/api/verifications/index.d.ts +169 -157
  64. package/dist/api/verifications/index.d.ts.map +1 -1
  65. package/dist/api/verifications/index.js +47 -95
  66. package/dist/api/verifications/index.js.map +1 -1
  67. package/dist/background/index.d.ts +0 -1
  68. package/dist/background/index.d.ts.map +1 -1
  69. package/dist/background/index.js.map +1 -1
  70. package/dist/background/index.workerd.js.map +1 -1
  71. package/dist/batch/index.d.ts +0 -1
  72. package/dist/batch/index.d.ts.map +1 -1
  73. package/dist/batch/index.js.map +1 -1
  74. package/dist/bin/index.js +1 -1
  75. package/dist/bin/index.js.map +1 -1
  76. package/dist/bucket/index.d.ts +27 -32
  77. package/dist/bucket/index.d.ts.map +1 -1
  78. package/dist/bucket/index.js +56 -26
  79. package/dist/bucket/index.js.map +1 -1
  80. package/dist/bucket/index.workerd.js +52 -24
  81. package/dist/bucket/index.workerd.js.map +1 -1
  82. package/dist/cache/core/index.d.ts +4 -6
  83. package/dist/cache/core/index.d.ts.map +1 -1
  84. package/dist/cache/core/index.js +4 -10
  85. package/dist/cache/core/index.js.map +1 -1
  86. package/dist/cache/core/index.workerd.js +4 -10
  87. package/dist/cache/core/index.workerd.js.map +1 -1
  88. package/dist/cache/database/index.d.ts +22 -23
  89. package/dist/cache/database/index.d.ts.map +1 -1
  90. package/dist/cache/database/index.js +11 -20
  91. package/dist/cache/database/index.js.map +1 -1
  92. package/dist/cache/redis/index.d.ts +3 -4
  93. package/dist/cache/redis/index.d.ts.map +1 -1
  94. package/dist/cache/redis/index.js +2 -2
  95. package/dist/cache/redis/index.js.map +1 -1
  96. package/dist/captcha/index.d.ts.map +1 -1
  97. package/dist/captcha/index.js +4 -4
  98. package/dist/captcha/index.js.map +1 -1
  99. package/dist/cli/config/index.d.ts +0 -1
  100. package/dist/cli/config/index.d.ts.map +1 -1
  101. package/dist/cli/core/index.d.ts +244 -475
  102. package/dist/cli/core/index.d.ts.map +1 -1
  103. package/dist/cli/core/index.js +308 -383
  104. package/dist/cli/core/index.js.map +1 -1
  105. package/dist/cli/devtools/index.d.ts +3 -9
  106. package/dist/cli/devtools/index.d.ts.map +1 -1
  107. package/dist/cli/devtools/index.js +3 -3
  108. package/dist/cli/devtools/index.js.map +1 -1
  109. package/dist/cli/i18n/index.d.ts +20 -39
  110. package/dist/cli/i18n/index.d.ts.map +1 -1
  111. package/dist/cli/i18n/index.js +51 -17
  112. package/dist/cli/i18n/index.js.map +1 -1
  113. package/dist/cli/platform/index.d.ts +89 -82
  114. package/dist/cli/platform/index.d.ts.map +1 -1
  115. package/dist/cli/platform/index.js +27 -33
  116. package/dist/cli/platform/index.js.map +1 -1
  117. package/dist/cli/platform-lib/index.d.ts +383 -410
  118. package/dist/cli/platform-lib/index.d.ts.map +1 -1
  119. package/dist/cli/platform-lib/index.js +300 -258
  120. package/dist/cli/platform-lib/index.js.map +1 -1
  121. package/dist/cli/vendor/index.d.ts +17 -41
  122. package/dist/cli/vendor/index.d.ts.map +1 -1
  123. package/dist/cli/vendor/index.js +10 -13
  124. package/dist/cli/vendor/index.js.map +1 -1
  125. package/dist/command/index.d.ts +82 -194
  126. package/dist/command/index.d.ts.map +1 -1
  127. package/dist/command/index.js +160 -563
  128. package/dist/command/index.js.map +1 -1
  129. package/dist/core/index.browser.js +845 -859
  130. package/dist/core/index.browser.js.map +1 -1
  131. package/dist/core/index.d.ts +787 -527
  132. package/dist/core/index.d.ts.map +1 -1
  133. package/dist/core/index.js +845 -859
  134. package/dist/core/index.js.map +1 -1
  135. package/dist/core/index.native.js +845 -859
  136. package/dist/core/index.native.js.map +1 -1
  137. package/dist/core/index.workerd.js +845 -859
  138. package/dist/core/index.workerd.js.map +1 -1
  139. package/dist/crypto/index.browser.js +1 -1
  140. package/dist/crypto/index.browser.js.map +1 -1
  141. package/dist/crypto/index.d.ts +3 -4
  142. package/dist/crypto/index.d.ts.map +1 -1
  143. package/dist/crypto/index.js +6 -3
  144. package/dist/crypto/index.js.map +1 -1
  145. package/dist/datetime/index.d.ts +12 -2
  146. package/dist/datetime/index.d.ts.map +1 -1
  147. package/dist/datetime/index.js +6 -1
  148. package/dist/datetime/index.js.map +1 -1
  149. package/dist/email/brevo/index.d.ts +0 -1
  150. package/dist/email/brevo/index.d.ts.map +1 -1
  151. package/dist/email/brevo/index.js +4 -4
  152. package/dist/email/brevo/index.js.map +1 -1
  153. package/dist/email/cloudflare/index.d.ts +0 -1
  154. package/dist/email/cloudflare/index.d.ts.map +1 -1
  155. package/dist/email/cloudflare/index.js +2 -2
  156. package/dist/email/cloudflare/index.js.map +1 -1
  157. package/dist/email/core/index.d.ts +15 -7
  158. package/dist/email/core/index.d.ts.map +1 -1
  159. package/dist/email/core/index.js +14 -5
  160. package/dist/email/core/index.js.map +1 -1
  161. package/dist/email/core/index.workerd.js +5 -1
  162. package/dist/email/core/index.workerd.js.map +1 -1
  163. package/dist/email/smtp/index.d.ts +8 -9
  164. package/dist/email/smtp/index.d.ts.map +1 -1
  165. package/dist/email/smtp/index.js +702 -479
  166. package/dist/email/smtp/index.js.map +1 -1
  167. package/dist/fake/index.d.ts +1580 -1238
  168. package/dist/fake/index.d.ts.map +1 -1
  169. package/dist/fake/index.js +11728 -32131
  170. package/dist/fake/index.js.map +1 -1
  171. package/dist/lock/core/index.d.ts +13 -9
  172. package/dist/lock/core/index.d.ts.map +1 -1
  173. package/dist/lock/core/index.js +5 -5
  174. package/dist/lock/core/index.js.map +1 -1
  175. package/dist/lock/redis/index.d.ts +0 -1
  176. package/dist/lock/redis/index.d.ts.map +1 -1
  177. package/dist/lock/redis/index.js.map +1 -1
  178. package/dist/logger/index.d.ts +81 -69
  179. package/dist/logger/index.d.ts.map +1 -1
  180. package/dist/logger/index.js +123 -56
  181. package/dist/logger/index.js.map +1 -1
  182. package/dist/mcp/index.d.ts +36 -90
  183. package/dist/mcp/index.d.ts.map +1 -1
  184. package/dist/mcp/index.js +65 -70
  185. package/dist/mcp/index.js.map +1 -1
  186. package/dist/orm/core/index.browser.js +54 -40
  187. package/dist/orm/core/index.browser.js.map +1 -1
  188. package/dist/orm/core/index.bun.js +140 -106
  189. package/dist/orm/core/index.bun.js.map +1 -1
  190. package/dist/orm/core/index.d.ts +145 -150
  191. package/dist/orm/core/index.d.ts.map +1 -1
  192. package/dist/orm/core/index.js +144 -109
  193. package/dist/orm/core/index.js.map +1 -1
  194. package/dist/orm/postgres/index.bun.js +64 -54
  195. package/dist/orm/postgres/index.bun.js.map +1 -1
  196. package/dist/orm/postgres/index.d.ts +36 -76
  197. package/dist/orm/postgres/index.d.ts.map +1 -1
  198. package/dist/orm/postgres/index.js +67 -57
  199. package/dist/orm/postgres/index.js.map +1 -1
  200. package/dist/queue/core/index.d.ts +62 -75
  201. package/dist/queue/core/index.d.ts.map +1 -1
  202. package/dist/queue/core/index.js +48 -71
  203. package/dist/queue/core/index.js.map +1 -1
  204. package/dist/queue/core/index.workerd.js +48 -71
  205. package/dist/queue/core/index.workerd.js.map +1 -1
  206. package/dist/queue/redis/index.d.ts +3 -4
  207. package/dist/queue/redis/index.d.ts.map +1 -1
  208. package/dist/queue/redis/index.js +2 -2
  209. package/dist/queue/redis/index.js.map +1 -1
  210. package/dist/react/auth/index.browser.js.map +1 -1
  211. package/dist/react/auth/index.d.ts +7 -4
  212. package/dist/react/auth/index.d.ts.map +1 -1
  213. package/dist/react/auth/index.js.map +1 -1
  214. package/dist/react/core/index.d.ts +87 -5
  215. package/dist/react/core/index.d.ts.map +1 -1
  216. package/dist/react/core/index.js +170 -23
  217. package/dist/react/core/index.js.map +1 -1
  218. package/dist/react/form/index.d.ts +4 -6
  219. package/dist/react/form/index.d.ts.map +1 -1
  220. package/dist/react/form/index.js +107 -71
  221. package/dist/react/form/index.js.map +1 -1
  222. package/dist/react/head/index.browser.js.map +1 -1
  223. package/dist/react/head/index.d.ts +0 -1
  224. package/dist/react/head/index.d.ts.map +1 -1
  225. package/dist/react/head/index.js.map +1 -1
  226. package/dist/react/i18n/index.d.ts +47 -5
  227. package/dist/react/i18n/index.d.ts.map +1 -1
  228. package/dist/react/i18n/index.js +116 -12
  229. package/dist/react/i18n/index.js.map +1 -1
  230. package/dist/react/intro/index.d.ts +1 -4
  231. package/dist/react/intro/index.d.ts.map +1 -1
  232. package/dist/react/intro/index.js.map +1 -1
  233. package/dist/react/router/index.browser.js +188 -29
  234. package/dist/react/router/index.browser.js.map +1 -1
  235. package/dist/react/router/index.d.ts +480 -372
  236. package/dist/react/router/index.d.ts.map +1 -1
  237. package/dist/react/router/index.js +261 -47
  238. package/dist/react/router/index.js.map +1 -1
  239. package/dist/react/sitemap/index.browser.js +35 -0
  240. package/dist/react/sitemap/index.browser.js.map +1 -0
  241. package/dist/react/sitemap/index.d.ts +91 -0
  242. package/dist/react/sitemap/index.d.ts.map +1 -0
  243. package/dist/react/sitemap/index.js +131 -0
  244. package/dist/react/sitemap/index.js.map +1 -0
  245. package/dist/react/testing/index.d.ts +4 -5
  246. package/dist/react/testing/index.d.ts.map +1 -1
  247. package/dist/react/testing/index.js +41 -15
  248. package/dist/react/testing/index.js.map +1 -1
  249. package/dist/react/testing/{chunk-BpyX8vjI.js → rolldown-runtime-Bl3dcgcQ.js} +1 -1
  250. package/dist/react/ui/index.d.ts +35 -34
  251. package/dist/react/ui/index.d.ts.map +1 -1
  252. package/dist/react/ui/index.js +12 -17
  253. package/dist/react/ui/index.js.map +1 -1
  254. package/dist/redis/index.bun.js +5 -5
  255. package/dist/redis/index.bun.js.map +1 -1
  256. package/dist/redis/index.d.ts +6 -7
  257. package/dist/redis/index.d.ts.map +1 -1
  258. package/dist/redis/index.js +6 -6
  259. package/dist/redis/index.js.map +1 -1
  260. package/dist/retry/index.d.ts +0 -1
  261. package/dist/retry/index.d.ts.map +1 -1
  262. package/dist/retry/index.js.map +1 -1
  263. package/dist/router/index.d.ts.map +1 -1
  264. package/dist/router/index.js.map +1 -1
  265. package/dist/scheduler/index.d.ts +4 -12
  266. package/dist/scheduler/index.d.ts.map +1 -1
  267. package/dist/scheduler/index.js +9 -4
  268. package/dist/scheduler/index.js.map +1 -1
  269. package/dist/scheduler/index.workerd.js +9 -4
  270. package/dist/scheduler/index.workerd.js.map +1 -1
  271. package/dist/security/index.browser.js +30 -28
  272. package/dist/security/index.browser.js.map +1 -1
  273. package/dist/security/index.d.ts +113 -44
  274. package/dist/security/index.d.ts.map +1 -1
  275. package/dist/security/index.js +452 -37
  276. package/dist/security/index.js.map +1 -1
  277. package/dist/server/auth/index.browser.js +19 -19
  278. package/dist/server/auth/index.browser.js.map +1 -1
  279. package/dist/server/auth/index.d.ts +215 -187
  280. package/dist/server/auth/index.d.ts.map +1 -1
  281. package/dist/server/auth/index.js +1145 -86
  282. package/dist/server/auth/index.js.map +1 -1
  283. package/dist/server/cookies/index.browser.js +103 -5
  284. package/dist/server/cookies/index.browser.js.map +1 -1
  285. package/dist/server/cookies/index.d.ts +86 -4
  286. package/dist/server/cookies/index.d.ts.map +1 -1
  287. package/dist/server/cookies/index.js +121 -8
  288. package/dist/server/cookies/index.js.map +1 -1
  289. package/dist/server/core/index.browser.js +22 -27
  290. package/dist/server/core/index.browser.js.map +1 -1
  291. package/dist/server/core/index.d.ts +134 -85
  292. package/dist/server/core/index.d.ts.map +1 -1
  293. package/dist/server/core/index.js +130 -118
  294. package/dist/server/core/index.js.map +1 -1
  295. package/dist/server/cors/index.d.ts +9 -10
  296. package/dist/server/cors/index.d.ts.map +1 -1
  297. package/dist/server/cors/index.js +14 -26
  298. package/dist/server/cors/index.js.map +1 -1
  299. package/dist/server/etag/index.d.ts +2 -3
  300. package/dist/server/etag/index.d.ts.map +1 -1
  301. package/dist/server/etag/index.js.map +1 -1
  302. package/dist/server/health/index.d.ts +18 -19
  303. package/dist/server/health/index.d.ts.map +1 -1
  304. package/dist/server/health/index.js +6 -6
  305. package/dist/server/health/index.js.map +1 -1
  306. package/dist/server/links/index.browser.js +15 -18
  307. package/dist/server/links/index.browser.js.map +1 -1
  308. package/dist/server/links/index.d.ts +66 -67
  309. package/dist/server/links/index.d.ts.map +1 -1
  310. package/dist/server/links/index.js +29 -32
  311. package/dist/server/links/index.js.map +1 -1
  312. package/dist/server/metrics/index.d.ts +0 -1
  313. package/dist/server/metrics/index.d.ts.map +1 -1
  314. package/dist/server/metrics/index.js +10 -3
  315. package/dist/server/metrics/index.js.map +1 -1
  316. package/dist/server/proxy/index.d.ts +0 -1
  317. package/dist/server/proxy/index.d.ts.map +1 -1
  318. package/dist/server/proxy/index.js.map +1 -1
  319. package/dist/server/rate-limit/index.d.ts +8 -9
  320. package/dist/server/rate-limit/index.d.ts.map +1 -1
  321. package/dist/server/rate-limit/index.js +6 -12
  322. package/dist/server/rate-limit/index.js.map +1 -1
  323. package/dist/server/static/index.d.ts +0 -1
  324. package/dist/server/static/index.d.ts.map +1 -1
  325. package/dist/server/static/index.js.map +1 -1
  326. package/dist/server/swagger/index.d.ts +4 -4
  327. package/dist/server/swagger/index.d.ts.map +1 -1
  328. package/dist/server/swagger/index.js +37 -25
  329. package/dist/server/swagger/index.js.map +1 -1
  330. package/dist/sms/index.d.ts +0 -1
  331. package/dist/sms/index.d.ts.map +1 -1
  332. package/dist/sms/index.js.map +1 -1
  333. package/dist/system/index.browser.js.map +1 -1
  334. package/dist/system/index.d.ts +0 -1
  335. package/dist/system/index.d.ts.map +1 -1
  336. package/dist/system/index.js +2 -1
  337. package/dist/system/index.js.map +1 -1
  338. package/dist/system/index.workerd.js.map +1 -1
  339. package/dist/topic/core/index.d.ts +19 -20
  340. package/dist/topic/core/index.d.ts.map +1 -1
  341. package/dist/topic/core/index.js +8 -8
  342. package/dist/topic/core/index.js.map +1 -1
  343. package/dist/topic/redis/index.d.ts +3 -4
  344. package/dist/topic/redis/index.d.ts.map +1 -1
  345. package/dist/topic/redis/index.js +2 -2
  346. package/dist/topic/redis/index.js.map +1 -1
  347. package/package.json +36 -36
  348. package/src/api/audits/__tests__/AuditJobs.spec.ts +83 -0
  349. package/src/api/audits/__tests__/AuditService.spec.ts +139 -1
  350. package/src/api/audits/controllers/AdminAuditController.ts +41 -41
  351. package/src/api/audits/entities/audits.ts +22 -22
  352. package/src/api/audits/index.ts +6 -1
  353. package/src/api/audits/jobs/AuditJobs.ts +29 -0
  354. package/src/api/audits/parameters/AuditParameters.ts +51 -0
  355. package/src/api/audits/primitives/$audit.ts +24 -0
  356. package/src/api/audits/schemas/auditQuerySchema.ts +13 -13
  357. package/src/api/audits/schemas/createAuditSchema.ts +18 -18
  358. package/src/api/audits/services/AuditService.ts +79 -7
  359. package/src/api/files/__tests__/FileController.spec.ts +5 -5
  360. package/src/api/files/__tests__/FileJobs.spec.ts +6 -0
  361. package/src/api/files/controllers/FileController.ts +25 -25
  362. package/src/api/files/entities/files.ts +15 -15
  363. package/src/api/files/schemas/fileCreatorSummarySchema.ts +7 -7
  364. package/src/api/files/schemas/fileQuerySchema.ts +9 -9
  365. package/src/api/files/schemas/fileResourceSchema.ts +7 -9
  366. package/src/api/files/schemas/storageStatsSchema.ts +13 -13
  367. package/src/api/jobs/__tests__/$job-hardening.spec.ts +289 -0
  368. package/src/api/jobs/__tests__/$job.spec.ts +18 -18
  369. package/src/api/jobs/controllers/AdminJobController.ts +8 -8
  370. package/src/api/jobs/entities/jobExecutionEntity.ts +29 -19
  371. package/src/api/jobs/providers/JobProvider.ts +128 -12
  372. package/src/api/jobs/providers/JobQueueProvider.ts +2 -2
  373. package/src/api/jobs/schemas/jobConfigAtom.ts +22 -22
  374. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +6 -6
  375. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +11 -15
  376. package/src/api/jobs/schemas/jobRegistrationSchema.ts +20 -19
  377. package/src/api/jobs/schemas/triggerJobSchema.ts +3 -3
  378. package/src/api/jobs/services/JobService.ts +6 -6
  379. package/src/api/keys/__tests__/ApiKeyService.spec.ts +2 -2
  380. package/src/api/keys/controllers/AdminApiKeyController.ts +10 -10
  381. package/src/api/keys/entities/apiKeyEntity.ts +15 -15
  382. package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +4 -4
  383. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +15 -15
  384. package/src/api/keys/schemas/createApiKeyBodySchema.ts +5 -5
  385. package/src/api/keys/schemas/createApiKeyResponseSchema.ts +9 -9
  386. package/src/api/keys/schemas/listApiKeyResponseSchema.ts +13 -13
  387. package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +3 -3
  388. package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +3 -3
  389. package/src/api/notifications/__tests__/AlephaApiNotifications.spec.ts +2 -2
  390. package/src/api/notifications/controllers/AdminNotificationController.ts +38 -14
  391. package/src/api/notifications/jobs/NotificationJobs.ts +7 -6
  392. package/src/api/notifications/primitives/$notification.ts +43 -4
  393. package/src/api/notifications/schemas/notificationContactPreferencesSchema.ts +4 -4
  394. package/src/api/notifications/schemas/notificationContactSchema.ts +7 -7
  395. package/src/api/notifications/schemas/notificationDetailResourceSchema.ts +9 -11
  396. package/src/api/notifications/schemas/notificationPayloadSchema.ts +11 -9
  397. package/src/api/notifications/schemas/notificationQuerySchema.ts +6 -6
  398. package/src/api/notifications/schemas/notificationResourceSchema.ts +14 -14
  399. package/src/api/notifications/services/NotificationSenderService.ts +38 -2
  400. package/src/api/oauth/__tests__/OAuthClientService.spec.ts +42 -0
  401. package/src/api/oauth/__tests__/OAuthController.spec.ts +128 -0
  402. package/src/api/oauth/controllers/OAuthController.ts +132 -12
  403. package/src/api/oauth/entities/oauthClientEntity.ts +29 -12
  404. package/src/api/oauth/helpers/oauthMetadata.ts +1 -0
  405. package/src/api/oauth/helpers/oidcMetadata.ts +19 -0
  406. package/src/api/oauth/index.ts +1 -0
  407. package/src/api/oauth/schemas/authorizeDecisionBodySchema.ts +12 -11
  408. package/src/api/oauth/schemas/authorizeQuerySchema.ts +12 -10
  409. package/src/api/oauth/schemas/registerClientBodySchema.ts +10 -11
  410. package/src/api/oauth/schemas/tokenRequestBodySchema.ts +9 -8
  411. package/src/api/oauth/services/OAuthClientService.ts +228 -15
  412. package/src/api/organizations/controllers/AdminOrganizationController.ts +8 -8
  413. package/src/api/organizations/entities/organizations.ts +6 -6
  414. package/src/api/organizations/schemas/createOrganizationSchema.ts +5 -5
  415. package/src/api/organizations/schemas/organizationQuerySchema.ts +4 -4
  416. package/src/api/organizations/schemas/updateOrganizationSchema.ts +1 -2
  417. package/src/api/parameters/__tests__/$parameter.spec.ts +229 -50
  418. package/src/api/parameters/controllers/AdminParameterController.ts +9 -12
  419. package/src/api/parameters/entities/parameters.ts +29 -16
  420. package/src/api/parameters/primitives/$parameter.ts +3 -3
  421. package/src/api/parameters/schemas/activateParameterBodySchema.ts +4 -4
  422. package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +15 -15
  423. package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +7 -7
  424. package/src/api/parameters/schemas/parameterCurrentResponseSchema.ts +7 -7
  425. package/src/api/parameters/schemas/parameterHistoryResponseSchema.ts +3 -3
  426. package/src/api/parameters/schemas/parameterNameParamSchema.ts +2 -3
  427. package/src/api/parameters/schemas/parameterNamesResponseSchema.ts +3 -3
  428. package/src/api/parameters/schemas/parameterResponseSchema.ts +3 -3
  429. package/src/api/parameters/schemas/parameterStatusSchema.ts +2 -2
  430. package/src/api/parameters/schemas/parameterTreeNodeSchema.ts +6 -6
  431. package/src/api/parameters/schemas/parameterVersionParamSchema.ts +5 -6
  432. package/src/api/parameters/schemas/parameterVersionResponseSchema.ts +3 -3
  433. package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +6 -9
  434. package/src/api/parameters/services/ParameterProvider.ts +152 -65
  435. package/src/api/payments/controllers/AdminPaymentController.ts +7 -7
  436. package/src/api/payments/controllers/MockCheckoutController.ts +79 -28
  437. package/src/api/payments/controllers/PaymentController.ts +4 -4
  438. package/src/api/payments/entities/paymentIntents.ts +11 -11
  439. package/src/api/payments/entities/paymentMethods.ts +11 -11
  440. package/src/api/payments/entities/refunds.ts +9 -9
  441. package/src/api/payments/providers/PaymentProvider.ts +18 -0
  442. package/src/api/payments/schemas/intentSchemas.ts +25 -25
  443. package/src/api/payments/schemas/paymentMethodSchemas.ts +3 -3
  444. package/src/api/payments/services/PaymentService.ts +60 -3
  445. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +14 -0
  446. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +11 -11
  447. package/src/api/subscriptions/controllers/SubscriptionController.ts +5 -4
  448. package/src/api/subscriptions/entities/subscriptionEvents.ts +15 -15
  449. package/src/api/subscriptions/entities/subscriptions.ts +22 -22
  450. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +22 -22
  451. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +4 -4
  452. package/src/api/subscriptions/schemas/changePlanSchema.ts +5 -5
  453. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +14 -7
  454. package/src/api/subscriptions/schemas/entitlementsSchema.ts +10 -10
  455. package/src/api/subscriptions/schemas/mrrSchema.ts +9 -9
  456. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +21 -21
  457. package/src/api/subscriptions/schemas/planResourceSchema.ts +19 -19
  458. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +8 -8
  459. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +7 -7
  460. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +17 -17
  461. package/src/api/subscriptions/services/SubscriptionConfig.ts +2 -2
  462. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +11 -11
  463. package/src/api/users/atoms/realmAuthSettingsAtom.ts +111 -119
  464. package/src/api/users/controllers/AdminIdentityController.ts +29 -19
  465. package/src/api/users/controllers/AdminSessionController.ts +37 -27
  466. package/src/api/users/controllers/AdminUserController.ts +75 -53
  467. package/src/api/users/controllers/MySessionController.ts +125 -0
  468. package/src/api/users/controllers/RealmController.ts +9 -9
  469. package/src/api/users/controllers/UserController.ts +55 -55
  470. package/src/api/users/entities/identities.ts +8 -8
  471. package/src/api/users/entities/sessions.ts +17 -17
  472. package/src/api/users/entities/users.ts +17 -17
  473. package/src/api/users/index.ts +3 -0
  474. package/src/api/users/notifications/UserNotifications.ts +76 -24
  475. package/src/api/users/primitives/$realm.ts +12 -0
  476. package/src/api/users/schemas/completePasswordResetRequestSchema.ts +8 -12
  477. package/src/api/users/schemas/completeRegistrationRequestSchema.ts +17 -20
  478. package/src/api/users/schemas/createUserSchema.ts +2 -2
  479. package/src/api/users/schemas/identityQuerySchema.ts +4 -4
  480. package/src/api/users/schemas/identityResourceSchema.ts +3 -2
  481. package/src/api/users/schemas/loginSchema.ts +4 -4
  482. package/src/api/users/schemas/passwordResetIntentResponseSchema.ts +6 -8
  483. package/src/api/users/schemas/realmConfigSchema.ts +10 -10
  484. package/src/api/users/schemas/registerQuerySchema.ts +6 -6
  485. package/src/api/users/schemas/registerRequestSchema.ts +21 -43
  486. package/src/api/users/schemas/registerResponseSchema.ts +2 -2
  487. package/src/api/users/schemas/registerSchema.ts +13 -31
  488. package/src/api/users/schemas/registrationIntentResponseSchema.ts +19 -23
  489. package/src/api/users/schemas/resetPasswordSchema.ts +10 -17
  490. package/src/api/users/schemas/sessionQuerySchema.ts +3 -3
  491. package/src/api/users/schemas/sessionResourceSchema.ts +25 -25
  492. package/src/api/users/schemas/updateUserSchema.ts +3 -4
  493. package/src/api/users/schemas/userQuerySchema.ts +7 -7
  494. package/src/api/users/services/RegistrationService.ts +25 -11
  495. package/src/api/users/services/UserService.ts +12 -6
  496. package/src/api/verifications/__tests__/CodeVerification.spec.ts +63 -101
  497. package/src/api/verifications/__tests__/LinkVerification.spec.ts +23 -92
  498. package/src/api/verifications/controllers/VerificationController.ts +13 -27
  499. package/src/api/verifications/entities/verifications.ts +13 -14
  500. package/src/api/verifications/schemas/requestVerificationCodeResponseSchema.ts +17 -14
  501. package/src/api/verifications/schemas/validateVerificationCodeResponseSchema.ts +9 -10
  502. package/src/api/verifications/schemas/verificationSettingsSchema.ts +65 -66
  503. package/src/api/verifications/schemas/verificationTypeEnumSchema.ts +2 -2
  504. package/src/api/verifications/services/VerificationService.ts +12 -0
  505. package/src/background/__tests__/BackgroundTaskProvider.spec.ts +36 -0
  506. package/src/batch/__tests__/$batch.spec.ts +22 -22
  507. package/src/batch/__tests__/startup-buffering.spec.ts +9 -9
  508. package/src/bin/index.ts +1 -1
  509. package/src/bucket/__tests__/TenantScopedBucket.spec.ts +60 -0
  510. package/src/bucket/providers/LocalFileStorageProvider.ts +14 -6
  511. package/src/bucket/providers/MemoryFileStorageProvider.ts +18 -7
  512. package/src/bucket/providers/R2FileStorageProvider.ts +14 -6
  513. package/src/bucket/providers/S3FileStorageProvider.ts +31 -15
  514. package/src/cache/core/primitives/$cache.ts +7 -10
  515. package/src/cache/database/entities/cacheEntries.ts +16 -27
  516. package/src/cache/database/providers/DatabaseCacheProvider.ts +15 -13
  517. package/src/cache/redis/providers/RedisCacheProvider.ts +6 -6
  518. package/src/captcha/providers/TurnstileCaptchaProvider.ts +4 -4
  519. package/src/cli/core/__tests__/BuildCloudflareTask.spec.ts +178 -0
  520. package/src/cli/core/__tests__/BuildDockerTask.spec.ts +0 -2
  521. package/src/cli/core/__tests__/DbCommand.spec.ts +108 -0
  522. package/src/cli/core/atoms/appEntryOptions.ts +5 -5
  523. package/src/cli/core/atoms/buildOptions.ts +76 -88
  524. package/src/cli/core/atoms/changelogOptions.ts +3 -3
  525. package/src/cli/core/atoms/devOptions.ts +3 -3
  526. package/src/cli/core/commands/build.ts +36 -49
  527. package/src/cli/core/commands/db.ts +171 -83
  528. package/src/cli/core/commands/dev.ts +8 -8
  529. package/src/cli/core/commands/gen/changelog.ts +12 -14
  530. package/src/cli/core/commands/gen/env.ts +6 -6
  531. package/src/cli/core/commands/gen/openapi.ts +6 -6
  532. package/src/cli/core/commands/init.ts +28 -33
  533. package/src/cli/core/commands/pack.ts +10 -10
  534. package/src/cli/core/commands/root.ts +7 -8
  535. package/src/cli/core/commands/test.ts +17 -20
  536. package/src/cli/core/index.ts +0 -3
  537. package/src/cli/core/tasks/BuildCloudflareTask.ts +138 -245
  538. package/src/cli/core/tasks/BuildPrerenderTask.ts +44 -7
  539. package/src/cli/core/templates/apiHelloResponseSchemaTs.ts +4 -4
  540. package/src/cli/devtools/atoms/devtoolsOptions.ts +6 -6
  541. package/src/cli/i18n/__tests__/I18nCheckService.spec.ts +48 -0
  542. package/src/cli/i18n/atoms/i18nOptions.ts +8 -8
  543. package/src/cli/i18n/services/I18nCheckService.ts +65 -11
  544. package/src/cli/platform/commands/SecretsCommand.ts +24 -25
  545. package/src/cli/platform/commands/platform.ts +40 -46
  546. package/src/cli/platform/index.ts +1 -1
  547. package/src/cli/platform-lib/__tests__/CloudflareAdapter.spec.ts +0 -4
  548. package/src/cli/platform-lib/__tests__/PlatformInspector.spec.ts +10 -3
  549. package/src/cli/platform-lib/__tests__/VercelAdapter.spec.ts +0 -2
  550. package/src/cli/platform-lib/adapters/CloudflareAdapter.ts +141 -50
  551. package/src/cli/platform-lib/adapters/VercelAdapter.ts +6 -11
  552. package/src/cli/platform-lib/atoms/platformOptions.ts +46 -25
  553. package/src/cli/platform-lib/schemas/cloudflare.ts +87 -87
  554. package/src/cli/platform-lib/schemas/platform.ts +51 -51
  555. package/src/cli/platform-lib/schemas/vercel.ts +28 -28
  556. package/src/cli/platform-lib/services/CloudflareApi.ts +5 -5
  557. package/src/cli/platform-lib/services/VercelApi.ts +4 -4
  558. package/src/cli/platform-lib/services/VercelCli.ts +6 -15
  559. package/src/cli/platform-lib/services/WranglerApi.ts +6 -15
  560. package/src/cli/vendor/atoms/vendorOptions.ts +9 -9
  561. package/src/cli/vendor/commands/VendorCommand.ts +11 -12
  562. package/src/command/__tests__/$command.spec.ts +82 -83
  563. package/src/command/__tests__/Asker.spec.ts +6 -13
  564. package/src/command/__tests__/CliProvider.spec.ts +136 -149
  565. package/src/command/__tests__/Runner.spec.ts +86 -110
  566. package/src/command/helpers/Asker.ts +23 -58
  567. package/src/command/helpers/Runner.ts +34 -110
  568. package/src/command/index.ts +4 -9
  569. package/src/command/primitives/$command.ts +10 -10
  570. package/src/command/providers/CliProvider.ts +183 -161
  571. package/src/core/Alepha.ts +62 -13
  572. package/src/core/__tests__/$atom.spec.ts +52 -3
  573. package/src/core/__tests__/$computed.spec.ts +129 -0
  574. package/src/core/__tests__/$env.spec.ts +13 -13
  575. package/src/core/__tests__/$inject.spec.ts +4 -4
  576. package/src/core/__tests__/$module.spec.ts +1 -1
  577. package/src/core/__tests__/Alepha-graph.spec.ts +1 -1
  578. package/src/core/__tests__/Alepha-parseEnv.spec.ts +32 -32
  579. package/src/core/__tests__/Alepha-start.spec.ts +3 -3
  580. package/src/core/__tests__/CodecManager.spec.ts +113 -94
  581. package/src/core/__tests__/KeylessJsonSchemaCodec.spec.ts +138 -138
  582. package/src/core/__tests__/SchemaValidator.spec.ts +43 -44
  583. package/src/core/__tests__/StateManager.persist.browser.spec.ts +87 -0
  584. package/src/core/__tests__/StateManager.spec.ts +423 -0
  585. package/src/core/__tests__/TypeBox-usecases.spec.ts +8 -8
  586. package/src/core/__tests__/TypeProvider.spec.ts +314 -309
  587. package/src/core/__tests__/dump.spec.ts +6 -6
  588. package/src/core/__tests__/pagination.spec.ts +4 -4
  589. package/src/core/__tests__/scoped-after-start.spec.ts +43 -0
  590. package/src/core/errors/TypeBoxError.ts +10 -4
  591. package/src/core/helpers/FileLike.ts +5 -5
  592. package/src/core/helpers/coerceStrings.ts +70 -0
  593. package/src/core/helpers/jsonSchemaToZod.ts +112 -0
  594. package/src/core/index.shared.ts +4 -1
  595. package/src/core/primitives/$atom.ts +95 -27
  596. package/src/core/primitives/$computed.ts +148 -0
  597. package/src/core/primitives/$env.ts +5 -5
  598. package/src/core/primitives/$state.ts +1 -1
  599. package/src/core/providers/AlsProvider.ts +26 -0
  600. package/src/core/providers/CodecManager.ts +1 -2
  601. package/src/core/providers/JsonSchemaCodec.ts +1 -2
  602. package/src/core/providers/KeylessJsonSchemaCodec.ts +82 -57
  603. package/src/core/providers/SchemaValidator.ts +48 -158
  604. package/src/core/providers/StateManager.ts +383 -9
  605. package/src/core/providers/TypeProvider.ts +80 -734
  606. package/src/core/providers/ZodProvider.ts +380 -0
  607. package/src/core/providers/zodAugment.ts +69 -0
  608. package/src/core/schemas/pageQuerySchema.ts +19 -21
  609. package/src/core/schemas/pageSchema.ts +47 -57
  610. package/src/crypto/__tests__/SecretProvider.spec.ts +31 -0
  611. package/src/crypto/providers/SecretProvider.ts +16 -10
  612. package/src/datetime/primitives/$throttle.ts +6 -1
  613. package/src/email/brevo/providers/BrevoEmailProvider.ts +4 -4
  614. package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +6 -6
  615. package/src/email/core/index.ts +7 -2
  616. package/src/email/core/primitives/$email.ts +5 -1
  617. package/src/email/core/providers/LocalEmailProvider.ts +5 -5
  618. package/src/email/smtp/providers/NodemailerEmailProvider.ts +41 -52
  619. package/src/fake/__tests__/FakeProvider.spec.ts +110 -110
  620. package/src/fake/__tests__/keyName.example.ts +21 -21
  621. package/src/fake/__tests__/keyName.spec.ts +41 -41
  622. package/src/fake/__tests__/module.example.ts +8 -8
  623. package/src/fake/providers/FakeProvider.ts +122 -121
  624. package/src/lock/core/__tests__/lock-mutual-exclusion.spec.ts +44 -0
  625. package/src/lock/core/index.ts +1 -0
  626. package/src/lock/core/primitives/$lock.ts +13 -6
  627. package/src/logger/__tests__/CliFormatterProvider.spec.ts +76 -0
  628. package/src/logger/__tests__/Logger.spec.ts +49 -0
  629. package/src/logger/index.ts +25 -18
  630. package/src/logger/providers/CliFormatterProvider.ts +75 -0
  631. package/src/logger/schemas/logEntrySchema.ts +10 -10
  632. package/src/logger/services/Logger.ts +18 -0
  633. package/src/mcp/__tests__/$prompt.spec.ts +21 -23
  634. package/src/mcp/__tests__/$tool.spec.ts +22 -22
  635. package/src/mcp/__tests__/McpServerProvider.spec.ts +82 -11
  636. package/src/mcp/__tests__/StreamableHttpMcpTransport.spec.ts +2 -2
  637. package/src/mcp/__tests__/integration.spec.ts +33 -33
  638. package/src/mcp/primitives/$prompt.ts +11 -9
  639. package/src/mcp/primitives/$tool.ts +27 -86
  640. package/src/mcp/providers/McpServerProvider.ts +55 -0
  641. package/src/mcp/transports/StreamableHttpMcpTransport.ts +7 -7
  642. package/src/orm/__tests__/$repository-tests.ts +133 -27
  643. package/src/orm/__tests__/$repository.spec.ts +23 -0
  644. package/src/orm/__tests__/$transactional-tests.ts +4 -4
  645. package/src/orm/__tests__/ModelBuilder-tests.ts +28 -28
  646. package/src/orm/__tests__/ModelBuilder.spec.ts +124 -106
  647. package/src/orm/__tests__/QueryManager.spec.ts +5 -5
  648. package/src/orm/__tests__/delete-returning-tests.ts +11 -11
  649. package/src/orm/__tests__/deletedAt-tests.ts +3 -3
  650. package/src/orm/__tests__/enums.spec.ts +29 -25
  651. package/src/orm/__tests__/execute-tests.ts +8 -8
  652. package/src/orm/__tests__/fixtures/bigEntitySchema.ts +48 -48
  653. package/src/orm/__tests__/fixtures/userEntitySchema.ts +6 -6
  654. package/src/orm/__tests__/joins-tests.ts +30 -30
  655. package/src/orm/__tests__/organization-tests.ts +105 -3
  656. package/src/orm/__tests__/organization.spec.ts +46 -0
  657. package/src/orm/__tests__/orm-errors.spec.ts +10 -10
  658. package/src/orm/__tests__/orm-next-tests.ts +29 -29
  659. package/src/orm/__tests__/orm-showcase-tests.ts +9 -9
  660. package/src/orm/__tests__/primaryKey.spec.ts +4 -4
  661. package/src/orm/__tests__/query-date-encoding-tests.ts +17 -17
  662. package/src/orm/__tests__/ref-auto-onDelete.spec.ts +14 -14
  663. package/src/orm/__tests__/references.spec.ts +7 -7
  664. package/src/orm/__tests__/security.spec.ts +17 -17
  665. package/src/orm/__tests__/string-operators-tests.ts +5 -5
  666. package/src/orm/__tests__/timestamps-tests.ts +14 -14
  667. package/src/orm/__tests__/validation-tests.ts +5 -5
  668. package/src/orm/core/__tests__/BunSqliteProvider.bun.spec.ts +8 -8
  669. package/src/orm/core/constants/PG_SYMBOLS.ts +13 -1
  670. package/src/orm/core/entities/alephaSequences.ts +8 -8
  671. package/src/orm/core/helpers/pgAttr.ts +4 -4
  672. package/src/orm/core/primitives/$entity.ts +10 -6
  673. package/src/orm/core/providers/DatabaseTypeProvider.ts +46 -53
  674. package/src/orm/core/providers/drivers/BunSqliteProvider.ts +8 -8
  675. package/src/orm/core/providers/drivers/CloudflareD1Provider.ts +3 -5
  676. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +8 -8
  677. package/src/orm/core/schemas/databaseEnvSchema.ts +4 -4
  678. package/src/orm/core/schemas/insertSchema.ts +14 -18
  679. package/src/orm/core/schemas/legacyIdSchema.ts +2 -2
  680. package/src/orm/core/schemas/updateSchema.ts +10 -16
  681. package/src/orm/core/services/PgRelationManager.ts +2 -2
  682. package/src/orm/core/services/QueryManager.ts +13 -2
  683. package/src/orm/core/services/Repository.ts +88 -33
  684. package/src/orm/core/services/SqliteModelBuilder.ts +38 -45
  685. package/src/orm/postgres/__tests__/BunPostgresProvider.bun.spec.ts +4 -4
  686. package/src/orm/postgres/providers/CloudflareHyperdriveProvider.ts +4 -6
  687. package/src/orm/postgres/schemas/postgresEnvSchema.ts +6 -6
  688. package/src/orm/postgres/services/PostgresModelBuilder.ts +127 -114
  689. package/src/queue/core/__tests__/$consumer.spec.ts +4 -4
  690. package/src/queue/core/__tests__/WorkerProvider.spec.ts +4 -4
  691. package/src/queue/core/__tests__/shared.ts +6 -6
  692. package/src/queue/core/primitives/$consumer.ts +5 -5
  693. package/src/queue/core/primitives/$queue.ts +44 -61
  694. package/src/queue/core/providers/CloudflareQueueProvider.ts +6 -0
  695. package/src/queue/core/providers/WorkerProvider.ts +17 -14
  696. package/src/queue/redis/providers/RedisQueueProvider.ts +3 -3
  697. package/src/react/core/__tests__/ErrorBoundary.browser.spec.tsx +92 -0
  698. package/src/react/core/__tests__/Router.spec.tsx +4 -4
  699. package/src/react/core/__tests__/useComputed.browser.spec.tsx +192 -0
  700. package/src/react/core/__tests__/useQuery.browser.spec.tsx +48 -0
  701. package/src/react/core/__tests__/useSelector.browser.spec.tsx +105 -0
  702. package/src/react/core/__tests__/useStore.browser.spec.tsx +113 -0
  703. package/src/react/core/components/ErrorBoundary.tsx +42 -0
  704. package/src/react/core/hooks/useAction.ts +56 -19
  705. package/src/react/core/hooks/useComputed.ts +91 -0
  706. package/src/react/core/hooks/useSelector.ts +67 -0
  707. package/src/react/core/hooks/useStore.ts +36 -17
  708. package/src/react/core/index.ts +3 -0
  709. package/src/react/core/utils/shallowEqual.ts +36 -0
  710. package/src/react/form/__tests__/FormModel-submit-loading.spec.ts +71 -0
  711. package/src/react/form/__tests__/form-submitting-reactive.browser.spec.tsx +96 -0
  712. package/src/react/form/__tests__/useForm.browser.spec.tsx +54 -54
  713. package/src/react/form/errors/FormValidationError.ts +0 -2
  714. package/src/react/form/hooks/useForm.ts +19 -4
  715. package/src/react/form/hooks/useFormQuerySync.ts +0 -0
  716. package/src/react/form/services/FormModel.ts +124 -86
  717. package/src/react/form/services/parseField.ts +66 -27
  718. package/src/react/i18n/__tests__/I18nProvider.spec.ts +89 -0
  719. package/src/react/i18n/__tests__/Localize.spec.tsx +1 -1
  720. package/src/react/i18n/__tests__/locale-routing.spec.ts +107 -0
  721. package/src/react/i18n/providers/I18nProvider.ts +173 -14
  722. package/src/react/router/__tests__/$page.browser.spec.tsx +19 -19
  723. package/src/react/router/__tests__/$page.spec.tsx +21 -21
  724. package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +87 -1
  725. package/src/react/router/__tests__/RouterLocaleProvider.spec.ts +127 -0
  726. package/src/react/router/atoms/ssrManifestAtom.ts +16 -16
  727. package/src/react/router/components/NestedView.tsx +11 -3
  728. package/src/react/router/hooks/useQueryParams.ts +1 -1
  729. package/src/react/router/index.browser.ts +4 -0
  730. package/src/react/router/index.shared.ts +1 -0
  731. package/src/react/router/index.ts +9 -0
  732. package/src/react/router/primitives/$page.ts +2 -2
  733. package/src/react/router/providers/ReactBrowserProvider.ts +64 -13
  734. package/src/react/router/providers/ReactBrowserRouterProvider.ts +15 -1
  735. package/src/react/router/providers/ReactPageProvider.ts +38 -13
  736. package/src/react/router/providers/ReactServerProvider.ts +105 -16
  737. package/src/react/router/providers/RootComponentsProvider.ts +13 -0
  738. package/src/react/router/providers/RouterLocaleProvider.ts +125 -0
  739. package/src/react/router/providers/__tests__/RootComponentsProvider.spec.ts +15 -0
  740. package/src/react/router/providers/__tests__/rootComponents.ssr.browser.spec.tsx +67 -0
  741. package/src/react/sitemap/__tests__/$sitemap.spec.ts +131 -0
  742. package/src/react/sitemap/index.browser.ts +21 -0
  743. package/src/react/sitemap/index.ts +25 -0
  744. package/src/react/sitemap/primitives/$sitemap.browser.ts +26 -0
  745. package/src/react/sitemap/primitives/$sitemap.ts +196 -0
  746. package/src/react/ui/atoms/uiAtom.ts +6 -6
  747. package/src/react/ui/atoms/uiThemeListAtom.ts +7 -7
  748. package/src/react/ui/hooks/useColorMode.ts +11 -4
  749. package/src/react/ui/services/SchemaControl.ts +4 -4
  750. package/src/redis/providers/BunRedisProvider.ts +19 -11
  751. package/src/redis/providers/NodeRedisProvider.ts +3 -3
  752. package/src/scheduler/primitives/$scheduler.ts +21 -8
  753. package/src/security/__tests__/assertRealmScope.spec.ts +29 -0
  754. package/src/security/atoms/currentTenantAtom.ts +6 -6
  755. package/src/security/atoms/currentUserAtom.ts +2 -2
  756. package/src/security/primitives/$issuer.ts +24 -2
  757. package/src/security/providers/JwtProvider.ts +100 -0
  758. package/src/security/providers/SecurityProvider.ts +43 -2
  759. package/src/security/schemas/permissionSchema.ts +19 -19
  760. package/src/security/schemas/roleSchema.ts +22 -28
  761. package/src/security/schemas/userAccountInfoSchema.ts +47 -37
  762. package/src/server/auth/__tests__/appleClientSecret.spec.ts +34 -0
  763. package/src/server/auth/__tests__/federationRedirectReplay.spec.ts +44 -0
  764. package/src/server/auth/helpers/appleClientSecret.ts +24 -0
  765. package/src/server/auth/helpers/jtiReplayGuard.ts +41 -0
  766. package/src/server/auth/helpers/safeRedirectPath.ts +19 -0
  767. package/src/server/auth/index.ts +1 -0
  768. package/src/server/auth/primitives/$auth.ts +6 -6
  769. package/src/server/auth/primitives/$authApple.ts +10 -10
  770. package/src/server/auth/primitives/$authFacebook.ts +10 -10
  771. package/src/server/auth/primitives/$authFranceConnect.ts +10 -10
  772. package/src/server/auth/primitives/$authGithub.ts +10 -10
  773. package/src/server/auth/primitives/$authGoogle.ts +10 -10
  774. package/src/server/auth/primitives/$authMicrosoft.ts +14 -14
  775. package/src/server/auth/providers/ServerAuthProvider.ts +67 -52
  776. package/src/server/auth/schemas/authenticationProviderSchema.ts +9 -12
  777. package/src/server/auth/schemas/tokenResponseSchema.ts +2 -2
  778. package/src/server/auth/schemas/tokensSchema.ts +16 -16
  779. package/src/server/auth/schemas/userinfoResponseSchema.ts +3 -3
  780. package/src/server/cookies/__tests__/AtomCookieBinding.spec.ts +80 -0
  781. package/src/server/cookies/__tests__/AtomCookiePersistence.browser.spec.ts +169 -0
  782. package/src/server/cookies/__tests__/AtomCookiePersistence.spec.ts +294 -0
  783. package/src/server/cookies/__tests__/ServerCookiesProvider.spec.ts +82 -12
  784. package/src/server/cookies/index.browser.ts +4 -1
  785. package/src/server/cookies/index.ts +8 -1
  786. package/src/server/cookies/primitives/$cookie.browser.ts +1 -1
  787. package/src/server/cookies/primitives/$cookie.ts +16 -0
  788. package/src/server/cookies/providers/AtomCookiePersistence.browser.ts +133 -0
  789. package/src/server/cookies/providers/AtomCookiePersistence.ts +148 -0
  790. package/src/server/cookies/providers/ServerCookiesProvider.ts +32 -4
  791. package/src/server/cookies/services/CookieParser.ts +6 -1
  792. package/src/server/core/__tests__/$action.spec.ts +13 -13
  793. package/src/server/core/__tests__/$middleware.spec.ts +10 -10
  794. package/src/server/core/__tests__/$route.spec.ts +9 -9
  795. package/src/server/core/__tests__/$sse.spec.ts +26 -26
  796. package/src/server/core/__tests__/BunHttpServerProvider.bun.spec.ts +6 -6
  797. package/src/server/core/__tests__/HttpClient.spec.ts +2 -2
  798. package/src/server/core/__tests__/NodeHttpServerProvider.spec.ts +15 -3
  799. package/src/server/core/__tests__/ServerBodyParserProvider.spec.ts +14 -14
  800. package/src/server/core/__tests__/ServerMultipartProvider.spec.ts +33 -33
  801. package/src/server/core/__tests__/ServerRouterProvider-errorHandler.spec.ts +5 -1
  802. package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +25 -25
  803. package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +9 -5
  804. package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +56 -24
  805. package/src/server/core/errors/ValidationError.ts +6 -3
  806. package/src/server/core/helpers/isMultipart.ts +2 -1
  807. package/src/server/core/index.ts +5 -2
  808. package/src/server/core/interfaces/ServerRequest.ts +14 -14
  809. package/src/server/core/primitives/$action.ts +26 -36
  810. package/src/server/core/primitives/$route.ts +27 -0
  811. package/src/server/core/primitives/$sse.ts +3 -3
  812. package/src/server/core/providers/BunHttpServerProvider.ts +8 -9
  813. package/src/server/core/providers/NodeHttpServerProvider.ts +8 -9
  814. package/src/server/core/providers/ServerBodyParserProvider.ts +20 -12
  815. package/src/server/core/providers/ServerCompressProvider.ts +9 -10
  816. package/src/server/core/providers/ServerHelmetProvider.ts +26 -27
  817. package/src/server/core/providers/ServerMultipartProvider.ts +19 -19
  818. package/src/server/core/providers/ServerRouterProvider.ts +44 -15
  819. package/src/server/core/schemas/errorSchema.ts +20 -25
  820. package/src/server/core/schemas/okSchema.ts +9 -14
  821. package/src/server/core/services/HttpClient.ts +13 -1
  822. package/src/server/core/services/ServerRequestParser.ts +6 -6
  823. package/src/server/cors/providers/ServerCorsProvider.ts +26 -28
  824. package/src/server/health/schemas/healthSchema.ts +6 -6
  825. package/src/server/links/__tests__/$remote.spec.ts +3 -3
  826. package/src/server/links/__tests__/BatchEndpoint.spec.ts +9 -9
  827. package/src/server/links/__tests__/LinkProvider.spec.ts +9 -9
  828. package/src/server/links/__tests__/ServerLinksProvider.spec.ts +23 -23
  829. package/src/server/links/__tests__/fixtures/CrudApp.ts +21 -21
  830. package/src/server/links/atoms/apiLinksAtom.ts +2 -2
  831. package/src/server/links/atoms/linkOptionsAtom.ts +6 -6
  832. package/src/server/links/primitives/$remote.ts +3 -3
  833. package/src/server/links/providers/LinkProvider.ts +3 -3
  834. package/src/server/links/providers/ServerLinksProvider.ts +20 -20
  835. package/src/server/links/schemas/apiLinksResponseSchema.ts +23 -23
  836. package/src/server/proxy/__tests__/$proxy.spec.ts +9 -9
  837. package/src/server/proxy/providers/ServerProxyProvider.ts +5 -0
  838. package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +18 -20
  839. package/src/server/swagger/__tests__/$swagger.spec.ts +91 -94
  840. package/src/server/swagger/__tests__/ui.spec.ts +3 -3
  841. package/src/server/swagger/providers/ServerSwaggerProvider.ts +66 -43
  842. package/src/system/__tests__/NodeShellProvider.spec.ts +46 -0
  843. package/src/system/providers/NodeShellProvider.ts +4 -1
  844. package/src/topic/core/__tests__/$subscriber.spec.ts +4 -4
  845. package/src/topic/core/__tests__/shared.ts +8 -8
  846. package/src/topic/core/primitives/$subscriber.ts +5 -5
  847. package/src/topic/core/primitives/$topic.ts +14 -14
  848. package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
  849. package/dist/container/core/index.d.ts +0 -236
  850. package/dist/container/core/index.d.ts.map +0 -1
  851. package/dist/container/core/index.js +0 -231
  852. package/dist/container/core/index.js.map +0 -1
  853. package/dist/container/core/index.workerd.js +0 -192
  854. package/dist/container/core/index.workerd.js.map +0 -1
  855. package/src/cli/core/tasks/BuildSitemapTask.ts +0 -130
  856. package/src/command/helpers/PrettyAsker.ts +0 -256
  857. package/src/command/helpers/PrettyPrint.ts +0 -332
  858. package/src/container/core/__tests__/$container.spec.ts +0 -83
  859. package/src/container/core/index.ts +0 -50
  860. package/src/container/core/index.workerd.ts +0 -53
  861. package/src/container/core/interfaces/ContainerOptions.ts +0 -69
  862. package/src/container/core/primitives/$container.ts +0 -100
  863. package/src/container/core/providers/CloudflareContainerProvider.ts +0 -70
  864. package/src/container/core/providers/ContainerProvider.ts +0 -92
  865. package/src/container/core/providers/MockContainerProvider.ts +0 -62
  866. package/src/container/core/providers/NodeContainerProvider.ts +0 -53
  867. package/src/core/__tests__/jsonSchemaToTypeBox.spec.ts +0 -771
  868. package/src/core/helpers/jsonSchemaToTypeBox.ts +0 -359
  869. /package/dist/orm/core/{chunk-B4FMCO8f.js → rolldown-runtime-B4FMCO8f.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/api/oauth/helpers/consentPage.ts","../../../src/api/oauth/helpers/oauthMetadata.ts","../../../src/api/oauth/schemas/authorizeDecisionBodySchema.ts","../../../src/api/oauth/schemas/authorizeQuerySchema.ts","../../../src/api/oauth/schemas/registerClientBodySchema.ts","../../../src/api/oauth/schemas/tokenRequestBodySchema.ts","../../../src/api/oauth/entities/oauthClientEntity.ts","../../../src/api/oauth/services/OAuthClientService.ts","../../../src/api/oauth/controllers/OAuthController.ts","../../../src/api/oauth/index.ts"],"sourcesContent":["/**\n * Renders the OAuth consent screen as a self-contained HTML document.\n * Pure server-rendered HTML — no client framework, no @alepha/ui dependency.\n * All authorization parameters are emitted as hidden inputs so the POST to\n * /oauth/authorize is stateless.\n */\nexport interface ConsentPageOptions {\n clientName: string;\n userName: string;\n scopes: string[];\n /**\n * Hidden field name -> value; round-trips the authorization request.\n */\n hidden: Record<string, string>;\n}\n\nconst escapeHtml = (s: string): string =>\n s.replace(\n /[&<>\"']/g,\n (c) =>\n ({\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n })[c] as string,\n );\n\nexport const renderConsentPage = (options: ConsentPageOptions): string => {\n const hidden = Object.entries(options.hidden)\n .map(\n ([k, v]) =>\n `<input type=\"hidden\" name=\"${escapeHtml(k)}\" value=\"${escapeHtml(v)}\" />`,\n )\n .join(\"\");\n const scopes = options.scopes.length\n ? options.scopes.map((s) => `<li>${escapeHtml(s)}</li>`).join(\"\")\n : \"<li>Basic access</li>\";\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<title>Authorize ${escapeHtml(options.clientName)}</title>\n<style>\nbody{font-family:system-ui,sans-serif;background:#0b0b0f;color:#e5e5e5;\ndisplay:flex;min-height:100vh;align-items:center;justify-content:center;margin:0}\n.card{background:#16161d;border:1px solid #2a2a35;border-radius:12px;\npadding:32px;max-width:380px;width:100%}\nh1{font-size:18px;margin:0 0 4px}p{color:#9a9aa5;font-size:14px;margin:4px 0 16px}\nul{font-size:14px;padding-left:18px}\n.row{display:flex;gap:8px;margin-top:20px}\nbutton{flex:1;padding:10px;border-radius:8px;border:0;font-size:14px;cursor:pointer}\n.allow{background:#6d5cf0;color:#fff}.deny{background:#2a2a35;color:#e5e5e5}\n</style></head><body>\n<div class=\"card\">\n<h1>${escapeHtml(options.clientName)} wants to connect</h1>\n<p>Signed in as ${escapeHtml(options.userName)}</p>\n<p>It will be able to:</p>\n<ul>${scopes}</ul>\n<form method=\"POST\" action=\"/oauth/authorize\">${hidden}\n<div class=\"row\">\n<button class=\"deny\" type=\"submit\" name=\"decision\" value=\"deny\">Deny</button>\n<button class=\"allow\" type=\"submit\" name=\"decision\" value=\"allow\">Allow</button>\n</div></form></div></body></html>`;\n};\n","/**\n * RFC 8414 — OAuth 2.0 Authorization Server Metadata.\n * `baseUrl` is the absolute origin of the deployment (e.g. https://app.com).\n */\nexport const buildAuthorizationServerMetadata = (baseUrl: string) => ({\n issuer: baseUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n response_types_supported: [\"code\"],\n grant_types_supported: [\"authorization_code\", \"refresh_token\"],\n code_challenge_methods_supported: [\"S256\"],\n token_endpoint_auth_methods_supported: [\"none\"],\n scopes_supported: [\"mcp\"],\n});\n\n/**\n * RFC 9728 — OAuth 2.0 Protected Resource Metadata.\n * `resource` is the absolute URL of the MCP endpoint being protected.\n */\nexport const buildProtectedResourceMetadata = (\n baseUrl: string,\n resource: string,\n) => ({\n resource,\n authorization_servers: [baseUrl],\n scopes_supported: [\"mcp\"],\n bearer_methods_supported: [\"header\"],\n});\n","import { t } from \"alepha\";\n\n/**\n * Body posted by the consent screen. All authorization-request parameters\n * are round-tripped through hidden form fields so the POST handler can\n * re-validate them without server-side session state.\n */\nexport const authorizeDecisionBodySchema = t.object({\n decision: t.text(),\n response_type: t.text(),\n client_id: t.text(),\n redirect_uri: t.text({ maxLength: 2048 }),\n code_challenge: t.text(),\n code_challenge_method: t.text(),\n scope: t.optional(t.text({ maxLength: 1024 })),\n state: t.optional(t.text({ maxLength: 512 })),\n resource: t.optional(t.text({ maxLength: 2048 })),\n});\n","import { t } from \"alepha\";\n\n/**\n * OAuth 2.1 authorization request query parameters (GET /oauth/authorize).\n */\nexport const authorizeQuerySchema = t.object({\n response_type: t.text(),\n client_id: t.text(),\n redirect_uri: t.text({ maxLength: 2048 }),\n code_challenge: t.text(),\n code_challenge_method: t.text(),\n scope: t.optional(t.text({ maxLength: 1024 })),\n state: t.optional(t.text({ maxLength: 512 })),\n resource: t.optional(t.text({ maxLength: 2048 })),\n});\n","import { t } from \"alepha\";\n\n/**\n * RFC 7591 Dynamic Client Registration request body.\n * Only the fields Alepha consumes are typed; unknown fields are ignored.\n */\nexport const registerClientBodySchema = t.object(\n {\n client_name: t.optional(t.text({ maxLength: 200 })),\n redirect_uris: t.array(t.text({ maxLength: 2048 }), { minItems: 1 }),\n scope: t.optional(t.text({ maxLength: 1024 })),\n grant_types: t.optional(t.array(t.text())),\n token_endpoint_auth_method: t.optional(t.text()),\n },\n { additionalProperties: true },\n);\n","import { t } from \"alepha\";\n\n/**\n * Body of a POST /oauth/token request. OAuth 2.1 mandates\n * application/x-www-form-urlencoded encoding (section 3.2.2). All fields are\n * optional at the schema level; the handler enforces the grant-specific\n * requirements and returns the appropriate OAuth error responses.\n */\nexport const tokenRequestBodySchema = t.object({\n grant_type: t.optional(t.text()),\n code: t.optional(t.text({ maxLength: 4096 })),\n client_id: t.optional(t.text()),\n redirect_uri: t.optional(t.text({ maxLength: 2048 })),\n code_verifier: t.optional(t.text({ maxLength: 256 })),\n refresh_token: t.optional(t.text({ maxLength: 4096 })),\n});\n","import { type Static, t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\n/**\n * A registered OAuth 2.1 client application.\n *\n * Rows are created by Dynamic Client Registration (RFC 7591) when an MCP\n * client (e.g. Claude) first connects. `source` records who created the\n * client; for DCR it is always `\"dcr\"` and `createdByUserId` is null until\n * a user completes an authorization.\n */\nexport const oauthClientEntity = $entity({\n name: \"oauth_clients\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n clientId: t.text({ maxLength: 64 }),\n clientName: t.text({ maxLength: 200 }),\n redirectUris: db.default(t.array(t.text({ maxLength: 2048 })), []),\n scopes: db.default(t.array(t.text({ maxLength: 64 })), []),\n realm: t.text({ maxLength: 100 }),\n source: db.default(t.text({ maxLength: 16 }), \"dcr\"),\n createdByUserId: t.optional(t.uuid()),\n lastUsedAt: t.optional(t.datetime()),\n revokedAt: t.optional(t.datetime()),\n }),\n indexes: [{ columns: [\"clientId\"], unique: true }],\n});\n\nexport type OAuthClientEntity = Static<typeof oauthClientEntity.schema>;\n","import { createHash, randomUUID } from \"node:crypto\";\nimport { $inject, Alepha, AlephaError } from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport {\n type IssuerPrimitive,\n JwtProvider,\n type UserAccount,\n} from \"alepha/security\";\nimport {\n type OAuthClientEntity,\n oauthClientEntity,\n} from \"../entities/oauthClientEntity.ts\";\n\nexport interface RegisterClientOptions {\n realm: string;\n clientName: string;\n redirectUris: string[];\n scopes: string[];\n source?: \"dcr\" | \"user\" | \"admin\";\n createdByUserId?: string;\n}\n\n/**\n * Core OAuth 2.1 service backing the authorization server.\n *\n * Responsibilities:\n * - Client registration (RFC 7591 Dynamic Client Registration) and lookup,\n * with exact-match redirect_uri validation.\n * - Stateless PKCE authorization codes: minting short-lived signed JWTs that\n * carry the grant, and verifying/consuming them (replay, expiry, client and\n * redirect_uri checks, S256 PKCE).\n * - Realm issuer registry: realms register an issuer + user loader so the\n * token endpoint can mint access tokens without depending on realm wiring.\n */\nexport class OAuthClientService {\n protected readonly alepha = $inject(Alepha);\n protected readonly dateTime = $inject(DateTimeProvider);\n protected readonly log = $logger();\n protected readonly repo = $repository(oauthClientEntity);\n protected readonly jwt = $inject(JwtProvider);\n\n /**\n * Codes already redeemed in this process. Single-use enforcement only\n * needs to cover the ~60s code lifetime, so a bounded in-memory set is\n * sufficient even on serverless — an expired code fails JWT verification\n * regardless.\n */\n protected readonly usedCodes = new Set<string>();\n\n /**\n * Registry of realm issuers used to mint access tokens. Populated by\n * `$realm` (via `registerIssuer`) so the OAuth module does not depend on the\n * realm wiring directly.\n */\n protected readonly issuers = new Map<\n string,\n {\n issuer: IssuerPrimitive;\n loadUser: (userId: string) => Promise<UserAccount>;\n }\n >();\n\n /**\n * Register a realm issuer and a user loader. Called by `$realm` so the\n * OAuth token endpoint can mint access tokens for that realm.\n */\n public registerIssuer(\n realm: string,\n issuer: IssuerPrimitive,\n loadUser: (userId: string) => Promise<UserAccount>,\n ): void {\n this.issuers.set(realm, { issuer, loadUser });\n }\n\n /**\n * Mint an access token for a consumed authorization-code grant, using the\n * issuer registered for `realm`. Throws if the realm has no issuer.\n */\n public async issueAccessToken(\n realm: string,\n grant: {\n userId: string;\n scopes: string[];\n resource?: string;\n clientId?: string;\n },\n ): Promise<{\n access_token: string;\n expires_in?: number;\n refresh_token?: string;\n }> {\n const entry = this.issuers.get(realm);\n if (!entry) {\n throw new AlephaError(`No issuer registered for realm '${realm}'`);\n }\n const user = await entry.loadUser(grant.userId);\n // Tag the session the issuer creates with the OAuth client, so it can\n // later be surfaced as a \"connected app\" and revoked individually.\n const tokens = await entry.issuer.createToken(user, undefined, {\n clientId: grant.clientId,\n });\n return {\n access_token: tokens.access_token,\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n };\n }\n\n /**\n * Exchange a refresh token for a fresh access token (OAuth 2.1\n * `refresh_token` grant), using the issuer registered for `realm`. Lets an\n * MCP client stay connected for the refresh token's full lifetime without\n * re-running the authorization flow. Throws if the realm has no issuer or\n * the refresh token is invalid/expired.\n */\n public async refreshAccessToken(\n realm: string,\n refreshToken: string,\n ): Promise<{\n access_token: string;\n expires_in?: number;\n refresh_token?: string;\n }> {\n const entry = this.issuers.get(realm);\n if (!entry) {\n throw new AlephaError(`No issuer registered for realm '${realm}'`);\n }\n const { tokens } = await entry.issuer.refreshToken(refreshToken);\n return {\n access_token: tokens.access_token,\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n };\n }\n\n /**\n * Register a new OAuth client. Used by the RFC 7591 DCR endpoint and,\n * later, by user/admin UIs (via the `source` field).\n */\n public async register(\n options: RegisterClientOptions,\n ): Promise<OAuthClientEntity> {\n if (options.redirectUris.length === 0) {\n throw new AlephaError(\"At least one redirect_uri is required\");\n }\n for (const uri of options.redirectUris) {\n if (!uri.startsWith(\"https://\") && !uri.startsWith(\"http://localhost\")) {\n throw new AlephaError(`Invalid redirect_uri: ${uri}`);\n }\n }\n\n const clientId = `mcp_${randomUUID().replace(/-/g, \"\")}`;\n const client = await this.repo.create({\n clientId,\n clientName: options.clientName || \"MCP Client\",\n redirectUris: options.redirectUris,\n scopes: options.scopes,\n realm: options.realm,\n source: options.source ?? \"dcr\",\n createdByUserId: options.createdByUserId,\n });\n\n this.log.info(\"OAuth client registered\", {\n clientId,\n source: client.source,\n });\n return client;\n }\n\n /**\n * Look up a client by its public `clientId`. Returns null if unknown.\n */\n public async findByClientId(\n clientId: string,\n ): Promise<OAuthClientEntity | null> {\n return (\n (await this.repo.findOne({ where: { clientId: { eq: clientId } } })) ??\n null\n );\n }\n\n /**\n * Exact-match redirect_uri check. OAuth 2.1 forbids substring/prefix\n * matching — the value must equal a registered URI byte-for-byte.\n */\n public isRedirectUriAllowed(\n client: OAuthClientEntity,\n redirectUri: string,\n ): boolean {\n return client.redirectUris.includes(redirectUri);\n }\n\n /**\n * Mint a stateless authorization code: a short-lived signed JWT\n * (`typ: \"oauth_code\"`) carrying the grant. No server-side code storage.\n */\n public async createAuthorizationCode(\n realm: string,\n grant: {\n userId: string;\n clientId: string;\n redirectUri: string;\n codeChallenge: string;\n scopes: string[];\n resource?: string;\n },\n ): Promise<string> {\n const iat = this.dateTime.now().unix();\n return this.jwt.create(\n {\n sub: grant.userId,\n client_id: grant.clientId,\n redirect_uri: grant.redirectUri,\n code_challenge: grant.codeChallenge,\n scopes: grant.scopes,\n resource: grant.resource,\n iat,\n exp: iat + 60,\n jti: randomUUID(),\n },\n realm,\n { header: { typ: \"oauth_code\" } },\n );\n }\n\n /**\n * Verify and atomically consume an authorization code. Throws on expiry,\n * replay, client/redirect mismatch, or PKCE failure.\n */\n public async consumeAuthorizationCode(\n realm: string,\n code: string,\n check: { clientId: string; redirectUri: string; codeVerifier: string },\n ): Promise<{ userId: string; scopes: string[]; resource?: string }> {\n const { result } = await this.jwt.parse(code, realm, {\n typ: \"oauth_code\",\n });\n const payload = result.payload as Record<string, unknown>;\n\n const jti = payload.jti as string;\n if (this.usedCodes.has(jti)) {\n throw new AlephaError(\"Authorization code already used\");\n }\n if (payload.client_id !== check.clientId) {\n throw new AlephaError(\"client_id mismatch\");\n }\n if (payload.redirect_uri !== check.redirectUri) {\n throw new AlephaError(\"redirect_uri mismatch\");\n }\n\n const computed = createHash(\"sha256\")\n .update(check.codeVerifier)\n .digest(\"base64url\");\n if (computed !== payload.code_challenge) {\n throw new AlephaError(\"PKCE verification failed\");\n }\n\n this.usedCodes.add(jti);\n return {\n userId: payload.sub as string,\n scopes: (payload.scopes as string[]) ?? [],\n resource: payload.resource as string | undefined,\n };\n }\n}\n","import { $atom, $inject, $state, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $route } from \"alepha/server\";\nimport { renderConsentPage } from \"../helpers/consentPage.ts\";\nimport {\n buildAuthorizationServerMetadata,\n buildProtectedResourceMetadata,\n} from \"../helpers/oauthMetadata.ts\";\nimport { authorizeDecisionBodySchema } from \"../schemas/authorizeDecisionBodySchema.ts\";\nimport { authorizeQuerySchema } from \"../schemas/authorizeQuerySchema.ts\";\nimport { registerClientBodySchema } from \"../schemas/registerClientBodySchema.ts\";\nimport { tokenRequestBodySchema } from \"../schemas/tokenRequestBodySchema.ts\";\nimport { OAuthClientService } from \"../services/OAuthClientService.ts\";\n\n/**\n * Configuration for the OAuth authorization server.\n * `realm` is the issuer realm whose JWTs are minted as access tokens;\n * `resource` is the path of the protected MCP endpoint;\n * `loginPath` is the app-level login page unauthenticated users are\n * redirected to from the authorize endpoint.\n */\nexport const oauthOptions = $atom({\n name: \"alepha.api.oauth.options\",\n description: \"Configuration for the OAuth authorization server.\",\n schema: t.object({\n realm: t.text({ default: \"users\" }),\n resource: t.text({ default: \"/mcp\" }),\n loginPath: t.text({ default: \"/login\" }),\n }),\n default: { realm: \"users\", resource: \"/mcp\", loginPath: \"/login\" },\n});\n\n/**\n * OAuth 2.1 authorization server endpoints: discovery metadata and\n * RFC 7591 dynamic client registration. Authorize/token routes are added\n * separately.\n */\nexport class OAuthController {\n protected readonly log = $logger();\n protected readonly options = $state(oauthOptions);\n protected readonly clients = $inject(OAuthClientService);\n\n /**\n * Absolute origin of the current request, e.g. https://app.com.\n */\n protected baseUrl(url: URL): string {\n return `${url.protocol}//${url.host}`;\n }\n\n metadata = $route({\n method: \"GET\",\n path: \"/.well-known/oauth-authorization-server\",\n handler: ({ url, reply }) => {\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify(\n buildAuthorizationServerMetadata(this.baseUrl(url)),\n );\n },\n });\n\n protectedResource = $route({\n method: \"GET\",\n path: \"/.well-known/oauth-protected-resource\",\n handler: ({ url, reply }) => {\n const base = this.baseUrl(url);\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify(\n buildProtectedResourceMetadata(base, `${base}${this.options.resource}`),\n );\n },\n });\n\n register = $route({\n method: \"POST\",\n path: \"/oauth/register\",\n schema: { body: registerClientBodySchema },\n handler: async ({ body, reply }) => {\n const client = await this.clients.register({\n realm: this.options.realm,\n clientName: body.client_name ?? \"MCP Client\",\n redirectUris: body.redirect_uris,\n scopes: body.scope ? body.scope.split(\" \") : [\"mcp\"],\n source: \"dcr\",\n });\n reply.status = 201;\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify({\n client_id: client.clientId,\n client_id_issued_at: Math.floor(\n new Date(client.createdAt).getTime() / 1000,\n ),\n client_name: client.clientName,\n redirect_uris: client.redirectUris,\n grant_types: [\"authorization_code\"],\n token_endpoint_auth_method: \"none\",\n });\n },\n });\n\n /**\n * GET /oauth/authorize — OAuth 2.1 authorization request. If the user\n * has no session, redirect to the realm login page with a return URL.\n * If authenticated, render the consent screen.\n */\n authorize = $route({\n method: \"GET\",\n path: \"/oauth/authorize\",\n schema: { query: authorizeQuerySchema },\n use: [],\n handler: async ({ query, user, url, reply }) => {\n if (query.response_type !== \"code\") {\n reply.status = 400;\n reply.body = \"unsupported response_type\";\n return;\n }\n if (query.code_challenge_method !== \"S256\") {\n reply.status = 400;\n reply.body = \"code_challenge_method must be S256\";\n return;\n }\n const client = await this.clients.findByClientId(query.client_id);\n if (!client || client.revokedAt) {\n reply.status = 400;\n reply.body = \"unknown client_id\";\n return;\n }\n if (!this.clients.isRedirectUriAllowed(client, query.redirect_uri)) {\n reply.status = 400;\n reply.body = \"redirect_uri not registered\";\n return;\n }\n if (!user) {\n const returnTo = encodeURIComponent(url.pathname + url.search);\n reply.redirect(\n `${this.options.loginPath}?redirect_uri=${returnTo}`,\n 302,\n );\n return;\n }\n reply.headers[\"content-type\"] = \"text/html; charset=utf-8\";\n reply.body = renderConsentPage({\n clientName: client.clientName,\n userName: user.name ?? user.email ?? \"your account\",\n scopes: query.scope ? query.scope.split(\" \") : client.scopes,\n hidden: {\n response_type: query.response_type,\n client_id: query.client_id,\n redirect_uri: query.redirect_uri,\n code_challenge: query.code_challenge,\n code_challenge_method: query.code_challenge_method,\n scope: query.scope ?? \"\",\n state: query.state ?? \"\",\n resource: query.resource ?? \"\",\n },\n });\n },\n });\n\n /**\n * POST /oauth/authorize — consent decision. On \"allow\", mint an\n * authorization code and redirect back to the client's redirect_uri.\n *\n * CSRF: this route carries no CSRF token and relies solely on the session\n * cookie to identify the user. This is a deliberate MVP/MCP tradeoff — a\n * forged consent submit can still only issue an authorization code to an\n * already-registered client, and that code is bound by PKCE, so the\n * attacker cannot redeem it without the matching code_verifier.\n */\n authorizeDecision = $route({\n method: \"POST\",\n path: \"/oauth/authorize\",\n schema: { body: authorizeDecisionBodySchema },\n use: [],\n handler: async ({ body, user, reply }) => {\n if (!user) {\n reply.status = 401;\n reply.body = \"authentication required\";\n return;\n }\n const client = await this.clients.findByClientId(body.client_id);\n if (\n !client ||\n client.revokedAt ||\n !this.clients.isRedirectUriAllowed(client, body.redirect_uri)\n ) {\n reply.status = 400;\n reply.body = \"invalid client\";\n return;\n }\n const redirect = new URL(body.redirect_uri);\n if (body.decision !== \"allow\") {\n redirect.searchParams.set(\"error\", \"access_denied\");\n if (body.state) redirect.searchParams.set(\"state\", body.state);\n reply.redirect(redirect.toString(), 302);\n return;\n }\n const code = await this.clients.createAuthorizationCode(\n this.options.realm,\n {\n userId: user.id,\n clientId: body.client_id,\n redirectUri: body.redirect_uri,\n codeChallenge: body.code_challenge,\n scopes: body.scope ? body.scope.split(\" \") : client.scopes,\n resource: body.resource || undefined,\n },\n );\n redirect.searchParams.set(\"code\", code);\n if (body.state) redirect.searchParams.set(\"state\", body.state);\n reply.redirect(redirect.toString(), 302);\n },\n });\n\n /**\n * POST /oauth/token — supports the `authorization_code` grant (verifies\n * PKCE, mints an access token via the realm issuer) and the\n * `refresh_token` grant (exchanges a refresh token for a fresh access\n * token, so a client stays connected without re-running the flow).\n */\n token = $route({\n method: \"POST\",\n path: \"/oauth/token\",\n schema: { body: tokenRequestBodySchema },\n use: [],\n handler: async ({ body, reply }) => {\n reply.headers[\"content-type\"] = \"application/json\";\n try {\n if (body.grant_type === \"authorization_code\") {\n const grant = await this.clients.consumeAuthorizationCode(\n this.options.realm,\n body.code ?? \"\",\n {\n clientId: body.client_id ?? \"\",\n redirectUri: body.redirect_uri ?? \"\",\n codeVerifier: body.code_verifier ?? \"\",\n },\n );\n const tokens = await this.clients.issueAccessToken(\n this.options.realm,\n { ...grant, clientId: body.client_id ?? \"\" },\n );\n reply.body = JSON.stringify({\n access_token: tokens.access_token,\n token_type: \"Bearer\",\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n scope: grant.scopes.join(\" \"),\n });\n return;\n }\n\n if (body.grant_type === \"refresh_token\") {\n const tokens = await this.clients.refreshAccessToken(\n this.options.realm,\n body.refresh_token ?? \"\",\n );\n reply.body = JSON.stringify({\n access_token: tokens.access_token,\n token_type: \"Bearer\",\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n });\n return;\n }\n\n reply.status = 400;\n reply.body = JSON.stringify({ error: \"unsupported_grant_type\" });\n } catch (e) {\n this.log.warn(\"OAuth token exchange failed\", e);\n reply.status = 400;\n reply.body = JSON.stringify({ error: \"invalid_grant\" });\n }\n },\n });\n}\n","import { $module } from \"alepha\";\nimport { OAuthController } from \"./controllers/OAuthController.ts\";\nimport { OAuthClientService } from \"./services/OAuthClientService.ts\";\n\nexport {\n OAuthController,\n oauthOptions,\n} from \"./controllers/OAuthController.ts\";\nexport type { OAuthClientEntity } from \"./entities/oauthClientEntity.ts\";\nexport { oauthClientEntity } from \"./entities/oauthClientEntity.ts\";\nexport type { RegisterClientOptions } from \"./services/OAuthClientService.ts\";\nexport { OAuthClientService } from \"./services/OAuthClientService.ts\";\n\n/**\n * OAuth 2.1 authorization server module for MCP.\n *\n * **Features:**\n * - OAuth 2.1 authorization code flow with PKCE (RFC 7636)\n * - Dynamic Client Registration (RFC 7591)\n * - Authorization server metadata discovery (RFC 8414)\n * - Stateless authorization codes (short-lived signed JWTs)\n * - Single-use code enforcement\n *\n * **Integration:**\n * Register the module and configure the realm + protected resource path:\n *\n * ```ts\n * const app = Alepha.create()\n * .with(AlephaOAuth)\n * .set(oauthOptions, { realm: \"users\", resource: \"/mcp\" });\n * ```\n *\n * @module alepha.api.oauth\n */\nexport const AlephaOAuth = $module({\n name: \"alepha.api.oauth\",\n services: [OAuthClientService, OAuthController],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/api/oauth/helpers/consentPage.ts","../../../src/api/oauth/helpers/oauthMetadata.ts","../../../src/api/oauth/helpers/oidcMetadata.ts","../../../src/api/oauth/schemas/authorizeDecisionBodySchema.ts","../../../src/api/oauth/schemas/authorizeQuerySchema.ts","../../../src/api/oauth/schemas/registerClientBodySchema.ts","../../../src/api/oauth/schemas/tokenRequestBodySchema.ts","../../../src/api/oauth/entities/oauthClientEntity.ts","../../../src/api/oauth/services/OAuthClientService.ts","../../../src/api/oauth/controllers/OAuthController.ts","../../../src/api/oauth/index.ts"],"sourcesContent":["/**\n * Renders the OAuth consent screen as a self-contained HTML document.\n * Pure server-rendered HTML — no client framework, no @alepha/ui dependency.\n * All authorization parameters are emitted as hidden inputs so the POST to\n * /oauth/authorize is stateless.\n */\nexport interface ConsentPageOptions {\n clientName: string;\n userName: string;\n scopes: string[];\n /**\n * Hidden field name -> value; round-trips the authorization request.\n */\n hidden: Record<string, string>;\n}\n\nconst escapeHtml = (s: string): string =>\n s.replace(\n /[&<>\"']/g,\n (c) =>\n ({\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n })[c] as string,\n );\n\nexport const renderConsentPage = (options: ConsentPageOptions): string => {\n const hidden = Object.entries(options.hidden)\n .map(\n ([k, v]) =>\n `<input type=\"hidden\" name=\"${escapeHtml(k)}\" value=\"${escapeHtml(v)}\" />`,\n )\n .join(\"\");\n const scopes = options.scopes.length\n ? options.scopes.map((s) => `<li>${escapeHtml(s)}</li>`).join(\"\")\n : \"<li>Basic access</li>\";\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<title>Authorize ${escapeHtml(options.clientName)}</title>\n<style>\nbody{font-family:system-ui,sans-serif;background:#0b0b0f;color:#e5e5e5;\ndisplay:flex;min-height:100vh;align-items:center;justify-content:center;margin:0}\n.card{background:#16161d;border:1px solid #2a2a35;border-radius:12px;\npadding:32px;max-width:380px;width:100%}\nh1{font-size:18px;margin:0 0 4px}p{color:#9a9aa5;font-size:14px;margin:4px 0 16px}\nul{font-size:14px;padding-left:18px}\n.row{display:flex;gap:8px;margin-top:20px}\nbutton{flex:1;padding:10px;border-radius:8px;border:0;font-size:14px;cursor:pointer}\n.allow{background:#6d5cf0;color:#fff}.deny{background:#2a2a35;color:#e5e5e5}\n</style></head><body>\n<div class=\"card\">\n<h1>${escapeHtml(options.clientName)} wants to connect</h1>\n<p>Signed in as ${escapeHtml(options.userName)}</p>\n<p>It will be able to:</p>\n<ul>${scopes}</ul>\n<form method=\"POST\" action=\"/oauth/authorize\">${hidden}\n<div class=\"row\">\n<button class=\"deny\" type=\"submit\" name=\"decision\" value=\"deny\">Deny</button>\n<button class=\"allow\" type=\"submit\" name=\"decision\" value=\"allow\">Allow</button>\n</div></form></div></body></html>`;\n};\n","/**\n * RFC 8414 — OAuth 2.0 Authorization Server Metadata.\n * `baseUrl` is the absolute origin of the deployment (e.g. https://app.com).\n */\nexport const buildAuthorizationServerMetadata = (baseUrl: string) => ({\n issuer: baseUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n jwks_uri: `${baseUrl}/oauth/jwks`,\n response_types_supported: [\"code\"],\n grant_types_supported: [\"authorization_code\", \"refresh_token\"],\n code_challenge_methods_supported: [\"S256\"],\n token_endpoint_auth_methods_supported: [\"none\"],\n scopes_supported: [\"mcp\"],\n});\n\n/**\n * RFC 9728 — OAuth 2.0 Protected Resource Metadata.\n * `resource` is the absolute URL of the MCP endpoint being protected.\n */\nexport const buildProtectedResourceMetadata = (\n baseUrl: string,\n resource: string,\n) => ({\n resource,\n authorization_servers: [baseUrl],\n scopes_supported: [\"mcp\"],\n bearer_methods_supported: [\"header\"],\n});\n","/**\n * OpenID Connect Discovery 1.0 — provider metadata document\n * (`/.well-known/openid-configuration`). `baseUrl` is the absolute origin of\n * the OIDC provider (e.g. https://alepha.club).\n */\nexport const buildOpenIdConfiguration = (baseUrl: string) => ({\n issuer: baseUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n jwks_uri: `${baseUrl}/oauth/jwks`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n response_types_supported: [\"code\"],\n grant_types_supported: [\"authorization_code\", \"refresh_token\"],\n subject_types_supported: [\"public\"],\n id_token_signing_alg_values_supported: [\"EdDSA\", \"RS256\"],\n code_challenge_methods_supported: [\"S256\"],\n token_endpoint_auth_methods_supported: [\"none\", \"client_secret_post\"],\n scopes_supported: [\"openid\", \"email\", \"profile\"],\n});\n","import { z } from \"alepha\";\n\n/**\n * Body posted by the consent screen. All authorization-request parameters\n * are round-tripped through hidden form fields so the POST handler can\n * re-validate them without server-side session state.\n */\nexport const authorizeDecisionBodySchema = z.object({\n decision: z.text(),\n response_type: z.text(),\n client_id: z.text(),\n redirect_uri: z.text({ maxLength: 2048 }),\n code_challenge: z.text(),\n code_challenge_method: z.text(),\n scope: z.text({ maxLength: 1024 }).optional(),\n state: z.text({ maxLength: 512 }).optional(),\n resource: z.text({ maxLength: 2048 }).optional(),\n nonce: z.text({ maxLength: 512 }).optional(),\n});\n","import { z } from \"alepha\";\n\n/**\n * OAuth 2.1 authorization request query parameters (GET /oauth/authorize).\n */\nexport const authorizeQuerySchema = z.object({\n response_type: z.text(),\n client_id: z.text(),\n redirect_uri: z.text({ maxLength: 2048 }),\n code_challenge: z.text(),\n code_challenge_method: z.text(),\n scope: z.text({ maxLength: 1024 }).optional(),\n state: z.text({ maxLength: 512 }).optional(),\n resource: z.text({ maxLength: 2048 }).optional(),\n prompt: z.text({ maxLength: 64 }).optional(),\n nonce: z.text({ maxLength: 512 }).optional(),\n});\n","import { z } from \"alepha\";\n\n/**\n * RFC 7591 Dynamic Client Registration request body.\n * Only the fields Alepha consumes are typed; unknown fields are ignored.\n */\nexport const registerClientBodySchema = z\n .object({\n client_name: z.text({ maxLength: 200 }).optional(),\n redirect_uris: z.array(z.text({ maxLength: 2048 })).min(1),\n scope: z.text({ maxLength: 1024 }).optional(),\n grant_types: z.array(z.text()).optional(),\n token_endpoint_auth_method: z.text().optional(),\n })\n .meta({ additionalProperties: true });\n","import { z } from \"alepha\";\n\n/**\n * Body of a POST /oauth/token request. OAuth 2.1 mandates\n * application/x-www-form-urlencoded encoding (section 3.2.2). All fields are\n * optional at the schema level; the handler enforces the grant-specific\n * requirements and returns the appropriate OAuth error responses.\n */\nexport const tokenRequestBodySchema = z.object({\n grant_type: z.text().optional(),\n code: z.text({ maxLength: 4096 }).optional(),\n client_id: z.text().optional(),\n redirect_uri: z.text({ maxLength: 2048 }).optional(),\n code_verifier: z.text({ maxLength: 256 }).optional(),\n refresh_token: z.text({ maxLength: 4096 }).optional(),\n client_secret: z.text({ maxLength: 512 }).optional(),\n});\n","import { type Static, z } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\n/**\n * A registered OAuth 2.1 client application.\n *\n * Rows are created by Dynamic Client Registration (RFC 7591) when an MCP\n * client (e.g. Claude) first connects. `source` records who created the\n * client; for DCR it is always `\"dcr\"` and `createdByUserId` is null until\n * a user completes an authorization.\n */\nexport const oauthClientEntity = $entity({\n name: \"oauth_clients\",\n schema: z.object({\n id: db.primaryKey(z.uuid()),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n clientId: z.text({ maxLength: 64 }),\n clientName: z.text({ maxLength: 200 }),\n redirectUris: db.default(z.array(z.text({ maxLength: 2048 })), []),\n scopes: db.default(z.array(z.text({ maxLength: 64 })), []),\n realm: z.text({ maxLength: 100 }),\n /**\n * OAuth client type. `confidential` clients authenticate at the token\n * endpoint with a secret; `public` clients rely on PKCE only.\n */\n type: db.default(z.enum([\"public\", \"confidential\"]), \"public\"),\n /**\n * First-party client: skip the consent screen. Consent exists to protect a\n * user from THIRD-party apps requesting their data; a trusted client is the\n * authorization server's own product (same vendor), so an authenticated\n * user is sent straight back with a code — no \"App X wants to connect\" page.\n */\n trusted: db.default(z.boolean(), false),\n /**\n * Scrypt hash of the client secret (confidential clients only). Null for\n * public clients. Verified via `OAuthClientService.verifySecret`.\n */\n clientSecretHash: z.text({ maxLength: 256 }).optional(),\n source: db.default(z.text({ maxLength: 16 }), \"dcr\"),\n createdByUserId: z.uuid().optional(),\n lastUsedAt: z.datetime().optional(),\n revokedAt: z.datetime().optional(),\n }),\n indexes: [{ columns: [\"clientId\"], unique: true }],\n});\n\nexport type OAuthClientEntity = Static<typeof oauthClientEntity.schema>;\n","import { createHash, randomUUID } from \"node:crypto\";\nimport { $inject, Alepha, AlephaError } from \"alepha\";\nimport { CryptoProvider } from \"alepha/crypto\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport {\n type IssuerPrimitive,\n JwtProvider,\n type UserAccount,\n} from \"alepha/security\";\nimport {\n type OAuthClientEntity,\n oauthClientEntity,\n} from \"../entities/oauthClientEntity.ts\";\n\n/**\n * The user projection a realm's `loadUser` hands to the OAuth module —\n * a `UserAccount` plus the OIDC profile extras the id_token mints\n * (`email_verified`; `firstName`/`lastName` map to `given_name`/`family_name`).\n */\nexport interface OidcIssuerUser extends UserAccount {\n emailVerified?: boolean;\n}\n\nexport interface RegisterClientOptions {\n realm: string;\n /**\n * Explicit client id (OIDC clients registered by Platform). When omitted,\n * a `mcp_<uuid>` id is generated (Dynamic Client Registration).\n */\n clientId?: string;\n clientName?: string;\n redirectUris: string[];\n scopes?: string[];\n /**\n * `confidential` clients require a `secret` (stored hashed) and authenticate\n * at the token endpoint. Defaults to `public` (PKCE only).\n */\n type?: \"public\" | \"confidential\";\n /** First-party client — skip the consent screen (see the entity field). */\n trusted?: boolean;\n /** Raw secret for a confidential client; stored as a scrypt hash. */\n secret?: string;\n source?: \"dcr\" | \"user\" | \"admin\";\n createdByUserId?: string;\n}\n\n/**\n * Core OAuth 2.1 service backing the authorization server.\n *\n * Responsibilities:\n * - Client registration (RFC 7591 Dynamic Client Registration) and lookup,\n * with exact-match redirect_uri validation.\n * - Stateless PKCE authorization codes: minting short-lived signed JWTs that\n * carry the grant, and verifying/consuming them (replay, expiry, client and\n * redirect_uri checks, S256 PKCE).\n * - Realm issuer registry: realms register an issuer + user loader so the\n * token endpoint can mint access tokens without depending on realm wiring.\n */\nexport class OAuthClientService {\n protected readonly alepha = $inject(Alepha);\n protected readonly dateTime = $inject(DateTimeProvider);\n protected readonly log = $logger();\n protected readonly repo = $repository(oauthClientEntity);\n protected readonly jwt = $inject(JwtProvider);\n protected readonly crypto = $inject(CryptoProvider);\n\n /**\n * Codes already redeemed in this process. Single-use enforcement only\n * needs to cover the ~60s code lifetime, so a bounded in-memory set is\n * sufficient even on serverless — an expired code fails JWT verification\n * regardless.\n */\n protected readonly usedCodes = new Set<string>();\n\n /**\n * Registry of realm issuers used to mint access tokens. Populated by\n * `$realm` (via `registerIssuer`) so the OAuth module does not depend on the\n * realm wiring directly.\n */\n protected readonly issuers = new Map<\n string,\n {\n issuer: IssuerPrimitive;\n loadUser: (userId: string) => Promise<OidcIssuerUser>;\n }\n >();\n\n /**\n * Register a realm issuer and a user loader. Called by `$realm` so the\n * OAuth token endpoint can mint access tokens for that realm.\n */\n public registerIssuer(\n realm: string,\n issuer: IssuerPrimitive,\n loadUser: (userId: string) => Promise<OidcIssuerUser>,\n ): void {\n this.issuers.set(realm, { issuer, loadUser });\n }\n\n /**\n * Mint an access token for a consumed authorization-code grant, using the\n * issuer registered for `realm`. Throws if the realm has no issuer.\n */\n public async issueAccessToken(\n realm: string,\n grant: {\n userId: string;\n scopes: string[];\n resource?: string;\n clientId?: string;\n },\n ): Promise<{\n access_token: string;\n expires_in?: number;\n refresh_token?: string;\n }> {\n const entry = this.issuers.get(realm);\n if (!entry) {\n throw new AlephaError(`No issuer registered for realm '${realm}'`);\n }\n const user = await entry.loadUser(grant.userId);\n // Tag the session the issuer creates with the OAuth client, so it can\n // later be surfaced as a \"connected app\" and revoked individually.\n const tokens = await entry.issuer.createToken(user, undefined, {\n clientId: grant.clientId,\n });\n return {\n access_token: tokens.access_token,\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n };\n }\n\n /**\n * Mint an OIDC `id_token` for a consumed grant, signed by the realm's issuer\n * key (asymmetric when configured). Claims: iss, sub, aud (client_id), exp,\n * iat, nonce (when present), plus the standard profile claims the loader\n * provides: email, email_verified, name, given_name, family_name,\n * preferred_username, picture.\n */\n public async issueIdToken(\n realm: string,\n params: {\n userId: string;\n clientId: string;\n issuer: string;\n nonce?: string;\n },\n ): Promise<string> {\n const entry = this.issuers.get(realm);\n if (!entry) {\n throw new AlephaError(`No issuer registered for realm '${realm}'`);\n }\n const user = await entry.loadUser(params.userId);\n const iat = this.dateTime.now().unix();\n const exp = iat + entry.issuer.accessTokenExpiration.asSeconds();\n return this.jwt.create(\n {\n iss: params.issuer,\n sub: user.id,\n aud: params.clientId,\n exp,\n iat,\n ...(params.nonce ? { nonce: params.nonce } : {}),\n ...(user.email ? { email: user.email } : {}),\n ...(user.emailVerified !== undefined\n ? { email_verified: user.emailVerified }\n : {}),\n ...(user.name ? { name: user.name } : {}),\n ...(user.firstName ? { given_name: user.firstName } : {}),\n ...(user.lastName ? { family_name: user.lastName } : {}),\n ...(user.username ? { preferred_username: user.username } : {}),\n ...(user.picture ? { picture: user.picture } : {}),\n },\n realm,\n { header: { typ: \"JWT\" } },\n );\n }\n\n /**\n * Exchange a refresh token for a fresh access token (OAuth 2.1\n * `refresh_token` grant), using the issuer registered for `realm`. Lets an\n * MCP client stay connected for the refresh token's full lifetime without\n * re-running the authorization flow. Throws if the realm has no issuer or\n * the refresh token is invalid/expired.\n */\n public async refreshAccessToken(\n realm: string,\n refreshToken: string,\n ): Promise<{\n access_token: string;\n expires_in?: number;\n refresh_token?: string;\n /** Subject of the refreshed session — lets the token endpoint re-mint an\n * OIDC `id_token` for relying parties that forward it as the Bearer. */\n userId: string;\n }> {\n const entry = this.issuers.get(realm);\n if (!entry) {\n throw new AlephaError(`No issuer registered for realm '${realm}'`);\n }\n const { tokens, user } = await entry.issuer.refreshToken(refreshToken);\n return {\n access_token: tokens.access_token,\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n userId: user.id,\n };\n }\n\n /**\n * Register a new OAuth client. Used by the RFC 7591 DCR endpoint and,\n * later, by user/admin UIs (via the `source` field).\n */\n public async register(\n options: RegisterClientOptions,\n ): Promise<OAuthClientEntity> {\n if (options.redirectUris.length === 0) {\n throw new AlephaError(\"At least one redirect_uri is required\");\n }\n for (const uri of options.redirectUris) {\n this.assertValidRedirectUri(uri);\n }\n\n const type = options.type ?? \"public\";\n if (type === \"confidential\" && !options.secret) {\n throw new AlephaError(\"A confidential client requires a secret\");\n }\n\n const clientId =\n options.clientId ?? `mcp_${randomUUID().replace(/-/g, \"\")}`;\n const clientSecretHash = options.secret\n ? await this.crypto.hashPassword(options.secret)\n : undefined;\n\n const client = await this.repo.create({\n clientId,\n clientName: options.clientName || \"OAuth Client\",\n redirectUris: options.redirectUris,\n scopes: options.scopes ?? [\"openid\"],\n realm: options.realm,\n type,\n trusted: options.trusted ?? false,\n clientSecretHash,\n source: options.source ?? \"dcr\",\n createdByUserId: options.createdByUserId,\n });\n\n this.log.info(\"OAuth client registered\", {\n clientId,\n type,\n source: client.source,\n });\n return client;\n }\n\n /**\n * Idempotently align a registered client's redirect_uri allowlist with the\n * given list. No-op when the client is unknown or the list already matches —\n * safe to call from post-deploy seeders (allowlist changes ship as code, and\n * `register` alone would leave existing rows stale).\n */\n public async updateRedirectUris(\n clientId: string,\n redirectUris: string[],\n ): Promise<void> {\n if (redirectUris.length === 0) {\n throw new AlephaError(\"At least one redirect_uri is required\");\n }\n for (const uri of redirectUris) {\n this.assertValidRedirectUri(uri);\n }\n const client = await this.findByClientId(clientId);\n if (!client) {\n return;\n }\n if (\n client.redirectUris.length === redirectUris.length &&\n client.redirectUris.every((uri, i) => uri === redirectUris[i])\n ) {\n return;\n }\n await this.repo.updateById(client.id, { redirectUris });\n this.log.info(\"OAuth client redirect_uris updated\", {\n clientId,\n redirectUris,\n });\n }\n\n /**\n * Verify a confidential client's secret against its stored scrypt hash.\n * Returns false for unknown/revoked/public (no-hash) clients.\n */\n public async verifySecret(\n clientId: string,\n secret: string,\n ): Promise<boolean> {\n const client = await this.findByClientId(clientId);\n if (!client || client.revokedAt || !client.clientSecretHash) {\n return false;\n }\n return this.crypto.verifyPassword(secret, client.clientSecretHash);\n }\n\n /**\n * Validate a registered redirect_uri. https (or http://localhost) only, and\n * at most a single `*` which must live inside the host (see\n * `redirectUriMatches` for the matching rule).\n */\n protected assertValidRedirectUri(uri: string): void {\n const stars = (uri.match(/\\*/g) ?? []).length;\n if (stars > 1) {\n throw new AlephaError(\n `At most one '*' wildcard is allowed in redirect_uri: ${uri}`,\n );\n }\n const probe = uri.replace(\"*\", \"wildcard\");\n if (\n !probe.startsWith(\"https://\") &&\n !probe.startsWith(\"http://localhost\")\n ) {\n throw new AlephaError(`Invalid redirect_uri: ${uri}`);\n }\n if (stars === 1) {\n const host = uri.slice(uri.indexOf(\"://\") + 3).split(\"/\")[0] ?? \"\";\n if (!host.includes(\"*\")) {\n throw new AlephaError(\n `Wildcard '*' is only allowed in the host: ${uri}`,\n );\n }\n }\n }\n\n /**\n * Look up a client by its public `clientId`. Returns null if unknown.\n */\n public async findByClientId(\n clientId: string,\n ): Promise<OAuthClientEntity | null> {\n return (\n (await this.repo.findOne({ where: { clientId: { eq: clientId } } })) ??\n null\n );\n }\n\n /**\n * Narrow the scopes a client asks for to those it is actually registered\n * for. The requested scope string is attacker-controlled, so it must never\n * be trusted verbatim — a client registered for `[\"mcp\"]` that asks for\n * `mcp admin` must only be granted `mcp`. When nothing (usable) is\n * requested, the client's full registered set is the default grant.\n * Requested order is preserved and duplicates are dropped.\n */\n public intersectScopes(\n requested: string[] | undefined,\n allowed: string[],\n ): string[] {\n if (!requested || requested.length === 0) {\n return allowed;\n }\n const allowedSet = new Set(allowed);\n const granted: string[] = [];\n for (const scope of requested) {\n if (allowedSet.has(scope) && !granted.includes(scope)) {\n granted.push(scope);\n }\n }\n return granted;\n }\n\n /**\n * Redirect_uri check. A registered pattern is matched byte-exact unless it\n * contains a single `*`, which matches exactly ONE host label (no dots).\n * E.g. `https://*.alepha.club/auth/callback` matches\n * `https://b14.alepha.club/auth/callback` but NOT `https://alepha.club/...`\n * nor `https://a.b.alepha.club/...`.\n */\n public isRedirectUriAllowed(\n client: OAuthClientEntity,\n redirectUri: string,\n ): boolean {\n return client.redirectUris.some((pattern) =>\n this.redirectUriMatches(pattern, redirectUri),\n );\n }\n\n protected redirectUriMatches(pattern: string, candidate: string): boolean {\n if (!pattern.includes(\"*\")) {\n return pattern === candidate;\n }\n // Escape every regex metachar (incl. the `*` and the dots), then turn the\n // single escaped `*` into a one-label match (`[^.]+` — no dots).\n const escaped = pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const rx = new RegExp(`^${escaped.replace(\"\\\\*\", \"[^.]+\")}$`);\n return rx.test(candidate);\n }\n\n /**\n * Mint a stateless authorization code: a short-lived signed JWT\n * (`typ: \"oauth_code\"`) carrying the grant. No server-side code storage.\n */\n public async createAuthorizationCode(\n realm: string,\n grant: {\n userId: string;\n clientId: string;\n redirectUri: string;\n codeChallenge: string;\n scopes: string[];\n resource?: string;\n nonce?: string;\n },\n ): Promise<string> {\n const iat = this.dateTime.now().unix();\n return this.jwt.create(\n {\n sub: grant.userId,\n client_id: grant.clientId,\n redirect_uri: grant.redirectUri,\n code_challenge: grant.codeChallenge,\n scopes: grant.scopes,\n resource: grant.resource,\n nonce: grant.nonce,\n iat,\n exp: iat + 60,\n jti: randomUUID(),\n },\n realm,\n { header: { typ: \"oauth_code\" } },\n );\n }\n\n /**\n * Verify and atomically consume an authorization code. Throws on expiry,\n * replay, client/redirect mismatch, or PKCE failure.\n */\n public async consumeAuthorizationCode(\n realm: string,\n code: string,\n check: { clientId: string; redirectUri: string; codeVerifier: string },\n ): Promise<{\n userId: string;\n scopes: string[];\n resource?: string;\n nonce?: string;\n }> {\n const { result } = await this.jwt.parse(code, realm, {\n typ: \"oauth_code\",\n });\n const payload = result.payload as Record<string, unknown>;\n\n const jti = payload.jti as string;\n if (this.usedCodes.has(jti)) {\n throw new AlephaError(\"Authorization code already used\");\n }\n if (payload.client_id !== check.clientId) {\n throw new AlephaError(\"client_id mismatch\");\n }\n if (payload.redirect_uri !== check.redirectUri) {\n throw new AlephaError(\"redirect_uri mismatch\");\n }\n\n const computed = createHash(\"sha256\")\n .update(check.codeVerifier)\n .digest(\"base64url\");\n if (computed !== payload.code_challenge) {\n throw new AlephaError(\"PKCE verification failed\");\n }\n\n this.usedCodes.add(jti);\n return {\n userId: payload.sub as string,\n scopes: (payload.scopes as string[]) ?? [],\n resource: payload.resource as string | undefined,\n nonce: payload.nonce as string | undefined,\n };\n }\n}\n","import { $atom, $inject, $state, z } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { JwtProvider } from \"alepha/security\";\nimport { $route } from \"alepha/server\";\nimport { renderConsentPage } from \"../helpers/consentPage.ts\";\nimport {\n buildAuthorizationServerMetadata,\n buildProtectedResourceMetadata,\n} from \"../helpers/oauthMetadata.ts\";\nimport { buildOpenIdConfiguration } from \"../helpers/oidcMetadata.ts\";\nimport { authorizeDecisionBodySchema } from \"../schemas/authorizeDecisionBodySchema.ts\";\nimport { authorizeQuerySchema } from \"../schemas/authorizeQuerySchema.ts\";\nimport { registerClientBodySchema } from \"../schemas/registerClientBodySchema.ts\";\nimport { tokenRequestBodySchema } from \"../schemas/tokenRequestBodySchema.ts\";\nimport { OAuthClientService } from \"../services/OAuthClientService.ts\";\n\n/**\n * Configuration for the OAuth authorization server.\n * `realm` is the issuer realm whose JWTs are minted as access tokens;\n * `resource` is the path of the protected MCP endpoint;\n * `loginPath` is the app-level login page unauthenticated users are\n * redirected to from the authorize endpoint.\n */\nexport const oauthOptions = $atom({\n name: \"alepha.api.oauth.options\",\n description: \"Configuration for the OAuth authorization server.\",\n schema: z.object({\n realm: z.text({ default: \"users\" }),\n resource: z.text({ default: \"/mcp\" }),\n loginPath: z.text({ default: \"/login\" }),\n }),\n default: { realm: \"users\", resource: \"/mcp\", loginPath: \"/login\" },\n});\n\n/**\n * OAuth 2.1 authorization server endpoints: discovery metadata and\n * RFC 7591 dynamic client registration. Authorize/token routes are added\n * separately.\n */\nexport class OAuthController {\n protected readonly log = $logger();\n protected readonly options = $state(oauthOptions);\n protected readonly clients = $inject(OAuthClientService);\n protected readonly jwt = $inject(JwtProvider);\n\n /**\n * Absolute origin of the current request, e.g. https://app.com.\n */\n protected baseUrl(url: URL): string {\n return `${url.protocol}//${url.host}`;\n }\n\n metadata = $route({\n method: \"GET\",\n path: \"/.well-known/oauth-authorization-server\",\n handler: ({ url, reply }) => {\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify(\n buildAuthorizationServerMetadata(this.baseUrl(url)),\n );\n },\n });\n\n protectedResource = $route({\n method: \"GET\",\n path: \"/.well-known/oauth-protected-resource\",\n handler: ({ url, reply }) => {\n const base = this.baseUrl(url);\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify(\n buildProtectedResourceMetadata(base, `${base}${this.options.resource}`),\n );\n },\n });\n\n openidConfiguration = $route({\n method: \"GET\",\n path: \"/.well-known/openid-configuration\",\n handler: ({ url, reply }) => {\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify(buildOpenIdConfiguration(this.baseUrl(url)));\n },\n });\n\n jwks = $route({\n method: \"GET\",\n path: \"/oauth/jwks\",\n handler: async ({ reply }) => {\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify(await this.jwt.getJwks(this.options.realm));\n },\n });\n\n register = $route({\n method: \"POST\",\n path: \"/oauth/register\",\n schema: { body: registerClientBodySchema },\n handler: async ({ body, reply }) => {\n const client = await this.clients.register({\n realm: this.options.realm,\n clientName: body.client_name ?? \"MCP Client\",\n redirectUris: body.redirect_uris,\n scopes: body.scope ? body.scope.split(\" \") : [\"mcp\"],\n source: \"dcr\",\n });\n reply.status = 201;\n reply.headers[\"content-type\"] = \"application/json\";\n reply.body = JSON.stringify({\n client_id: client.clientId,\n client_id_issued_at: Math.floor(\n new Date(client.createdAt).getTime() / 1000,\n ),\n client_name: client.clientName,\n redirect_uris: client.redirectUris,\n grant_types: [\"authorization_code\"],\n token_endpoint_auth_method: \"none\",\n });\n },\n });\n\n /**\n * GET /oauth/authorize — OAuth 2.1 authorization request. If the user\n * has no session, redirect to the realm login page with a return URL.\n * If authenticated, render the consent screen.\n */\n authorize = $route({\n method: \"GET\",\n path: \"/oauth/authorize\",\n schema: { query: authorizeQuerySchema },\n use: [],\n handler: async ({ query, user, url, reply }) => {\n if (query.response_type !== \"code\") {\n reply.status = 400;\n reply.body = \"unsupported response_type\";\n return;\n }\n if (query.code_challenge_method !== \"S256\") {\n reply.status = 400;\n reply.body = \"code_challenge_method must be S256\";\n return;\n }\n const client = await this.clients.findByClientId(query.client_id);\n if (!client || client.revokedAt) {\n reply.status = 400;\n reply.body = \"unknown client_id\";\n return;\n }\n if (!this.clients.isRedirectUriAllowed(client, query.redirect_uri)) {\n reply.status = 400;\n reply.body = \"redirect_uri not registered\";\n return;\n }\n const silent = query.prompt === \"none\";\n // Skip the consent screen for `prompt=none` (silent SSO) AND for trusted\n // first-party clients (the AS's own product — consent is for third-party\n // apps). A non-silent trusted client still sends an unauthenticated user\n // through login first; it just never shows the \"wants to connect\" page.\n const skipConsent = silent || client.trusted === true;\n\n if (!user) {\n if (silent) {\n // Silent SSO with no IdP session → OIDC `login_required`.\n const redirect = new URL(query.redirect_uri);\n redirect.searchParams.set(\"error\", \"login_required\");\n if (query.state) redirect.searchParams.set(\"state\", query.state);\n reply.redirect(redirect.toString(), 302);\n return;\n }\n const returnTo = encodeURIComponent(url.pathname + url.search);\n reply.redirect(\n `${this.options.loginPath}?redirect_uri=${returnTo}`,\n 302,\n );\n return;\n }\n\n if (skipConsent) {\n // Authenticated + (prompt=none OR trusted client) → skip consent and\n // mint the code directly (silent SSO + first-party login).\n const code = await this.clients.createAuthorizationCode(\n this.options.realm,\n {\n userId: user.id,\n clientId: query.client_id,\n redirectUri: query.redirect_uri,\n codeChallenge: query.code_challenge,\n scopes: this.clients.intersectScopes(\n query.scope?.split(\" \"),\n client.scopes,\n ),\n resource: query.resource || undefined,\n nonce: query.nonce,\n },\n );\n const redirect = new URL(query.redirect_uri);\n redirect.searchParams.set(\"code\", code);\n if (query.state) redirect.searchParams.set(\"state\", query.state);\n reply.redirect(redirect.toString(), 302);\n return;\n }\n\n reply.headers[\"content-type\"] = \"text/html; charset=utf-8\";\n reply.body = renderConsentPage({\n clientName: client.clientName,\n userName: user.name ?? user.email ?? \"your account\",\n // Show the user the scopes they will actually grant, not the raw\n // (possibly over-broad) request.\n scopes: this.clients.intersectScopes(\n query.scope?.split(\" \"),\n client.scopes,\n ),\n hidden: {\n response_type: query.response_type,\n client_id: query.client_id,\n redirect_uri: query.redirect_uri,\n code_challenge: query.code_challenge,\n code_challenge_method: query.code_challenge_method,\n scope: query.scope ?? \"\",\n state: query.state ?? \"\",\n resource: query.resource ?? \"\",\n nonce: query.nonce ?? \"\",\n },\n });\n },\n });\n\n /**\n * POST /oauth/authorize — consent decision. On \"allow\", mint an\n * authorization code and redirect back to the client's redirect_uri.\n *\n * CSRF: this route carries no CSRF token and relies solely on the session\n * cookie to identify the user. This is a deliberate MVP/MCP tradeoff — a\n * forged consent submit can still only issue an authorization code to an\n * already-registered client, and that code is bound by PKCE, so the\n * attacker cannot redeem it without the matching code_verifier.\n */\n authorizeDecision = $route({\n method: \"POST\",\n path: \"/oauth/authorize\",\n schema: { body: authorizeDecisionBodySchema },\n use: [],\n handler: async ({ body, user, reply }) => {\n if (!user) {\n reply.status = 401;\n reply.body = \"authentication required\";\n return;\n }\n const client = await this.clients.findByClientId(body.client_id);\n if (\n !client ||\n client.revokedAt ||\n !this.clients.isRedirectUriAllowed(client, body.redirect_uri)\n ) {\n reply.status = 400;\n reply.body = \"invalid client\";\n return;\n }\n const redirect = new URL(body.redirect_uri);\n if (body.decision !== \"allow\") {\n redirect.searchParams.set(\"error\", \"access_denied\");\n if (body.state) redirect.searchParams.set(\"state\", body.state);\n reply.redirect(redirect.toString(), 302);\n return;\n }\n const code = await this.clients.createAuthorizationCode(\n this.options.realm,\n {\n userId: user.id,\n clientId: body.client_id,\n redirectUri: body.redirect_uri,\n codeChallenge: body.code_challenge,\n scopes: this.clients.intersectScopes(\n body.scope?.split(\" \"),\n client.scopes,\n ),\n resource: body.resource || undefined,\n nonce: body.nonce,\n },\n );\n redirect.searchParams.set(\"code\", code);\n if (body.state) redirect.searchParams.set(\"state\", body.state);\n reply.redirect(redirect.toString(), 302);\n },\n });\n\n /**\n * POST /oauth/token — supports the `authorization_code` grant (verifies\n * PKCE, mints an access token via the realm issuer) and the\n * `refresh_token` grant (exchanges a refresh token for a fresh access\n * token, so a client stays connected without re-running the flow).\n */\n token = $route({\n method: \"POST\",\n path: \"/oauth/token\",\n schema: { body: tokenRequestBodySchema },\n use: [],\n handler: async ({ body, url, reply }) => {\n reply.headers[\"content-type\"] = \"application/json\";\n try {\n if (body.grant_type === \"authorization_code\") {\n const client = await this.clients.findByClientId(\n body.client_id ?? \"\",\n );\n if (!client || client.revokedAt) {\n reply.status = 400;\n reply.body = JSON.stringify({ error: \"invalid_client\" });\n return;\n }\n if (client.type === \"confidential\") {\n const ok = await this.clients.verifySecret(\n client.clientId,\n body.client_secret ?? \"\",\n );\n if (!ok) {\n reply.status = 401;\n reply.body = JSON.stringify({ error: \"invalid_client\" });\n return;\n }\n }\n const grant = await this.clients.consumeAuthorizationCode(\n this.options.realm,\n body.code ?? \"\",\n {\n clientId: body.client_id ?? \"\",\n redirectUri: body.redirect_uri ?? \"\",\n codeVerifier: body.code_verifier ?? \"\",\n },\n );\n const tokens = await this.clients.issueAccessToken(\n this.options.realm,\n { ...grant, clientId: body.client_id ?? \"\" },\n );\n const response: Record<string, unknown> = {\n access_token: tokens.access_token,\n token_type: \"Bearer\",\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n scope: grant.scopes.join(\" \"),\n };\n if (grant.scopes.includes(\"openid\")) {\n response.id_token = await this.clients.issueIdToken(\n this.options.realm,\n {\n userId: grant.userId,\n clientId: body.client_id ?? \"\",\n issuer: this.baseUrl(url),\n nonce: grant.nonce,\n },\n );\n }\n reply.body = JSON.stringify(response);\n return;\n }\n\n if (body.grant_type === \"refresh_token\") {\n const tokens = await this.clients.refreshAccessToken(\n this.options.realm,\n body.refresh_token ?? \"\",\n );\n const response: Record<string, unknown> = {\n access_token: tokens.access_token,\n token_type: \"Bearer\",\n expires_in: tokens.expires_in,\n refresh_token: tokens.refresh_token,\n };\n // Re-mint an OIDC `id_token` so id_token-based relying parties (e.g. a\n // stateless OIDC RP that forwards the id_token as the request Bearer)\n // actually renew their identity on refresh — without it the RP keeps\n // forwarding the now-expired id_token and every call 401s. Per OIDC\n // Core §12.2 the refreshed id_token carries no `nonce`; `sub` is\n // unchanged. Requires `client_id` to set the `aud`.\n if (body.client_id) {\n response.id_token = await this.clients.issueIdToken(\n this.options.realm,\n {\n userId: tokens.userId,\n clientId: body.client_id,\n issuer: this.baseUrl(url),\n },\n );\n }\n reply.body = JSON.stringify(response);\n return;\n }\n\n reply.status = 400;\n reply.body = JSON.stringify({ error: \"unsupported_grant_type\" });\n } catch (e) {\n this.log.warn(\"OAuth token exchange failed\", e);\n reply.status = 400;\n reply.body = JSON.stringify({ error: \"invalid_grant\" });\n }\n },\n });\n}\n","import { $module } from \"alepha\";\nimport { OAuthController } from \"./controllers/OAuthController.ts\";\nimport { OAuthClientService } from \"./services/OAuthClientService.ts\";\n\nexport {\n OAuthController,\n oauthOptions,\n} from \"./controllers/OAuthController.ts\";\nexport type { OAuthClientEntity } from \"./entities/oauthClientEntity.ts\";\nexport { oauthClientEntity } from \"./entities/oauthClientEntity.ts\";\nexport { buildOpenIdConfiguration } from \"./helpers/oidcMetadata.ts\";\nexport type { RegisterClientOptions } from \"./services/OAuthClientService.ts\";\nexport { OAuthClientService } from \"./services/OAuthClientService.ts\";\n\n/**\n * OAuth 2.1 authorization server module for MCP.\n *\n * **Features:**\n * - OAuth 2.1 authorization code flow with PKCE (RFC 7636)\n * - Dynamic Client Registration (RFC 7591)\n * - Authorization server metadata discovery (RFC 8414)\n * - Stateless authorization codes (short-lived signed JWTs)\n * - Single-use code enforcement\n *\n * **Integration:**\n * Register the module and configure the realm + protected resource path:\n *\n * ```ts\n * const app = Alepha.create()\n * .with(AlephaOAuth)\n * .set(oauthOptions, { realm: \"users\", resource: \"/mcp\" });\n * ```\n *\n * @module alepha.api.oauth\n */\nexport const AlephaOAuth = $module({\n name: \"alepha.api.oauth\",\n services: [OAuthClientService, OAuthController],\n});\n"],"mappings":"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"}
@@ -1,19 +1,19 @@
1
- import { t } from "alepha";
1
+ import { z } from "alepha";
2
2
  import { $entity, db, pageQuerySchema } from "alepha/orm";
3
3
  //#region ../../src/api/organizations/entities/organizations.ts
4
4
  const organizations = $entity({
5
5
  name: "organizations",
6
- schema: t.object({
7
- id: db.primaryKey(t.uuid()),
6
+ schema: z.object({
7
+ id: db.primaryKey(z.uuid()),
8
8
  version: db.version(),
9
9
  createdAt: db.createdAt(),
10
10
  updatedAt: db.updatedAt(),
11
- name: t.text(),
12
- slug: t.text({
11
+ name: z.text(),
12
+ slug: z.text({
13
13
  minLength: 2,
14
14
  maxLength: 100
15
15
  }),
16
- enabled: db.default(t.boolean(), true)
16
+ enabled: db.default(z.boolean(), true)
17
17
  }),
18
18
  indexes: [{
19
19
  columns: ["slug"],
@@ -22,26 +22,26 @@ const organizations = $entity({
22
22
  });
23
23
  //#endregion
24
24
  //#region ../../src/api/organizations/schemas/createOrganizationSchema.ts
25
- const createOrganizationSchema = t.object({
26
- name: t.text(),
27
- slug: t.text({
25
+ const createOrganizationSchema = z.object({
26
+ name: z.text(),
27
+ slug: z.text({
28
28
  minLength: 2,
29
29
  maxLength: 100
30
30
  }),
31
- enabled: t.optional(t.boolean())
31
+ enabled: z.boolean().optional()
32
32
  });
33
33
  //#endregion
34
34
  //#region ../../src/api/organizations/schemas/organizationQuerySchema.ts
35
- const organizationQuerySchema = t.extend(pageQuerySchema, {
36
- name: t.optional(t.text({ description: "Filter by name (partial match)" })),
37
- enabled: t.optional(t.boolean({ description: "Filter by enabled status" }))
35
+ const organizationQuerySchema = pageQuerySchema.extend({
36
+ name: z.text({ description: "Filter by name (partial match)" }).optional(),
37
+ enabled: z.boolean().describe("Filter by enabled status").optional()
38
38
  });
39
39
  //#endregion
40
40
  //#region ../../src/api/organizations/schemas/organizationResourceSchema.ts
41
41
  const organizationResourceSchema = organizations.schema;
42
42
  //#endregion
43
43
  //#region ../../src/api/organizations/schemas/updateOrganizationSchema.ts
44
- const updateOrganizationSchema = t.partial(createOrganizationSchema);
44
+ const updateOrganizationSchema = createOrganizationSchema.partial();
45
45
  //#endregion
46
46
  export { createOrganizationSchema, organizationQuerySchema, organizationResourceSchema, organizations, updateOrganizationSchema };
47
47
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/api/organizations/entities/organizations.ts","../../../src/api/organizations/schemas/createOrganizationSchema.ts","../../../src/api/organizations/schemas/organizationQuerySchema.ts","../../../src/api/organizations/schemas/organizationResourceSchema.ts","../../../src/api/organizations/schemas/updateOrganizationSchema.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const organizations = $entity({\n name: \"organizations\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n version: db.version(),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n\n name: t.text(),\n slug: t.text({ minLength: 2, maxLength: 100 }),\n enabled: db.default(t.boolean(), true),\n }),\n indexes: [{ columns: [\"slug\"], unique: true }],\n});\n\nexport type OrganizationEntity = Static<typeof organizations.schema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\n\nexport const createOrganizationSchema = t.object({\n name: t.text(),\n slug: t.text({ minLength: 2, maxLength: 100 }),\n enabled: t.optional(t.boolean()),\n});\n\nexport type CreateOrganization = Static<typeof createOrganizationSchema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const organizationQuerySchema = t.extend(pageQuerySchema, {\n name: t.optional(t.text({ description: \"Filter by name (partial match)\" })),\n enabled: t.optional(t.boolean({ description: \"Filter by enabled status\" })),\n});\n\nexport type OrganizationQuery = Static<typeof organizationQuerySchema>;\n","import type { Static } from \"alepha\";\nimport { organizations } from \"../entities/organizations.ts\";\n\nexport const organizationResourceSchema = organizations.schema;\n\nexport type OrganizationResource = Static<typeof organizationResourceSchema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { createOrganizationSchema } from \"./createOrganizationSchema.ts\";\n\nexport const updateOrganizationSchema = t.partial(createOrganizationSchema);\n\nexport type UpdateOrganization = Static<typeof updateOrganizationSchema>;\n"],"mappings":";;;AAIA,MAAa,gBAAgB,QAAQ;CACnC,MAAM;CACN,QAAQ,EAAE,OAAO;EACf,IAAI,GAAG,WAAW,EAAE,KAAK,CAAC;EAC1B,SAAS,GAAG,QAAQ;EACpB,WAAW,GAAG,UAAU;EACxB,WAAW,GAAG,UAAU;EAExB,MAAM,EAAE,KAAK;EACb,MAAM,EAAE,KAAK;GAAE,WAAW;GAAG,WAAW;EAAI,CAAC;EAC7C,SAAS,GAAG,QAAQ,EAAE,QAAQ,GAAG,IAAI;CACvC,CAAC;CACD,SAAS,CAAC;EAAE,SAAS,CAAC,MAAM;EAAG,QAAQ;CAAK,CAAC;AAC/C,CAAC;;;ACdD,MAAa,2BAA2B,EAAE,OAAO;CAC/C,MAAM,EAAE,KAAK;CACb,MAAM,EAAE,KAAK;EAAE,WAAW;EAAG,WAAW;CAAI,CAAC;CAC7C,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;AACjC,CAAC;;;ACHD,MAAa,0BAA0B,EAAE,OAAO,iBAAiB;CAC/D,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,iCAAiC,CAAC,CAAC;CAC1E,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,2BAA2B,CAAC,CAAC;AAC5E,CAAC;;;ACJD,MAAa,6BAA6B,cAAc;;;ACCxD,MAAa,2BAA2B,EAAE,QAAQ,wBAAwB"}
1
+ {"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/api/organizations/entities/organizations.ts","../../../src/api/organizations/schemas/createOrganizationSchema.ts","../../../src/api/organizations/schemas/organizationQuerySchema.ts","../../../src/api/organizations/schemas/organizationResourceSchema.ts","../../../src/api/organizations/schemas/updateOrganizationSchema.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { z } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const organizations = $entity({\n name: \"organizations\",\n schema: z.object({\n id: db.primaryKey(z.uuid()),\n version: db.version(),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n\n name: z.text(),\n slug: z.text({ minLength: 2, maxLength: 100 }),\n enabled: db.default(z.boolean(), true),\n }),\n indexes: [{ columns: [\"slug\"], unique: true }],\n});\n\nexport type OrganizationEntity = Static<typeof organizations.schema>;\n","import type { Static } from \"alepha\";\nimport { z } from \"alepha\";\n\nexport const createOrganizationSchema = z.object({\n name: z.text(),\n slug: z.text({ minLength: 2, maxLength: 100 }),\n enabled: z.boolean().optional(),\n});\n\nexport type CreateOrganization = Static<typeof createOrganizationSchema>;\n","import type { Static } from \"alepha\";\nimport { z } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const organizationQuerySchema = pageQuerySchema.extend({\n name: z.text({ description: \"Filter by name (partial match)\" }).optional(),\n enabled: z.boolean().describe(\"Filter by enabled status\").optional(),\n});\n\nexport type OrganizationQuery = Static<typeof organizationQuerySchema>;\n","import type { Static } from \"alepha\";\nimport { organizations } from \"../entities/organizations.ts\";\n\nexport const organizationResourceSchema = organizations.schema;\n\nexport type OrganizationResource = Static<typeof organizationResourceSchema>;\n","import type { Static } from \"alepha\";\nimport { createOrganizationSchema } from \"./createOrganizationSchema.ts\";\n\nexport const updateOrganizationSchema = createOrganizationSchema.partial();\n\nexport type UpdateOrganization = Static<typeof updateOrganizationSchema>;\n"],"mappings":";;;AAIA,MAAa,gBAAgB,QAAQ;CACnC,MAAM;CACN,QAAQ,EAAE,OAAO;EACf,IAAI,GAAG,WAAW,EAAE,KAAK,CAAC;EAC1B,SAAS,GAAG,QAAQ;EACpB,WAAW,GAAG,UAAU;EACxB,WAAW,GAAG,UAAU;EAExB,MAAM,EAAE,KAAK;EACb,MAAM,EAAE,KAAK;GAAE,WAAW;GAAG,WAAW;EAAI,CAAC;EAC7C,SAAS,GAAG,QAAQ,EAAE,QAAQ,GAAG,IAAI;CACvC,CAAC;CACD,SAAS,CAAC;EAAE,SAAS,CAAC,MAAM;EAAG,QAAQ;CAAK,CAAC;AAC/C,CAAC;;;ACdD,MAAa,2BAA2B,EAAE,OAAO;CAC/C,MAAM,EAAE,KAAK;CACb,MAAM,EAAE,KAAK;EAAE,WAAW;EAAG,WAAW;CAAI,CAAC;CAC7C,SAAS,EAAE,QAAQ,CAAC,CAAC,SAAS;AAChC,CAAC;;;ACHD,MAAa,0BAA0B,gBAAgB,OAAO;CAC5D,MAAM,EAAE,KAAK,EAAE,aAAa,iCAAiC,CAAC,CAAC,CAAC,SAAS;CACzE,SAAS,EAAE,QAAQ,CAAC,CAAC,SAAS,0BAA0B,CAAC,CAAC,SAAS;AACrE,CAAC;;;ACJD,MAAa,6BAA6B,cAAc;;;ACAxD,MAAa,2BAA2B,yBAAyB,QAAQ"}