alepha 0.20.2 → 0.20.4

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 (304) hide show
  1. package/README.md +0 -1
  2. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  3. package/assets/swagger-ui/swagger-ui.css +1 -1
  4. package/dist/api/audits/index.browser.js +49 -0
  5. package/dist/api/audits/index.browser.js.map +1 -1
  6. package/dist/api/audits/index.js +49 -0
  7. package/dist/api/audits/index.js.map +1 -1
  8. package/dist/api/files/index.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts +2 -61
  10. package/dist/api/jobs/index.d.ts.map +1 -1
  11. package/dist/api/jobs/index.js.map +1 -1
  12. package/dist/api/keys/index.d.ts +4 -4
  13. package/dist/api/keys/index.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +1 -10
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/parameters/index.browser.js +37 -0
  17. package/dist/api/parameters/index.browser.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +12 -68
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/parameters/index.js +57 -4
  21. package/dist/api/parameters/index.js.map +1 -1
  22. package/dist/api/payments/index.js.map +1 -1
  23. package/dist/api/users/index.browser.js +6 -0
  24. package/dist/api/users/index.browser.js.map +1 -1
  25. package/dist/api/users/index.d.ts +148 -227
  26. package/dist/api/users/index.d.ts.map +1 -1
  27. package/dist/api/users/index.js +60 -14
  28. package/dist/api/users/index.js.map +1 -1
  29. package/dist/api/verifications/index.d.ts.map +1 -1
  30. package/dist/api/verifications/index.js +2 -1
  31. package/dist/api/verifications/index.js.map +1 -1
  32. package/dist/bucket/index.d.ts +77 -107
  33. package/dist/bucket/index.d.ts.map +1 -1
  34. package/dist/bucket/index.js +153 -5
  35. package/dist/bucket/index.js.map +1 -1
  36. package/dist/bucket/index.workerd.js +12 -2
  37. package/dist/bucket/index.workerd.js.map +1 -1
  38. package/dist/cache/core/index.d.ts +26 -0
  39. package/dist/cache/core/index.d.ts.map +1 -1
  40. package/dist/cache/core/index.js +11 -1
  41. package/dist/cache/core/index.js.map +1 -1
  42. package/dist/cache/core/index.workerd.js +11 -1
  43. package/dist/cache/core/index.workerd.js.map +1 -1
  44. package/dist/captcha/index.js.map +1 -1
  45. package/dist/cli/config/index.d.ts +7 -5
  46. package/dist/cli/config/index.d.ts.map +1 -1
  47. package/dist/cli/config/index.js +2 -3
  48. package/dist/cli/config/index.js.map +1 -1
  49. package/dist/cli/core/index.d.ts +637 -11660
  50. package/dist/cli/core/index.d.ts.map +1 -1
  51. package/dist/cli/core/index.js +707 -532
  52. package/dist/cli/core/index.js.map +1 -1
  53. package/dist/cli/devtools/index.d.ts +4 -8
  54. package/dist/cli/devtools/index.d.ts.map +1 -1
  55. package/dist/cli/devtools/index.js +20 -16
  56. package/dist/cli/devtools/index.js.map +1 -1
  57. package/dist/cli/platform/index.d.ts +51 -77
  58. package/dist/cli/platform/index.d.ts.map +1 -1
  59. package/dist/cli/platform/index.js +65 -15
  60. package/dist/cli/platform/index.js.map +1 -1
  61. package/dist/cli/vendor/index.d.ts +10 -13
  62. package/dist/cli/vendor/index.d.ts.map +1 -1
  63. package/dist/cli/vendor/index.js +30 -12
  64. package/dist/cli/vendor/index.js.map +1 -1
  65. package/dist/command/index.js +1 -1
  66. package/dist/command/index.js.map +1 -1
  67. package/dist/core/index.browser.js +27 -3
  68. package/dist/core/index.browser.js.map +1 -1
  69. package/dist/core/index.d.ts +8 -11
  70. package/dist/core/index.d.ts.map +1 -1
  71. package/dist/core/index.js +27 -3
  72. package/dist/core/index.js.map +1 -1
  73. package/dist/core/index.native.js +27 -3
  74. package/dist/core/index.native.js.map +1 -1
  75. package/dist/core/index.workerd.js +27 -3
  76. package/dist/core/index.workerd.js.map +1 -1
  77. package/dist/crypto/index.js.map +1 -1
  78. package/dist/datetime/index.d.ts +69 -10
  79. package/dist/datetime/index.d.ts.map +1 -1
  80. package/dist/datetime/index.js +135 -13
  81. package/dist/datetime/index.js.map +1 -1
  82. package/dist/email/core/index.js.map +1 -1
  83. package/dist/email/smtp/index.js +130 -16
  84. package/dist/email/smtp/index.js.map +1 -1
  85. package/dist/fake/index.js.map +1 -1
  86. package/dist/lock/core/index.d.ts +30 -2
  87. package/dist/lock/core/index.d.ts.map +1 -1
  88. package/dist/lock/core/index.js +35 -12
  89. package/dist/lock/core/index.js.map +1 -1
  90. package/dist/lock/redis/index.js.map +1 -1
  91. package/dist/logger/index.js +32 -1
  92. package/dist/logger/index.js.map +1 -1
  93. package/dist/mcp/index.d.ts +238 -31
  94. package/dist/mcp/index.d.ts.map +1 -1
  95. package/dist/mcp/index.js +198 -67
  96. package/dist/mcp/index.js.map +1 -1
  97. package/dist/orm/core/index.browser.js +2 -362
  98. package/dist/orm/core/index.browser.js.map +1 -1
  99. package/dist/orm/core/index.bun.js +18 -409
  100. package/dist/orm/core/index.bun.js.map +1 -1
  101. package/dist/orm/core/index.d.ts +41 -194
  102. package/dist/orm/core/index.d.ts.map +1 -1
  103. package/dist/orm/core/index.js +27 -422
  104. package/dist/orm/core/index.js.map +1 -1
  105. package/dist/orm/postgres/index.bun.js +17 -20
  106. package/dist/orm/postgres/index.bun.js.map +1 -1
  107. package/dist/orm/postgres/index.d.ts +1 -5
  108. package/dist/orm/postgres/index.d.ts.map +1 -1
  109. package/dist/orm/postgres/index.js +17 -20
  110. package/dist/orm/postgres/index.js.map +1 -1
  111. package/dist/react/core/index.d.ts +102 -1
  112. package/dist/react/core/index.d.ts.map +1 -1
  113. package/dist/react/core/index.js +65 -1
  114. package/dist/react/core/index.js.map +1 -1
  115. package/dist/react/form/index.d.ts +6 -0
  116. package/dist/react/form/index.d.ts.map +1 -1
  117. package/dist/react/form/index.js +7 -7
  118. package/dist/react/form/index.js.map +1 -1
  119. package/dist/react/i18n/index.d.ts +7 -1
  120. package/dist/react/i18n/index.d.ts.map +1 -1
  121. package/dist/react/i18n/index.js +6 -0
  122. package/dist/react/i18n/index.js.map +1 -1
  123. package/dist/react/intro/index.js +22 -17
  124. package/dist/react/intro/index.js.map +1 -1
  125. package/dist/react/router/index.browser.js +98 -4
  126. package/dist/react/router/index.browser.js.map +1 -1
  127. package/dist/react/router/index.d.ts +58 -5
  128. package/dist/react/router/index.d.ts.map +1 -1
  129. package/dist/react/router/index.js +122 -6
  130. package/dist/react/router/index.js.map +1 -1
  131. package/dist/react/testing/{chunk-DBEY4PJZ.js → chunk-6Ep1yQYe.js} +1 -1
  132. package/dist/react/testing/index.js +1 -1
  133. package/dist/react/testing/index.js.map +1 -1
  134. package/dist/react/ui/index.d.ts +195 -1
  135. package/dist/react/ui/index.d.ts.map +1 -1
  136. package/dist/react/ui/index.js +64 -1
  137. package/dist/react/ui/index.js.map +1 -1
  138. package/dist/react/websocket/index.js.map +1 -1
  139. package/dist/redis/index.js.map +1 -1
  140. package/dist/scheduler/index.d.ts +1 -2
  141. package/dist/scheduler/index.d.ts.map +1 -1
  142. package/dist/scheduler/index.js +1 -1
  143. package/dist/scheduler/index.js.map +1 -1
  144. package/dist/scheduler/index.workerd.js +1 -1
  145. package/dist/scheduler/index.workerd.js.map +1 -1
  146. package/dist/security/index.browser.js.map +1 -1
  147. package/dist/security/index.d.ts.map +1 -1
  148. package/dist/security/index.js +2 -2
  149. package/dist/security/index.js.map +1 -1
  150. package/dist/server/auth/index.d.ts.map +1 -1
  151. package/dist/server/auth/index.js +24 -10
  152. package/dist/server/auth/index.js.map +1 -1
  153. package/dist/server/cookies/index.js.map +1 -1
  154. package/dist/server/core/index.browser.js +10 -3
  155. package/dist/server/core/index.browser.js.map +1 -1
  156. package/dist/server/core/index.d.ts +1 -4
  157. package/dist/server/core/index.d.ts.map +1 -1
  158. package/dist/server/core/index.js +47 -9
  159. package/dist/server/core/index.js.map +1 -1
  160. package/dist/server/links/index.browser.js.map +1 -1
  161. package/dist/server/links/index.js.map +1 -1
  162. package/dist/server/metrics/index.js +19 -1
  163. package/dist/server/metrics/index.js.map +1 -1
  164. package/dist/server/rate-limit/index.js.map +1 -1
  165. package/dist/server/static/index.js.map +1 -1
  166. package/dist/server/swagger/index.d.ts.map +1 -1
  167. package/dist/server/swagger/index.js +4 -5
  168. package/dist/server/swagger/index.js.map +1 -1
  169. package/dist/sms/index.js.map +1 -1
  170. package/dist/system/index.browser.js.map +1 -1
  171. package/dist/system/index.js.map +1 -1
  172. package/dist/system/index.workerd.js.map +1 -1
  173. package/dist/topic/core/index.js.map +1 -1
  174. package/dist/websocket/index.browser.js +32 -5
  175. package/dist/websocket/index.browser.js.map +1 -1
  176. package/dist/websocket/index.d.ts +3 -1
  177. package/dist/websocket/index.d.ts.map +1 -1
  178. package/dist/websocket/index.js +42 -6
  179. package/dist/websocket/index.js.map +1 -1
  180. package/package.json +685 -274
  181. package/src/api/files/__tests__/FileController.spec.ts +1 -1
  182. package/src/api/jobs/__tests__/$job.spec.ts +5 -1
  183. package/src/api/parameters/services/ParameterProvider.ts +21 -4
  184. package/src/api/users/__tests__/SessionService.spec.ts +99 -0
  185. package/src/api/users/__tests__/UserJobs.spec.ts +67 -0
  186. package/src/api/users/atoms/realmAuthSettingsAtom.ts +15 -0
  187. package/src/api/users/entities/sessions.ts +6 -0
  188. package/src/api/users/jobs/UserJobs.ts +44 -17
  189. package/src/api/users/providers/RealmProvider.ts +4 -0
  190. package/src/api/users/schemas/userQuerySchema.ts +0 -1
  191. package/src/api/users/services/SessionService.ts +27 -0
  192. package/src/api/users/services/UserService.ts +1 -5
  193. package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
  194. package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
  195. package/src/api/verifications/services/VerificationService.ts +1 -0
  196. package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +74 -0
  197. package/src/bucket/index.ts +19 -2
  198. package/src/bucket/primitives/$bucket.ts +9 -1
  199. package/src/bucket/providers/CloudflareR2Provider.ts +2 -137
  200. package/src/bucket/providers/NodeS3BucketProvider.ts +218 -0
  201. package/src/cache/core/index.ts +29 -0
  202. package/src/cache/core/primitives/$cache.ts +14 -1
  203. package/src/cli/config/defineConfig.ts +13 -15
  204. package/src/cli/core/__tests__/init.spec.ts +214 -7
  205. package/src/cli/core/commands/init.ts +12 -0
  206. package/src/cli/core/services/PackageManagerUtils.ts +23 -6
  207. package/src/cli/core/services/ProjectScaffolder.ts +315 -33
  208. package/src/cli/core/tasks/BuildCloudflareTask.ts +5 -0
  209. package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
  210. package/src/cli/core/tasks/BuildServerTask.ts +8 -0
  211. package/src/cli/core/templates/agentMd.ts +2 -10
  212. package/src/cli/core/templates/apiIndexTs.ts +23 -1
  213. package/src/cli/core/templates/componentsJsonTs.ts +39 -0
  214. package/src/cli/core/templates/mainCss.ts +1 -0
  215. package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
  216. package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
  217. package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
  218. package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
  219. package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
  220. package/src/cli/core/templates/webAppRouterTs.ts +104 -1
  221. package/src/cli/core/templates/webIndexTs.ts +23 -1
  222. package/src/cli/devtools/index.ts +12 -26
  223. package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
  224. package/src/cli/platform/index.ts +15 -24
  225. package/src/cli/vendor/atoms/vendorOptions.ts +1 -1
  226. package/src/cli/vendor/index.ts +14 -23
  227. package/src/command/providers/CliProvider.ts +1 -1
  228. package/src/core/Alepha.ts +11 -1
  229. package/src/core/helpers/ref.ts +18 -0
  230. package/src/core/index.shared.ts +1 -0
  231. package/src/core/interfaces/Service.ts +3 -1
  232. package/src/core/providers/SchemaValidator.ts +9 -1
  233. package/src/core/providers/TypeProvider.ts +2 -3
  234. package/src/datetime/REFACTORING.md +118 -0
  235. package/src/datetime/providers/DateTimeProvider.ts +203 -24
  236. package/src/lock/core/index.ts +31 -0
  237. package/src/lock/core/primitives/$lock.ts +14 -1
  238. package/src/logger/services/Logger.ts +1 -1
  239. package/src/mcp/__tests__/$resource.spec.ts +1 -1
  240. package/src/mcp/__tests__/$tool.spec.ts +1 -1
  241. package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
  242. package/src/mcp/__tests__/jsonrpc.spec.ts +1 -1
  243. package/src/mcp/helpers/jsonrpc.ts +26 -1
  244. package/src/mcp/index.ts +10 -5
  245. package/src/mcp/interfaces/McpTypes.ts +83 -6
  246. package/src/mcp/primitives/$prompt.ts +18 -1
  247. package/src/mcp/primitives/$resource.ts +18 -1
  248. package/src/mcp/primitives/$tool.ts +83 -7
  249. package/src/mcp/providers/McpServerProvider.ts +74 -16
  250. package/src/mcp/transports/StreamableHttpMcpTransport.ts +226 -0
  251. package/src/orm/REFACTORING.md +330 -0
  252. package/src/orm/__tests__/$repository-tests.ts +1 -0
  253. package/src/orm/__tests__/orm-next-tests.ts +2 -67
  254. package/src/orm/__tests__/orm-next.spec.ts +0 -21
  255. package/src/orm/core/index.shared.ts +0 -2
  256. package/src/orm/core/index.ts +1 -2
  257. package/src/orm/core/primitives/$repository.ts +3 -6
  258. package/src/orm/core/primitives/$transactional.ts +11 -0
  259. package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
  260. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
  261. package/src/orm/core/schemas/updateSchema.ts +1 -1
  262. package/src/orm/core/services/ModelBuilder.ts +1 -13
  263. package/src/orm/core/services/PgRelationManager.ts +4 -2
  264. package/src/orm/core/services/Repository.ts +1 -42
  265. package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
  266. package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
  267. package/src/react/core/__tests__/useQuery.browser.spec.tsx +86 -0
  268. package/src/react/core/hooks/useQuery.ts +153 -0
  269. package/src/react/core/index.ts +1 -0
  270. package/src/react/form/services/FormModel.ts +15 -6
  271. package/src/react/form/services/parseField.ts +8 -0
  272. package/src/react/i18n/providers/I18nProvider.ts +8 -2
  273. package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
  274. package/src/react/router/__tests__/$page.spec.tsx +0 -16
  275. package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
  276. package/src/react/router/__tests__/ssr.spec.tsx +339 -0
  277. package/src/react/router/primitives/$page.ts +28 -4
  278. package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
  279. package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
  280. package/src/react/router/providers/ReactPageProvider.ts +27 -9
  281. package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
  282. package/src/react/router/providers/ReactServerProvider.ts +1 -0
  283. package/src/react/ui/atoms/uiThemeListAtom.ts +36 -0
  284. package/src/react/ui/index.ts +6 -0
  285. package/src/react/ui/services/SchemaControl.ts +209 -0
  286. package/src/scheduler/providers/CronProvider.ts +1 -1
  287. package/src/security/primitives/$basicAuth.ts +1 -1
  288. package/src/security/primitives/$issuer.ts +6 -3
  289. package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
  290. package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +75 -0
  291. package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +306 -0
  292. package/src/server/core/errors/ValidationError.ts +13 -1
  293. package/src/server/core/interfaces/ServerRequest.ts +1 -0
  294. package/src/server/core/primitives/$action.ts +16 -5
  295. package/src/server/core/providers/ServerProvider.ts +1 -1
  296. package/src/server/core/providers/ServerRouterProvider.ts +28 -6
  297. package/src/server/core/services/HttpClient.ts +1 -1
  298. package/src/server/swagger/providers/ServerSwaggerProvider.ts +6 -8
  299. package/src/websocket/providers/NodeWebSocketServerProvider.ts +10 -4
  300. package/src/websocket/services/WebSocketClient.ts +11 -5
  301. package/src/mcp/transports/SseMcpTransport.ts +0 -182
  302. package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
  303. package/src/orm/core/helpers/parseQueryString.ts +0 -502
  304. package/src/orm/core/primitives/$view.ts +0 -88
@@ -98,25 +98,24 @@ describe("alepha init", () => {
98
98
  // ─────────────────────────────────────────────────────────────────────────────
99
99
 
100
100
  describe("AI agent files", () => {
101
- it("should create CLAUDE.md when claude CLI is installed", async () => {
102
- const { fs, shell, cli, cmd, json } = createTestEnv();
101
+ it("should create both AGENTS.md and CLAUDE.md", async () => {
102
+ const { fs, cli, cmd, json } = createTestEnv();
103
103
  await setupProject(fs, json);
104
- shell.installedCommands.add("claude");
105
104
 
106
105
  await cli.run(cmd.init, { root: "/project" });
107
106
 
107
+ expect(fs.wasWritten("/project/AGENTS.md")).toBe(true);
108
108
  expect(fs.wasWritten("/project/CLAUDE.md")).toBe(true);
109
- expect(fs.wasWritten("/project/AGENTS.md")).toBe(false);
110
109
  });
111
110
 
112
- it("should create AGENTS.md when claude CLI is not installed", async () => {
111
+ it("should write CLAUDE.md as a stub importing AGENTS.md", async () => {
113
112
  const { fs, cli, cmd, json } = createTestEnv();
114
113
  await setupProject(fs, json);
115
114
 
116
115
  await cli.run(cmd.init, { root: "/project" });
117
116
 
118
- expect(fs.wasWritten("/project/AGENTS.md")).toBe(true);
119
- expect(fs.wasWritten("/project/CLAUDE.md")).toBe(false);
117
+ const claude = await fs.readTextFile("/project/CLAUDE.md");
118
+ expect(claude.trim()).toBe("@AGENTS.md");
120
119
  });
121
120
 
122
121
  it("should include Alepha instructions in agent file", async () => {
@@ -493,6 +492,214 @@ describe("alepha init", () => {
493
492
  });
494
493
  });
495
494
 
495
+ // ─────────────────────────────────────────────────────────────────────────────
496
+ // SaaS preset (--saas flag)
497
+ // ─────────────────────────────────────────────────────────────────────────────
498
+
499
+ describe("--saas flag", () => {
500
+ it("should imply --shadcn / --tailwind / --react / --api", async () => {
501
+ const { fs, cli, cmd, json } = createTestEnv();
502
+ await setupProject(fs, json);
503
+
504
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
505
+
506
+ // shadcn → components.json + main.css uses tailwind
507
+ expect(fs.wasWritten("/project/components.json")).toBe(true);
508
+ expect(
509
+ fs.wasWrittenMatching("/project/src/main.css", /@import "tailwindcss"/),
510
+ ).toBe(true);
511
+ // tailwind → vite.config.ts
512
+ expect(fs.wasWritten("/project/vite.config.ts")).toBe(true);
513
+ // react → web/ tree
514
+ expect(fs.wasWritten("/project/src/web/AppRouter.ts")).toBe(true);
515
+ expect(fs.wasWritten("/project/src/main.browser.ts")).toBe(true);
516
+ // api → api/ tree
517
+ expect(fs.wasWritten("/project/src/api/index.ts")).toBe(true);
518
+ });
519
+
520
+ it("should wire AlephaApiUsers into api/index.ts", async () => {
521
+ const { fs, cli, cmd, json } = createTestEnv();
522
+ await setupProject(fs, json);
523
+
524
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
525
+
526
+ expect(
527
+ fs.wasWrittenMatching("/project/src/api/index.ts", /AlephaApiUsers/),
528
+ ).toBe(true);
529
+ expect(
530
+ fs.wasWrittenMatching(
531
+ "/project/src/api/index.ts",
532
+ /imports:\s*\[AlephaApiUsers\]/,
533
+ ),
534
+ ).toBe(true);
535
+ });
536
+
537
+ it("should scaffold src/api/providers/RealmProvider.ts with $realm", async () => {
538
+ const { fs, cli, cmd, json } = createTestEnv();
539
+ await setupProject(fs, json);
540
+
541
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
542
+
543
+ expect(fs.wasWritten("/project/src/api/providers/RealmProvider.ts")).toBe(
544
+ true,
545
+ );
546
+ expect(
547
+ fs.wasWrittenMatching(
548
+ "/project/src/api/providers/RealmProvider.ts",
549
+ /\$realm\(/,
550
+ ),
551
+ ).toBe(true);
552
+ expect(
553
+ fs.wasWrittenMatching(
554
+ "/project/src/api/providers/RealmProvider.ts",
555
+ /adminEmails:/,
556
+ ),
557
+ ).toBe(true);
558
+ expect(
559
+ fs.wasWrittenMatching(
560
+ "/project/src/api/providers/RealmProvider.ts",
561
+ /\$permission\(\s*\{[\s\S]*group:\s*"admin"[\s\S]*name:\s*"ui"/,
562
+ ),
563
+ ).toBe(true);
564
+ });
565
+
566
+ it("should register RealmProvider in the API module", async () => {
567
+ const { fs, cli, cmd, json } = createTestEnv();
568
+ await setupProject(fs, json);
569
+
570
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
571
+
572
+ expect(
573
+ fs.wasWrittenMatching(
574
+ "/project/src/api/index.ts",
575
+ /services:\s*\[HelloController,\s*RealmProvider\]/,
576
+ ),
577
+ ).toBe(true);
578
+ });
579
+
580
+ it("should scaffold auth pages + AuthLayout", async () => {
581
+ const { fs, cli, cmd, json } = createTestEnv();
582
+ await setupProject(fs, json);
583
+
584
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
585
+
586
+ expect(
587
+ fs.wasWritten("/project/src/web/components/auth/AuthLayout.tsx"),
588
+ ).toBe(true);
589
+ expect(fs.wasWritten("/project/src/web/components/auth/Login.tsx")).toBe(
590
+ true,
591
+ );
592
+ expect(
593
+ fs.wasWritten("/project/src/web/components/auth/Register.tsx"),
594
+ ).toBe(true);
595
+ expect(
596
+ fs.wasWritten("/project/src/web/components/auth/ResetPassword.tsx"),
597
+ ).toBe(true);
598
+ expect(
599
+ fs.wasWritten("/project/src/web/components/auth/VerifyEmail.tsx"),
600
+ ).toBe(true);
601
+ });
602
+
603
+ it("should scaffold admin AppShell + admin pages", async () => {
604
+ const { fs, cli, cmd, json } = createTestEnv();
605
+ await setupProject(fs, json);
606
+
607
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
608
+
609
+ expect(
610
+ fs.wasWritten("/project/src/web/components/admin/AdminLayout.tsx"),
611
+ ).toBe(true);
612
+ expect(
613
+ fs.wasWrittenMatching(
614
+ "/project/src/web/components/admin/AdminLayout.tsx",
615
+ /AppShell/,
616
+ ),
617
+ ).toBe(true);
618
+ expect(fs.wasWritten("/project/src/web/components/admin/Users.tsx")).toBe(
619
+ true,
620
+ );
621
+ expect(
622
+ fs.wasWritten("/project/src/web/components/admin/Sessions.tsx"),
623
+ ).toBe(true);
624
+ });
625
+
626
+ it("should wire /auth and /admin routes into AppRouter", async () => {
627
+ const { fs, cli, cmd, json } = createTestEnv();
628
+ await setupProject(fs, json);
629
+
630
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
631
+
632
+ expect(
633
+ fs.wasWrittenMatching(
634
+ "/project/src/web/AppRouter.ts",
635
+ /authLayout\s*=\s*\$page/,
636
+ ),
637
+ ).toBe(true);
638
+ expect(
639
+ fs.wasWrittenMatching(
640
+ "/project/src/web/AppRouter.ts",
641
+ /adminLayout\s*=\s*\$page/,
642
+ ),
643
+ ).toBe(true);
644
+ expect(
645
+ fs.wasWrittenMatching(
646
+ "/project/src/web/AppRouter.ts",
647
+ /adminUsers\s*=\s*\$page/,
648
+ ),
649
+ ).toBe(true);
650
+ });
651
+
652
+ it("should default the shadcn preset to b0", async () => {
653
+ const { fs, shell, cli, cmd, json } = createTestEnv();
654
+ await setupProject(fs, json);
655
+
656
+ await cli.run(cmd.init, { argv: "--shadcn", root: "/project" });
657
+
658
+ expect(shell.wasCalledMatching(/shadcn\s+init.*--preset\s+b0\b/)).toBe(
659
+ true,
660
+ );
661
+ });
662
+
663
+ it("should let --shadcn <id> override the preset", async () => {
664
+ const { fs, shell, cli, cmd, json } = createTestEnv();
665
+ await setupProject(fs, json);
666
+
667
+ await cli.run(cmd.init, {
668
+ argv: "--shadcn bOgTgBE1b",
669
+ root: "/project",
670
+ });
671
+
672
+ expect(
673
+ shell.wasCalledMatching(/shadcn\s+init.*--preset\s+bOgTgBE1b\b/),
674
+ ).toBe(true);
675
+ });
676
+
677
+ it("should let --saas <id> override the preset", async () => {
678
+ const { fs, shell, cli, cmd, json } = createTestEnv();
679
+ await setupProject(fs, json);
680
+
681
+ await cli.run(cmd.init, {
682
+ argv: "--saas bOgTgBE1b",
683
+ root: "/project",
684
+ });
685
+
686
+ expect(
687
+ shell.wasCalledMatching(/shadcn\s+init.*--preset\s+bOgTgBE1b\b/),
688
+ ).toBe(true);
689
+ });
690
+
691
+ it("should add the @alepha/saas registry bundle in one shot", async () => {
692
+ const { fs, cli, cmd, shell, json } = createTestEnv();
693
+ await setupProject(fs, json);
694
+
695
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
696
+
697
+ expect(shell.wasCalledMatching(/shadcn\s+add\s+@alepha\/saas/)).toBe(
698
+ true,
699
+ );
700
+ });
701
+ });
702
+
496
703
  // ─────────────────────────────────────────────────────────────────────────────
497
704
  // Non-empty directory guard (codegen flags)
498
705
  // ─────────────────────────────────────────────────────────────────────────────
@@ -42,6 +42,18 @@ export class InitCommand {
42
42
  description: "Include Tailwind CSS with Vite plugin. Implies --react",
43
43
  }),
44
44
  ),
45
+ shadcn: t.optional(
46
+ t.union([t.boolean(), t.text()], {
47
+ description:
48
+ "Set up shadcn/ui (components.json, cn helper, theme tokens, alepha registry). Pass an optional preset id (default: b0). Implies --react and --tailwind",
49
+ }),
50
+ ),
51
+ saas: t.optional(
52
+ t.union([t.boolean(), t.text()], {
53
+ description:
54
+ "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",
55
+ }),
56
+ ),
45
57
  test: t.optional(
46
58
  t.boolean({ description: "Include Vitest and create test directory" }),
47
59
  ),
@@ -297,7 +297,7 @@ export class PackageManagerUtils {
297
297
  public async removeYarn(root: string): Promise<void> {
298
298
  await this.removeFiles(root, [".yarn", ".yarnrc.yml", "yarn.lock"]);
299
299
  await this.editPackageJson(root, (pkg) => {
300
- delete pkg.packageManager;
300
+ pkg.packageManager = undefined;
301
301
  return pkg;
302
302
  });
303
303
  }
@@ -305,7 +305,7 @@ export class PackageManagerUtils {
305
305
  public async removePnpm(root: string): Promise<void> {
306
306
  await this.removeFiles(root, ["pnpm-lock.yaml", "pnpm-workspace.yaml"]);
307
307
  await this.editPackageJson(root, (pkg) => {
308
- delete pkg.packageManager;
308
+ pkg.packageManager = undefined;
309
309
  return pkg;
310
310
  });
311
311
  }
@@ -402,8 +402,9 @@ export class PackageManagerUtils {
402
402
  };
403
403
 
404
404
  // Only include drizzle-kit when the project uses a database.
405
- // React-only projects don't need it.
406
- if (!modes.react) {
405
+ // - React-only projects skip it (no ORM in scope).
406
+ // - SaaS pulls AlephaApiUsers which DOES need a DB → keep drizzle-kit.
407
+ if (!modes.react || modes.saas) {
407
408
  devDependencies["drizzle-kit"] = alephaDeps["drizzle-kit"];
408
409
  }
409
410
 
@@ -428,8 +429,18 @@ export class PackageManagerUtils {
428
429
  }
429
430
 
430
431
  if (modes.tailwind) {
431
- devDependencies.tailwindcss = "^4.2.0";
432
- devDependencies["@tailwindcss/vite"] = "^4.2.0";
432
+ devDependencies.tailwindcss = alephaDeps.tailwindcss;
433
+ devDependencies["@tailwindcss/vite"] = alephaDeps["@tailwindcss/vite"];
434
+ }
435
+
436
+ if (modes.shadcn) {
437
+ // Add `shadcn` CLI as a project devDep — `alepha init --shadcn` runs
438
+ // `yarn shadcn init` after install to scaffold components.json,
439
+ // theme tokens, cn() helper, and runtime deps (clsx, tailwind-merge,
440
+ // class-variance-authority, lucide-react, tw-animate-css). Keeping
441
+ // the CLI in the project lets users re-run `yarn shadcn add ...`
442
+ // without `npx`.
443
+ devDependencies.shadcn = alephaDeps.shadcn;
433
444
  }
434
445
 
435
446
  if (modes.react) {
@@ -463,6 +474,12 @@ export interface DependencyModes {
463
474
  react?: boolean;
464
475
  expo?: boolean;
465
476
  tailwind?: boolean;
477
+ shadcn?: boolean;
478
+ /**
479
+ * SaaS starter: implies `shadcn` + adds the alepha auth + admin registry
480
+ * components on top via `shadcn add @alepha/...`.
481
+ */
482
+ saas?: boolean;
466
483
  test?: boolean;
467
484
  /**
468
485
  * Skip biome/vitest when inside a workspace package (they're at root).