alepha 0.21.2 → 0.23.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 (519) hide show
  1. package/README.md +0 -1
  2. package/dist/api/audits/index.browser.js.map +1 -1
  3. package/dist/api/audits/index.d.ts +393 -403
  4. package/dist/api/audits/index.d.ts.map +1 -1
  5. package/dist/api/audits/index.js +25 -56
  6. package/dist/api/audits/index.js.map +1 -1
  7. package/dist/api/files/index.browser.js +31 -1
  8. package/dist/api/files/index.browser.js.map +1 -1
  9. package/dist/api/files/index.d.ts +313 -208
  10. package/dist/api/files/index.d.ts.map +1 -1
  11. package/dist/api/files/index.js +152 -42
  12. package/dist/api/files/index.js.map +1 -1
  13. package/dist/api/jobs/index.browser.js +2 -2
  14. package/dist/api/jobs/index.browser.js.map +1 -1
  15. package/dist/api/jobs/index.d.ts +282 -285
  16. package/dist/api/jobs/index.d.ts.map +1 -1
  17. package/dist/api/jobs/index.js +39 -33
  18. package/dist/api/jobs/index.js.map +1 -1
  19. package/dist/api/keys/index.d.ts +217 -222
  20. package/dist/api/keys/index.d.ts.map +1 -1
  21. package/dist/api/keys/index.js.map +1 -1
  22. package/dist/api/notifications/index.browser.js.map +1 -1
  23. package/dist/api/notifications/index.d.ts +188 -195
  24. package/dist/api/notifications/index.d.ts.map +1 -1
  25. package/dist/api/notifications/index.js.map +1 -1
  26. package/dist/api/oauth/index.d.ts +71 -76
  27. package/dist/api/oauth/index.d.ts.map +1 -1
  28. package/dist/api/oauth/index.js.map +1 -1
  29. package/dist/api/organizations/index.browser.js.map +1 -1
  30. package/dist/api/organizations/index.d.ts +104 -109
  31. package/dist/api/organizations/index.d.ts.map +1 -1
  32. package/dist/api/organizations/index.js.map +1 -1
  33. package/dist/api/parameters/index.browser.js +43 -16
  34. package/dist/api/parameters/index.browser.js.map +1 -1
  35. package/dist/api/parameters/index.d.ts +488 -344
  36. package/dist/api/parameters/index.d.ts.map +1 -1
  37. package/dist/api/parameters/index.js +175 -35
  38. package/dist/api/parameters/index.js.map +1 -1
  39. package/dist/api/payments/index.d.ts +396 -402
  40. package/dist/api/payments/index.d.ts.map +1 -1
  41. package/dist/api/payments/index.js.map +1 -1
  42. package/dist/api/subscriptions/index.d.ts +644 -652
  43. package/dist/api/subscriptions/index.d.ts.map +1 -1
  44. package/dist/api/subscriptions/index.js +1 -1
  45. package/dist/api/subscriptions/index.js.map +1 -1
  46. package/dist/api/users/index.browser.js +7 -0
  47. package/dist/api/users/index.browser.js.map +1 -1
  48. package/dist/api/users/index.d.ts +1106 -1005
  49. package/dist/api/users/index.d.ts.map +1 -1
  50. package/dist/api/users/index.js +307 -64
  51. package/dist/api/users/index.js.map +1 -1
  52. package/dist/api/verifications/index.browser.js.map +1 -1
  53. package/dist/api/verifications/index.d.ts +137 -143
  54. package/dist/api/verifications/index.d.ts.map +1 -1
  55. package/dist/api/verifications/index.js.map +1 -1
  56. package/dist/background/index.d.ts +95 -0
  57. package/dist/background/index.d.ts.map +1 -0
  58. package/dist/background/index.js +121 -0
  59. package/dist/background/index.js.map +1 -0
  60. package/dist/background/index.workerd.js +110 -0
  61. package/dist/background/index.workerd.js.map +1 -0
  62. package/dist/batch/index.d.ts +5 -7
  63. package/dist/batch/index.d.ts.map +1 -1
  64. package/dist/batch/index.js.map +1 -1
  65. package/dist/bin/index.js.map +1 -1
  66. package/dist/bucket/index.d.ts +76 -54
  67. package/dist/bucket/index.d.ts.map +1 -1
  68. package/dist/bucket/index.js +58 -11
  69. package/dist/bucket/index.js.map +1 -1
  70. package/dist/bucket/index.workerd.js +200 -5
  71. package/dist/bucket/index.workerd.js.map +1 -1
  72. package/dist/cache/core/index.d.ts +7 -10
  73. package/dist/cache/core/index.d.ts.map +1 -1
  74. package/dist/cache/core/index.js.map +1 -1
  75. package/dist/cache/core/index.workerd.js.map +1 -1
  76. package/dist/cache/database/index.d.ts +22 -26
  77. package/dist/cache/database/index.d.ts.map +1 -1
  78. package/dist/cache/database/index.js.map +1 -1
  79. package/dist/cache/redis/index.d.ts +4 -7
  80. package/dist/cache/redis/index.d.ts.map +1 -1
  81. package/dist/cache/redis/index.js.map +1 -1
  82. package/dist/captcha/index.d.ts +3 -6
  83. package/dist/captcha/index.d.ts.map +1 -1
  84. package/dist/captcha/index.js.map +1 -1
  85. package/dist/cli/config/index.d.ts.map +1 -1
  86. package/dist/cli/config/index.js.map +1 -1
  87. package/dist/cli/core/index.d.ts +458 -249
  88. package/dist/cli/core/index.d.ts.map +1 -1
  89. package/dist/cli/core/index.js +372 -660
  90. package/dist/cli/core/index.js.map +1 -1
  91. package/dist/cli/devtools/index.d.ts +3 -5
  92. package/dist/cli/devtools/index.d.ts.map +1 -1
  93. package/dist/cli/devtools/index.js.map +1 -1
  94. package/dist/cli/i18n/index.d.ts +20 -17
  95. package/dist/cli/i18n/index.d.ts.map +1 -1
  96. package/dist/cli/i18n/index.js +45 -11
  97. package/dist/cli/i18n/index.js.map +1 -1
  98. package/dist/cli/platform/index.d.ts +126 -1342
  99. package/dist/cli/platform/index.d.ts.map +1 -1
  100. package/dist/cli/platform/index.js +136 -2374
  101. package/dist/cli/platform/index.js.map +1 -1
  102. package/dist/cli/platform-lib/index.d.ts +1472 -0
  103. package/dist/cli/platform-lib/index.d.ts.map +1 -0
  104. package/dist/cli/platform-lib/index.js +2660 -0
  105. package/dist/cli/platform-lib/index.js.map +1 -0
  106. package/dist/cli/vendor/index.d.ts +17 -21
  107. package/dist/cli/vendor/index.d.ts.map +1 -1
  108. package/dist/cli/vendor/index.js.map +1 -1
  109. package/dist/command/index.d.ts +20 -19
  110. package/dist/command/index.d.ts.map +1 -1
  111. package/dist/command/index.js +39 -10
  112. package/dist/command/index.js.map +1 -1
  113. package/dist/{containers → container}/core/index.d.ts +13 -15
  114. package/dist/container/core/index.d.ts.map +1 -0
  115. package/dist/{containers → container}/core/index.js +23 -14
  116. package/dist/container/core/index.js.map +1 -0
  117. package/dist/{containers → container}/core/index.workerd.js +37 -22
  118. package/dist/container/core/index.workerd.js.map +1 -0
  119. package/dist/core/index.browser.js +27 -1
  120. package/dist/core/index.browser.js.map +1 -1
  121. package/dist/core/index.d.ts +48 -24
  122. package/dist/core/index.d.ts.map +1 -1
  123. package/dist/core/index.js +27 -1
  124. package/dist/core/index.js.map +1 -1
  125. package/dist/core/index.native.js +27 -1
  126. package/dist/core/index.native.js.map +1 -1
  127. package/dist/core/index.workerd.js +27 -1
  128. package/dist/core/index.workerd.js.map +1 -1
  129. package/dist/crypto/index.browser.js.map +1 -1
  130. package/dist/crypto/index.d.ts +5 -8
  131. package/dist/crypto/index.d.ts.map +1 -1
  132. package/dist/crypto/index.js.map +1 -1
  133. package/dist/datetime/index.d.ts +3 -4
  134. package/dist/datetime/index.d.ts.map +1 -1
  135. package/dist/datetime/index.js.map +1 -1
  136. package/dist/email/brevo/index.d.ts +2 -4
  137. package/dist/email/brevo/index.d.ts.map +1 -1
  138. package/dist/email/brevo/index.js.map +1 -1
  139. package/dist/email/cloudflare/index.d.ts +20 -7
  140. package/dist/email/cloudflare/index.d.ts.map +1 -1
  141. package/dist/email/cloudflare/index.js +46 -9
  142. package/dist/email/cloudflare/index.js.map +1 -1
  143. package/dist/email/core/index.d.ts +6 -9
  144. package/dist/email/core/index.d.ts.map +1 -1
  145. package/dist/email/core/index.js.map +1 -1
  146. package/dist/email/core/index.workerd.js.map +1 -1
  147. package/dist/email/smtp/index.d.ts +10 -13
  148. package/dist/email/smtp/index.d.ts.map +1 -1
  149. package/dist/email/smtp/index.js +107 -32
  150. package/dist/email/smtp/index.js.map +1 -1
  151. package/dist/fake/index.d.ts +1 -2
  152. package/dist/fake/index.d.ts.map +1 -1
  153. package/dist/fake/index.js.map +1 -1
  154. package/dist/lock/core/index.d.ts +9 -14
  155. package/dist/lock/core/index.d.ts.map +1 -1
  156. package/dist/lock/core/index.js.map +1 -1
  157. package/dist/lock/redis/index.d.ts +2 -4
  158. package/dist/lock/redis/index.d.ts.map +1 -1
  159. package/dist/lock/redis/index.js.map +1 -1
  160. package/dist/logger/index.d.ts +105 -76
  161. package/dist/logger/index.d.ts.map +1 -1
  162. package/dist/logger/index.js +196 -174
  163. package/dist/logger/index.js.map +1 -1
  164. package/dist/mcp/index.d.ts +25 -20
  165. package/dist/mcp/index.d.ts.map +1 -1
  166. package/dist/mcp/index.js +23 -0
  167. package/dist/mcp/index.js.map +1 -1
  168. package/dist/orm/core/index.browser.js.map +1 -1
  169. package/dist/orm/core/index.bun.js +19 -1
  170. package/dist/orm/core/index.bun.js.map +1 -1
  171. package/dist/orm/core/index.d.ts +76 -62
  172. package/dist/orm/core/index.d.ts.map +1 -1
  173. package/dist/orm/core/index.js +20 -2
  174. package/dist/orm/core/index.js.map +1 -1
  175. package/dist/orm/postgres/index.bun.js.map +1 -1
  176. package/dist/orm/postgres/index.d.ts +28 -20
  177. package/dist/orm/postgres/index.d.ts.map +1 -1
  178. package/dist/orm/postgres/index.js.map +1 -1
  179. package/dist/queue/core/index.d.ts +12 -15
  180. package/dist/queue/core/index.d.ts.map +1 -1
  181. package/dist/queue/core/index.js.map +1 -1
  182. package/dist/queue/core/index.workerd.js.map +1 -1
  183. package/dist/queue/redis/index.d.ts +3 -5
  184. package/dist/queue/redis/index.d.ts.map +1 -1
  185. package/dist/queue/redis/index.js.map +1 -1
  186. package/dist/react/auth/index.browser.js +9 -2
  187. package/dist/react/auth/index.browser.js.map +1 -1
  188. package/dist/react/auth/index.d.ts +14 -9
  189. package/dist/react/auth/index.d.ts.map +1 -1
  190. package/dist/react/auth/index.js +9 -2
  191. package/dist/react/auth/index.js.map +1 -1
  192. package/dist/react/core/index.d.ts +7 -8
  193. package/dist/react/core/index.d.ts.map +1 -1
  194. package/dist/react/core/index.js +6 -3
  195. package/dist/react/core/index.js.map +1 -1
  196. package/dist/react/form/index.d.ts +2 -5
  197. package/dist/react/form/index.d.ts.map +1 -1
  198. package/dist/react/form/index.js +16 -15
  199. package/dist/react/form/index.js.map +1 -1
  200. package/dist/react/head/index.browser.js.map +1 -1
  201. package/dist/react/head/index.d.ts +2 -4
  202. package/dist/react/head/index.d.ts.map +1 -1
  203. package/dist/react/head/index.js.map +1 -1
  204. package/dist/react/i18n/index.d.ts +90 -11
  205. package/dist/react/i18n/index.d.ts.map +1 -1
  206. package/dist/react/i18n/index.js +147 -11
  207. package/dist/react/i18n/index.js.map +1 -1
  208. package/dist/react/intro/index.d.ts +1 -2
  209. package/dist/react/intro/index.d.ts.map +1 -1
  210. package/dist/react/intro/index.js +2 -2
  211. package/dist/react/intro/index.js.map +1 -1
  212. package/dist/react/router/index.browser.js +193 -24
  213. package/dist/react/router/index.browser.js.map +1 -1
  214. package/dist/react/router/index.d.ts +434 -222
  215. package/dist/react/router/index.d.ts.map +1 -1
  216. package/dist/react/router/index.js +249 -35
  217. package/dist/react/router/index.js.map +1 -1
  218. package/dist/react/sitemap/index.browser.js +35 -0
  219. package/dist/react/sitemap/index.browser.js.map +1 -0
  220. package/dist/react/sitemap/index.d.ts +92 -0
  221. package/dist/react/sitemap/index.d.ts.map +1 -0
  222. package/dist/react/sitemap/index.js +131 -0
  223. package/dist/react/sitemap/index.js.map +1 -0
  224. package/dist/react/testing/index.d.ts +1 -2
  225. package/dist/react/testing/index.d.ts.map +1 -1
  226. package/dist/react/testing/index.js +16 -17
  227. package/dist/react/testing/index.js.map +1 -1
  228. package/dist/react/ui/index.d.ts +20 -25
  229. package/dist/react/ui/index.d.ts.map +1 -1
  230. package/dist/react/ui/index.js.map +1 -1
  231. package/dist/redis/index.bun.js.map +1 -1
  232. package/dist/redis/index.d.ts +17 -19
  233. package/dist/redis/index.d.ts.map +1 -1
  234. package/dist/redis/index.js.map +1 -1
  235. package/dist/retry/index.d.ts +2 -4
  236. package/dist/retry/index.d.ts.map +1 -1
  237. package/dist/retry/index.js.map +1 -1
  238. package/dist/router/index.d.ts.map +1 -1
  239. package/dist/router/index.js.map +1 -1
  240. package/dist/scheduler/index.d.ts +10 -13
  241. package/dist/scheduler/index.d.ts.map +1 -1
  242. package/dist/scheduler/index.js.map +1 -1
  243. package/dist/scheduler/index.workerd.js.map +1 -1
  244. package/dist/security/index.browser.js.map +1 -1
  245. package/dist/security/index.d.ts +45 -48
  246. package/dist/security/index.d.ts.map +1 -1
  247. package/dist/security/index.js.map +1 -1
  248. package/dist/server/auth/index.browser.js.map +1 -1
  249. package/dist/server/auth/index.d.ts +272 -173
  250. package/dist/server/auth/index.d.ts.map +1 -1
  251. package/dist/server/auth/index.js +1608 -15
  252. package/dist/server/auth/index.js.map +1 -1
  253. package/dist/server/cookies/index.browser.js.map +1 -1
  254. package/dist/server/cookies/index.d.ts +20 -7
  255. package/dist/server/cookies/index.d.ts.map +1 -1
  256. package/dist/server/cookies/index.js +22 -3
  257. package/dist/server/cookies/index.js.map +1 -1
  258. package/dist/server/core/index.browser.js.map +1 -1
  259. package/dist/server/core/index.d.ts +106 -73
  260. package/dist/server/core/index.d.ts.map +1 -1
  261. package/dist/server/core/index.js +44 -0
  262. package/dist/server/core/index.js.map +1 -1
  263. package/dist/server/cors/index.d.ts +11 -14
  264. package/dist/server/cors/index.d.ts.map +1 -1
  265. package/dist/server/cors/index.js.map +1 -1
  266. package/dist/server/etag/index.d.ts +6 -9
  267. package/dist/server/etag/index.d.ts.map +1 -1
  268. package/dist/server/etag/index.js.map +1 -1
  269. package/dist/server/health/index.d.ts +18 -21
  270. package/dist/server/health/index.d.ts.map +1 -1
  271. package/dist/server/health/index.js.map +1 -1
  272. package/dist/server/links/index.browser.js +2 -0
  273. package/dist/server/links/index.browser.js.map +1 -1
  274. package/dist/server/links/index.d.ts +63 -67
  275. package/dist/server/links/index.d.ts.map +1 -1
  276. package/dist/server/links/index.js +2 -0
  277. package/dist/server/links/index.js.map +1 -1
  278. package/dist/server/metrics/index.d.ts +5 -7
  279. package/dist/server/metrics/index.d.ts.map +1 -1
  280. package/dist/server/metrics/index.js.map +1 -1
  281. package/dist/server/proxy/index.d.ts +3 -5
  282. package/dist/server/proxy/index.d.ts.map +1 -1
  283. package/dist/server/proxy/index.js.map +1 -1
  284. package/dist/server/rate-limit/index.d.ts +10 -13
  285. package/dist/server/rate-limit/index.d.ts.map +1 -1
  286. package/dist/server/rate-limit/index.js.map +1 -1
  287. package/dist/server/static/index.d.ts +3 -5
  288. package/dist/server/static/index.d.ts.map +1 -1
  289. package/dist/server/static/index.js.map +1 -1
  290. package/dist/server/swagger/index.d.ts +5 -8
  291. package/dist/server/swagger/index.d.ts.map +1 -1
  292. package/dist/server/swagger/index.js.map +1 -1
  293. package/dist/sms/index.d.ts +3 -5
  294. package/dist/sms/index.d.ts.map +1 -1
  295. package/dist/sms/index.js.map +1 -1
  296. package/dist/system/index.browser.js.map +1 -1
  297. package/dist/system/index.d.ts +2 -4
  298. package/dist/system/index.d.ts.map +1 -1
  299. package/dist/system/index.js.map +1 -1
  300. package/dist/system/index.workerd.js.map +1 -1
  301. package/dist/topic/core/index.d.ts +4 -6
  302. package/dist/topic/core/index.d.ts.map +1 -1
  303. package/dist/topic/core/index.js.map +1 -1
  304. package/dist/topic/redis/index.d.ts +5 -8
  305. package/dist/topic/redis/index.d.ts.map +1 -1
  306. package/dist/topic/redis/index.js.map +1 -1
  307. package/package.json +59 -23
  308. package/src/api/audits/__tests__/AuditService.spec.ts +18 -110
  309. package/src/api/audits/controllers/AdminAuditController.ts +14 -0
  310. package/src/api/audits/services/AuditService.ts +21 -88
  311. package/src/api/files/__tests__/FileService.spec.ts +207 -2
  312. package/src/api/files/index.ts +3 -0
  313. package/src/api/files/schemas/fileCreatorSummarySchema.ts +22 -0
  314. package/src/api/files/schemas/fileResourceSchema.ts +10 -1
  315. package/src/api/files/services/FileService.ts +170 -72
  316. package/src/api/jobs/__tests__/$job.spec.ts +24 -1
  317. package/src/api/jobs/index.ts +4 -3
  318. package/src/api/jobs/primitives/$job.ts +7 -3
  319. package/src/api/jobs/providers/DirectJobDispatcher.ts +17 -36
  320. package/src/api/jobs/providers/JobProvider.ts +53 -24
  321. package/src/api/jobs/schemas/jobConfigAtom.ts +1 -1
  322. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +4 -1
  323. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +3 -1
  324. package/src/api/parameters/__tests__/$parameter.spec.ts +19 -2
  325. package/src/api/parameters/audits/ParameterAudits.ts +17 -0
  326. package/src/api/parameters/controllers/AdminParameterController.ts +95 -19
  327. package/src/api/parameters/index.ts +3 -0
  328. package/src/api/parameters/schemas/activateParameterBodySchema.ts +3 -3
  329. package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +3 -2
  330. package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +25 -0
  331. package/src/api/parameters/schemas/parameterResponseSchema.ts +5 -0
  332. package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +4 -2
  333. package/src/api/parameters/services/ParameterProvider.ts +69 -6
  334. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +1 -1
  335. package/src/api/users/__tests__/AdminSessionController.spec.ts +37 -0
  336. package/src/api/users/audits/SessionAudits.ts +33 -0
  337. package/src/api/users/audits/UserAudits.ts +19 -43
  338. package/src/api/users/controllers/AdminUserController.ts +66 -1
  339. package/src/api/users/controllers/RealmController.ts +1 -0
  340. package/src/api/users/entities/sessions.ts +6 -0
  341. package/src/api/users/entities/users.ts +2 -0
  342. package/src/api/users/index.ts +9 -1
  343. package/src/api/users/primitives/$realm.ts +29 -0
  344. package/src/api/users/providers/RealmProvider.ts +15 -0
  345. package/src/api/users/schemas/realmConfigSchema.ts +14 -0
  346. package/src/api/users/schemas/sessionResourceSchema.ts +16 -0
  347. package/src/api/users/schemas/updateUserSchema.ts +1 -8
  348. package/src/api/users/schemas/userQuerySchema.ts +7 -0
  349. package/src/api/users/services/CredentialService.ts +15 -6
  350. package/src/api/users/services/IdentityService.ts +2 -1
  351. package/src/api/users/services/RegistrationService.ts +2 -1
  352. package/src/api/users/services/SessionCrudService.ts +19 -2
  353. package/src/api/users/services/SessionService.ts +39 -19
  354. package/src/api/users/services/UserService.ts +106 -8
  355. package/src/background/__tests__/BackgroundTaskProvider.spec.ts +96 -0
  356. package/src/background/index.ts +37 -0
  357. package/src/background/index.workerd.ts +28 -0
  358. package/src/background/providers/BackgroundTaskProvider.ts +70 -0
  359. package/src/background/providers/WorkerdBackgroundTaskProvider.ts +43 -0
  360. package/src/bucket/__tests__/$bucket.spec.ts +18 -0
  361. package/src/bucket/__tests__/LocalFileStorageProvider.spec.ts +5 -0
  362. package/src/bucket/__tests__/MemoryFileStorageProvider.spec.ts +5 -0
  363. package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +23 -4
  364. package/src/bucket/__tests__/shared.ts +30 -0
  365. package/src/bucket/index.ts +5 -5
  366. package/src/bucket/index.workerd.ts +11 -4
  367. package/src/bucket/primitives/$bucket.ts +27 -0
  368. package/src/bucket/providers/FileStorageProvider.ts +13 -0
  369. package/src/bucket/providers/LocalFileStorageProvider.ts +17 -1
  370. package/src/bucket/providers/MemoryFileStorageProvider.ts +7 -0
  371. package/src/bucket/providers/{CloudflareR2Provider.ts → R2FileStorageProvider.ts} +10 -1
  372. package/src/bucket/providers/{NodeS3BucketProvider.ts → S3FileStorageProvider.ts} +27 -5
  373. package/src/cli/core/__tests__/BuildDockerTask.spec.ts +25 -1
  374. package/src/cli/core/__tests__/init.spec.ts +0 -219
  375. package/src/cli/core/atoms/buildOptions.ts +0 -12
  376. package/src/cli/core/commands/__tests__/BuildCommand.spec.ts +43 -0
  377. package/src/cli/core/commands/build.ts +105 -37
  378. package/src/cli/core/commands/init.ts +0 -12
  379. package/src/cli/core/commands/pack.ts +133 -0
  380. package/src/cli/core/index.ts +3 -3
  381. package/src/cli/core/providers/ViteDevServerProvider.ts +40 -16
  382. package/src/cli/core/services/PackageManagerUtils.ts +0 -16
  383. package/src/cli/core/services/ProjectScaffolder.ts +29 -291
  384. package/src/cli/core/tasks/BuildCloudflareTask.ts +382 -56
  385. package/src/cli/core/tasks/BuildDockerTask.ts +33 -3
  386. package/src/cli/core/tasks/BuildPrerenderTask.ts +44 -7
  387. package/src/cli/core/tasks/BuildTask.ts +34 -0
  388. package/src/cli/core/templates/apiIndexTs.ts +1 -22
  389. package/src/cli/core/templates/mainCss.ts +0 -1
  390. package/src/cli/core/templates/webAppRouterTs.ts +0 -99
  391. package/src/cli/core/templates/webIndexTs.ts +1 -22
  392. package/src/cli/i18n/__tests__/I18nCheckService.spec.ts +48 -0
  393. package/src/cli/i18n/services/I18nCheckService.ts +65 -11
  394. package/src/cli/platform/__tests__/SecretsCommand.spec.ts +5 -3
  395. package/src/cli/platform/commands/SecretsCommand.ts +8 -6
  396. package/src/cli/platform/commands/platform.ts +192 -46
  397. package/src/cli/platform/index.ts +12 -52
  398. package/src/cli/{platform → platform-lib}/__tests__/CloudflareAdapter.spec.ts +426 -169
  399. package/src/cli/{platform → platform-lib}/__tests__/NamingService.spec.ts +91 -4
  400. package/src/cli/{platform → platform-lib}/__tests__/VercelAdapter.spec.ts +56 -85
  401. package/src/cli/{platform → platform-lib}/adapters/CloudflareAdapter.ts +519 -190
  402. package/src/cli/{platform → platform-lib}/adapters/PlatformAdapter.ts +62 -35
  403. package/src/cli/{platform → platform-lib}/adapters/VercelAdapter.ts +6 -10
  404. package/src/cli/{platform → platform-lib}/atoms/platformOptions.ts +34 -1
  405. package/src/cli/platform-lib/index.ts +67 -0
  406. package/src/cli/platform-lib/services/NamingService.ts +136 -0
  407. package/src/cli/{platform → platform-lib}/services/PlatformInspector.ts +60 -13
  408. package/src/cli/{platform → platform-lib}/services/PlatformOrchestrator.ts +54 -43
  409. package/src/cli/{platform → platform-lib}/services/WranglerApi.ts +4 -2
  410. package/src/command/__tests__/Runner.spec.ts +20 -0
  411. package/src/command/helpers/EnvUtils.ts +19 -3
  412. package/src/command/helpers/Runner.ts +12 -2
  413. package/src/command/providers/CliProvider.ts +34 -1
  414. package/src/{containers → container}/core/__tests__/$container.spec.ts +5 -5
  415. package/src/{containers → container}/core/index.ts +4 -4
  416. package/src/{containers → container}/core/index.workerd.ts +19 -3
  417. package/src/{containers → container}/core/primitives/$container.ts +1 -1
  418. package/src/{containers → container}/core/providers/CloudflareContainerProvider.ts +17 -19
  419. package/src/{containers → container}/core/providers/ContainerProvider.ts +16 -2
  420. package/src/{containers → container}/core/providers/MockContainerProvider.ts +1 -1
  421. package/src/core/Alepha.ts +49 -1
  422. package/src/core/__tests__/$env.spec.ts +42 -0
  423. package/src/core/__tests__/dump.spec.ts +47 -0
  424. package/src/email/cloudflare/__tests__/CloudflareEmailProvider.spec.ts +42 -10
  425. package/src/email/cloudflare/index.ts +14 -5
  426. package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +54 -9
  427. package/src/logger/__tests__/Logger.spec.ts +55 -0
  428. package/src/logger/index.ts +13 -0
  429. package/src/logger/services/Logger.ts +31 -1
  430. package/src/mcp/__tests__/McpServerProvider.spec.ts +71 -0
  431. package/src/mcp/providers/McpServerProvider.ts +55 -0
  432. package/src/orm/__tests__/orm-showcase-tests.ts +27 -0
  433. package/src/orm/__tests__/orm-showcase.spec.ts +12 -0
  434. package/src/orm/core/interfaces/PgQuery.ts +4 -1
  435. package/src/orm/core/services/Repository.ts +27 -11
  436. package/src/react/auth/hooks/useAuth.ts +10 -5
  437. package/src/react/core/__tests__/useQuery.browser.spec.tsx +25 -0
  438. package/src/react/core/hooks/useAction.ts +14 -3
  439. package/src/react/core/hooks/useQuery.ts +24 -4
  440. package/src/react/form/__tests__/FormModel-submit-loading.spec.ts +71 -0
  441. package/src/react/form/__tests__/form-submitting-reactive.browser.spec.tsx +96 -0
  442. package/src/react/form/services/FormModel.ts +57 -39
  443. package/src/react/i18n/__tests__/I18nProvider.spec.ts +89 -0
  444. package/src/react/i18n/__tests__/locale-routing.spec.ts +107 -0
  445. package/src/react/i18n/components/Translate.tsx +47 -0
  446. package/src/react/i18n/index.ts +2 -0
  447. package/src/react/i18n/providers/I18nProvider.ts +171 -12
  448. package/src/react/intro/components/GettingStartedAdminSlide.tsx +2 -2
  449. package/src/react/router/__tests__/$page.spec.tsx +3 -2
  450. package/src/react/router/__tests__/RouterLocaleProvider.spec.ts +127 -0
  451. package/src/react/router/__tests__/page-can.spec.ts +18 -13
  452. package/src/react/router/hooks/useQueryParams.ts +114 -14
  453. package/src/react/router/index.browser.ts +4 -0
  454. package/src/react/router/index.shared.ts +1 -0
  455. package/src/react/router/index.ts +9 -0
  456. package/src/react/router/primitives/$page.ts +85 -4
  457. package/src/react/router/providers/ReactBrowserRouterProvider.ts +18 -8
  458. package/src/react/router/providers/ReactPageProvider.ts +12 -1
  459. package/src/react/router/providers/ReactServerProvider.ts +96 -14
  460. package/src/react/router/providers/RootComponentsProvider.ts +13 -0
  461. package/src/react/router/providers/RouterLocaleProvider.ts +125 -0
  462. package/src/react/router/providers/__tests__/RootComponentsProvider.spec.ts +15 -0
  463. package/src/react/router/providers/__tests__/rootComponents.ssr.browser.spec.tsx +67 -0
  464. package/src/react/sitemap/__tests__/$sitemap.spec.ts +131 -0
  465. package/src/react/sitemap/index.browser.ts +21 -0
  466. package/src/react/sitemap/index.ts +25 -0
  467. package/src/react/sitemap/primitives/$sitemap.browser.ts +26 -0
  468. package/src/react/sitemap/primitives/$sitemap.ts +196 -0
  469. package/src/react/ui/services/SchemaControl.ts +3 -4
  470. package/src/server/auth/__tests__/appleClientSecret.spec.ts +34 -0
  471. package/src/server/auth/__tests__/authFederationClient.spec.ts +40 -0
  472. package/src/server/auth/__tests__/federationAssertion.spec.ts +146 -0
  473. package/src/server/auth/__tests__/federationRedirectReplay.spec.ts +44 -0
  474. package/src/server/auth/helpers/appleClientSecret.ts +24 -0
  475. package/src/server/auth/helpers/federationAssertion.ts +74 -0
  476. package/src/server/auth/helpers/jtiReplayGuard.ts +41 -0
  477. package/src/server/auth/helpers/safeRedirectPath.ts +19 -0
  478. package/src/server/auth/index.ts +4 -0
  479. package/src/server/auth/primitives/$authFederationBroker.ts +273 -0
  480. package/src/server/auth/primitives/$authFederationClient.ts +89 -0
  481. package/src/server/auth/providers/ServerAuthProvider.ts +18 -4
  482. package/src/server/cookies/__tests__/ServerCookiesProvider.spec.ts +70 -0
  483. package/src/server/cookies/providers/ServerCookiesProvider.ts +23 -3
  484. package/src/server/core/interfaces/ServerRequest.ts +8 -0
  485. package/src/server/core/primitives/$route.ts +27 -0
  486. package/src/server/core/providers/ServerMultipartProvider.ts +19 -0
  487. package/src/server/links/providers/LinkProvider.ts +10 -0
  488. package/dist/containers/core/index.d.ts.map +0 -1
  489. package/dist/containers/core/index.js.map +0 -1
  490. package/dist/containers/core/index.workerd.js.map +0 -1
  491. package/src/cli/core/tasks/BuildSitemapTask.ts +0 -130
  492. package/src/cli/core/templates/componentsJsonTs.ts +0 -39
  493. package/src/cli/core/templates/saasAdminLayoutTsx.ts +0 -77
  494. package/src/cli/core/templates/saasAdminPagesTsx.ts +0 -26
  495. package/src/cli/core/templates/saasAuthLayoutTsx.ts +0 -22
  496. package/src/cli/core/templates/saasAuthPagesTsx.ts +0 -62
  497. package/src/cli/core/templates/saasRealmProviderTs.ts +0 -52
  498. package/src/cli/platform/services/NamingService.ts +0 -54
  499. /package/dist/orm/core/{chunk-o8xxKEmq.js → chunk-B4FMCO8f.js} +0 -0
  500. /package/dist/react/testing/{chunk-6Ep1yQYe.js → chunk-BpyX8vjI.js} +0 -0
  501. /package/src/cli/{platform → platform-lib}/__tests__/GitHubSecretStore.spec.ts +0 -0
  502. /package/src/cli/{platform → platform-lib}/__tests__/PlatformCacheProvider.spec.ts +0 -0
  503. /package/src/cli/{platform → platform-lib}/__tests__/PlatformInspector.spec.ts +0 -0
  504. /package/src/cli/{platform → platform-lib}/__tests__/PlatformOrchestrator.spec.ts +0 -0
  505. /package/src/cli/{platform → platform-lib}/__tests__/SecretFilterService.spec.ts +0 -0
  506. /package/src/cli/{platform → platform-lib}/__tests__/detectResources.spec.ts +0 -0
  507. /package/src/cli/{platform → platform-lib}/providers/GitHubSecretStore.ts +0 -0
  508. /package/src/cli/{platform → platform-lib}/providers/MemorySecretStore.ts +0 -0
  509. /package/src/cli/{platform → platform-lib}/providers/PlatformCacheProvider.ts +0 -0
  510. /package/src/cli/{platform → platform-lib}/providers/SecretStoreProvider.ts +0 -0
  511. /package/src/cli/{platform → platform-lib}/schemas/cloudflare.ts +0 -0
  512. /package/src/cli/{platform → platform-lib}/schemas/platform.ts +0 -0
  513. /package/src/cli/{platform → platform-lib}/schemas/vercel.ts +0 -0
  514. /package/src/cli/{platform → platform-lib}/services/CloudflareApi.ts +0 -0
  515. /package/src/cli/{platform → platform-lib}/services/SecretFilterService.ts +0 -0
  516. /package/src/cli/{platform → platform-lib}/services/VercelApi.ts +0 -0
  517. /package/src/cli/{platform → platform-lib}/services/VercelCli.ts +0 -0
  518. /package/src/{containers → container}/core/interfaces/ContainerOptions.ts +0 -0
  519. /package/src/{containers → container}/core/providers/NodeContainerProvider.ts +0 -0
@@ -4,11 +4,18 @@ import { FileSystemProvider } from "alepha/system";
4
4
  import { BuildTask, type BuildTaskContext } from "./BuildTask.ts";
5
5
 
6
6
  /**
7
- * Pre-render static pages defined in the Alepha application.
7
+ * Pre-render static pages and routes defined in the Alepha application.
8
8
  *
9
- * Queries all page primitives with `static: true` and generates
10
- * static HTML files for each page. Supports pages with parameterized
11
- * routes via `static.entries` configuration.
9
+ * Two passes, both writing into `dist/public`:
10
+ * - **pages** every `$page` with `static: true` is rendered to an HTML file
11
+ * (supports parameterized routes via `static.entries`).
12
+ * - **routes** — every `static` route primitive (a `$route({ static: true })`
13
+ * or a `$sitemap`) is invoked in-process and its body written verbatim to
14
+ * `{path}` (e.g. `sitemap.xml`, `robots.txt`).
15
+ *
16
+ * Both passes read the primitive registry and call a method on the already
17
+ * created primitive instances — no provider is re-injected, so this works in
18
+ * the build's configured-but-not-started container.
12
19
  */
13
20
  export class BuildPrerenderTask extends BuildTask {
14
21
  protected readonly fs = $inject(FileSystemProvider);
@@ -22,7 +29,8 @@ export class BuildPrerenderTask extends BuildTask {
22
29
  }
23
30
 
24
31
  const pages = this.getStaticPages(ctx);
25
- if (pages.length === 0) {
32
+ const routes = this.getStaticRoutePrimitives(ctx);
33
+ if (pages.length === 0 && routes.length === 0) {
26
34
  return;
27
35
  }
28
36
 
@@ -31,13 +39,18 @@ export class BuildPrerenderTask extends BuildTask {
31
39
  const dist = this.fs.join(ctx.root, distDir, publicDir);
32
40
 
33
41
  await ctx.run({
34
- name: "pre-render pages",
42
+ name: "pre-render",
35
43
  handler: async () => {
36
44
  // TODO: running configure here is a temporary workaround
37
45
  if (!ctx.alepha.isConfigured()) {
38
46
  await ctx.alepha.events.emit("configure", ctx.alepha);
39
47
  }
40
- await this.prerenderFromAlepha(pages, dist);
48
+ if (pages.length > 0) {
49
+ await this.prerenderFromAlepha(pages, dist);
50
+ }
51
+ if (routes.length > 0) {
52
+ await this.prerenderRoutes(routes, dist);
53
+ }
41
54
  },
42
55
  });
43
56
  }
@@ -50,6 +63,18 @@ export class BuildPrerenderTask extends BuildTask {
50
63
  });
51
64
  }
52
65
 
66
+ /**
67
+ * Static route primitives to snapshot: `$route({ static: true })` and every
68
+ * `$sitemap`. Both expose an async `prerender(): { path, body }`.
69
+ */
70
+ protected getStaticRoutePrimitives(ctx: BuildTaskContext): any[] {
71
+ const routes = (ctx.alepha.primitives("route") as any[]).filter(
72
+ (route) => route.options?.static === true,
73
+ );
74
+ const sitemaps = ctx.alepha.primitives("sitemap") as any[];
75
+ return [...routes, ...sitemaps];
76
+ }
77
+
53
78
  protected async prerenderFromAlepha(
54
79
  pages: any[],
55
80
  dist: string,
@@ -77,6 +102,18 @@ export class BuildPrerenderTask extends BuildTask {
77
102
  return count;
78
103
  }
79
104
 
105
+ protected async prerenderRoutes(
106
+ primitives: any[],
107
+ dist: string,
108
+ ): Promise<void> {
109
+ for (const primitive of primitives) {
110
+ const { path, body } = await primitive.prerender();
111
+ const filepath = this.fs.join(dist, path);
112
+ await this.fs.mkdir(dirname(filepath));
113
+ await this.fs.writeFile(filepath, body);
114
+ }
115
+ }
116
+
80
117
  protected async renderFile(
81
118
  page: any,
82
119
  options: any,
@@ -2,6 +2,7 @@ import type { Alepha } from "alepha";
2
2
  import type { RunnerMethod } from "alepha/command";
3
3
  import type { BuildOptions } from "../atoms/buildOptions.ts";
4
4
  import type { AppEntry } from "../providers/AppEntryProvider.ts";
5
+ import type { BuildManifest } from "./BuildCloudflareTask.ts";
5
6
 
6
7
  export interface BuildTaskContext {
7
8
  /**
@@ -43,6 +44,39 @@ export interface BuildTaskContext {
43
44
  * Raw CLI flags passed through from the command.
44
45
  * Tasks can read flags relevant to their domain.
45
46
  */
47
+ /**
48
+ * Build-time snapshot of primitive data, read from
49
+ * `dist/manifest.json`. Populated only in `--prebuilt` mode when a
50
+ * previous build's manifest is present — lets BuildCloudflareTask
51
+ * regenerate `wrangler.jsonc` without re-booting the workspace.
52
+ * `null` when introspection (`ctx.alepha`) is the source of truth.
53
+ */
54
+ manifest: BuildManifest | null;
55
+
56
+ /**
57
+ * Resolved `platform({ default, environments, ... })` options from
58
+ * the workspace's `alepha.config.ts`. Populated by `BuildCommand`
59
+ * from the CLI's Alepha instance (where alepha.config.ts ran) —
60
+ * BuildCloudflareTask uses these to write the corresponding fields
61
+ * into `dist/manifest.json` so the deploy side doesn't need to
62
+ * re-load `alepha.config.ts`. `null` when no platform options were
63
+ * declared.
64
+ */
65
+ platformOptions: {
66
+ default?: string;
67
+ tenancy?: "none" | "optional" | "required";
68
+ environments?: Record<
69
+ string,
70
+ {
71
+ adapter: "cloudflare" | "vercel";
72
+ domain?: string;
73
+ zone?: string;
74
+ jurisdiction?: "eu" | "fedramp";
75
+ accountId?: string;
76
+ }
77
+ >;
78
+ } | null;
79
+
46
80
  flags?: {
47
81
  image?: boolean | string;
48
82
  /**
@@ -1,30 +1,9 @@
1
1
  export interface ApiIndexTsOptions {
2
2
  appName?: string;
3
- /**
4
- * Include `AlephaApiUsers` (realms, sessions, registration, identities,
5
- * password reset, email verification, admin endpoints) plus the local
6
- * `RealmProvider` that declares `$realm({ ... })`.
7
- */
8
- saas?: boolean;
9
3
  }
10
4
 
11
5
  export const apiIndexTs = (options: ApiIndexTsOptions = {}) => {
12
- const { appName = "app", saas = false } = options;
13
-
14
- if (saas) {
15
- return `
16
- import { $module } from "alepha";
17
- import { AlephaApiUsers } from "alepha/api/users";
18
- import { HelloController } from "./controllers/HelloController.ts";
19
- import { RealmProvider } from "./providers/RealmProvider.ts";
20
-
21
- export const ApiModule = $module({
22
- name: "${appName}.api",
23
- services: [HelloController, RealmProvider],
24
- imports: [AlephaApiUsers],
25
- });
26
- `.trim();
27
- }
6
+ const { appName = "app" } = options;
28
7
 
29
8
  return `
30
9
  import { $module } from "alepha";
@@ -11,7 +11,6 @@ export const mainCss = (opts: { tailwind?: boolean } = {}) => {
11
11
  *
12
12
  * Options:
13
13
  * - Tailwind CSS: Use \`alepha init --tailwind\` to add Tailwind CSS
14
- * - shadcn/ui: Use \`alepha init --shadcn\` to add shadcn/ui setup
15
14
  * - Raw CSS: Write your own styles below
16
15
  */
17
16
 
@@ -1,16 +1,8 @@
1
1
  export interface WebAppRouterOptions {
2
2
  api?: boolean;
3
- saas?: boolean;
4
3
  }
5
4
 
6
5
  export const webAppRouterTs = (options: WebAppRouterOptions) => {
7
- if (options.saas) {
8
- return saasAppRouterTs();
9
- }
10
- return basicAppRouterTs(options);
11
- };
12
-
13
- const basicAppRouterTs = (options: WebAppRouterOptions) => {
14
6
  const imports: string[] = ['import { $page } from "alepha/react/router";'];
15
7
  const classMembers: string[] = [];
16
8
 
@@ -39,94 +31,3 @@ export class AppRouter {
39
31
  ${classMembers.join("\n\n")}
40
32
  }`;
41
33
  };
42
-
43
- /**
44
- * SaaS router wires three trees onto the app:
45
- * / → Home
46
- * /auth/* → AuthLayout + login / register / reset / verify
47
- * /admin/* → AdminLayout + users / sessions / api-keys / parameters / audits
48
- *
49
- * Each auth page resolves the realm config from its loader, so the registry
50
- * components render with everything they need on first paint.
51
- */
52
- const saasAppRouterTs =
53
- () => `import type { RealmController } from "alepha/api/users";
54
- import { $page, NotFound } from "alepha/react/router";
55
- import { $secure } from "alepha/security";
56
- import { $client } from "alepha/server/links";
57
- import type { HelloController } from "../api/controllers/HelloController.ts";
58
-
59
- export class AppRouter {
60
- protected readonly api = $client<HelloController>();
61
- protected readonly realmApi = $client<RealmController>();
62
-
63
- home = $page({
64
- path: "/",
65
- lazy: () => import("./components/Home.tsx"),
66
- loader: () => this.api.hello(),
67
- });
68
-
69
- // ── /auth — login, register, reset, verify ─────────────────────────────
70
- authLayout = $page({
71
- path: "/auth",
72
- lazy: () => import("./components/auth/AuthLayout.tsx"),
73
- });
74
-
75
- login = $page({
76
- parent: this.authLayout,
77
- path: "/login",
78
- name: "login",
79
- head: { title: "Sign in" },
80
- lazy: () => import("./components/auth/Login.tsx"),
81
- loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
82
- });
83
-
84
- register = $page({
85
- parent: this.authLayout,
86
- path: "/register",
87
- name: "register",
88
- head: { title: "Sign up" },
89
- lazy: () => import("./components/auth/Register.tsx"),
90
- loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
91
- });
92
-
93
- resetPassword = $page({
94
- parent: this.authLayout,
95
- path: "/reset-password",
96
- head: { title: "Reset password" },
97
- lazy: () => import("./components/auth/ResetPassword.tsx"),
98
- loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
99
- });
100
-
101
- verifyEmail = $page({
102
- parent: this.authLayout,
103
- path: "/verify-email",
104
- head: { title: "Verify email" },
105
- lazy: () => import("./components/auth/VerifyEmail.tsx"),
106
- });
107
-
108
- // ── /admin — gated by 'admin:ui' permission, declared in RealmProvider.
109
- // Children inherit the gate via the parent chain.
110
- adminLayout = $page({
111
- path: "/admin",
112
- use: [$secure({ permissions: ["admin:ui"] })],
113
- lazy: () => import("./components/admin/AdminLayout.tsx"),
114
- });
115
-
116
- adminUsers = $page({
117
- parent: this.adminLayout,
118
- path: "/users",
119
- head: { title: "Users" },
120
- lazy: () => import("./components/admin/Users.tsx"),
121
- });
122
-
123
- adminSessions = $page({
124
- parent: this.adminLayout,
125
- path: "/sessions",
126
- head: { title: "Sessions" },
127
- lazy: () => import("./components/admin/Sessions.tsx"),
128
- });
129
-
130
- notFound = $page({ path: "/*", component: NotFound });
131
- }
132
- `;
@@ -1,30 +1,9 @@
1
1
  export interface WebIndexTsOptions {
2
2
  appName?: string;
3
- /**
4
- * SaaS bundle: auth pages need `useAuth()` (ReactAuth) which lives in the
5
- * `alepha.react.auth` module. Importing it here registers ReactAuth in the
6
- * container so the auth-* registry components can inject it.
7
- */
8
- saas?: boolean;
9
3
  }
10
4
 
11
5
  export const webIndexTs = (options: WebIndexTsOptions = {}) => {
12
- const { appName = "app", saas = false } = options;
13
-
14
- if (saas) {
15
- return `
16
- import { $module } from "alepha";
17
- import { AlephaReactAuth } from "alepha/react/auth";
18
- import { AlephaReactI18n } from "alepha/react/i18n";
19
- import { AppRouter } from "./AppRouter.ts";
20
-
21
- export const WebModule = $module({
22
- name: "${appName}.web",
23
- services: [AppRouter],
24
- imports: [AlephaReactAuth, AlephaReactI18n],
25
- });
26
- `.trim();
27
- }
6
+ const { appName = "app" } = options;
28
7
 
29
8
  return `
30
9
  import { $module } from "alepha";
@@ -109,6 +109,54 @@ ${body}
109
109
  expect(result.unused).toEqual(["home.title"]);
110
110
  });
111
111
 
112
+ it("extracts keys from lazily-imported per-language files", async () => {
113
+ await env.fs.mkdir(`${ROOT}/src/web/i18n`, { recursive: true });
114
+ // Marker file declares `$dictionary` but the keys live in split,
115
+ // markerless per-language files referenced via `lazy: () => import(...)`.
116
+ // A sibling `$page` lazy import must NOT be mistaken for a key file.
117
+ await env.fs.writeFile(
118
+ `${ROOT}/src/web/Router.ts`,
119
+ `import { $dictionary } from "alepha/react/i18n";
120
+ export class Router {
121
+ fr = $dictionary({ lazy: () => import("./i18n/fr.ts"), lang: "fr" });
122
+ en = $dictionary({ lazy: () => import("./i18n/en.ts"), lang: "en" });
123
+ page = $page({ lazy: () => import("./Home.tsx") });
124
+ }
125
+ `,
126
+ );
127
+ await env.fs.writeFile(
128
+ `${ROOT}/src/web/i18n/fr.ts`,
129
+ `export default { "home.title": "Accueil", "home.unused": "Rien" };`,
130
+ );
131
+ await env.fs.writeFile(
132
+ `${ROOT}/src/web/i18n/en.ts`,
133
+ `export default { "home.title": "Home", "home.unused": "Nothing" };`,
134
+ );
135
+ // The only reference — `home.unused` is dead in both languages. The
136
+ // `"home.title": "…"` lines in the sibling language file must not count
137
+ // as references (key files are excluded from the usage corpus).
138
+ await env.fs.writeFile(
139
+ `${ROOT}/src/web/Home.tsx`,
140
+ `export const Home = () => tr("home.title");`,
141
+ );
142
+
143
+ const result = await env.service.check({
144
+ root: ROOT,
145
+ scan: ["src"],
146
+ dynamicPrefixes: [],
147
+ exclude: [],
148
+ });
149
+
150
+ expect(result.totalKeys).toBe(2);
151
+ expect(result.unused).toEqual(["home.unused"]);
152
+ // The resolved language file is treated as a dictionary; the sibling
153
+ // `$page` lazy import is not (it contributed no keys and stays in the
154
+ // usage corpus). `en.ts` is also a dictionary file but adds no *new*
155
+ // keys, so only the first contributor is listed.
156
+ expect(result.dictionaryFiles).toContain(`${ROOT}/src/web/i18n/fr.ts`);
157
+ expect(result.dictionaryFiles).not.toContain(`${ROOT}/src/web/Home.tsx`);
158
+ });
159
+
112
160
  it("returns totalKeys=0 when no dictionary is found", async () => {
113
161
  await env.fs.mkdir(`${ROOT}/src`, { recursive: true });
114
162
  await env.fs.writeFile(
@@ -35,6 +35,22 @@ const KEY_DECLARATION_RE = /"([\w-]+(?:\.[\w-]+)+)"\s*:/g;
35
35
  */
36
36
  const DICTIONARY_MARKER = "$dictionary";
37
37
 
38
+ /**
39
+ * Captures the module specifier of a lazily-imported dictionary, i.e. the
40
+ * `"./fr.ts"` in `$dictionary({ lazy: () => import("./fr.ts") })`. Apps
41
+ * commonly split each language into its own file so a session only ships the
42
+ * active locale — those key files carry no `$dictionary` marker, so without
43
+ * this the keys would be invisible to the check.
44
+ *
45
+ * `[^{}]*?` keeps the match inside the `$dictionary` call's own object literal
46
+ * (it stops at the first brace), so unrelated lazy imports in the same file —
47
+ * e.g. a sibling `$page({ lazy: () => import("./Page.tsx") })` or a
48
+ * `$dictionary` whose `lazy` returns an inline `({ default: {…} })` object —
49
+ * are never mistaken for dictionary key files.
50
+ */
51
+ const DICTIONARY_LAZY_IMPORT_RE =
52
+ /\$dictionary\s*\(\s*\{[^{}]*?import\s*\(\s*["']([^"']+)["']/g;
53
+
38
54
  export interface I18nCheckOptions {
39
55
  root: string;
40
56
  scan: string[];
@@ -62,11 +78,11 @@ export class I18nCheckService {
62
78
  * Find unused translation keys.
63
79
  *
64
80
  * Discovery is fully static: we walk `scan` dirs, identify files
65
- * that import `$dictionary` (matched via the literal substring),
66
- * extract every `"a.b.c": ...` property key declared in them, then
67
- * grep the remaining source files for a quoted-literal occurrence
68
- * of each key. Anything matching a `dynamicPrefixes` entry is
69
- * exempted.
81
+ * that import `$dictionary` (matched via the literal substring) plus
82
+ * any per-language files they lazily `import(...)`, extract every
83
+ * `"a.b.c": ...` property key declared across them, then grep the
84
+ * remaining source files for a quoted-literal occurrence of each key.
85
+ * Anything matching a `dynamicPrefixes` entry is exempted.
70
86
  */
71
87
  async check(options: I18nCheckOptions): Promise<I18nCheckResult> {
72
88
  const { root, scan, dynamicPrefixes, exclude } = options;
@@ -91,14 +107,31 @@ export class I18nCheckService {
91
107
  }
92
108
  }
93
109
 
94
- const dictionaryFiles: string[] = [];
95
- const allKeys = new Set<string>();
96
110
  const fileContents = new Map<string, string>();
97
-
98
111
  for (const file of allFiles) {
99
- const text = (await this.fs.readFile(file)).toString("utf8");
100
- fileContents.set(file, text);
112
+ fileContents.set(file, (await this.fs.readFile(file)).toString("utf8"));
113
+ }
114
+
115
+ // A file is a dictionary if it declares `$dictionary` OR it is the target
116
+ // of a `$dictionary({ lazy: () => import("…") })` (the split per-language
117
+ // key files, which carry no marker of their own). Resolving the lazy
118
+ // targets first lets their keys be extracted below and keeps them out of
119
+ // the usage corpus (their `"key": "value"` lines aren't references).
120
+ const dictionarySet = new Set<string>();
121
+ for (const [file, text] of fileContents) {
101
122
  if (!text.includes(DICTIONARY_MARKER)) continue;
123
+ dictionarySet.add(file);
124
+ for (const m of text.matchAll(DICTIONARY_LAZY_IMPORT_RE)) {
125
+ const target = this.resolveImport(file, m[1], fileContents);
126
+ if (target) dictionarySet.add(target);
127
+ }
128
+ }
129
+
130
+ const dictionaryFiles: string[] = [];
131
+ const allKeys = new Set<string>();
132
+ for (const file of dictionarySet) {
133
+ const text = fileContents.get(file);
134
+ if (!text) continue;
102
135
  const before = allKeys.size;
103
136
  for (const m of text.matchAll(KEY_DECLARATION_RE)) {
104
137
  allKeys.add(m[1]);
@@ -108,7 +141,6 @@ export class I18nCheckService {
108
141
 
109
142
  // Concatenate every non-dictionary file into one corpus so each
110
143
  // key is tested with a single regex run rather than O(files × keys).
111
- const dictionarySet = new Set(dictionaryFiles);
112
144
  const corpusParts: string[] = [];
113
145
  let scannedFiles = 0;
114
146
  for (const [file, text] of fileContents) {
@@ -141,4 +173,26 @@ export class I18nCheckService {
141
173
  unused: unused.sort(),
142
174
  };
143
175
  }
176
+
177
+ /**
178
+ * Resolve a relative `import("…")` specifier from `fromFile` to an absolute
179
+ * path that was actually scanned. Returns `undefined` for bare/package
180
+ * specifiers or targets outside the scan set. Extensionless specifiers are
181
+ * probed against each supported source extension.
182
+ */
183
+ protected resolveImport(
184
+ fromFile: string,
185
+ spec: string,
186
+ files: Map<string, string>,
187
+ ): string | undefined {
188
+ if (!spec.startsWith(".")) return undefined;
189
+ // `join(file, "..", spec)` drops the filename then applies the relative
190
+ // specifier — i.e. resolves against `fromFile`'s directory.
191
+ const base = this.fs.join(fromFile, "..", spec);
192
+ if (files.has(base)) return base;
193
+ for (const ext of SCAN_EXTS) {
194
+ if (files.has(base + ext)) return base + ext;
195
+ }
196
+ return undefined;
197
+ }
144
198
  }
@@ -1,11 +1,13 @@
1
1
  import { Alepha } from "alepha";
2
+ import {
3
+ MemorySecretStore,
4
+ platformOptions,
5
+ type SecretStoreProvider,
6
+ } from "alepha/cli/platform-lib";
2
7
  import { CliProvider } from "alepha/command";
3
8
  import { FileSystemProvider, MemoryFileSystemProvider } from "alepha/system";
4
9
  import { describe, test } from "vitest";
5
- import { platformOptions } from "../atoms/platformOptions.ts";
6
10
  import { SecretsCommand } from "../commands/SecretsCommand.ts";
7
- import { MemorySecretStore } from "../providers/MemorySecretStore.ts";
8
- import type { SecretStoreProvider } from "../providers/SecretStoreProvider.ts";
9
11
 
10
12
  class TestSecretsCommand extends SecretsCommand {
11
13
  public readonly testList = this.list;
@@ -1,12 +1,14 @@
1
1
  import { $inject, $state, AlephaError, t } from "alepha";
2
+ import {
3
+ GitHubSecretStore,
4
+ NamingService,
5
+ PlatformInspector,
6
+ platformOptions,
7
+ SecretFilterService,
8
+ type SecretStoreProvider,
9
+ } from "alepha/cli/platform-lib";
2
10
  import { $command, EnvUtils } from "alepha/command";
3
11
  import { $logger, ConsoleColorProvider } from "alepha/logger";
4
- import { platformOptions } from "../atoms/platformOptions.ts";
5
- import { GitHubSecretStore } from "../providers/GitHubSecretStore.ts";
6
- import type { SecretStoreProvider } from "../providers/SecretStoreProvider.ts";
7
- import { NamingService } from "../services/NamingService.ts";
8
- import { PlatformInspector } from "../services/PlatformInspector.ts";
9
- import { SecretFilterService } from "../services/SecretFilterService.ts";
10
12
 
11
13
  export class SecretsCommand {
12
14
  protected readonly log = $logger();