alepha 0.18.2 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (397) hide show
  1. package/assets/devtools-ui/200.html +2 -2
  2. package/assets/devtools-ui/200.html.br +0 -0
  3. package/assets/devtools-ui/404.html +2 -2
  4. package/assets/devtools-ui/404.html.br +0 -0
  5. package/assets/devtools-ui/{asset.BfSBZ5Dd.css → asset.hG_f8HuK.css} +1 -1
  6. package/assets/devtools-ui/asset.hG_f8HuK.css.br +0 -0
  7. package/assets/devtools-ui/chunk.B3au4Lhg.js +1 -0
  8. package/assets/devtools-ui/chunk.B3au4Lhg.js.br +0 -0
  9. package/assets/devtools-ui/chunk.BLOrlnMB.js +1 -0
  10. package/assets/devtools-ui/chunk.BLOrlnMB.js.br +0 -0
  11. package/assets/devtools-ui/chunk.BLR01ljW.js +1 -0
  12. package/assets/devtools-ui/chunk.BLR01ljW.js.br +0 -0
  13. package/assets/devtools-ui/chunk.BTXaIUlA.js +1 -0
  14. package/assets/devtools-ui/chunk.BTXaIUlA.js.br +0 -0
  15. package/assets/devtools-ui/{chunk.lJL-lgnW.js → chunk.BhJaxmm8.js} +1 -1
  16. package/assets/devtools-ui/chunk.BhJaxmm8.js.br +0 -0
  17. package/assets/devtools-ui/chunk.BtoNxFuL.js +1 -0
  18. package/assets/devtools-ui/chunk.BtoNxFuL.js.br +0 -0
  19. package/assets/devtools-ui/chunk.C8YUV2Wd.js +1 -0
  20. package/assets/devtools-ui/chunk.C8YUV2Wd.js.br +0 -0
  21. package/assets/devtools-ui/{chunk.M6wyKO_3.js → chunk.CBbIgDzE.js} +2 -2
  22. package/assets/devtools-ui/chunk.CBbIgDzE.js.br +0 -0
  23. package/assets/devtools-ui/chunk.CFqIniwA.js +1 -0
  24. package/assets/devtools-ui/chunk.CFqIniwA.js.br +0 -0
  25. package/assets/devtools-ui/chunk.CLFF7f7-.js +1 -0
  26. package/assets/devtools-ui/chunk.CLFF7f7-.js.br +0 -0
  27. package/assets/devtools-ui/chunk.CRsBbA10.js +1 -0
  28. package/assets/devtools-ui/chunk.CRsBbA10.js.br +0 -0
  29. package/assets/devtools-ui/{chunk.DbEH1oOB.js → chunk.CZPo6v95.js} +1 -1
  30. package/assets/devtools-ui/chunk.CZPo6v95.js.br +0 -0
  31. package/assets/devtools-ui/chunk.D0fWgNos.js +1 -0
  32. package/assets/devtools-ui/chunk.D0fWgNos.js.br +1 -0
  33. package/assets/devtools-ui/chunk.D7-0ziQ6.js +1 -0
  34. package/assets/devtools-ui/chunk.D7-0ziQ6.js.br +0 -0
  35. package/assets/devtools-ui/chunk.DAewe0vm.js +1 -0
  36. package/assets/devtools-ui/chunk.DAewe0vm.js.br +0 -0
  37. package/assets/devtools-ui/chunk.DJRQEYqK.js +1 -0
  38. package/assets/devtools-ui/chunk.DJRQEYqK.js.br +0 -0
  39. package/assets/devtools-ui/{chunk.CZl6J9DF.js → chunk.DMAxv14p.js} +1 -1
  40. package/assets/devtools-ui/chunk.DMAxv14p.js.br +0 -0
  41. package/assets/devtools-ui/{chunk.BT2IiBkZ.js → chunk.DMImnNjU.js} +1 -1
  42. package/assets/devtools-ui/chunk.DMImnNjU.js.br +0 -0
  43. package/assets/devtools-ui/chunk.DeeQsidk.js +9 -0
  44. package/assets/devtools-ui/chunk.DeeQsidk.js.br +0 -0
  45. package/assets/devtools-ui/chunk.DqEwn9Vj.js +7 -0
  46. package/assets/devtools-ui/chunk.DqEwn9Vj.js.br +0 -0
  47. package/assets/devtools-ui/chunk.Dt8OsQey.js +1 -0
  48. package/assets/devtools-ui/chunk.Dt8OsQey.js.br +0 -0
  49. package/assets/devtools-ui/{chunk.B9pX3zit.js → chunk.Dtp8oa_f.js} +1 -1
  50. package/assets/devtools-ui/chunk.Dtp8oa_f.js.br +0 -0
  51. package/assets/devtools-ui/chunk.Dx3JzAYM.js +1 -0
  52. package/assets/devtools-ui/chunk.Dx3JzAYM.js.br +0 -0
  53. package/assets/devtools-ui/chunk.GCOj1-5E.js +1 -0
  54. package/assets/devtools-ui/chunk.GCOj1-5E.js.br +0 -0
  55. package/assets/devtools-ui/chunk.IC1LD8BH.js +1 -0
  56. package/assets/devtools-ui/chunk.IC1LD8BH.js.br +0 -0
  57. package/assets/devtools-ui/chunk.IwuB_TqW.js +1 -0
  58. package/assets/devtools-ui/chunk.IwuB_TqW.js.br +0 -0
  59. package/assets/devtools-ui/chunk.Qqapj2zq.js +1 -0
  60. package/assets/devtools-ui/chunk.Qqapj2zq.js.br +0 -0
  61. package/assets/devtools-ui/{chunk.C79YouPp.js → chunk.TKKKndOy.js} +1 -1
  62. package/assets/devtools-ui/chunk.TKKKndOy.js.br +0 -0
  63. package/assets/devtools-ui/chunk.YHTVhFQT.js +1 -0
  64. package/assets/devtools-ui/chunk.YHTVhFQT.js.br +0 -0
  65. package/assets/devtools-ui/chunk.fnod6uEi.js +1 -0
  66. package/assets/devtools-ui/chunk.fnod6uEi.js.br +0 -0
  67. package/assets/devtools-ui/chunk.mOCRmXjo.js +1 -0
  68. package/assets/devtools-ui/chunk.mOCRmXjo.js.br +0 -0
  69. package/assets/devtools-ui/chunk.qZTNEAK0.js +1 -0
  70. package/assets/devtools-ui/chunk.qZTNEAK0.js.br +0 -0
  71. package/assets/devtools-ui/chunk.rc9m0y4-.js +1 -0
  72. package/assets/devtools-ui/chunk.rc9m0y4-.js.br +0 -0
  73. package/assets/devtools-ui/entry.Cxc5QLCU.js +80 -0
  74. package/assets/devtools-ui/entry.Cxc5QLCU.js.br +0 -0
  75. package/assets/devtools-ui/index.html +2 -2
  76. package/assets/devtools-ui/index.html.br +0 -0
  77. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  78. package/assets/swagger-ui/swagger-ui.css +1 -1
  79. package/dist/api/audits/index.d.ts +61 -5
  80. package/dist/api/audits/index.d.ts.map +1 -1
  81. package/dist/api/files/index.d.ts +61 -5
  82. package/dist/api/files/index.d.ts.map +1 -1
  83. package/dist/api/jobs/index.d.ts +61 -5
  84. package/dist/api/jobs/index.d.ts.map +1 -1
  85. package/dist/api/jobs/index.js +4 -2
  86. package/dist/api/jobs/index.js.map +1 -1
  87. package/dist/api/keys/index.d.ts +5 -5
  88. package/dist/api/notifications/index.browser.js +44 -1
  89. package/dist/api/notifications/index.browser.js.map +1 -1
  90. package/dist/api/notifications/index.d.ts +187 -2
  91. package/dist/api/notifications/index.d.ts.map +1 -1
  92. package/dist/api/notifications/index.js +143 -8
  93. package/dist/api/notifications/index.js.map +1 -1
  94. package/dist/api/parameters/index.d.ts +61 -5
  95. package/dist/api/parameters/index.d.ts.map +1 -1
  96. package/dist/api/users/index.d.ts +330 -93
  97. package/dist/api/users/index.d.ts.map +1 -1
  98. package/dist/api/users/index.js +27 -36
  99. package/dist/api/users/index.js.map +1 -1
  100. package/dist/cli/config/index.d.ts +46 -0
  101. package/dist/cli/config/index.d.ts.map +1 -0
  102. package/dist/cli/config/index.js +20 -0
  103. package/dist/cli/config/index.js.map +1 -0
  104. package/dist/cli/core/index.d.ts +69 -66
  105. package/dist/cli/core/index.d.ts.map +1 -1
  106. package/dist/cli/core/index.js +329 -196
  107. package/dist/cli/core/index.js.map +1 -1
  108. package/dist/cli/platform/index.d.ts +302 -63
  109. package/dist/cli/platform/index.d.ts.map +1 -1
  110. package/dist/cli/platform/index.js +455 -25
  111. package/dist/cli/platform/index.js.map +1 -1
  112. package/dist/core/index.browser.js +125 -87
  113. package/dist/core/index.browser.js.map +1 -1
  114. package/dist/core/index.d.ts +62 -53
  115. package/dist/core/index.d.ts.map +1 -1
  116. package/dist/core/index.js +125 -87
  117. package/dist/core/index.js.map +1 -1
  118. package/dist/core/index.native.js +125 -87
  119. package/dist/core/index.native.js.map +1 -1
  120. package/dist/core/index.workerd.js +125 -87
  121. package/dist/core/index.workerd.js.map +1 -1
  122. package/dist/crypto/index.d.ts +18 -1
  123. package/dist/crypto/index.d.ts.map +1 -1
  124. package/dist/crypto/index.js +29 -3
  125. package/dist/crypto/index.js.map +1 -1
  126. package/dist/devtools/index.js +3 -12
  127. package/dist/devtools/index.js.map +1 -1
  128. package/dist/logger/index.d.ts +10 -1
  129. package/dist/logger/index.d.ts.map +1 -1
  130. package/dist/logger/index.js +19 -9
  131. package/dist/logger/index.js.map +1 -1
  132. package/dist/orm/core/index.browser.js +57 -1
  133. package/dist/orm/core/index.browser.js.map +1 -1
  134. package/dist/orm/core/index.bun.js +378 -19
  135. package/dist/orm/core/index.bun.js.map +1 -1
  136. package/dist/orm/core/index.d.ts +328 -9
  137. package/dist/orm/core/index.d.ts.map +1 -1
  138. package/dist/orm/core/index.js +384 -21
  139. package/dist/orm/core/index.js.map +1 -1
  140. package/dist/orm/postgres/index.bun.js +49 -17
  141. package/dist/orm/postgres/index.bun.js.map +1 -1
  142. package/dist/orm/postgres/index.d.ts +47 -21
  143. package/dist/orm/postgres/index.d.ts.map +1 -1
  144. package/dist/orm/postgres/index.js +52 -17
  145. package/dist/orm/postgres/index.js.map +1 -1
  146. package/dist/react/core/index.d.ts +1 -1
  147. package/dist/react/core/index.d.ts.map +1 -1
  148. package/dist/react/core/index.js +6 -1
  149. package/dist/react/core/index.js.map +1 -1
  150. package/dist/react/form/index.d.ts +28 -18
  151. package/dist/react/form/index.d.ts.map +1 -1
  152. package/dist/react/form/index.js +92 -56
  153. package/dist/react/form/index.js.map +1 -1
  154. package/dist/react/router/index.browser.js +448 -116
  155. package/dist/react/router/index.browser.js.map +1 -1
  156. package/dist/react/router/index.d.ts +102 -40
  157. package/dist/react/router/index.d.ts.map +1 -1
  158. package/dist/react/router/index.js +453 -92
  159. package/dist/react/router/index.js.map +1 -1
  160. package/dist/security/index.d.ts +3 -11
  161. package/dist/security/index.d.ts.map +1 -1
  162. package/dist/security/index.js +6 -11
  163. package/dist/security/index.js.map +1 -1
  164. package/dist/server/auth/index.d.ts +22 -24
  165. package/dist/server/auth/index.d.ts.map +1 -1
  166. package/dist/server/auth/index.js +102 -82
  167. package/dist/server/auth/index.js.map +1 -1
  168. package/dist/server/cookies/index.d.ts +7 -4
  169. package/dist/server/cookies/index.d.ts.map +1 -1
  170. package/dist/server/cookies/index.js +13 -12
  171. package/dist/server/cookies/index.js.map +1 -1
  172. package/dist/server/core/index.d.ts +288 -4
  173. package/dist/server/core/index.d.ts.map +1 -1
  174. package/dist/server/core/index.js +375 -2
  175. package/dist/server/core/index.js.map +1 -1
  176. package/dist/server/links/index.browser.js +10 -71
  177. package/dist/server/links/index.browser.js.map +1 -1
  178. package/dist/server/links/index.d.ts +32 -49
  179. package/dist/server/links/index.d.ts.map +1 -1
  180. package/dist/server/links/index.js +73 -100
  181. package/dist/server/links/index.js.map +1 -1
  182. package/dist/system/index.browser.js +221 -2
  183. package/dist/system/index.browser.js.map +1 -1
  184. package/dist/system/index.d.ts +63 -1
  185. package/dist/system/index.d.ts.map +1 -1
  186. package/dist/system/index.js +221 -1
  187. package/dist/system/index.js.map +1 -1
  188. package/dist/system/index.workerd.js +224 -4
  189. package/dist/system/index.workerd.js.map +1 -1
  190. package/package.json +10 -5
  191. package/src/api/jobs/providers/JobProvider.ts +6 -3
  192. package/src/api/notifications/controllers/AdminNotificationController.ts +83 -0
  193. package/src/api/notifications/index.browser.ts +3 -0
  194. package/src/api/notifications/index.ts +14 -2
  195. package/src/api/notifications/jobs/NotificationJobs.ts +11 -2
  196. package/src/api/notifications/schemas/notificationDetailResourceSchema.ts +20 -0
  197. package/src/api/notifications/schemas/notificationQuerySchema.ts +19 -0
  198. package/src/api/notifications/schemas/notificationResourceSchema.ts +18 -0
  199. package/src/api/notifications/services/NotificationSenderService.ts +15 -2
  200. package/src/api/users/atoms/realmAuthSettingsAtom.ts +28 -32
  201. package/src/api/users/buckets/UserBuckets.ts +1 -1
  202. package/src/api/users/jobs/UserJobs.ts +1 -1
  203. package/src/api/users/primitives/$realm.ts +8 -49
  204. package/src/api/users/providers/RealmProvider.ts +2 -3
  205. package/src/api/users/services/RegistrationService.spec.ts +7 -7
  206. package/src/api/users/services/RegistrationService.ts +3 -3
  207. package/src/api/users/services/SessionService.spec.ts +4 -4
  208. package/src/api/users/services/SessionService.ts +3 -3
  209. package/src/cli/{core → config}/defineConfig.ts +14 -20
  210. package/src/cli/config/index.ts +1 -0
  211. package/src/cli/core/commands/db.ts +65 -1
  212. package/src/cli/core/commands/dev.ts +1 -0
  213. package/src/cli/core/commands/init.ts +2 -192
  214. package/src/cli/core/index.ts +34 -11
  215. package/src/cli/core/providers/ViteDevServerProvider.ts +52 -13
  216. package/src/cli/core/services/PackageManagerUtils.ts +43 -21
  217. package/src/cli/core/services/ProjectScaffolder.ts +214 -2
  218. package/src/cli/core/services/ViteUtils.ts +57 -0
  219. package/src/cli/core/tasks/BuildClientTask.ts +7 -2
  220. package/src/cli/core/tasks/BuildCloudflareTask.ts +4 -12
  221. package/src/cli/core/tasks/BuildServerTask.ts +2 -0
  222. package/src/cli/core/tasks/BuildVercelTask.ts +165 -168
  223. package/src/cli/core/templates/alephaConfigTs.ts +1 -1
  224. package/src/cli/core/templates/apiAppSecurityTs.ts +5 -8
  225. package/src/cli/core/templates/tsconfigJson.ts +6 -1
  226. package/src/cli/platform/adapters/CloudflareAdapter.spec.ts +1 -1
  227. package/src/cli/platform/adapters/CloudflareAdapter.ts +30 -29
  228. package/src/cli/platform/atoms/platformOptions.ts +21 -0
  229. package/src/cli/platform/commands/SecretsCommand.spec.ts +298 -0
  230. package/src/cli/platform/commands/SecretsCommand.ts +283 -0
  231. package/src/cli/platform/commands/platform.ts +12 -0
  232. package/src/cli/platform/index.ts +14 -28
  233. package/src/cli/platform/providers/GitHubSecretStore.spec.ts +153 -0
  234. package/src/cli/platform/providers/GitHubSecretStore.ts +112 -0
  235. package/src/cli/platform/providers/MemorySecretStore.ts +114 -0
  236. package/src/cli/platform/providers/SecretStoreProvider.ts +39 -0
  237. package/src/cli/platform/schemas/cloudflare.ts +2 -0
  238. package/src/cli/platform/services/CloudflareApi.ts +5 -2
  239. package/src/cli/platform/services/DockerComposeGenerator.spec.ts +115 -0
  240. package/src/cli/platform/services/DockerComposeGenerator.ts +46 -1
  241. package/src/cli/platform/services/SecretFilterService.spec.ts +111 -0
  242. package/src/cli/platform/services/SecretFilterService.ts +54 -0
  243. package/src/core/Alepha.ts +94 -25
  244. package/src/core/__tests__/Alepha-parseEnv.spec.ts +20 -0
  245. package/src/core/primitives/$memoize.ts +38 -26
  246. package/src/core/providers/AlsProvider.ts +2 -0
  247. package/src/core/providers/EventManager.ts +4 -0
  248. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +1 -4
  249. package/src/core/providers/KeylessJsonSchemaCodec.ts +19 -125
  250. package/src/core/providers/SchemaValidator.spec.ts +36 -0
  251. package/src/core/providers/SchemaValidator.ts +9 -0
  252. package/src/crypto/index.ts +6 -1
  253. package/src/crypto/providers/SecretProvider.ts +36 -0
  254. package/src/devtools/providers/DevToolsProvider.ts +3 -12
  255. package/src/logger/index.ts +33 -6
  256. package/src/logger/providers/PrettyFormatterProvider.ts +5 -3
  257. package/src/orm/__tests__/orm-next-tests.ts +492 -0
  258. package/src/orm/__tests__/orm-next.spec.ts +140 -0
  259. package/src/orm/core/constants/PG_SYMBOLS.ts +17 -0
  260. package/src/orm/core/index.bun.ts +3 -6
  261. package/src/orm/core/index.shared-server.ts +2 -0
  262. package/src/orm/core/index.shared.ts +2 -0
  263. package/src/orm/core/index.ts +5 -7
  264. package/src/orm/core/interfaces/AggregateQuery.ts +103 -0
  265. package/src/orm/core/interfaces/PgQueryWhere.ts +7 -0
  266. package/src/orm/core/primitives/$entity.ts +8 -0
  267. package/src/orm/core/primitives/$repository.ts +6 -3
  268. package/src/orm/core/primitives/$view.ts +88 -0
  269. package/src/orm/core/providers/DbCacheProvider.ts +66 -0
  270. package/src/orm/core/providers/DrizzleKitProvider.ts +42 -0
  271. package/src/orm/core/providers/drivers/BunSqliteProvider.ts +2 -3
  272. package/src/orm/core/providers/drivers/CloudflareD1Provider.ts +12 -0
  273. package/src/orm/core/providers/drivers/DatabaseProvider.ts +39 -0
  274. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +2 -3
  275. package/src/orm/core/schemas/databaseEnvSchema.ts +31 -0
  276. package/src/orm/core/schemas/insertSchema.ts +13 -3
  277. package/src/orm/core/schemas/updateSchema.ts +14 -3
  278. package/src/orm/core/services/ModelBuilder.ts +26 -14
  279. package/src/orm/core/services/QueryManager.ts +13 -0
  280. package/src/orm/core/services/Repository.ts +307 -5
  281. package/src/orm/core/services/SqliteModelBuilder.ts +38 -0
  282. package/src/orm/postgres/index.bun.ts +4 -7
  283. package/src/orm/postgres/index.ts +4 -7
  284. package/src/orm/postgres/providers/BunPostgresProvider.ts +12 -2
  285. package/src/orm/postgres/providers/NodePostgresProvider.ts +7 -0
  286. package/src/orm/postgres/providers/PglitePostgresProvider.ts +10 -17
  287. package/src/orm/postgres/providers/PostgresProvider.ts +7 -36
  288. package/src/orm/postgres/schemas/postgresEnvSchema.ts +32 -0
  289. package/src/orm/postgres/services/PostgresModelBuilder.ts +40 -0
  290. package/src/react/core/components/ErrorBoundary.tsx +5 -2
  291. package/src/react/form/hooks/useFieldValue.ts +34 -0
  292. package/src/react/form/hooks/useForm.browser.spec.tsx +94 -9
  293. package/src/react/form/hooks/useForm.ts +14 -2
  294. package/src/react/form/hooks/useFormState.ts +10 -10
  295. package/src/react/form/hooks/useFormValues.ts +29 -0
  296. package/src/react/form/index.ts +3 -1
  297. package/src/react/form/services/FormModel.ts +53 -122
  298. package/src/react/router/components/ErrorViewer.tsx +333 -34
  299. package/src/react/router/components/NestedView.tsx +10 -3
  300. package/src/react/router/primitives/$page.browser.spec.tsx +34 -0
  301. package/src/react/router/primitives/$page.spec.tsx +20 -0
  302. package/src/react/router/primitives/$page.ts +24 -0
  303. package/src/react/router/providers/ReactBrowserRouterProvider.ts +14 -2
  304. package/src/react/router/providers/ReactPageProvider.ts +156 -73
  305. package/src/react/router/providers/ReactServerProvider.ts +40 -2
  306. package/src/react/router/providers/ReactServerTemplateProvider.ts +13 -1
  307. package/src/security/providers/SecurityProvider.ts +5 -27
  308. package/src/server/auth/primitives/$auth.ts +52 -19
  309. package/src/server/auth/providers/ServerAuthProvider.ts +145 -139
  310. package/src/server/cookies/providers/ServerCookiesProvider.ts +12 -24
  311. package/src/server/core/index.ts +3 -1
  312. package/src/server/core/primitives/$sse.spec.ts +315 -0
  313. package/src/server/core/primitives/$sse.ts +715 -0
  314. package/src/server/links/index.browser.ts +1 -3
  315. package/src/server/links/index.ts +0 -3
  316. package/src/server/links/providers/LinkProvider.spec.ts +12 -21
  317. package/src/server/links/providers/LinkProvider.ts +20 -52
  318. package/src/server/links/providers/ServerLinksProvider.spec.ts +106 -0
  319. package/src/server/links/providers/ServerLinksProvider.ts +113 -73
  320. package/src/server/links/schemas/apiLinksResponseSchema.ts +4 -21
  321. package/src/server/links/services/BatchCollector.ts +5 -3
  322. package/src/system/index.browser.ts +1 -0
  323. package/src/system/index.ts +3 -0
  324. package/src/system/index.workerd.ts +39 -1
  325. package/src/system/providers/WorkerdFileSystemProvider.ts +365 -0
  326. package/assets/devtools-ui/asset.BfSBZ5Dd.css.br +0 -0
  327. package/assets/devtools-ui/chunk.2NYaoqWt.js +0 -1
  328. package/assets/devtools-ui/chunk.2NYaoqWt.js.br +0 -0
  329. package/assets/devtools-ui/chunk.B052Z_xQ.js +0 -1
  330. package/assets/devtools-ui/chunk.B052Z_xQ.js.br +0 -0
  331. package/assets/devtools-ui/chunk.B4kVY90C.js +0 -1
  332. package/assets/devtools-ui/chunk.B4kVY90C.js.br +0 -0
  333. package/assets/devtools-ui/chunk.B7QJXctB.js +0 -1
  334. package/assets/devtools-ui/chunk.B7QJXctB.js.br +0 -0
  335. package/assets/devtools-ui/chunk.B9pX3zit.js.br +0 -0
  336. package/assets/devtools-ui/chunk.BKF9JxIo.js +0 -1
  337. package/assets/devtools-ui/chunk.BKF9JxIo.js.br +0 -0
  338. package/assets/devtools-ui/chunk.BOHgdTP-.js +0 -1
  339. package/assets/devtools-ui/chunk.BOHgdTP-.js.br +0 -0
  340. package/assets/devtools-ui/chunk.BOVFxkYC.js +0 -1
  341. package/assets/devtools-ui/chunk.BOVFxkYC.js.br +0 -0
  342. package/assets/devtools-ui/chunk.BR842zj5.js +0 -1
  343. package/assets/devtools-ui/chunk.BR842zj5.js.br +0 -0
  344. package/assets/devtools-ui/chunk.BT2IiBkZ.js.br +0 -0
  345. package/assets/devtools-ui/chunk.C79YouPp.js.br +0 -0
  346. package/assets/devtools-ui/chunk.C8mlBrjW.js +0 -9
  347. package/assets/devtools-ui/chunk.C8mlBrjW.js.br +0 -0
  348. package/assets/devtools-ui/chunk.CK0ow3AZ.js +0 -1
  349. package/assets/devtools-ui/chunk.CK0ow3AZ.js.br +0 -0
  350. package/assets/devtools-ui/chunk.CZl6J9DF.js.br +0 -0
  351. package/assets/devtools-ui/chunk.CdNr0YzS.js +0 -1
  352. package/assets/devtools-ui/chunk.CdNr0YzS.js.br +0 -0
  353. package/assets/devtools-ui/chunk.Ce6_6iIF.js +0 -1
  354. package/assets/devtools-ui/chunk.Ce6_6iIF.js.br +0 -0
  355. package/assets/devtools-ui/chunk.CpyDMr6O.js +0 -1
  356. package/assets/devtools-ui/chunk.CpyDMr6O.js.br +0 -0
  357. package/assets/devtools-ui/chunk.CyPmvPnY.js +0 -1
  358. package/assets/devtools-ui/chunk.CyPmvPnY.js.br +0 -0
  359. package/assets/devtools-ui/chunk.DTI_geWu.js +0 -1
  360. package/assets/devtools-ui/chunk.DTI_geWu.js.br +0 -0
  361. package/assets/devtools-ui/chunk.DbEH1oOB.js.br +0 -0
  362. package/assets/devtools-ui/chunk.Ddeqj5gv.js +0 -1
  363. package/assets/devtools-ui/chunk.Ddeqj5gv.js.br +0 -0
  364. package/assets/devtools-ui/chunk.DpRnB4vJ.js +0 -1
  365. package/assets/devtools-ui/chunk.DpRnB4vJ.js.br +0 -0
  366. package/assets/devtools-ui/chunk.DxPGTlsg.js +0 -1
  367. package/assets/devtools-ui/chunk.DxPGTlsg.js.br +0 -0
  368. package/assets/devtools-ui/chunk.G7_MMBJS.js +0 -1
  369. package/assets/devtools-ui/chunk.G7_MMBJS.js.br +0 -0
  370. package/assets/devtools-ui/chunk.M6wyKO_3.js.br +0 -0
  371. package/assets/devtools-ui/chunk.OUxNGmQ6.js +0 -1
  372. package/assets/devtools-ui/chunk.OUxNGmQ6.js.br +0 -0
  373. package/assets/devtools-ui/chunk.T1kle-fF.js +0 -1
  374. package/assets/devtools-ui/chunk.T1kle-fF.js.br +0 -0
  375. package/assets/devtools-ui/chunk.WjpsbQAv.js +0 -1
  376. package/assets/devtools-ui/chunk.WjpsbQAv.js.br +0 -0
  377. package/assets/devtools-ui/chunk.c6YgVx86.js +0 -1
  378. package/assets/devtools-ui/chunk.c6YgVx86.js.br +0 -0
  379. package/assets/devtools-ui/chunk.dwU3E_MU.js +0 -1
  380. package/assets/devtools-ui/chunk.dwU3E_MU.js.br +0 -0
  381. package/assets/devtools-ui/chunk.lJL-lgnW.js.br +0 -0
  382. package/assets/devtools-ui/chunk.lPWRmvA-.js +0 -7
  383. package/assets/devtools-ui/chunk.lPWRmvA-.js.br +0 -0
  384. package/assets/devtools-ui/chunk.p3HJvugM.js +0 -1
  385. package/assets/devtools-ui/chunk.p3HJvugM.js.br +0 -0
  386. package/assets/devtools-ui/chunk.r_Xoa_CI.js +0 -1
  387. package/assets/devtools-ui/chunk.r_Xoa_CI.js.br +0 -0
  388. package/assets/devtools-ui/chunk.sRNuTYXb.js +0 -1
  389. package/assets/devtools-ui/chunk.sRNuTYXb.js.br +0 -0
  390. package/assets/devtools-ui/chunk.tUjcyX5C.js +0 -1
  391. package/assets/devtools-ui/chunk.tUjcyX5C.js.br +0 -0
  392. package/assets/devtools-ui/chunk.thjBxvCA.js +0 -1
  393. package/assets/devtools-ui/chunk.thjBxvCA.js.br +0 -0
  394. package/assets/devtools-ui/entry.GYhBVRpC.js +0 -78
  395. package/assets/devtools-ui/entry.GYhBVRpC.js.br +0 -0
  396. package/src/server/links/services/DefinitionsPool.spec.ts +0 -86
  397. package/src/server/links/services/DefinitionsPool.ts +0 -43
@@ -8,6 +8,7 @@ import {
8
8
  type TSchema,
9
9
  t,
10
10
  } from "alepha";
11
+ import { DateTimeProvider } from "alepha/datetime";
11
12
  import { $logger } from "alepha/logger";
12
13
  import { AlephaContext, ClientOnly } from "alepha/react";
13
14
  import type { Head } from "alepha/react/head";
@@ -24,6 +25,8 @@ import {
24
25
  type PagePrimitiveOptions,
25
26
  } from "../primitives/$page.ts";
26
27
 
28
+ // -------------------------------------------------------------------------------------------------------------------
29
+
27
30
  export const reactPageOptions = $atom({
28
31
  name: "alepha.react.page.options",
29
32
  description: "Configuration options for the React page provider.",
@@ -32,20 +35,87 @@ export const reactPageOptions = $atom({
32
35
  * Enable React StrictMode wrapper.
33
36
  */
34
37
  strictMode: t.boolean({ default: true }),
38
+ /**
39
+ * RegExp pattern (as string) to detect file-like URLs (e.g. /hello.txt, /wp-login.php).
40
+ * When a request hits the catch-all wildcard route and matches this pattern,
41
+ * SSR is skipped and a plain 404 response is returned instead.
42
+ *
43
+ * Set to empty string to disable this behavior.
44
+ *
45
+ * @default "\\.[a-zA-Z0-9]{1,10}$"
46
+ */
47
+ staticFilePattern: t.string(),
35
48
  }),
36
49
  default: {
37
50
  strictMode: true,
51
+ staticFilePattern: "\\.[a-zA-Z0-9]{1,10}$",
38
52
  },
39
53
  });
40
54
 
55
+ // -------------------------------------------------------------------------------------------------------------------
56
+
41
57
  /**
42
58
  * Handle page routes for React applications. (Browser and Server)
43
59
  */
44
60
  export class ReactPageProvider {
61
+ protected readonly dateTimeProvider = $inject(DateTimeProvider);
45
62
  protected readonly log = $logger();
46
63
  protected readonly options = $use(reactPageOptions);
47
64
  protected readonly alepha = $inject(Alepha);
48
65
  protected readonly pages: PageRoute[] = [];
66
+ protected nextIdCursor = 0;
67
+
68
+ protected readonly configure = $hook({
69
+ on: "configure",
70
+ handler: () => {
71
+ let hasNotFoundHandler = false;
72
+ const pages = this.alepha.primitives($page);
73
+
74
+ const hasParent = (it: PagePrimitive) => {
75
+ if (it.options.parent) {
76
+ return true;
77
+ }
78
+
79
+ for (const page of pages) {
80
+ const children = page.options.children
81
+ ? Array.isArray(page.options.children)
82
+ ? page.options.children
83
+ : page.options.children()
84
+ : [];
85
+ if (children.includes(it)) {
86
+ return true;
87
+ }
88
+ }
89
+ };
90
+
91
+ for (const page of pages) {
92
+ if (page.options.path === "/*") {
93
+ hasNotFoundHandler = true;
94
+ }
95
+
96
+ // skip children, we only want root pages
97
+ if (hasParent(page)) {
98
+ continue;
99
+ }
100
+
101
+ this.add(this.map(pages, page));
102
+ }
103
+
104
+ if (!hasNotFoundHandler && pages.length > 0) {
105
+ // add a default 404 page if not already defined
106
+ this.add({
107
+ path: "/*",
108
+ name: "notFound",
109
+ component: NotFoundPage,
110
+ onServerResponse: ({ reply }) => {
111
+ reply.status = 404;
112
+ },
113
+ });
114
+ }
115
+ },
116
+ });
117
+
118
+ // -------------------------------------------------------------------------------------------------------------------
49
119
 
50
120
  public getPages(): PageRoute[] {
51
121
  return this.pages;
@@ -210,7 +280,7 @@ export class ReactPageProvider {
210
280
  ? this.alepha.codec.decode(route.schema.query, state.query)
211
281
  : {};
212
282
  } catch (e) {
213
- it.error = e as Error;
283
+ it.error = e instanceof Error ? e : new Error(String(e));
214
284
  break;
215
285
  }
216
286
 
@@ -219,7 +289,7 @@ export class ReactPageProvider {
219
289
  ? this.alepha.codec.decode(route.schema.params, state.params)
220
290
  : {};
221
291
  } catch (e) {
222
- it.error = e as Error;
292
+ it.error = e instanceof Error ? e : new Error(String(e));
223
293
  break;
224
294
  }
225
295
 
@@ -258,6 +328,11 @@ export class ReactPageProvider {
258
328
  forceRefresh = true;
259
329
  }
260
330
 
331
+ // redirect shorthand
332
+ if (route.redirect) {
333
+ return { redirect: route.redirect };
334
+ }
335
+
261
336
  // no loader, render a basic view by default
262
337
  if (!route.loader) {
263
338
  continue;
@@ -288,7 +363,7 @@ export class ReactPageProvider {
288
363
 
289
364
  this.log.error("Page loader has failed", e);
290
365
 
291
- it.error = e as Error;
366
+ it.error = e instanceof Error ? e : new Error(String(e));
292
367
  break;
293
368
  }
294
369
  }
@@ -322,14 +397,18 @@ export class ReactPageProvider {
322
397
  // normal use case
323
398
  if (!it.error) {
324
399
  try {
325
- const element = await this.createElement(it.route, {
326
- // default props attached to page
327
- ...(it.route.props ? it.route.props() : {}),
328
- // resolved props
329
- ...props,
330
- // context props (from previous layers)
331
- ...context,
332
- });
400
+ const element = await this.createElement(
401
+ it.route,
402
+ {
403
+ // default props attached to page
404
+ ...(it.route.props ? it.route.props() : {}),
405
+ // resolved props
406
+ ...props,
407
+ // context props (from previous layers)
408
+ ...context,
409
+ },
410
+ state.url,
411
+ );
333
412
 
334
413
  state.layers.push({
335
414
  name: it.route.name,
@@ -343,7 +422,7 @@ export class ReactPageProvider {
343
422
  cache: it.cache,
344
423
  });
345
424
  } catch (e) {
346
- it.error = e as Error;
425
+ it.error = e instanceof Error ? e : new Error(String(e));
347
426
  }
348
427
  }
349
428
 
@@ -377,6 +456,7 @@ export class ReactPageProvider {
377
456
  index: i + 1,
378
457
  path,
379
458
  route: it.route,
459
+ cache: it.cache,
380
460
  });
381
461
  break;
382
462
  } catch (e) {
@@ -405,6 +485,7 @@ export class ReactPageProvider {
405
485
  protected async createElement(
406
486
  page: PageRoute,
407
487
  props: Record<string, any>,
488
+ targetUrl?: URL,
408
489
  ): Promise<ReactNode> {
409
490
  if (page.lazy && page.component) {
410
491
  this.log.warn(
@@ -413,8 +494,17 @@ export class ReactPageProvider {
413
494
  }
414
495
 
415
496
  if (page.lazy) {
416
- const component = await page.lazy(); // load component
417
- return createElement(component.default, props);
497
+ try {
498
+ const component = await page.lazy();
499
+ return createElement(component.default, props);
500
+ } catch (error) {
501
+ if (this.alepha.isBrowser() && this.isChunkLoadError(error)) {
502
+ if (this.reloadAfterChunkError(targetUrl)) {
503
+ return undefined;
504
+ }
505
+ }
506
+ throw error;
507
+ }
418
508
  }
419
509
 
420
510
  if (page.component) {
@@ -424,6 +514,46 @@ export class ReactPageProvider {
424
514
  return undefined;
425
515
  }
426
516
 
517
+ /**
518
+ * Detect chunk load errors caused by stale dynamic imports after a deployment.
519
+ * When new assets are deployed with different hashes, old chunk URLs return 404.
520
+ */
521
+ protected isChunkLoadError(error: unknown): boolean {
522
+ if (!(error instanceof Error)) return false;
523
+ const msg = error.message;
524
+ return (
525
+ /Failed to fetch dynamically imported module/.test(msg) ||
526
+ /error loading dynamically imported module/i.test(msg) ||
527
+ /Unable to preload CSS/.test(msg) ||
528
+ /Importing a module script failed/.test(msg)
529
+ );
530
+ }
531
+
532
+ /**
533
+ * Navigate to the target URL to fetch updated assets after a chunk load failure.
534
+ * Uses sessionStorage to prevent infinite reload loops.
535
+ * Returns true if navigation was initiated.
536
+ */
537
+ protected reloadAfterChunkError(url?: URL): boolean {
538
+ const key = "alepha:chunk-reload";
539
+ const lastReload = sessionStorage.getItem(key);
540
+ const now = this.dateTimeProvider.nowMillis();
541
+
542
+ if (lastReload && now - Number(lastReload) < 10_000) {
543
+ this.log.error(
544
+ "Chunk load failed after recent reload, not retrying to avoid loop",
545
+ );
546
+ return false;
547
+ }
548
+
549
+ this.log.warn("Chunk load failed after deployment, reloading page");
550
+ sessionStorage.setItem(key, String(now));
551
+ window.location.assign(
552
+ url ? url.pathname + url.search : window.location.href,
553
+ );
554
+ return true;
555
+ }
556
+
427
557
  public renderError(error: Error): ReactNode {
428
558
  return createElement(ErrorViewer, { error, alepha: this.alepha });
429
559
  }
@@ -490,56 +620,6 @@ export class ReactPageProvider {
490
620
  );
491
621
  }
492
622
 
493
- protected readonly configure = $hook({
494
- on: "configure",
495
- handler: () => {
496
- let hasNotFoundHandler = false;
497
- const pages = this.alepha.primitives($page);
498
-
499
- const hasParent = (it: PagePrimitive) => {
500
- if (it.options.parent) {
501
- return true;
502
- }
503
-
504
- for (const page of pages) {
505
- const children = page.options.children
506
- ? Array.isArray(page.options.children)
507
- ? page.options.children
508
- : page.options.children()
509
- : [];
510
- if (children.includes(it)) {
511
- return true;
512
- }
513
- }
514
- };
515
-
516
- for (const page of pages) {
517
- if (page.options.path === "/*") {
518
- hasNotFoundHandler = true;
519
- }
520
-
521
- // skip children, we only want root pages
522
- if (hasParent(page)) {
523
- continue;
524
- }
525
-
526
- this.add(this.map(pages, page));
527
- }
528
-
529
- if (!hasNotFoundHandler && pages.length > 0) {
530
- // add a default 404 page if not already defined
531
- this.add({
532
- path: "/*",
533
- name: "notFound",
534
- component: NotFoundPage,
535
- onServerResponse: ({ reply }) => {
536
- reply.status = 404;
537
- },
538
- });
539
- }
540
- },
541
- });
542
-
543
623
  protected map(
544
624
  pages: Array<PagePrimitive>,
545
625
  target: PagePrimitive,
@@ -607,14 +687,14 @@ export class ReactPageProvider {
607
687
  return path;
608
688
  }
609
689
 
610
- protected _next = 0;
611
-
612
690
  protected nextId(): string {
613
- this._next += 1;
614
- return `P${this._next}`;
691
+ this.nextIdCursor += 1;
692
+ return `P${this.nextIdCursor}`;
615
693
  }
616
694
  }
617
695
 
696
+ // ---------------------------------------------------------------------------------------------------------------------
697
+
618
698
  export const isPageRoute = (it: any): it is PageRoute => {
619
699
  return (
620
700
  it &&
@@ -644,6 +724,11 @@ export interface PageRoute extends PageRouteEntry {
644
724
  name: string;
645
725
  parent?: PageRoute;
646
726
  match: string;
727
+
728
+ /**
729
+ * Optional meta information associated with the page route, can be used for any purpose (e.g. menu label, icon, etc.).
730
+ */
731
+ label?: string;
647
732
  }
648
733
 
649
734
  export interface Layer {
@@ -709,7 +794,9 @@ export interface ReactRouterState {
709
794
  */
710
795
  head: Head;
711
796
 
712
- //
797
+ /**
798
+ * Optional name of the current page route
799
+ */
713
800
  name?: string;
714
801
  }
715
802
 
@@ -721,10 +808,6 @@ export interface RouterStackItem {
721
808
  cache?: boolean;
722
809
  }
723
810
 
724
- export interface TransitionOptions {
725
- previous?: PreviousLayerData[];
726
- }
727
-
728
811
  export interface CreateLayersResult {
729
812
  redirect?: string;
730
813
  state?: ReactRouterState;
@@ -29,6 +29,7 @@ import {
29
29
  type PageRoute,
30
30
  ReactPageProvider,
31
31
  type ReactRouterState,
32
+ reactPageOptions,
32
33
  } from "./ReactPageProvider.ts";
33
34
  import { ReactServerTemplateProvider } from "./ReactServerTemplateProvider.ts";
34
35
  import { SSRManifestProvider } from "./SSRManifestProvider.ts";
@@ -72,6 +73,7 @@ export class ReactServerProvider {
72
73
  protected hasServerLinksProvider = false;
73
74
 
74
75
  protected readonly options = $use(reactServerOptions);
76
+ protected readonly pageOptions = $use(reactPageOptions);
75
77
 
76
78
  /**
77
79
  * Configure the React server provider.
@@ -124,7 +126,7 @@ export class ReactServerProvider {
124
126
  this.hasServerLinksProvider = this.alepha.has(ServerLinksProvider);
125
127
 
126
128
  for (const page of this.pageApi.getPages()) {
127
- if (page.component || page.lazy) {
129
+ if (page.component || page.lazy || page.redirect) {
128
130
  this.log.debug(`+ ${page.match} -> ${page.name}`);
129
131
 
130
132
  // Separate $cache from server-level middleware.
@@ -250,6 +252,16 @@ export class ReactServerProvider {
250
252
  });
251
253
  }
252
254
 
255
+ /**
256
+ * Resolve the static file pattern from page options.
257
+ * Returns a compiled RegExp, or `false` if disabled (empty string).
258
+ */
259
+ protected resolveStaticFilePattern(): RegExp | false {
260
+ const pattern = this.pageOptions.staticFilePattern;
261
+ if (!pattern) return false;
262
+ return new RegExp(pattern);
263
+ }
264
+
253
265
  /**
254
266
  * Create the request handler for a page route.
255
267
  *
@@ -261,10 +273,23 @@ export class ReactServerProvider {
261
273
  cacheMiddleware: Middleware[] = [],
262
274
  ): ServerHandler {
263
275
  const hasCache = cacheMiddleware.length > 0;
276
+ const isCatchAll = route.match === "/*";
277
+ const staticFilePattern = isCatchAll
278
+ ? this.resolveStaticFilePattern()
279
+ : false;
264
280
 
265
281
  return async (serverRequest) => {
266
282
  const { url, reply, query, params } = serverRequest;
267
283
 
284
+ // Skip SSR for file-like URLs hitting the catch-all wildcard.
285
+ // Bots and crawlers often probe paths like /hello.txt, /wp-login.php, etc.
286
+ // Rendering a full React page for these is wasteful — return a plain 404 instead.
287
+ if (staticFilePattern && staticFilePattern.test(url.pathname)) {
288
+ reply.status = 404;
289
+ reply.headers["content-type"] = "text/plain";
290
+ return "Not Found";
291
+ }
292
+
268
293
  this.log.trace("Rendering page", { name: route.name });
269
294
 
270
295
  // Initialize router state
@@ -366,6 +391,7 @@ export class ReactServerProvider {
366
391
  },
367
392
  {
368
393
  hydration: true,
394
+ state,
369
395
  onError: (error) => {
370
396
  if (error instanceof Redirection) {
371
397
  this.log.debug("Streaming resulted in redirection", {
@@ -382,7 +408,13 @@ export class ReactServerProvider {
382
408
 
383
409
  this.log.trace("Page streaming started (early head optimization)");
384
410
  route.onServerResponse?.(serverRequest);
385
- reply.body = htmlStream;
411
+ reply.body = htmlStream.pipeThrough(
412
+ new TransformStream({
413
+ flush: () => {
414
+ this.log.info("Page streaming completed", { name: route.name });
415
+ },
416
+ }),
417
+ );
386
418
  };
387
419
  }
388
420
 
@@ -567,6 +599,12 @@ declare module "alepha" {
567
599
  /**
568
600
  * React server provider configuration atom
569
601
  */
602
+ /**
603
+ * Default pattern matching file-like URLs (e.g. /hello.txt, /wp-login.php).
604
+ * Matches paths whose last segment contains a dot followed by 1-10 alphanumeric characters.
605
+ */
606
+ export const DEFAULT_STATIC_FILE_PATTERN = "\\.[a-zA-Z0-9]{1,10}$";
607
+
570
608
  export const reactServerOptions = $atom({
571
609
  name: "alepha.react.server.options",
572
610
  schema: t.object({
@@ -300,6 +300,7 @@ export class ReactServerTemplateProvider {
300
300
  >,
301
301
  options: {
302
302
  hydration?: boolean;
303
+ state?: ReactRouterState;
303
304
  onError?: (error: unknown) => void;
304
305
  } = {},
305
306
  ): ReadableStream<Uint8Array> {
@@ -308,7 +309,7 @@ export class ReactServerTemplateProvider {
308
309
 
309
310
  let headClosed = false;
310
311
  let bodyStarted = false;
311
- let routerState: ReactRouterState | undefined;
312
+ let routerState: ReactRouterState | undefined = options.state;
312
313
 
313
314
  return new ReadableStream<Uint8Array>({
314
315
  start: async (controller) => {
@@ -469,6 +470,17 @@ export class ReactServerTemplateProvider {
469
470
  );
470
471
 
471
472
  controller.enqueue(slots.ROOT_CLOSE);
473
+
474
+ if (routerState) {
475
+ controller.enqueue(slots.HYDRATION_PREFIX);
476
+ controller.enqueue(
477
+ encoder.encode(
478
+ this.safeJsonSerialize(this.buildHydrationData(routerState)),
479
+ ),
480
+ );
481
+ controller.enqueue(slots.HYDRATION_SUFFIX);
482
+ }
483
+
472
484
  controller.enqueue(slots.BODY_HTML_CLOSE);
473
485
  }
474
486
 
@@ -1,13 +1,11 @@
1
1
  import {
2
- $env,
3
2
  $hook,
4
3
  $inject,
5
4
  Alepha,
6
5
  AppNotStartedError,
7
6
  ContainerLockedError,
8
- type Static,
9
- t,
10
7
  } from "alepha";
8
+ import { SecretProvider } from "alepha/crypto";
11
9
  import { $logger } from "alepha/logger";
12
10
  import { ForbiddenError } from "alepha/server";
13
11
  import type { JSONWebKeySet, JWTPayload } from "jose";
@@ -27,20 +25,6 @@ import {
27
25
  } from "../schemas/userAccountInfoSchema.ts";
28
26
  import { JwtProvider } from "./JwtProvider.ts";
29
27
 
30
- export const DEFAULT_APP_SECRET = "05759934015388327323179852515731"; // (32)
31
-
32
- export const alephaSecurityEnvSchema = t.object({
33
- APP_SECRET: t.text({
34
- description:
35
- "The secret key used for signing JWTs and other security features. It should be a strong, random string of at least 32 characters for HS256. Do not use the default value in production.",
36
- default: DEFAULT_APP_SECRET,
37
- }),
38
- });
39
-
40
- declare module "alepha" {
41
- interface Env extends Partial<Static<typeof alephaSecurityEnvSchema>> {}
42
- }
43
-
44
28
  export class SecurityProvider {
45
29
  protected readonly UNKNOWN_USER_NAME = "Anonymous User";
46
30
  protected readonly PERMISSION_REGEXP = /^[\w-]+((:[\w-]+)+)?$/;
@@ -49,11 +33,11 @@ export class SecurityProvider {
49
33
 
50
34
  protected readonly log = $logger();
51
35
  protected readonly jwt = $inject(JwtProvider);
52
- protected readonly env = $env(alephaSecurityEnvSchema);
53
36
  protected readonly alepha = $inject(Alepha);
37
+ protected readonly secretProvider = $inject(SecretProvider);
54
38
 
55
- public get secretKey() {
56
- return this.env.APP_SECRET;
39
+ public get secretKey(): string {
40
+ return this.secretProvider.secretKey;
57
41
  }
58
42
 
59
43
  /**
@@ -68,7 +52,7 @@ export class SecurityProvider {
68
52
  ? [
69
53
  {
70
54
  name: "default",
71
- secret: this.env.APP_SECRET,
55
+ secret: this.secretKey,
72
56
  roles: [
73
57
  {
74
58
  name: "admin",
@@ -86,12 +70,6 @@ export class SecurityProvider {
86
70
  protected start = $hook({
87
71
  on: "start",
88
72
  handler: async () => {
89
- if (this.alepha.isProduction() && this.secretKey === DEFAULT_APP_SECRET) {
90
- this.log.warn(
91
- "Using default APP_SECRET in production is not recommended. Please set a strong APP_SECRET value.",
92
- );
93
- }
94
-
95
73
  for (const realm of this.realms) {
96
74
  if (realm.secret) {
97
75
  const secret =
@@ -255,7 +255,29 @@ export class AuthPrimitive extends Primitive<AuthPrimitiveOptions> {
255
255
  protected readonly securityProvider = $inject(SecurityProvider);
256
256
  protected readonly dateTimeProvider = $inject(DateTimeProvider);
257
257
 
258
- public oauth?: Configuration;
258
+ protected oauthConfig?: Configuration;
259
+ protected oauthInitializer?: () => Promise<Configuration>;
260
+
261
+ public get oauth(): Configuration | undefined {
262
+ return this.oauthConfig;
263
+ }
264
+
265
+ /**
266
+ * Get the OAuth2/OIDC configuration, initializing lazily if needed (serverless mode).
267
+ */
268
+ public async getOAuth(): Promise<Configuration | undefined> {
269
+ if (this.oauthConfig) {
270
+ return this.oauthConfig;
271
+ }
272
+
273
+ if (this.oauthInitializer) {
274
+ this.oauthConfig = await this.oauthInitializer();
275
+ this.oauthInitializer = undefined;
276
+ return this.oauthConfig;
277
+ }
278
+
279
+ return undefined;
280
+ }
259
281
 
260
282
  public get name() {
261
283
  return this.options.name ?? this.config.propertyKey;
@@ -320,10 +342,13 @@ export class AuthPrimitive extends Primitive<AuthPrimitiveOptions> {
320
342
  },
321
343
  );
322
344
  });
323
- } else if (this.oauth) {
345
+ }
346
+
347
+ const oauth = await this.getOAuth();
348
+ if (oauth) {
324
349
  try {
325
350
  return {
326
- ...(await refreshTokenGrant(this.oauth, refreshToken)),
351
+ ...(await refreshTokenGrant(oauth, refreshToken)),
327
352
  issued_at: this.dateTimeProvider.now().unix(),
328
353
  };
329
354
  } catch (error) {
@@ -399,30 +424,38 @@ export class AuthPrimitive extends Primitive<AuthPrimitiveOptions> {
399
424
  }
400
425
 
401
426
  public async prepare() {
402
- const addons: Array<(config: Configuration) => void> = [];
403
-
404
- addons.push(allowInsecureRequests);
405
-
406
427
  if ("oidc" in this.options) {
407
428
  const { oidc } = this.options;
408
429
 
409
- this.oauth = await discovery(
410
- new URL(oidc.issuer),
411
- oidc.clientId,
412
- {
413
- client_secret: oidc.clientSecret,
414
- },
415
- undefined,
416
- {
417
- execute: addons,
418
- },
419
- );
430
+ const discoverOidc = async () => {
431
+ const execute: Array<(config: Configuration) => void> = [];
432
+ execute.push(allowInsecureRequests);
433
+
434
+ return discovery(
435
+ new URL(oidc.issuer),
436
+ oidc.clientId,
437
+ {
438
+ client_secret: oidc.clientSecret,
439
+ },
440
+ undefined,
441
+ {
442
+ execute,
443
+ },
444
+ );
445
+ };
446
+
447
+ // Defer OIDC discovery in serverless/dev to avoid cold start penalty
448
+ if (this.alepha.isServerless() || !this.alepha.isProduction()) {
449
+ this.oauthInitializer = discoverOidc;
450
+ } else {
451
+ this.oauthConfig = await discoverOidc();
452
+ }
420
453
  }
421
454
 
422
455
  if ("oauth" in this.options) {
423
456
  const { oauth } = this.options;
424
457
 
425
- this.oauth = new Configuration(
458
+ this.oauthConfig = new Configuration(
426
459
  {
427
460
  authorization_endpoint: oauth.authorization,
428
461
  token_endpoint: oauth.token,