alepha 0.21.2 → 0.22.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 (463) 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 +289 -292
  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 +211 -216
  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 +1073 -1006
  49. package/dist/api/users/index.d.ts.map +1 -1
  50. package/dist/api/users/index.js +283 -61
  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 +134 -140
  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 +417 -214
  88. package/dist/cli/core/index.d.ts.map +1 -1
  89. package/dist/cli/core/index.js +325 -563
  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 +8 -12
  95. package/dist/cli/i18n/index.d.ts.map +1 -1
  96. package/dist/cli/i18n/index.js.map +1 -1
  97. package/dist/cli/platform/index.d.ts +126 -1342
  98. package/dist/cli/platform/index.d.ts.map +1 -1
  99. package/dist/cli/platform/index.js +136 -2374
  100. package/dist/cli/platform/index.js.map +1 -1
  101. package/dist/cli/platform-lib/index.d.ts +1446 -0
  102. package/dist/cli/platform-lib/index.d.ts.map +1 -0
  103. package/dist/cli/platform-lib/index.js +2597 -0
  104. package/dist/cli/platform-lib/index.js.map +1 -0
  105. package/dist/cli/vendor/index.d.ts +17 -21
  106. package/dist/cli/vendor/index.d.ts.map +1 -1
  107. package/dist/cli/vendor/index.js.map +1 -1
  108. package/dist/command/index.d.ts +21 -20
  109. package/dist/command/index.d.ts.map +1 -1
  110. package/dist/command/index.js +39 -10
  111. package/dist/command/index.js.map +1 -1
  112. package/dist/{containers → container}/core/index.d.ts +13 -15
  113. package/dist/container/core/index.d.ts.map +1 -0
  114. package/dist/{containers → container}/core/index.js +23 -14
  115. package/dist/container/core/index.js.map +1 -0
  116. package/dist/{containers → container}/core/index.workerd.js +37 -22
  117. package/dist/container/core/index.workerd.js.map +1 -0
  118. package/dist/core/index.browser.js +27 -1
  119. package/dist/core/index.browser.js.map +1 -1
  120. package/dist/core/index.d.ts +48 -24
  121. package/dist/core/index.d.ts.map +1 -1
  122. package/dist/core/index.js +27 -1
  123. package/dist/core/index.js.map +1 -1
  124. package/dist/core/index.native.js +27 -1
  125. package/dist/core/index.native.js.map +1 -1
  126. package/dist/core/index.workerd.js +27 -1
  127. package/dist/core/index.workerd.js.map +1 -1
  128. package/dist/crypto/index.browser.js.map +1 -1
  129. package/dist/crypto/index.d.ts +5 -8
  130. package/dist/crypto/index.d.ts.map +1 -1
  131. package/dist/crypto/index.js.map +1 -1
  132. package/dist/datetime/index.d.ts +3 -4
  133. package/dist/datetime/index.d.ts.map +1 -1
  134. package/dist/datetime/index.js.map +1 -1
  135. package/dist/email/brevo/index.d.ts +2 -4
  136. package/dist/email/brevo/index.d.ts.map +1 -1
  137. package/dist/email/brevo/index.js.map +1 -1
  138. package/dist/email/cloudflare/index.d.ts +20 -7
  139. package/dist/email/cloudflare/index.d.ts.map +1 -1
  140. package/dist/email/cloudflare/index.js +46 -9
  141. package/dist/email/cloudflare/index.js.map +1 -1
  142. package/dist/email/core/index.d.ts +6 -9
  143. package/dist/email/core/index.d.ts.map +1 -1
  144. package/dist/email/core/index.js.map +1 -1
  145. package/dist/email/core/index.workerd.js.map +1 -1
  146. package/dist/email/smtp/index.d.ts +10 -13
  147. package/dist/email/smtp/index.d.ts.map +1 -1
  148. package/dist/email/smtp/index.js +107 -32
  149. package/dist/email/smtp/index.js.map +1 -1
  150. package/dist/fake/index.d.ts +1 -2
  151. package/dist/fake/index.d.ts.map +1 -1
  152. package/dist/fake/index.js.map +1 -1
  153. package/dist/lock/core/index.d.ts +9 -14
  154. package/dist/lock/core/index.d.ts.map +1 -1
  155. package/dist/lock/core/index.js.map +1 -1
  156. package/dist/lock/redis/index.d.ts +2 -4
  157. package/dist/lock/redis/index.d.ts.map +1 -1
  158. package/dist/lock/redis/index.js.map +1 -1
  159. package/dist/logger/index.d.ts +105 -76
  160. package/dist/logger/index.d.ts.map +1 -1
  161. package/dist/logger/index.js +196 -174
  162. package/dist/logger/index.js.map +1 -1
  163. package/dist/mcp/index.d.ts +16 -20
  164. package/dist/mcp/index.d.ts.map +1 -1
  165. package/dist/mcp/index.js.map +1 -1
  166. package/dist/orm/core/index.browser.js.map +1 -1
  167. package/dist/orm/core/index.bun.js +19 -1
  168. package/dist/orm/core/index.bun.js.map +1 -1
  169. package/dist/orm/core/index.d.ts +76 -62
  170. package/dist/orm/core/index.d.ts.map +1 -1
  171. package/dist/orm/core/index.js +20 -2
  172. package/dist/orm/core/index.js.map +1 -1
  173. package/dist/orm/postgres/index.bun.js.map +1 -1
  174. package/dist/orm/postgres/index.d.ts +28 -20
  175. package/dist/orm/postgres/index.d.ts.map +1 -1
  176. package/dist/orm/postgres/index.js.map +1 -1
  177. package/dist/queue/core/index.d.ts +12 -15
  178. package/dist/queue/core/index.d.ts.map +1 -1
  179. package/dist/queue/core/index.js.map +1 -1
  180. package/dist/queue/core/index.workerd.js.map +1 -1
  181. package/dist/queue/redis/index.d.ts +3 -5
  182. package/dist/queue/redis/index.d.ts.map +1 -1
  183. package/dist/queue/redis/index.js.map +1 -1
  184. package/dist/react/auth/index.browser.js +9 -2
  185. package/dist/react/auth/index.browser.js.map +1 -1
  186. package/dist/react/auth/index.d.ts +14 -9
  187. package/dist/react/auth/index.d.ts.map +1 -1
  188. package/dist/react/auth/index.js +9 -2
  189. package/dist/react/auth/index.js.map +1 -1
  190. package/dist/react/core/index.d.ts +7 -8
  191. package/dist/react/core/index.d.ts.map +1 -1
  192. package/dist/react/core/index.js +6 -3
  193. package/dist/react/core/index.js.map +1 -1
  194. package/dist/react/form/index.d.ts +2 -4
  195. package/dist/react/form/index.d.ts.map +1 -1
  196. package/dist/react/form/index.js.map +1 -1
  197. package/dist/react/head/index.browser.js.map +1 -1
  198. package/dist/react/head/index.d.ts +2 -4
  199. package/dist/react/head/index.d.ts.map +1 -1
  200. package/dist/react/head/index.js.map +1 -1
  201. package/dist/react/i18n/index.d.ts +47 -11
  202. package/dist/react/i18n/index.d.ts.map +1 -1
  203. package/dist/react/i18n/index.js +33 -1
  204. package/dist/react/i18n/index.js.map +1 -1
  205. package/dist/react/intro/index.d.ts +1 -2
  206. package/dist/react/intro/index.d.ts.map +1 -1
  207. package/dist/react/intro/index.js +2 -2
  208. package/dist/react/intro/index.js.map +1 -1
  209. package/dist/react/router/index.browser.js +65 -19
  210. package/dist/react/router/index.browser.js.map +1 -1
  211. package/dist/react/router/index.d.ts +327 -222
  212. package/dist/react/router/index.d.ts.map +1 -1
  213. package/dist/react/router/index.js +65 -29
  214. package/dist/react/router/index.js.map +1 -1
  215. package/dist/react/testing/index.d.ts +1 -2
  216. package/dist/react/testing/index.d.ts.map +1 -1
  217. package/dist/react/testing/index.js +16 -17
  218. package/dist/react/testing/index.js.map +1 -1
  219. package/dist/react/ui/index.d.ts +20 -25
  220. package/dist/react/ui/index.d.ts.map +1 -1
  221. package/dist/react/ui/index.js.map +1 -1
  222. package/dist/redis/index.bun.js.map +1 -1
  223. package/dist/redis/index.d.ts +17 -19
  224. package/dist/redis/index.d.ts.map +1 -1
  225. package/dist/redis/index.js.map +1 -1
  226. package/dist/retry/index.d.ts +2 -4
  227. package/dist/retry/index.d.ts.map +1 -1
  228. package/dist/retry/index.js.map +1 -1
  229. package/dist/router/index.d.ts.map +1 -1
  230. package/dist/router/index.js.map +1 -1
  231. package/dist/scheduler/index.d.ts +10 -13
  232. package/dist/scheduler/index.d.ts.map +1 -1
  233. package/dist/scheduler/index.js.map +1 -1
  234. package/dist/scheduler/index.workerd.js.map +1 -1
  235. package/dist/security/index.browser.js.map +1 -1
  236. package/dist/security/index.d.ts +45 -48
  237. package/dist/security/index.d.ts.map +1 -1
  238. package/dist/security/index.js.map +1 -1
  239. package/dist/server/auth/index.browser.js.map +1 -1
  240. package/dist/server/auth/index.d.ts +167 -172
  241. package/dist/server/auth/index.d.ts.map +1 -1
  242. package/dist/server/auth/index.js +4 -8
  243. package/dist/server/auth/index.js.map +1 -1
  244. package/dist/server/cookies/index.browser.js.map +1 -1
  245. package/dist/server/cookies/index.d.ts +5 -7
  246. package/dist/server/cookies/index.d.ts.map +1 -1
  247. package/dist/server/cookies/index.js.map +1 -1
  248. package/dist/server/core/index.browser.js.map +1 -1
  249. package/dist/server/core/index.d.ts +88 -73
  250. package/dist/server/core/index.d.ts.map +1 -1
  251. package/dist/server/core/index.js +19 -0
  252. package/dist/server/core/index.js.map +1 -1
  253. package/dist/server/cors/index.d.ts +11 -14
  254. package/dist/server/cors/index.d.ts.map +1 -1
  255. package/dist/server/cors/index.js.map +1 -1
  256. package/dist/server/etag/index.d.ts +6 -9
  257. package/dist/server/etag/index.d.ts.map +1 -1
  258. package/dist/server/etag/index.js.map +1 -1
  259. package/dist/server/health/index.d.ts +18 -21
  260. package/dist/server/health/index.d.ts.map +1 -1
  261. package/dist/server/health/index.js.map +1 -1
  262. package/dist/server/links/index.browser.js +2 -0
  263. package/dist/server/links/index.browser.js.map +1 -1
  264. package/dist/server/links/index.d.ts +63 -67
  265. package/dist/server/links/index.d.ts.map +1 -1
  266. package/dist/server/links/index.js +2 -0
  267. package/dist/server/links/index.js.map +1 -1
  268. package/dist/server/metrics/index.d.ts +5 -7
  269. package/dist/server/metrics/index.d.ts.map +1 -1
  270. package/dist/server/metrics/index.js.map +1 -1
  271. package/dist/server/proxy/index.d.ts +3 -5
  272. package/dist/server/proxy/index.d.ts.map +1 -1
  273. package/dist/server/proxy/index.js.map +1 -1
  274. package/dist/server/rate-limit/index.d.ts +10 -13
  275. package/dist/server/rate-limit/index.d.ts.map +1 -1
  276. package/dist/server/rate-limit/index.js.map +1 -1
  277. package/dist/server/static/index.d.ts +3 -5
  278. package/dist/server/static/index.d.ts.map +1 -1
  279. package/dist/server/static/index.js.map +1 -1
  280. package/dist/server/swagger/index.d.ts +5 -8
  281. package/dist/server/swagger/index.d.ts.map +1 -1
  282. package/dist/server/swagger/index.js.map +1 -1
  283. package/dist/sms/index.d.ts +3 -5
  284. package/dist/sms/index.d.ts.map +1 -1
  285. package/dist/sms/index.js.map +1 -1
  286. package/dist/system/index.browser.js.map +1 -1
  287. package/dist/system/index.d.ts +2 -4
  288. package/dist/system/index.d.ts.map +1 -1
  289. package/dist/system/index.js.map +1 -1
  290. package/dist/system/index.workerd.js.map +1 -1
  291. package/dist/topic/core/index.d.ts +4 -6
  292. package/dist/topic/core/index.d.ts.map +1 -1
  293. package/dist/topic/core/index.js.map +1 -1
  294. package/dist/topic/redis/index.d.ts +5 -8
  295. package/dist/topic/redis/index.d.ts.map +1 -1
  296. package/dist/topic/redis/index.js.map +1 -1
  297. package/package.json +45 -22
  298. package/src/api/audits/__tests__/AuditService.spec.ts +18 -110
  299. package/src/api/audits/controllers/AdminAuditController.ts +14 -0
  300. package/src/api/audits/services/AuditService.ts +21 -88
  301. package/src/api/files/__tests__/FileService.spec.ts +207 -2
  302. package/src/api/files/index.ts +3 -0
  303. package/src/api/files/schemas/fileCreatorSummarySchema.ts +22 -0
  304. package/src/api/files/schemas/fileResourceSchema.ts +10 -1
  305. package/src/api/files/services/FileService.ts +170 -72
  306. package/src/api/jobs/__tests__/$job.spec.ts +24 -1
  307. package/src/api/jobs/index.ts +4 -3
  308. package/src/api/jobs/primitives/$job.ts +7 -3
  309. package/src/api/jobs/providers/DirectJobDispatcher.ts +17 -36
  310. package/src/api/jobs/providers/JobProvider.ts +53 -24
  311. package/src/api/jobs/schemas/jobConfigAtom.ts +1 -1
  312. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +4 -1
  313. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +3 -1
  314. package/src/api/parameters/__tests__/$parameter.spec.ts +19 -2
  315. package/src/api/parameters/audits/ParameterAudits.ts +17 -0
  316. package/src/api/parameters/controllers/AdminParameterController.ts +95 -19
  317. package/src/api/parameters/index.ts +3 -0
  318. package/src/api/parameters/schemas/activateParameterBodySchema.ts +3 -3
  319. package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +3 -2
  320. package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +25 -0
  321. package/src/api/parameters/schemas/parameterResponseSchema.ts +5 -0
  322. package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +4 -2
  323. package/src/api/parameters/services/ParameterProvider.ts +69 -6
  324. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +1 -1
  325. package/src/api/users/__tests__/AdminSessionController.spec.ts +37 -0
  326. package/src/api/users/audits/SessionAudits.ts +33 -0
  327. package/src/api/users/audits/UserAudits.ts +19 -43
  328. package/src/api/users/controllers/AdminUserController.ts +66 -1
  329. package/src/api/users/entities/sessions.ts +6 -0
  330. package/src/api/users/entities/users.ts +2 -0
  331. package/src/api/users/index.ts +9 -1
  332. package/src/api/users/primitives/$realm.ts +3 -0
  333. package/src/api/users/schemas/sessionResourceSchema.ts +16 -0
  334. package/src/api/users/schemas/updateUserSchema.ts +1 -8
  335. package/src/api/users/schemas/userQuerySchema.ts +7 -0
  336. package/src/api/users/services/CredentialService.ts +15 -6
  337. package/src/api/users/services/IdentityService.ts +2 -1
  338. package/src/api/users/services/RegistrationService.ts +2 -1
  339. package/src/api/users/services/SessionCrudService.ts +19 -2
  340. package/src/api/users/services/SessionService.ts +39 -19
  341. package/src/api/users/services/UserService.ts +106 -8
  342. package/src/background/__tests__/BackgroundTaskProvider.spec.ts +96 -0
  343. package/src/background/index.ts +37 -0
  344. package/src/background/index.workerd.ts +28 -0
  345. package/src/background/providers/BackgroundTaskProvider.ts +70 -0
  346. package/src/background/providers/WorkerdBackgroundTaskProvider.ts +43 -0
  347. package/src/bucket/__tests__/$bucket.spec.ts +18 -0
  348. package/src/bucket/__tests__/LocalFileStorageProvider.spec.ts +5 -0
  349. package/src/bucket/__tests__/MemoryFileStorageProvider.spec.ts +5 -0
  350. package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +23 -4
  351. package/src/bucket/__tests__/shared.ts +30 -0
  352. package/src/bucket/index.ts +5 -5
  353. package/src/bucket/index.workerd.ts +11 -4
  354. package/src/bucket/primitives/$bucket.ts +27 -0
  355. package/src/bucket/providers/FileStorageProvider.ts +13 -0
  356. package/src/bucket/providers/LocalFileStorageProvider.ts +17 -1
  357. package/src/bucket/providers/MemoryFileStorageProvider.ts +7 -0
  358. package/src/bucket/providers/{CloudflareR2Provider.ts → R2FileStorageProvider.ts} +10 -1
  359. package/src/bucket/providers/{NodeS3BucketProvider.ts → S3FileStorageProvider.ts} +27 -5
  360. package/src/cli/core/__tests__/BuildDockerTask.spec.ts +25 -1
  361. package/src/cli/core/__tests__/init.spec.ts +0 -219
  362. package/src/cli/core/commands/__tests__/BuildCommand.spec.ts +43 -0
  363. package/src/cli/core/commands/build.ts +108 -30
  364. package/src/cli/core/commands/init.ts +0 -12
  365. package/src/cli/core/commands/pack.ts +133 -0
  366. package/src/cli/core/index.ts +3 -0
  367. package/src/cli/core/providers/ViteDevServerProvider.ts +40 -16
  368. package/src/cli/core/services/PackageManagerUtils.ts +0 -16
  369. package/src/cli/core/services/ProjectScaffolder.ts +29 -291
  370. package/src/cli/core/tasks/BuildCloudflareTask.ts +353 -47
  371. package/src/cli/core/tasks/BuildDockerTask.ts +33 -3
  372. package/src/cli/core/tasks/BuildTask.ts +34 -0
  373. package/src/cli/core/templates/apiIndexTs.ts +1 -22
  374. package/src/cli/core/templates/mainCss.ts +0 -1
  375. package/src/cli/core/templates/webAppRouterTs.ts +0 -99
  376. package/src/cli/core/templates/webIndexTs.ts +1 -22
  377. package/src/cli/platform/__tests__/SecretsCommand.spec.ts +5 -3
  378. package/src/cli/platform/commands/SecretsCommand.ts +8 -6
  379. package/src/cli/platform/commands/platform.ts +192 -46
  380. package/src/cli/platform/index.ts +12 -52
  381. package/src/cli/{platform → platform-lib}/__tests__/CloudflareAdapter.spec.ts +426 -169
  382. package/src/cli/{platform → platform-lib}/__tests__/NamingService.spec.ts +91 -4
  383. package/src/cli/{platform → platform-lib}/__tests__/VercelAdapter.spec.ts +56 -85
  384. package/src/cli/{platform → platform-lib}/adapters/CloudflareAdapter.ts +402 -165
  385. package/src/cli/{platform → platform-lib}/adapters/PlatformAdapter.ts +62 -35
  386. package/src/cli/{platform → platform-lib}/adapters/VercelAdapter.ts +6 -10
  387. package/src/cli/{platform → platform-lib}/atoms/platformOptions.ts +34 -1
  388. package/src/cli/platform-lib/index.ts +67 -0
  389. package/src/cli/platform-lib/services/NamingService.ts +136 -0
  390. package/src/cli/{platform → platform-lib}/services/PlatformInspector.ts +60 -13
  391. package/src/cli/{platform → platform-lib}/services/PlatformOrchestrator.ts +54 -43
  392. package/src/cli/{platform → platform-lib}/services/WranglerApi.ts +4 -2
  393. package/src/command/__tests__/Runner.spec.ts +20 -0
  394. package/src/command/helpers/EnvUtils.ts +19 -3
  395. package/src/command/helpers/Runner.ts +12 -2
  396. package/src/command/providers/CliProvider.ts +34 -1
  397. package/src/{containers → container}/core/__tests__/$container.spec.ts +5 -5
  398. package/src/{containers → container}/core/index.ts +4 -4
  399. package/src/{containers → container}/core/index.workerd.ts +19 -3
  400. package/src/{containers → container}/core/primitives/$container.ts +1 -1
  401. package/src/{containers → container}/core/providers/CloudflareContainerProvider.ts +17 -19
  402. package/src/{containers → container}/core/providers/ContainerProvider.ts +16 -2
  403. package/src/{containers → container}/core/providers/MockContainerProvider.ts +1 -1
  404. package/src/core/Alepha.ts +49 -1
  405. package/src/core/__tests__/$env.spec.ts +42 -0
  406. package/src/core/__tests__/dump.spec.ts +47 -0
  407. package/src/email/cloudflare/__tests__/CloudflareEmailProvider.spec.ts +42 -10
  408. package/src/email/cloudflare/index.ts +14 -5
  409. package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +54 -9
  410. package/src/logger/__tests__/Logger.spec.ts +55 -0
  411. package/src/logger/index.ts +13 -0
  412. package/src/logger/services/Logger.ts +31 -1
  413. package/src/orm/__tests__/orm-showcase-tests.ts +27 -0
  414. package/src/orm/__tests__/orm-showcase.spec.ts +12 -0
  415. package/src/orm/core/interfaces/PgQuery.ts +4 -1
  416. package/src/orm/core/services/Repository.ts +27 -11
  417. package/src/react/auth/hooks/useAuth.ts +10 -5
  418. package/src/react/core/__tests__/useQuery.browser.spec.tsx +25 -0
  419. package/src/react/core/hooks/useAction.ts +14 -3
  420. package/src/react/core/hooks/useQuery.ts +24 -4
  421. package/src/react/i18n/components/Translate.tsx +47 -0
  422. package/src/react/i18n/index.ts +2 -0
  423. package/src/react/intro/components/GettingStartedAdminSlide.tsx +2 -2
  424. package/src/react/router/__tests__/$page.spec.tsx +3 -2
  425. package/src/react/router/__tests__/page-can.spec.ts +18 -13
  426. package/src/react/router/hooks/useQueryParams.ts +114 -14
  427. package/src/react/router/primitives/$page.ts +85 -4
  428. package/src/react/router/providers/ReactBrowserRouterProvider.ts +3 -7
  429. package/src/react/router/providers/ReactServerProvider.ts +4 -13
  430. package/src/react/ui/services/SchemaControl.ts +3 -4
  431. package/src/server/core/providers/ServerMultipartProvider.ts +19 -0
  432. package/src/server/links/providers/LinkProvider.ts +10 -0
  433. package/dist/containers/core/index.d.ts.map +0 -1
  434. package/dist/containers/core/index.js.map +0 -1
  435. package/dist/containers/core/index.workerd.js.map +0 -1
  436. package/src/cli/core/templates/componentsJsonTs.ts +0 -39
  437. package/src/cli/core/templates/saasAdminLayoutTsx.ts +0 -77
  438. package/src/cli/core/templates/saasAdminPagesTsx.ts +0 -26
  439. package/src/cli/core/templates/saasAuthLayoutTsx.ts +0 -22
  440. package/src/cli/core/templates/saasAuthPagesTsx.ts +0 -62
  441. package/src/cli/core/templates/saasRealmProviderTs.ts +0 -52
  442. package/src/cli/platform/services/NamingService.ts +0 -54
  443. /package/dist/orm/core/{chunk-o8xxKEmq.js → chunk-B4FMCO8f.js} +0 -0
  444. /package/dist/react/testing/{chunk-6Ep1yQYe.js → chunk-BpyX8vjI.js} +0 -0
  445. /package/src/cli/{platform → platform-lib}/__tests__/GitHubSecretStore.spec.ts +0 -0
  446. /package/src/cli/{platform → platform-lib}/__tests__/PlatformCacheProvider.spec.ts +0 -0
  447. /package/src/cli/{platform → platform-lib}/__tests__/PlatformInspector.spec.ts +0 -0
  448. /package/src/cli/{platform → platform-lib}/__tests__/PlatformOrchestrator.spec.ts +0 -0
  449. /package/src/cli/{platform → platform-lib}/__tests__/SecretFilterService.spec.ts +0 -0
  450. /package/src/cli/{platform → platform-lib}/__tests__/detectResources.spec.ts +0 -0
  451. /package/src/cli/{platform → platform-lib}/providers/GitHubSecretStore.ts +0 -0
  452. /package/src/cli/{platform → platform-lib}/providers/MemorySecretStore.ts +0 -0
  453. /package/src/cli/{platform → platform-lib}/providers/PlatformCacheProvider.ts +0 -0
  454. /package/src/cli/{platform → platform-lib}/providers/SecretStoreProvider.ts +0 -0
  455. /package/src/cli/{platform → platform-lib}/schemas/cloudflare.ts +0 -0
  456. /package/src/cli/{platform → platform-lib}/schemas/platform.ts +0 -0
  457. /package/src/cli/{platform → platform-lib}/schemas/vercel.ts +0 -0
  458. /package/src/cli/{platform → platform-lib}/services/CloudflareApi.ts +0 -0
  459. /package/src/cli/{platform → platform-lib}/services/SecretFilterService.ts +0 -0
  460. /package/src/cli/{platform → platform-lib}/services/VercelApi.ts +0 -0
  461. /package/src/cli/{platform → platform-lib}/services/VercelCli.ts +0 -0
  462. /package/src/{containers → container}/core/interfaces/ContainerOptions.ts +0 -0
  463. /package/src/{containers → container}/core/providers/NodeContainerProvider.ts +0 -0
@@ -10,9 +10,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:pat
10
10
  import pkg from "alepha/package.json" with { type: "json" };
11
11
  import { analyzer } from "vite-bundle-analyzer";
12
12
  import { KV_DEFAULT_BINDING } from "alepha/cache";
13
- import { $container } from "alepha/containers";
14
- import { EmailProvider } from "alepha/email";
15
- import { CloudflareEmailProvider, SEND_EMAIL_DEFAULT_BINDING } from "alepha/email/cloudflare";
13
+ import { SEND_EMAIL_DEFAULT_BINDING } from "alepha/email/cloudflare";
16
14
  import { QUEUE_DEFAULT_BINDING } from "alepha/queue";
17
15
  import { promisify } from "node:util";
18
16
  import { brotliCompress, gzip } from "node:zlib";
@@ -1109,7 +1107,6 @@ var PackageManagerUtils = class {
1109
1107
  devDependencies.tailwindcss = alephaDeps.tailwindcss;
1110
1108
  devDependencies["@tailwindcss/vite"] = alephaDeps["@tailwindcss/vite"];
1111
1109
  }
1112
- if (modes.shadcn) devDependencies.shadcn = alephaDeps.shadcn;
1113
1110
  if (modes.react) {
1114
1111
  dependencies.react = alephaDeps.react;
1115
1112
  dependencies["react-dom"] = alephaDeps["react-dom"];
@@ -1279,19 +1276,7 @@ export type HelloResponse = Static<typeof helloResponseSchema>;
1279
1276
  //#endregion
1280
1277
  //#region ../../src/cli/core/templates/apiIndexTs.ts
1281
1278
  const apiIndexTs = (options = {}) => {
1282
- const { appName = "app", saas = false } = options;
1283
- if (saas) return `
1284
- import { $module } from "alepha";
1285
- import { AlephaApiUsers } from "alepha/api/users";
1286
- import { HelloController } from "./controllers/HelloController.ts";
1287
- import { RealmProvider } from "./providers/RealmProvider.ts";
1288
-
1289
- export const ApiModule = $module({
1290
- name: "${appName}.api",
1291
- services: [HelloController, RealmProvider],
1292
- imports: [AlephaApiUsers],
1293
- });
1294
- `.trim();
1279
+ const { appName = "app" } = options;
1295
1280
  return `
1296
1281
  import { $module } from "alepha";
1297
1282
  import { HelloController } from "./controllers/HelloController.ts";
@@ -1362,46 +1347,6 @@ const biomeJson = () => `
1362
1347
  }
1363
1348
  `.trim();
1364
1349
  //#endregion
1365
- //#region ../../src/cli/core/templates/componentsJsonTs.ts
1366
- /**
1367
- * `components.json` is the shadcn CLI's project config — it tells
1368
- * `shadcn add` where to drop primitives, which tailwind tokens to use,
1369
- * which icon library to wire up, and which custom registries to resolve.
1370
- *
1371
- * Aliases follow shadcn's defaults (`@/components`, `@/lib/utils`) so the
1372
- * CLI honors them across `init` + `add` calls. Alepha app code lives at
1373
- * `src/web/` (Home, AppRouter, …) and the shadcn primitives live at
1374
- * `src/components/` — kept separate to make the registry components
1375
- * trivially upgradable via `shadcn add --overwrite`.
1376
- *
1377
- * The `registries` block pre-wires the public Alepha registry — consumers
1378
- * can immediately run e.g. `shadcn add @alepha/auth-login`.
1379
- */
1380
- const componentsJsonTs = () => `{
1381
- "$schema": "https://ui.shadcn.com/schema.json",
1382
- "style": "new-york",
1383
- "rsc": false,
1384
- "tsx": true,
1385
- "tailwind": {
1386
- "config": "",
1387
- "css": "src/main.css",
1388
- "baseColor": "neutral",
1389
- "cssVariables": true
1390
- },
1391
- "aliases": {
1392
- "components": "@/components",
1393
- "utils": "@/lib/utils",
1394
- "ui": "@/components/ui",
1395
- "lib": "@/lib",
1396
- "hooks": "@/hooks"
1397
- },
1398
- "iconLibrary": "lucide",
1399
- "registries": {
1400
- "@alepha": "https://alepha.dev/r/{name}.json"
1401
- }
1402
- }
1403
- `;
1404
- //#endregion
1405
1350
  //#region ../../src/cli/core/templates/dummySpecTs.ts
1406
1351
  /**
1407
1352
  * Starter spec written by `alepha init`. It doubles as a worked example:
@@ -1555,7 +1500,6 @@ const mainCss = (opts = {}) => {
1555
1500
  *
1556
1501
  * Options:
1557
1502
  * - Tailwind CSS: Use \`alepha init --tailwind\` to add Tailwind CSS
1558
- * - shadcn/ui: Use \`alepha init --shadcn\` to add shadcn/ui setup
1559
1503
  * - Raw CSS: Write your own styles below
1560
1504
  */
1561
1505
 
@@ -1586,241 +1530,6 @@ run(alepha);
1586
1530
  `.trim();
1587
1531
  };
1588
1532
  //#endregion
1589
- //#region ../../src/cli/core/templates/saasAdminLayoutTsx.ts
1590
- /**
1591
- * SaaS admin layout — full AppShell on /admin with a sidebar, breadcrumbs,
1592
- * a Sonner toaster, and a confirm provider. The page list grows with
1593
- * whatever `admin-*` registry components the user adds.
1594
- *
1595
- * All UI primitives come from `src/components/*` where `shadcn add` drops
1596
- * them; alepha app code lives in `src/web/*` and references them via the
1597
- * `@/components/*` alias.
1598
- */
1599
- const saasAdminLayoutTsx = () => `import { AppShell } from "@/components/app-shell/app-shell";
1600
- import { Toaster } from "@/components/ui/sonner";
1601
- import { TooltipProvider } from "@/components/ui/tooltip";
1602
- import { DialogProvider } from "@/components/use-dialog/use-dialog";
1603
- import { NestedView, useRouterState } from "alepha/react/router";
1604
- import { ShieldCheck, Users } from "lucide-react";
1605
-
1606
- const NAV = [
1607
- {
1608
- label: "Identity",
1609
- items: [
1610
- { href: "/admin/users", label: "Users", icon: Users },
1611
- { href: "/admin/sessions", label: "Sessions", icon: ShieldCheck },
1612
- ],
1613
- },
1614
- ] as const;
1615
-
1616
- const findCrumbs = (pathname: string): { label: string; href?: string }[] => {
1617
- for (const group of NAV) {
1618
- const match = group.items.find((it) => it.href === pathname);
1619
- if (match) return [{ label: group.label }, { label: match.label }];
1620
- }
1621
- return [];
1622
- };
1623
-
1624
- const AdminLayout = () => {
1625
- const state = useRouterState();
1626
- const crumbs = findCrumbs(state.url.pathname);
1627
-
1628
- return (
1629
- <TooltipProvider>
1630
- <DialogProvider>
1631
- <AppShell
1632
- brand={
1633
- <a
1634
- href="/admin"
1635
- className="flex items-center gap-2 px-2 py-2 font-semibold group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0"
1636
- >
1637
- <span className="bg-primary text-primary-foreground flex size-7 shrink-0 items-center justify-center rounded">
1638
- α
1639
- </span>
1640
- <span className="truncate group-data-[collapsible=icon]:hidden">
1641
- Admin
1642
- </span>
1643
- </a>
1644
- }
1645
- nav={NAV.map((group) => ({
1646
- label: group.label,
1647
- items: group.items.map((it) => ({
1648
- href: it.href,
1649
- label: it.label,
1650
- icon: it.icon,
1651
- active: it.href === state.url.pathname,
1652
- })),
1653
- }))}
1654
- breadcrumbs={crumbs.length ? crumbs : undefined}
1655
- >
1656
- <NestedView />
1657
- </AppShell>
1658
- <Toaster />
1659
- </DialogProvider>
1660
- </TooltipProvider>
1661
- );
1662
- };
1663
-
1664
- export default AdminLayout;
1665
- `;
1666
- //#endregion
1667
- //#region ../../src/cli/core/templates/saasAdminPagesTsx.ts
1668
- /**
1669
- * Admin pages — each is a thin wrapper around the matching `admin-*`
1670
- * registry component (placed at `src/components/admin/*`). The starter
1671
- * ships with Users + Sessions; add more by `shadcn add @alepha/admin-…`
1672
- * and a matching `$page(...)` in AppRouter.
1673
- */
1674
- const saasAdminUsersTsx = () => `import { AdminUsers } from "@/components/admin/admin-users";
1675
-
1676
- const AdminUsersPage = () => {
1677
- return <AdminUsers />;
1678
- };
1679
-
1680
- export default AdminUsersPage;
1681
- `;
1682
- const saasAdminSessionsTsx = () => `import { AdminSessions } from "@/components/admin/admin-sessions";
1683
-
1684
- const AdminSessionsPage = () => {
1685
- return <AdminSessions />;
1686
- };
1687
-
1688
- export default AdminSessionsPage;
1689
- `;
1690
- //#endregion
1691
- //#region ../../src/cli/core/templates/saasAuthLayoutTsx.ts
1692
- /**
1693
- * SaaS auth layout — route parent for every /auth/* page (login, register,
1694
- * reset-password, verify-email), mounted as children so they share it.
1695
- *
1696
- * The auth-* blocks from the registry are self-contained full-page layouts
1697
- * (they own their own min-height, centering and padding), so this layout is
1698
- * just a passthrough — wrapping them in another centered, padded, full-height
1699
- * box would overflow the viewport and add a scrollbar.
1700
- */
1701
- const saasAuthLayoutTsx = () => `import { NestedView } from "alepha/react/router";
1702
-
1703
- const AuthLayout = () => {
1704
- return (
1705
- <div className="bg-background">
1706
- <NestedView />
1707
- </div>
1708
- );
1709
- };
1710
-
1711
- export default AuthLayout;
1712
- `;
1713
- //#endregion
1714
- //#region ../../src/cli/core/templates/saasAuthPagesTsx.ts
1715
- /**
1716
- * Per-page wrapper around the registry components. The registry component
1717
- * receives the realm config from the page loader; the page itself stays a
1718
- * thin shell so apps can layer their branding around it.
1719
- *
1720
- * Registry components land at `src/components/auth/*` (shadcn defaults).
1721
- */
1722
- const saasAuthLoginTsx = () => `import { AuthLogin } from "@/components/auth/auth-login";
1723
- import type { RealmConfig } from "alepha/api/users";
1724
-
1725
- export interface AuthLoginPageProps {
1726
- realmConfig: RealmConfig;
1727
- }
1728
-
1729
- const AuthLoginPage = (props: AuthLoginPageProps) => {
1730
- return <AuthLogin realmConfig={props.realmConfig} />;
1731
- };
1732
-
1733
- export default AuthLoginPage;
1734
- `;
1735
- const saasAuthRegisterTsx = () => `import { AuthRegister } from "@/components/auth/auth-register";
1736
- import type { RealmConfig } from "alepha/api/users";
1737
-
1738
- export interface AuthRegisterPageProps {
1739
- realmConfig: RealmConfig;
1740
- }
1741
-
1742
- const AuthRegisterPage = (props: AuthRegisterPageProps) => {
1743
- return <AuthRegister realmConfig={props.realmConfig} />;
1744
- };
1745
-
1746
- export default AuthRegisterPage;
1747
- `;
1748
- const saasAuthResetPasswordTsx = () => `import { AuthResetPassword } from "@/components/auth/auth-reset-password";
1749
- import type { RealmConfig } from "alepha/api/users";
1750
-
1751
- export interface AuthResetPasswordPageProps {
1752
- realmConfig: RealmConfig;
1753
- }
1754
-
1755
- const AuthResetPasswordPage = (props: AuthResetPasswordPageProps) => {
1756
- return <AuthResetPassword realmConfig={props.realmConfig} />;
1757
- };
1758
-
1759
- export default AuthResetPasswordPage;
1760
- `;
1761
- const saasAuthVerifyEmailTsx = () => `import { AuthVerifyEmail } from "@/components/auth/auth-verify-email";
1762
-
1763
- const AuthVerifyEmailPage = () => {
1764
- return <AuthVerifyEmail />;
1765
- };
1766
-
1767
- export default AuthVerifyEmailPage;
1768
- `;
1769
- //#endregion
1770
- //#region ../../src/cli/core/templates/saasRealmProviderTs.ts
1771
- /**
1772
- * Realm provider scaffolded by `alepha init --saas`.
1773
- *
1774
- * Minimal hello-world setup: credentials login with email, admins seeded
1775
- * from the `ADMIN_EMAILS` env var, and an `admin:ui` permission used by the
1776
- * AppRouter to gate `/admin/*`. The default `admin` role grants `*` (so it
1777
- * inherits `admin:ui`); the default `user` role excludes `admin:*` (so
1778
- * non-admins get a 403 before the shell renders).
1779
- *
1780
- * Admin emails are read from the environment, never hard-coded — they are
1781
- * deployment config (different per environment, and personal data) and
1782
- * belong in `.env`, not in committed source.
1783
- */
1784
- const saasRealmProviderTs = () => {
1785
- return `import { $env, t } from "alepha";
1786
- import { $realm } from "alepha/api/users";
1787
- import { $permission } from "alepha/security";
1788
-
1789
- export class RealmProvider {
1790
- /**
1791
- * Permission required to open the admin UI. Wired into AppRouter.adminLayout
1792
- * via \`$secure({ permissions: ["admin:ui"] })\`.
1793
- */
1794
- adminUi = $permission({
1795
- group: "admin",
1796
- name: "ui",
1797
- description: "Access to the admin UI shell",
1798
- });
1799
-
1800
- /**
1801
- * Admin emails — set \`ADMIN_EMAILS\` in \`.env\` (comma-separated for
1802
- * several). Keep emails out of source: they are config, not code.
1803
- */
1804
- protected readonly env = $env(
1805
- t.object({
1806
- ADMIN_EMAILS: t.text({ default: "" }),
1807
- }),
1808
- );
1809
-
1810
- realm = $realm({
1811
- settings: {
1812
- adminEmails: this.env.ADMIN_EMAILS.split(",")
1813
- .map((email) => email.trim())
1814
- .filter(Boolean),
1815
- },
1816
- identities: {
1817
- credentials: true,
1818
- },
1819
- });
1820
- }
1821
- `;
1822
- };
1823
- //#endregion
1824
1533
  //#region ../../src/cli/core/templates/tsconfigJson.ts
1825
1534
  const tsconfigJson = () => `
1826
1535
  {
@@ -1886,10 +1595,6 @@ const vscodeSettingsJson = () => `
1886
1595
  //#endregion
1887
1596
  //#region ../../src/cli/core/templates/webAppRouterTs.ts
1888
1597
  const webAppRouterTs = (options) => {
1889
- if (options.saas) return saasAppRouterTs();
1890
- return basicAppRouterTs(options);
1891
- };
1892
- const basicAppRouterTs = (options) => {
1893
1598
  const imports = ["import { $page } from \"alepha/react/router\";"];
1894
1599
  const classMembers = [];
1895
1600
  if (options.api) {
@@ -1911,95 +1616,6 @@ export class AppRouter {
1911
1616
  ${classMembers.join("\n\n")}
1912
1617
  }`;
1913
1618
  };
1914
- /**
1915
- * SaaS router wires three trees onto the app:
1916
- * / → Home
1917
- * /auth/* → AuthLayout + login / register / reset / verify
1918
- * /admin/* → AdminLayout + users / sessions / api-keys / parameters / audits
1919
- *
1920
- * Each auth page resolves the realm config from its loader, so the registry
1921
- * components render with everything they need on first paint.
1922
- */
1923
- const saasAppRouterTs = () => `import type { RealmController } from "alepha/api/users";
1924
- import { $page, NotFound } from "alepha/react/router";
1925
- import { $secure } from "alepha/security";
1926
- import { $client } from "alepha/server/links";
1927
- import type { HelloController } from "../api/controllers/HelloController.ts";
1928
-
1929
- export class AppRouter {
1930
- protected readonly api = $client<HelloController>();
1931
- protected readonly realmApi = $client<RealmController>();
1932
-
1933
- home = $page({
1934
- path: "/",
1935
- lazy: () => import("./components/Home.tsx"),
1936
- loader: () => this.api.hello(),
1937
- });
1938
-
1939
- // ── /auth — login, register, reset, verify ─────────────────────────────
1940
- authLayout = $page({
1941
- path: "/auth",
1942
- lazy: () => import("./components/auth/AuthLayout.tsx"),
1943
- });
1944
-
1945
- login = $page({
1946
- parent: this.authLayout,
1947
- path: "/login",
1948
- name: "login",
1949
- head: { title: "Sign in" },
1950
- lazy: () => import("./components/auth/Login.tsx"),
1951
- loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
1952
- });
1953
-
1954
- register = $page({
1955
- parent: this.authLayout,
1956
- path: "/register",
1957
- name: "register",
1958
- head: { title: "Sign up" },
1959
- lazy: () => import("./components/auth/Register.tsx"),
1960
- loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
1961
- });
1962
-
1963
- resetPassword = $page({
1964
- parent: this.authLayout,
1965
- path: "/reset-password",
1966
- head: { title: "Reset password" },
1967
- lazy: () => import("./components/auth/ResetPassword.tsx"),
1968
- loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
1969
- });
1970
-
1971
- verifyEmail = $page({
1972
- parent: this.authLayout,
1973
- path: "/verify-email",
1974
- head: { title: "Verify email" },
1975
- lazy: () => import("./components/auth/VerifyEmail.tsx"),
1976
- });
1977
-
1978
- // ── /admin — gated by 'admin:ui' permission, declared in RealmProvider.
1979
- // Children inherit the gate via the parent chain.
1980
- adminLayout = $page({
1981
- path: "/admin",
1982
- use: [$secure({ permissions: ["admin:ui"] })],
1983
- lazy: () => import("./components/admin/AdminLayout.tsx"),
1984
- });
1985
-
1986
- adminUsers = $page({
1987
- parent: this.adminLayout,
1988
- path: "/users",
1989
- head: { title: "Users" },
1990
- lazy: () => import("./components/admin/Users.tsx"),
1991
- });
1992
-
1993
- adminSessions = $page({
1994
- parent: this.adminLayout,
1995
- path: "/sessions",
1996
- head: { title: "Sessions" },
1997
- lazy: () => import("./components/admin/Sessions.tsx"),
1998
- });
1999
-
2000
- notFound = $page({ path: "/*", component: NotFound });
2001
- }
2002
- `;
2003
1619
  //#endregion
2004
1620
  //#region ../../src/cli/core/templates/webHomeComponentTsx.ts
2005
1621
  const webHomeComponentTsx = (options = {}) => {
@@ -2028,19 +1644,7 @@ export default Home;
2028
1644
  //#endregion
2029
1645
  //#region ../../src/cli/core/templates/webIndexTs.ts
2030
1646
  const webIndexTs = (options = {}) => {
2031
- const { appName = "app", saas = false } = options;
2032
- if (saas) return `
2033
- import { $module } from "alepha";
2034
- import { AlephaReactAuth } from "alepha/react/auth";
2035
- import { AlephaReactI18n } from "alepha/react/i18n";
2036
- import { AppRouter } from "./AppRouter.ts";
2037
-
2038
- export const WebModule = $module({
2039
- name: "${appName}.web",
2040
- services: [AppRouter],
2041
- imports: [AlephaReactAuth, AlephaReactI18n],
2042
- });
2043
- `.trim();
1647
+ const { appName = "app" } = options;
2044
1648
  return `
2045
1649
  import { $module } from "alepha";
2046
1650
  import { AppRouter } from "./AppRouter.ts";
@@ -2066,7 +1670,6 @@ var ProjectScaffolder = class {
2066
1670
  log = $logger();
2067
1671
  colors = $inject(ConsoleColorProvider);
2068
1672
  fs = $inject(FileSystemProvider);
2069
- shell = $inject(ShellProvider);
2070
1673
  pm = $inject(PackageManagerUtils);
2071
1674
  utils = $inject(AlephaCliUtils);
2072
1675
  /**
@@ -2088,10 +1691,7 @@ var ProjectScaffolder = class {
2088
1691
  const force = opts.force ?? false;
2089
1692
  const checkWorkspace = opts.checkWorkspace ?? false;
2090
1693
  if (opts.packageJson) tasks.push(this.pm.ensurePackageJson(root, typeof opts.packageJson === "boolean" ? {} : opts.packageJson).then(() => {}));
2091
- if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, {
2092
- force,
2093
- localOnly: opts.tsconfigJson === "local"
2094
- }));
1694
+ if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, { force }));
2095
1695
  if (opts.biomeJson) tasks.push(this.ensureBiomeConfig(root, {
2096
1696
  force,
2097
1697
  checkWorkspace
@@ -2108,7 +1708,7 @@ var ProjectScaffolder = class {
2108
1708
  await Promise.all(tasks);
2109
1709
  }
2110
1710
  async ensureTsConfig(root, opts = {}) {
2111
- const exists = opts.localOnly ? await this.fs.exists(this.fs.join(root, "tsconfig.json")) : await this.existsInParents(root, "tsconfig.json");
1711
+ const exists = await this.existsInParents(root, "tsconfig.json");
2112
1712
  if (!opts.force && exists) return;
2113
1713
  await this.fs.writeFile(this.fs.join(root, "tsconfig.json"), tsconfigJson());
2114
1714
  }
@@ -2185,33 +1785,9 @@ var ProjectScaffolder = class {
2185
1785
  const appName = this.getAppName(root);
2186
1786
  await this.fs.mkdir(this.fs.join(root, "src/api/controllers"), { recursive: true });
2187
1787
  await this.fs.mkdir(this.fs.join(root, "src/api/schemas"), { recursive: true });
2188
- await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
2189
- appName,
2190
- saas: opts.saas
2191
- }), opts.force);
1788
+ await this.ensureFile(root, "src/api/index.ts", apiIndexTs({ appName }), opts.force);
2192
1789
  await this.ensureFile(root, "src/api/controllers/HelloController.ts", apiHelloControllerTs({ appName }), opts.force);
2193
1790
  await this.ensureFile(root, "src/api/schemas/helloResponseSchema.ts", apiHelloResponseSchemaTs(), opts.force);
2194
- if (opts.saas) {
2195
- await this.fs.mkdir(this.fs.join(root, "src/api/providers"), { recursive: true });
2196
- await this.ensureFile(root, "src/api/providers/RealmProvider.ts", saasRealmProviderTs(), opts.force);
2197
- const adminEmail = await this.detectGitEmail() ?? "admin@alepha.dev";
2198
- await this.ensureFile(root, ".env", `ADMIN_EMAILS=${adminEmail}\n`, opts.force);
2199
- }
2200
- }
2201
- /**
2202
- * Best-effort lookup for the developer's git email — seeded as
2203
- * `ADMIN_EMAILS` in the SaaS project's `.env`. Returns undefined if git
2204
- * isn't available or `user.email` isn't configured; the caller then falls
2205
- * back to the neutral `admin@alepha.dev`.
2206
- */
2207
- async detectGitEmail() {
2208
- try {
2209
- const email = (await this.shell.run("git config --get user.email", { capture: true }) ?? "").trim();
2210
- if (!email || !email.includes("@")) return void 0;
2211
- return email;
2212
- } catch {
2213
- return;
2214
- }
2215
1791
  }
2216
1792
  /**
2217
1793
  * Ensure web/React project structure exists.
@@ -2224,35 +1800,14 @@ var ProjectScaffolder = class {
2224
1800
  async ensureWebProject(root, opts = {}) {
2225
1801
  const appName = this.getAppName(root);
2226
1802
  await this.fs.mkdir(this.fs.join(root, "src/web/components"), { recursive: true });
2227
- if (opts.saas) {
2228
- await this.fs.mkdir(this.fs.join(root, "src/web/components/auth"), { recursive: true });
2229
- await this.fs.mkdir(this.fs.join(root, "src/web/components/admin"), { recursive: true });
2230
- }
2231
1803
  await this.fs.mkdir(this.fs.join(root, "public"), { recursive: true });
2232
1804
  await this.ensureFile(root, "public/favicon.svg", logoSvg, opts.force);
2233
1805
  await this.ensureFile(root, "src/main.css", mainCss({ tailwind: opts.tailwind }), opts.force);
2234
1806
  if (opts.tailwind) await this.ensureFile(root, "vite.config.ts", viteConfigTs(), opts.force);
2235
- if (opts.shadcn) await this.ensureFile(root, "components.json", componentsJsonTs(), opts.force);
2236
- await this.ensureFile(root, "src/web/index.ts", webIndexTs({
2237
- appName,
2238
- saas: opts.saas
2239
- }), opts.force);
2240
- await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({
2241
- api: opts.api,
2242
- saas: opts.saas
2243
- }), opts.force);
1807
+ await this.ensureFile(root, "src/web/index.ts", webIndexTs({ appName }), opts.force);
1808
+ await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({ api: opts.api }), opts.force);
2244
1809
  await this.ensureFile(root, "src/web/components/Home.tsx", webHomeComponentTsx({ api: opts.api }), opts.force);
2245
1810
  await this.ensureFile(root, "src/main.browser.ts", mainBrowserTs(), opts.force);
2246
- if (opts.saas) {
2247
- await this.ensureFile(root, "src/web/components/auth/AuthLayout.tsx", saasAuthLayoutTsx(), opts.force);
2248
- await this.ensureFile(root, "src/web/components/auth/Login.tsx", saasAuthLoginTsx(), opts.force);
2249
- await this.ensureFile(root, "src/web/components/auth/Register.tsx", saasAuthRegisterTsx(), opts.force);
2250
- await this.ensureFile(root, "src/web/components/auth/ResetPassword.tsx", saasAuthResetPasswordTsx(), opts.force);
2251
- await this.ensureFile(root, "src/web/components/auth/VerifyEmail.tsx", saasAuthVerifyEmailTsx(), opts.force);
2252
- await this.ensureFile(root, "src/web/components/admin/AdminLayout.tsx", saasAdminLayoutTsx(), opts.force);
2253
- await this.ensureFile(root, "src/web/components/admin/Users.tsx", saasAdminUsersTsx(), opts.force);
2254
- await this.ensureFile(root, "src/web/components/admin/Sessions.tsx", saasAdminSessionsTsx(), opts.force);
2255
- }
2256
1811
  }
2257
1812
  /**
2258
1813
  * Ensure test directory exists with a dummy test file + a self-contained
@@ -2275,21 +1830,16 @@ var ProjectScaffolder = class {
2275
1830
  * Full project init — scaffolds files, installs deps, sets up PM and git.
2276
1831
  */
2277
1832
  async init({ run, root, flags, args }) {
1833
+ if (!args) {
1834
+ if (!await this.fs.exists(this.fs.join(root, "package.json"))) args = "my-app";
1835
+ }
2278
1836
  if (args) {
2279
1837
  root = this.fs.join(root, args);
2280
1838
  await this.fs.mkdir(root, { force: true });
2281
1839
  }
2282
- const shadcnPreset = typeof flags.saas === "string" && flags.saas || typeof flags.shadcn === "string" && flags.shadcn || "b0";
2283
- const f = flags;
2284
- f.shadcn = !!flags.shadcn;
2285
- f.saas = !!flags.saas;
2286
- if (f.saas) {
2287
- f.shadcn = true;
2288
- f.api = true;
2289
- }
2290
- if (f.shadcn) f.tailwind = true;
2291
1840
  if (flags.tailwind) flags.react = true;
2292
- if ((flags.api || flags.react || flags.tailwind || flags.shadcn || flags.saas) && !flags.force) {
1841
+ const f = flags;
1842
+ if ((flags.api || flags.react || flags.tailwind) && !flags.force) {
2293
1843
  if ((await this.fs.ls(root)).filter((f) => f !== "package.json").length > 0) throw new AlephaError(`Target directory is not empty (${root}). Use --force to overwrite existing files.`);
2294
1844
  }
2295
1845
  const workspace = await this.pm.getWorkspaceContext(root);
@@ -2305,7 +1855,7 @@ var ProjectScaffolder = class {
2305
1855
  ...f,
2306
1856
  isPackage: workspace.isPackage
2307
1857
  },
2308
- tsconfigJson: f.shadcn ? "local" : !workspace.config.tsconfigJson,
1858
+ tsconfigJson: !workspace.config.tsconfigJson,
2309
1859
  biomeJson: true,
2310
1860
  editorconfig: !workspace.config.editorconfig,
2311
1861
  agentMd: writeAgentMd,
@@ -2317,15 +1867,10 @@ var ProjectScaffolder = class {
2317
1867
  react: !!flags.react && !isExpo,
2318
1868
  force
2319
1869
  });
2320
- if (flags.api) await this.ensureApiProject(root, {
2321
- saas: !!flags.saas,
2322
- force
2323
- });
1870
+ if (flags.api) await this.ensureApiProject(root, { force });
2324
1871
  if (flags.react && !isExpo) await this.ensureWebProject(root, {
2325
1872
  api: !!flags.api,
2326
1873
  tailwind: !!flags.tailwind,
2327
- shadcn: !!flags.shadcn,
2328
- saas: !!flags.saas,
2329
1874
  force
2330
1875
  });
2331
1876
  }
@@ -2343,18 +1888,6 @@ var ProjectScaffolder = class {
2343
1888
  root: installRoot
2344
1889
  });
2345
1890
  await this.ensureTestDir(root);
2346
- const exec = pmExecPrefix(pmName);
2347
- if (flags.shadcn) {
2348
- await run(`${exec} shadcn init --no-monorepo --base radix -t vite --yes --force --reinstall --preset ${escapeShellArg(shadcnPreset)}`, {
2349
- alias: `running shadcn init (preset ${shadcnPreset})`,
2350
- root
2351
- });
2352
- await this.fs.writeFile(this.fs.join(root, "components.json"), componentsJsonTs());
2353
- }
2354
- if (flags.saas) await run(`${exec} shadcn add @alepha/saas --yes --overwrite`, {
2355
- alias: "adding alepha saas registry bundle",
2356
- root
2357
- });
2358
1891
  try {
2359
1892
  await run(`${pmName} run lint`, {
2360
1893
  alias: "running linter",
@@ -2401,30 +1934,6 @@ var ProjectScaffolder = class {
2401
1934
  }
2402
1935
  }
2403
1936
  };
2404
- /**
2405
- * Map a package manager name to the command that runs a project-local binary.
2406
- *
2407
- * - npm: `npx`
2408
- * - yarn: `yarn` (yarn auto-resolves binary names; `yarn shadcn ...` works)
2409
- * - pnpm: `pnpm exec`
2410
- * - bun: `bunx`
2411
- *
2412
- * Used to invoke `shadcn init` / `shadcn add` regardless of the user's PM —
2413
- * `npm shadcn ...` is invalid (it tries to run a script named `shadcn`).
2414
- */
2415
- /** Quote a value so it survives shell parsing. */
2416
- const escapeShellArg = (value) => {
2417
- if (/^[A-Za-z0-9_./@:-]+$/.test(value)) return value;
2418
- return `'${value.replace(/'/g, "'\\''")}'`;
2419
- };
2420
- const pmExecPrefix = (pmName) => {
2421
- switch (pmName) {
2422
- case "npm": return "npx";
2423
- case "pnpm": return "pnpm exec";
2424
- case "bun": return "bunx";
2425
- default: return "yarn";
2426
- }
2427
- };
2428
1937
  //#endregion
2429
1938
  //#region ../../src/cli/core/tasks/BuildTask.ts
2430
1939
  /**
@@ -2563,6 +2072,7 @@ var BuildClientTask = class extends BuildTask {
2563
2072
  };
2564
2073
  //#endregion
2565
2074
  //#region ../../src/cli/core/tasks/BuildCloudflareTask.ts
2075
+ const CLOUDFLARE_EMAIL_PROVIDER_NAME = "CloudflareEmailProvider";
2566
2076
  /**
2567
2077
  * Generate Cloudflare Workers deployment configuration.
2568
2078
  *
@@ -2586,7 +2096,7 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2586
2096
  }
2587
2097
  async generateCloudflare(ctx, distDir) {
2588
2098
  const root = ctx.root;
2589
- const name = basename(root);
2099
+ const name = basename(root).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
2590
2100
  const hasAssets = await this.fs.exists(this.fs.join(root, distDir, "public"));
2591
2101
  const wrangler = {
2592
2102
  name,
@@ -2617,8 +2127,71 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2617
2127
  this.enhanceEmail(ctx, wrangler);
2618
2128
  const containers = this.enhanceContainers(ctx, wrangler);
2619
2129
  await this.fs.writeFile(this.fs.join(root, distDir, "wrangler.jsonc"), JSON.stringify(wrangler, null, 2));
2130
+ if (!ctx.manifest) await this.writeManifest(ctx, root, distDir, name, containers);
2620
2131
  await this.writeWorkerEntryPoint(root, distDir, containers);
2621
2132
  }
2133
+ /**
2134
+ * Write `dist/manifest.json` — a build-time snapshot of everything
2135
+ * downstream tooling needs to know about the app without re-booting
2136
+ * it. Used by `alepha platform up --prebuilt` (and Alepha Rocket) so
2137
+ * the deploy path can skip the Vite-based introspection step and the
2138
+ * workspace's runtime npm install.
2139
+ */
2140
+ async writeManifest(ctx, root, distDir, name, containers) {
2141
+ let hasDatabase = false;
2142
+ let hasBucket = false;
2143
+ let hasKV = false;
2144
+ let hasQueue = false;
2145
+ let crons = [];
2146
+ try {
2147
+ hasDatabase = (ctx.alepha.inject("RepositoryProvider").getRepositories?.() ?? []).length > 0;
2148
+ } catch {}
2149
+ try {
2150
+ hasBucket = ctx.alepha.primitives("$bucket").length > 0;
2151
+ } catch {}
2152
+ try {
2153
+ hasKV = ctx.alepha.primitives("cache").filter((p) => p.options?.provider == null).length > 0;
2154
+ } catch {}
2155
+ try {
2156
+ hasQueue = ctx.alepha.primitives("$queue").length > 0;
2157
+ } catch {}
2158
+ try {
2159
+ const cronProvider = ctx.alepha.inject("CronProvider");
2160
+ crons = [...new Set((cronProvider.getCronJobs?.() ?? []).map((c) => c.expression))];
2161
+ } catch {}
2162
+ const defaultEnv = ctx.platformOptions?.default ?? "production";
2163
+ const environments = ctx.platformOptions?.environments ?? {};
2164
+ let env = [];
2165
+ try {
2166
+ env = Object.keys(ctx.alepha.dump().env).sort();
2167
+ } catch {}
2168
+ const manifest = {
2169
+ version: 1,
2170
+ project: name,
2171
+ defaultEnv,
2172
+ tenancy: ctx.platformOptions?.tenancy,
2173
+ environments,
2174
+ resources: {
2175
+ hasDatabase,
2176
+ hasBucket,
2177
+ hasKV,
2178
+ hasQueue,
2179
+ hasCron: crons.length > 0
2180
+ },
2181
+ crons,
2182
+ containers: containers.map((c) => ({
2183
+ name: c.name,
2184
+ className: c.className,
2185
+ image: c.image,
2186
+ port: c.port,
2187
+ sleepAfter: c.sleepAfter,
2188
+ instanceType: c.instanceType,
2189
+ maxInstances: c.maxInstances
2190
+ })),
2191
+ env
2192
+ };
2193
+ await this.fs.writeFile(this.fs.join(root, distDir, "manifest.json"), JSON.stringify(manifest, null, 2));
2194
+ }
2622
2195
  enhanceDomain(wrangler) {
2623
2196
  const domain = process.env.CLOUDFLARE_DOMAIN;
2624
2197
  if (!domain) return;
@@ -2637,16 +2210,20 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2637
2210
  }];
2638
2211
  }
2639
2212
  enhanceCron(ctx, wrangler) {
2640
- if (ctx.alepha.primitives("scheduler").length === 0) return;
2213
+ const cronExpressions = ctx.manifest ? ctx.manifest.crons : this.discoverCrons(ctx);
2214
+ if (cronExpressions.length === 0) return;
2215
+ wrangler.triggers ??= {};
2216
+ wrangler.triggers.crons = cronExpressions;
2217
+ }
2218
+ discoverCrons(ctx) {
2219
+ if (ctx.alepha.primitives("scheduler").length === 0) return [];
2641
2220
  let cronProvider;
2642
2221
  try {
2643
2222
  cronProvider = ctx.alepha.inject("CronProvider");
2644
2223
  } catch {}
2645
2224
  const crons = cronProvider?.getCronJobs();
2646
- if (!crons || crons.length === 0) return;
2647
- const cronExpressions = [...new Set(crons.map((c) => c.expression))];
2648
- wrangler.triggers ??= {};
2649
- wrangler.triggers.crons = cronExpressions;
2225
+ if (!crons || crons.length === 0) return [];
2226
+ return [...new Set(crons.map((c) => c.expression))];
2650
2227
  }
2651
2228
  enhanceDatabase(wrangler) {
2652
2229
  if (process.env.HYPERDRIVE_ID) {
@@ -2720,18 +2297,15 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2720
2297
  wrangler.queues.consumers.push({ queue: queueName });
2721
2298
  }
2722
2299
  enhanceEmail(ctx, wrangler) {
2723
- let provider;
2300
+ if (ctx.manifest || !ctx.alepha) return;
2724
2301
  try {
2725
- provider = ctx.alepha.inject(EmailProvider);
2302
+ ctx.alepha.inject(CLOUDFLARE_EMAIL_PROVIDER_NAME);
2726
2303
  } catch {
2727
2304
  return;
2728
2305
  }
2729
- if (!(provider instanceof CloudflareEmailProvider)) return;
2730
2306
  wrangler.send_email = wrangler.send_email || [];
2731
2307
  if (wrangler.send_email.some((b) => b.name === SEND_EMAIL_DEFAULT_BINDING)) return;
2732
2308
  const entry = { name: SEND_EMAIL_DEFAULT_BINDING };
2733
- const destination = process.env.EMAIL_FROM;
2734
- if (destination) entry.destination_address = destination;
2735
2309
  wrangler.send_email.push(entry);
2736
2310
  }
2737
2311
  /**
@@ -2744,19 +2318,45 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2744
2318
  * `writeWorkerEntryPoint` can emit `export class <NAME> extends
2745
2319
  * Container` declarations referencing them.
2746
2320
  */
2747
- enhanceContainers(ctx, wrangler) {
2748
- const primitives = ctx.alepha.primitives($container);
2749
- if (primitives.length === 0) return [];
2750
- const descriptors = primitives.map((p) => ({
2321
+ discoverContainers(ctx) {
2322
+ return ctx.alepha.primitives("container").map((p) => ({
2751
2323
  name: p.name.toUpperCase(),
2752
2324
  className: p.name.split(/[^a-zA-Z0-9]/).filter(Boolean).map((s) => s[0].toUpperCase() + s.slice(1)).join(""),
2753
2325
  image: p.options.image,
2754
2326
  port: p.options.port ?? 3e3,
2755
2327
  sleepAfter: typeof p.options.sleepAfter === "string" ? p.options.sleepAfter : "15m",
2756
- instanceType: p.options.instanceType ?? "dev",
2328
+ instanceType: p.options.instanceType === "dev" ? "lite" : p.options.instanceType ?? "lite",
2757
2329
  maxInstances: p.options.maxInstances ?? 5,
2758
2330
  envVars: p.options.envVars
2759
2331
  }));
2332
+ }
2333
+ /**
2334
+ * Expand a short image ref (e.g. `alepha-rocket:0.1.0`) into the
2335
+ * fully-qualified `registry.cloudflare.com/<account>/<image>:<tag>`
2336
+ * URL that wrangler validates at deploy time.
2337
+ *
2338
+ * Cloudflare Containers only pulls from `registry.cloudflare.com`;
2339
+ * wrangler accepts either a Dockerfile path or a fully-qualified
2340
+ * registry URL in the `image` field — not a bare DockerHub-style
2341
+ * name. We let `$container({ image })` callers write the short
2342
+ * form (it matches what `wrangler containers push <local>` accepts
2343
+ * + matches the local docker tag) and rewrite to the CF registry
2344
+ * URL here.
2345
+ *
2346
+ * Pass-through cases:
2347
+ * - already a full URL: starts with `registry.cloudflare.com/`
2348
+ * or contains a scheme/`://`
2349
+ * - looks like a Dockerfile path: starts with `./` or `/`
2350
+ */
2351
+ resolveContainerImage(image) {
2352
+ if (image.startsWith("./") || image.startsWith("/") || image.startsWith("registry.cloudflare.com/") || image.includes("://")) return image;
2353
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
2354
+ if (!accountId) return image;
2355
+ return `registry.cloudflare.com/${accountId}/${image}`;
2356
+ }
2357
+ enhanceContainers(ctx, wrangler) {
2358
+ const descriptors = ctx.manifest ? ctx.manifest.containers : this.discoverContainers(ctx);
2359
+ if (descriptors.length === 0) return [];
2760
2360
  wrangler.containers = wrangler.containers || [];
2761
2361
  wrangler.durable_objects = wrangler.durable_objects || {};
2762
2362
  wrangler.durable_objects.bindings = wrangler.durable_objects.bindings || [];
@@ -2765,7 +2365,7 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2765
2365
  for (const d of descriptors) {
2766
2366
  wrangler.containers.push({
2767
2367
  class_name: d.className,
2768
- image: d.image,
2368
+ image: this.resolveContainerImage(d.image),
2769
2369
  instance_type: d.instanceType,
2770
2370
  max_instances: d.maxInstances
2771
2371
  });
@@ -2784,9 +2384,8 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
2784
2384
  async writeWorkerEntryPoint(root, distDir, containers = []) {
2785
2385
  const containerDeclarations = containers.map((c) => {
2786
2386
  const envVars = c.envVars ? ` envVars = ${JSON.stringify(c.envVars)};\n` : "";
2787
- return `export class ${c.className} extends Container {\n defaultPort = ${c.port};\n sleepAfter = "${c.sleepAfter}";\n${envVars}}`;
2387
+ return `export class ${c.className} extends globalThis.__alepha_CloudflareContainer {\n defaultPort = ${c.port};\n sleepAfter = "${c.sleepAfter}";\n${envVars}}`;
2788
2388
  }).join("\n\n");
2789
- const containerImport = containers.length > 0 ? `import { Container } from "@cloudflare/containers";\n\n${containerDeclarations}\n\n` : "";
2790
2389
  const workerCode = `
2791
2390
  import "./index.js";
2792
2391
 
@@ -2801,11 +2400,19 @@ const setWaitUntil = (executionCtx) => {
2801
2400
  }
2802
2401
  };
2803
2402
 
2403
+ // Bind the per-invocation Worker \`env\`: keep the full binding (D1, R2, KV, …)
2404
+ // in the store for providers, and lift its string values (secrets/vars like
2405
+ // PUBLIC_URL) into \`alepha.env\` so \`$env\` resolves them at runtime.
2406
+ const bindEnv = (env) => {
2407
+ __alepha.set("cloudflare.env", env);
2408
+ __alepha.loadEnv(env);
2409
+ };
2410
+
2804
2411
  export default {
2805
2412
  fetch: async (request, env, executionCtx) => {
2806
2413
  const ctx = { req: request, res: undefined };
2807
2414
 
2808
- __alepha.set("cloudflare.env", env);
2415
+ bindEnv(env);
2809
2416
  setWaitUntil(executionCtx);
2810
2417
 
2811
2418
  try {
@@ -2821,7 +2428,7 @@ export default {
2821
2428
  },
2822
2429
 
2823
2430
  scheduled: async (event, env, executionCtx) => {
2824
- __alepha.set("cloudflare.env", env);
2431
+ bindEnv(env);
2825
2432
  setWaitUntil(executionCtx);
2826
2433
 
2827
2434
  try {
@@ -2838,7 +2445,7 @@ export default {
2838
2445
  },
2839
2446
 
2840
2447
  queue: async (batch, env, executionCtx) => {
2841
- __alepha.set("cloudflare.env", env);
2448
+ bindEnv(env);
2842
2449
  setWaitUntil(executionCtx);
2843
2450
 
2844
2451
  try {
@@ -2859,7 +2466,8 @@ export default {
2859
2466
  },
2860
2467
  };
2861
2468
  `.trim();
2862
- await this.fs.writeFile(this.fs.join(root, distDir, "main.cloudflare.js"), `${this.warningComment}\n${containerImport}${workerCode}`.trim());
2469
+ const containerBlock = containers.length > 0 ? `${containerDeclarations}\n\n` : "";
2470
+ await this.fs.writeFile(this.fs.join(root, distDir, "main.cloudflare.js"), `${this.warningComment}\n${containerBlock}${workerCode}`.trim());
2863
2471
  }
2864
2472
  };
2865
2473
  //#endregion
@@ -2979,6 +2587,7 @@ var BuildDockerTask = class extends BuildTask {
2979
2587
  name: "generate deploy config (docker)",
2980
2588
  handler: async () => {
2981
2589
  const migrationsCopied = await this.copyMigrations(ctx.root, distDir);
2590
+ const hasDeps = await this.hasRuntimeDeps(ctx.root, distDir);
2982
2591
  await this.writeDockerfile(ctx.root, distDir, {
2983
2592
  compile,
2984
2593
  standard: {
@@ -2986,6 +2595,7 @@ var BuildDockerTask = class extends BuildTask {
2986
2595
  command: dockerCommand
2987
2596
  },
2988
2597
  hasMigrations: migrationsCopied,
2598
+ hasDeps,
2989
2599
  install: ctx.options.docker?.install ?? []
2990
2600
  });
2991
2601
  }
@@ -3071,6 +2681,21 @@ var BuildDockerTask = class extends BuildTask {
3071
2681
  }
3072
2682
  return false;
3073
2683
  }
2684
+ /**
2685
+ * Whether the produced `dist/package.json` declares any runtime
2686
+ * dependencies. Alepha apps normally bundle everything into the
2687
+ * server entry via Vite, leaving `dependencies: {}` — in which case
2688
+ * the generated Dockerfile's `RUN npm install` is wasted work
2689
+ * (and emits deprecation noise). Skip the line when empty.
2690
+ */
2691
+ async hasRuntimeDeps(root, distDir) {
2692
+ try {
2693
+ const pkg = await this.fs.readJsonFile(this.fs.join(root, distDir, "package.json"));
2694
+ return Object.keys(pkg.dependencies ?? {}).length > 0;
2695
+ } catch {
2696
+ return false;
2697
+ }
2698
+ }
3074
2699
  async writeDockerfile(root, distDir, opts) {
3075
2700
  const header = "# This file was automatically generated. DO NOT MODIFY.\n# Changes to this file will be lost when the code is regenerated.\n";
3076
2701
  const migrationsLine = opts.hasMigrations ? "COPY migrations ./migrations\n" : "";
@@ -3086,14 +2711,12 @@ ENTRYPOINT ["/app/app"]
3086
2711
  `;
3087
2712
  else {
3088
2713
  const { image, command } = opts.standard;
3089
- const installLine = opts.install.length ? `RUN npm install --no-save --no-fund --no-audit ${opts.install.join(" ")}\n` : "";
3090
2714
  dockerfile = `${header}FROM ${image}
3091
2715
  WORKDIR /app
3092
2716
 
3093
2717
  COPY . .
3094
2718
 
3095
- RUN ${command === "bun" ? "bun" : "npm"} install
3096
- ${installLine}
2719
+ ${opts.hasDeps ? `RUN ${command === "bun" ? "bun" : "npm"} install\n` : ""}${opts.install.length ? `RUN npm install --no-save --no-fund --no-audit ${opts.install.join(" ")}\n` : ""}
3097
2720
  ENV SERVER_HOST=0.0.0.0
3098
2721
 
3099
2722
  CMD ["${command}", "index.js"]
@@ -3801,6 +3424,23 @@ var BuildCommand = class {
3801
3424
  $inject(BuildCompressTask)
3802
3425
  ];
3803
3426
  /**
3427
+ * Value aliases accepted for `--target`.
3428
+ *
3429
+ * These let the CLI accept short forms (e.g. `--target cf`) that are
3430
+ * canonicalized to a real {@link BuildTarget} before they flow into the
3431
+ * pipeline. The enum in `flags.target` must also list the alias so it
3432
+ * passes schema validation.
3433
+ */
3434
+ targetAliases = { cf: "cloudflare" };
3435
+ /**
3436
+ * Canonicalize a raw `--target` value, mapping any known alias
3437
+ * (e.g. `cf` → `cloudflare`) to its real {@link BuildTarget}.
3438
+ */
3439
+ resolveTarget(target) {
3440
+ if (!target) return;
3441
+ return this.targetAliases[target] ?? target;
3442
+ }
3443
+ /**
3804
3444
  * Resolve the effective runtime based on target and explicit runtime flag.
3805
3445
  *
3806
3446
  * Some targets force a specific runtime:
@@ -3832,10 +3472,11 @@ var BuildCommand = class {
3832
3472
  "docker",
3833
3473
  "vercel",
3834
3474
  "cloudflare",
3475
+ "cf",
3835
3476
  "static"
3836
3477
  ], {
3837
3478
  aliases: ["t"],
3838
- description: "Deployment target"
3479
+ description: "Deployment target (cf = cloudflare)"
3839
3480
  })),
3840
3481
  runtime: t.optional(t.enum([
3841
3482
  "node",
@@ -3862,17 +3503,20 @@ var BuildCommand = class {
3862
3503
  await this.scaffolder.ensureConfig(root, { tsconfigJson: true });
3863
3504
  const entry = await this.boot.getAppEntry(root);
3864
3505
  this.log.trace("Entry file found", { entry });
3865
- this.alepha.store.mut(buildOptions, (current) => ({
3866
- ...current,
3867
- stats: flags.stats ?? current.stats ?? false,
3868
- target: flags.target ?? current.target,
3869
- runtime: this.resolveRuntime(flags.target ?? current.target, flags.runtime ?? current.runtime),
3870
- ...flags.compile !== void 0 && { docker: {
3871
- ...current.docker,
3872
- compile: flags.compile ? current.docker?.compile ?? true : false
3873
- } },
3874
- ...flags.sitemap && { sitemap: { hostname: flags.sitemap } }
3875
- }));
3506
+ this.alepha.store.mut(buildOptions, (current) => {
3507
+ const target = this.resolveTarget(flags.target) ?? current.target;
3508
+ return {
3509
+ ...current,
3510
+ stats: flags.stats ?? current.stats ?? false,
3511
+ target,
3512
+ runtime: this.resolveRuntime(target, flags.runtime ?? current.runtime),
3513
+ ...flags.compile !== void 0 && { docker: {
3514
+ ...current.docker,
3515
+ compile: flags.compile ? current.docker?.compile ?? true : false
3516
+ } },
3517
+ ...flags.sitemap && { sitemap: { hostname: flags.sitemap } }
3518
+ };
3519
+ });
3876
3520
  const options = this.options;
3877
3521
  const distDir = options.output?.dist ?? "dist";
3878
3522
  if (!flags.prebuilt) await run.rm(distDir, { alias: "clean dist" });
@@ -3886,23 +3530,30 @@ var BuildCommand = class {
3886
3530
  target,
3887
3531
  runtime: options.runtime
3888
3532
  });
3533
+ let manifest = null;
3534
+ if (flags.prebuilt) manifest = await this.loadManifest(root);
3889
3535
  let appAlepha;
3890
3536
  let hasClient = false;
3891
- await run({
3892
- name: "analyze app",
3893
- handler: async () => {
3894
- appAlepha = await this.viteBuildProvider.init({ entry });
3895
- hasClient = this.viteBuildProvider.hasClient();
3896
- }
3897
- });
3898
- if (!appAlepha) throw new AlephaError("Alepha instance not found");
3537
+ if (!manifest) {
3538
+ await run({
3539
+ name: "analyze app",
3540
+ handler: async () => {
3541
+ appAlepha = await this.viteBuildProvider.init({ entry });
3542
+ hasClient = this.viteBuildProvider.hasClient();
3543
+ }
3544
+ });
3545
+ if (!appAlepha) throw new AlephaError("Alepha instance not found");
3546
+ }
3547
+ const platformOptions = this.alepha.store.get("alepha.cli.platform.options") ?? null;
3899
3548
  const ctx = {
3900
- alepha: appAlepha,
3549
+ alepha: appAlepha ?? null,
3901
3550
  options,
3902
3551
  root,
3903
3552
  run,
3904
3553
  entry,
3905
3554
  hasClient,
3555
+ manifest,
3556
+ platformOptions,
3906
3557
  flags: {
3907
3558
  image: flags.image,
3908
3559
  prebuilt: flags.prebuilt
@@ -3911,6 +3562,21 @@ var BuildCommand = class {
3911
3562
  for (const task of this.pipeline) await task.run(ctx);
3912
3563
  }
3913
3564
  });
3565
+ /**
3566
+ * Read `dist/manifest.json` produced by a previous `alepha build`.
3567
+ * Returns null when absent or unparseable — caller falls back to the
3568
+ * Vite-introspection path.
3569
+ */
3570
+ async loadManifest(root) {
3571
+ try {
3572
+ const fs = await import("node:fs/promises");
3573
+ const path = await import("node:path");
3574
+ const raw = await fs.readFile(path.join(root, "dist", "manifest.json"), "utf-8");
3575
+ return JSON.parse(raw);
3576
+ } catch {
3577
+ return null;
3578
+ }
3579
+ }
3914
3580
  };
3915
3581
  //#endregion
3916
3582
  //#region ../../src/cli/core/commands/clean.ts
@@ -4506,8 +4172,10 @@ var ViteDevServerProvider = class {
4506
4172
  handleHotUpdate: async (ctx) => {
4507
4173
  if (/[/\\]\.idea[/\\]/.test(ctx.file)) return [];
4508
4174
  if (this.waitingForRetry) return [];
4509
- const firstModule = ctx.modules[0];
4510
- if (firstModule && !firstModule._ssrModule) return;
4175
+ if (!/\.(tsx|jsx)$/.test(ctx.file)) {
4176
+ const firstModule = ctx.modules[0];
4177
+ if (firstModule && !firstModule._ssrModule) return;
4178
+ }
4511
4179
  this.changedFiles.add(ctx.file);
4512
4180
  if (/\.(tsx|jsx)$/.test(ctx.file)) {
4513
4181
  if (this.reloadDebounceTimer) {
@@ -4702,7 +4370,17 @@ if (import.meta.hot) {
4702
4370
  process.env.SERVER_PORT ??= `${port}`;
4703
4371
  }
4704
4372
  /**
4705
- * Invalidate modules and all their importers.
4373
+ * Invalidate modules and all their importers, across both client and
4374
+ * SSR module graphs.
4375
+ *
4376
+ * Vite registers a file under multiple module ids (one per query
4377
+ * variant — e.g. `?v=…`, `?import` and the bare path), and `getModuleById`
4378
+ * only matches one. For workspace-linked source files (`@alepha/ui/...`)
4379
+ * the SSR-graph entry is keyed by the absolute path while the client
4380
+ * may use the package-qualified id. `getModulesByFile` returns every
4381
+ * variant Vite knows about for a given absolute path — invalidating
4382
+ * each catches both halves of the dual graph and prevents stale SSR
4383
+ * compiled exports from surviving across edits.
4706
4384
  */
4707
4385
  invalidateModulesWithImporters(changedFiles) {
4708
4386
  const graph = this.server.moduleGraph;
@@ -4711,11 +4389,16 @@ if (import.meta.hot) {
4711
4389
  while (queue.length > 0) {
4712
4390
  const file = queue.pop();
4713
4391
  if (invalidated.has(file)) continue;
4714
- const mod = this.server.moduleGraph.getModuleById(file);
4715
- if (!mod) continue;
4716
- graph.invalidateModule(mod);
4717
4392
  invalidated.add(file);
4718
- for (const importer of mod.importers) if (importer.id && !invalidated.has(importer.id)) queue.push(importer.id);
4393
+ const mods = new Set([...graph.getModulesByFile(file) ?? [], ...graph.getModuleById(file) ? [graph.getModuleById(file)] : []]);
4394
+ if (mods.size === 0) continue;
4395
+ for (const mod of mods) {
4396
+ graph.invalidateModule(mod);
4397
+ for (const importer of mod.importers) {
4398
+ const key = importer.file ?? importer.id;
4399
+ if (key && !invalidated.has(key)) queue.push(key);
4400
+ }
4401
+ }
4719
4402
  }
4720
4403
  const entryPath = this.options.entry.server;
4721
4404
  const absoluteEntryPath = join(this.options.root, entryPath);
@@ -5299,8 +4982,6 @@ var InitCommand = class {
5299
4982
  description: "Include React dependencies and web module (src/web/)"
5300
4983
  })),
5301
4984
  tailwind: t.optional(t.boolean({ description: "Include Tailwind CSS with Vite plugin. Implies --react" })),
5302
- shadcn: t.optional(t.union([t.boolean(), t.text()], { description: "Set up shadcn/ui (components.json, cn helper, theme tokens, alepha registry). Pass an optional preset id (default: b0). Implies --react and --tailwind" })),
5303
- saas: t.optional(t.union([t.boolean(), t.text()], { description: "Scaffold a SaaS starter: auth (login/register/reset/verify) + admin panel (/admin AppShell with users/sessions/api-keys/parameters/audits). Pass an optional preset id (default: b0). Implies --shadcn and --api" })),
5304
4985
  force: t.optional(t.boolean({
5305
4986
  aliases: ["f"],
5306
4987
  description: "Override existing files"
@@ -5334,6 +5015,86 @@ var LintCommand = class {
5334
5015
  });
5335
5016
  };
5336
5017
  //#endregion
5018
+ //#region ../../src/cli/core/commands/pack.ts
5019
+ /**
5020
+ * Pack the workspace into a deployable `tar.gz`.
5021
+ *
5022
+ * The tar contains everything a remote runner (Alepha Rocket, or any
5023
+ * `alepha platform <op> --prebuilt` consumer) needs to deploy the app:
5024
+ *
5025
+ * dist/ pre-built output (incl. manifest.json)
5026
+ * migrations/ SQL files (if present)
5027
+ *
5028
+ * No source, no `alepha.config.ts`, no `package.json` — the deploy
5029
+ * side reads everything from `dist/manifest.json` and never touches
5030
+ * source. Excludes: `node_modules`, `.DS_Store`, macOS AppleDouble
5031
+ * (`._*`), `.alepha` build cache, `e2e`, `playwright-report`,
5032
+ * `coverage`.
5033
+ *
5034
+ * Output name: `<project-name>-<tag>.tar.gz` (default tag
5035
+ * "latest"). Project name comes from `package.json.name`. Naming
5036
+ * mirrors Docker tags — same artifact, different tag = different
5037
+ * file.
5038
+ */
5039
+ var PackCommand = class {
5040
+ log = $logger();
5041
+ fs = $inject(FileSystemProvider);
5042
+ shell = $inject(ShellProvider);
5043
+ pack = $command({
5044
+ name: "pack",
5045
+ description: "Pack the workspace into a deployable tar.gz (for `alepha platform --prebuilt` consumers like Alepha Rocket).",
5046
+ flags: t.object({
5047
+ tag: t.optional(t.text({
5048
+ aliases: ["t"],
5049
+ description: "Tag suffix for the artifact name (Docker-style). Defaults to `latest` → `<project>-latest.tar.gz`. Pass a real version like `0.0.2` for a pinned artifact."
5050
+ })),
5051
+ output: t.optional(t.text({
5052
+ aliases: ["o"],
5053
+ description: "Output directory for the tar.gz (default: current dir)."
5054
+ }))
5055
+ }),
5056
+ handler: async ({ flags, root, run }) => {
5057
+ const pkgPath = this.fs.join(root, "package.json");
5058
+ let project;
5059
+ try {
5060
+ const pkg = await this.fs.readJsonFile(pkgPath);
5061
+ if (!pkg.name) throw new AlephaError("Missing \"name\" in package.json — `alepha pack` needs it for the artifact filename.");
5062
+ project = pkg.name;
5063
+ } catch (err) {
5064
+ if (err instanceof AlephaError) throw err;
5065
+ throw new AlephaError(`Could not read package.json at ${pkgPath}. Run \`alepha pack\` from a workspace directory.`);
5066
+ }
5067
+ const tag = flags.tag ?? "latest";
5068
+ const outputDir = flags.output ?? root;
5069
+ const filename = `${project}-${tag}.tar.gz`;
5070
+ const outputPath = this.fs.join(outputDir, filename);
5071
+ const candidates = ["dist", "migrations"];
5072
+ const includes = [];
5073
+ for (const candidate of candidates) if (await this.fs.exists(this.fs.join(root, candidate))) includes.push(candidate);
5074
+ if (!includes.includes("dist")) throw new AlephaError("dist/ missing — run `alepha build --target=cloudflare` before `alepha pack`.");
5075
+ const manifestPath = this.fs.join(root, "dist", "manifest.json");
5076
+ if (!await this.fs.exists(manifestPath)) throw new AlephaError(`dist/manifest.json missing — required for prebuilt deploys. Rebuild with the current alepha version (\`alepha build --target=cloudflare\`).`);
5077
+ const cmd = `sh -c "COPYFILE_DISABLE=1 ${`tar -czf '${outputPath}' ${[
5078
+ "node_modules",
5079
+ ".DS_Store",
5080
+ "._*",
5081
+ ".alepha",
5082
+ "e2e",
5083
+ "playwright-report",
5084
+ "test-results",
5085
+ "coverage"
5086
+ ].map((p) => `--exclude='${p}'`).join(" ")} ${includes.map((p) => `'${p}'`).join(" ")}`}"`;
5087
+ await run({
5088
+ name: `pack → ${filename}`,
5089
+ handler: async () => {
5090
+ await this.shell.run(cmd, { root });
5091
+ }
5092
+ });
5093
+ this.log.info(`Packed ${filename} → ${outputPath}`);
5094
+ }
5095
+ });
5096
+ };
5097
+ //#endregion
5337
5098
  //#region ../../src/cli/core/commands/root.ts
5338
5099
  var RootCommand = class {
5339
5100
  log = $logger();
@@ -5497,6 +5258,7 @@ const AlephaCli = $module({
5497
5258
  DevCommand,
5498
5259
  InitCommand,
5499
5260
  LintCommand,
5261
+ PackCommand,
5500
5262
  RootCommand,
5501
5263
  TestCommand,
5502
5264
  TypecheckCommand,
@@ -5515,6 +5277,6 @@ const AlephaCli = $module({
5515
5277
  ]
5516
5278
  });
5517
5279
  //#endregion
5518
- export { AlephaCli, AlephaCliExtensionProvider, AlephaCliServices, AlephaCliUtils, AppEntryProvider, BuildAssetsTask, BuildClientTask, BuildCloudflareTask, BuildCommand, BuildCompressTask, BuildDockerTask, BuildPrerenderTask, BuildServerTask, BuildSitemapTask, BuildStaticTask, BuildTask, BuildVercelTask, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DevCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, OpenApiCommand, PackageManagerUtils, ProjectScaffolder, RootCommand, TestCommand, TypecheckCommand, VerifyCommand, ViteBuildProvider, ViteDevServerProvider, ViteUtils, alephaPackageJson, appEntryOptions, buildOptions, changelogOptions, devOptions, version };
5280
+ export { AlephaCli, AlephaCliExtensionProvider, AlephaCliServices, AlephaCliUtils, AppEntryProvider, BuildAssetsTask, BuildClientTask, BuildCloudflareTask, BuildCommand, BuildCompressTask, BuildDockerTask, BuildPrerenderTask, BuildServerTask, BuildSitemapTask, BuildStaticTask, BuildTask, BuildVercelTask, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DevCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, OpenApiCommand, PackCommand, PackageManagerUtils, ProjectScaffolder, RootCommand, TestCommand, TypecheckCommand, VerifyCommand, ViteBuildProvider, ViteDevServerProvider, ViteUtils, alephaPackageJson, appEntryOptions, buildOptions, changelogOptions, devOptions, version };
5519
5281
 
5520
5282
  //# sourceMappingURL=index.js.map