alepha 0.20.2 → 0.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) 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.d.ts.map +1 -1
  7. package/dist/api/audits/index.js +49 -0
  8. package/dist/api/audits/index.js.map +1 -1
  9. package/dist/api/files/index.d.ts.map +1 -1
  10. package/dist/api/files/index.js.map +1 -1
  11. package/dist/api/jobs/index.d.ts +16 -75
  12. package/dist/api/jobs/index.d.ts.map +1 -1
  13. package/dist/api/jobs/index.js.map +1 -1
  14. package/dist/api/keys/index.js.map +1 -1
  15. package/dist/api/notifications/index.d.ts +1 -10
  16. package/dist/api/notifications/index.d.ts.map +1 -1
  17. package/dist/api/organizations/index.d.ts.map +1 -1
  18. package/dist/api/parameters/index.browser.js +37 -0
  19. package/dist/api/parameters/index.browser.js.map +1 -1
  20. package/dist/api/parameters/index.d.ts +4 -65
  21. package/dist/api/parameters/index.d.ts.map +1 -1
  22. package/dist/api/parameters/index.js +37 -0
  23. package/dist/api/parameters/index.js.map +1 -1
  24. package/dist/api/payments/index.d.ts.map +1 -1
  25. package/dist/api/payments/index.js.map +1 -1
  26. package/dist/api/users/index.d.ts +207 -5184
  27. package/dist/api/users/index.d.ts.map +1 -1
  28. package/dist/api/users/index.js +2 -4
  29. package/dist/api/users/index.js.map +1 -1
  30. package/dist/api/verifications/index.d.ts.map +1 -1
  31. package/dist/api/verifications/index.js +2 -1
  32. package/dist/api/verifications/index.js.map +1 -1
  33. package/dist/bucket/index.js +5 -1
  34. package/dist/bucket/index.js.map +1 -1
  35. package/dist/bucket/index.workerd.js +5 -1
  36. package/dist/bucket/index.workerd.js.map +1 -1
  37. package/dist/cache/core/index.js.map +1 -1
  38. package/dist/cache/core/index.workerd.js.map +1 -1
  39. package/dist/captcha/index.js.map +1 -1
  40. package/dist/cli/core/index.d.ts +217 -11647
  41. package/dist/cli/core/index.d.ts.map +1 -1
  42. package/dist/cli/core/index.js +706 -42
  43. package/dist/cli/core/index.js.map +1 -1
  44. package/dist/cli/devtools/index.js +7 -1
  45. package/dist/cli/devtools/index.js.map +1 -1
  46. package/dist/cli/platform/index.d.ts +41 -64
  47. package/dist/cli/platform/index.d.ts.map +1 -1
  48. package/dist/cli/platform/index.js +47 -0
  49. package/dist/cli/platform/index.js.map +1 -1
  50. package/dist/cli/vendor/index.js +15 -0
  51. package/dist/cli/vendor/index.js.map +1 -1
  52. package/dist/command/index.js +1 -1
  53. package/dist/command/index.js.map +1 -1
  54. package/dist/core/index.browser.js.map +1 -1
  55. package/dist/core/index.d.ts +2 -8
  56. package/dist/core/index.d.ts.map +1 -1
  57. package/dist/core/index.js.map +1 -1
  58. package/dist/core/index.native.js.map +1 -1
  59. package/dist/core/index.workerd.js.map +1 -1
  60. package/dist/crypto/index.js.map +1 -1
  61. package/dist/datetime/index.js.map +1 -1
  62. package/dist/email/core/index.js.map +1 -1
  63. package/dist/email/smtp/index.js +2 -10522
  64. package/dist/email/smtp/index.js.map +1 -1
  65. package/dist/fake/index.d.ts +4 -8085
  66. package/dist/fake/index.d.ts.map +1 -1
  67. package/dist/fake/index.js +3 -33554
  68. package/dist/fake/index.js.map +1 -1
  69. package/dist/lock/core/index.js.map +1 -1
  70. package/dist/lock/redis/index.js.map +1 -1
  71. package/dist/logger/index.js +32 -1
  72. package/dist/logger/index.js.map +1 -1
  73. package/dist/mcp/index.js +5 -1
  74. package/dist/mcp/index.js.map +1 -1
  75. package/dist/orm/core/index.browser.js +1 -361
  76. package/dist/orm/core/index.browser.js.map +1 -1
  77. package/dist/orm/core/index.bun.js +14 -406
  78. package/dist/orm/core/index.bun.js.map +1 -1
  79. package/dist/orm/core/index.d.ts +96 -5117
  80. package/dist/orm/core/index.d.ts.map +1 -1
  81. package/dist/orm/core/index.js +23 -419
  82. package/dist/orm/core/index.js.map +1 -1
  83. package/dist/orm/postgres/index.bun.js +17 -20
  84. package/dist/orm/postgres/index.bun.js.map +1 -1
  85. package/dist/orm/postgres/index.d.ts +2 -613
  86. package/dist/orm/postgres/index.d.ts.map +1 -1
  87. package/dist/orm/postgres/index.js +17 -20
  88. package/dist/orm/postgres/index.js.map +1 -1
  89. package/dist/react/core/index.js.map +1 -1
  90. package/dist/react/i18n/index.js.map +1 -1
  91. package/dist/react/intro/index.js +22 -17
  92. package/dist/react/intro/index.js.map +1 -1
  93. package/dist/react/router/index.browser.js +78 -2
  94. package/dist/react/router/index.browser.js.map +1 -1
  95. package/dist/react/router/index.d.ts +22 -1
  96. package/dist/react/router/index.d.ts.map +1 -1
  97. package/dist/react/router/index.js +102 -4
  98. package/dist/react/router/index.js.map +1 -1
  99. package/dist/react/testing/index.d.ts +1 -411
  100. package/dist/react/testing/index.d.ts.map +1 -1
  101. package/dist/react/testing/index.js +13 -12293
  102. package/dist/react/testing/index.js.map +1 -1
  103. package/dist/react/ui/index.js +3 -0
  104. package/dist/react/ui/index.js.map +1 -1
  105. package/dist/react/websocket/index.js.map +1 -1
  106. package/dist/redis/index.js.map +1 -1
  107. package/dist/scheduler/index.d.ts +1 -83
  108. package/dist/scheduler/index.d.ts.map +1 -1
  109. package/dist/scheduler/index.js +2 -391
  110. package/dist/scheduler/index.js.map +1 -1
  111. package/dist/scheduler/index.workerd.js +2 -391
  112. package/dist/scheduler/index.workerd.js.map +1 -1
  113. package/dist/security/index.browser.js.map +1 -1
  114. package/dist/security/index.d.ts +2 -325
  115. package/dist/security/index.d.ts.map +1 -1
  116. package/dist/security/index.js +3 -1362
  117. package/dist/security/index.js.map +1 -1
  118. package/dist/server/auth/index.d.ts +1 -1054
  119. package/dist/server/auth/index.d.ts.map +1 -1
  120. package/dist/server/auth/index.js +16 -1224
  121. package/dist/server/auth/index.js.map +1 -1
  122. package/dist/server/cookies/index.js.map +1 -1
  123. package/dist/server/core/index.browser.js.map +1 -1
  124. package/dist/server/core/index.d.ts +1 -4
  125. package/dist/server/core/index.d.ts.map +1 -1
  126. package/dist/server/core/index.js +19 -4
  127. package/dist/server/core/index.js.map +1 -1
  128. package/dist/server/links/index.browser.js.map +1 -1
  129. package/dist/server/links/index.js.map +1 -1
  130. package/dist/server/metrics/index.d.ts +1 -514
  131. package/dist/server/metrics/index.d.ts.map +1 -1
  132. package/dist/server/metrics/index.js +4 -4356
  133. package/dist/server/metrics/index.js.map +1 -1
  134. package/dist/server/rate-limit/index.js.map +1 -1
  135. package/dist/server/static/index.js.map +1 -1
  136. package/dist/server/swagger/index.js +1 -1
  137. package/dist/server/swagger/index.js.map +1 -1
  138. package/dist/sms/index.js.map +1 -1
  139. package/dist/system/index.browser.js.map +1 -1
  140. package/dist/system/index.js.map +1 -1
  141. package/dist/system/index.workerd.js.map +1 -1
  142. package/dist/topic/core/index.js.map +1 -1
  143. package/dist/websocket/index.browser.js +21 -0
  144. package/dist/websocket/index.browser.js.map +1 -1
  145. package/dist/websocket/index.js +21 -0
  146. package/dist/websocket/index.js.map +1 -1
  147. package/package.json +18 -15
  148. package/src/api/files/__tests__/FileController.spec.ts +1 -1
  149. package/src/api/jobs/__tests__/$job.spec.ts +5 -1
  150. package/src/api/users/schemas/userQuerySchema.ts +0 -1
  151. package/src/api/users/services/UserService.ts +1 -5
  152. package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
  153. package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
  154. package/src/api/verifications/services/VerificationService.ts +1 -0
  155. package/src/cli/core/__tests__/init.spec.ts +208 -0
  156. package/src/cli/core/commands/init.ts +12 -0
  157. package/src/cli/core/services/PackageManagerUtils.ts +23 -6
  158. package/src/cli/core/services/ProjectScaffolder.ts +298 -20
  159. package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
  160. package/src/cli/core/tasks/BuildServerTask.ts +8 -0
  161. package/src/cli/core/templates/apiIndexTs.ts +23 -1
  162. package/src/cli/core/templates/componentsJsonTs.ts +39 -0
  163. package/src/cli/core/templates/mainCss.ts +1 -0
  164. package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
  165. package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
  166. package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
  167. package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
  168. package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
  169. package/src/cli/core/templates/webAppRouterTs.ts +104 -1
  170. package/src/cli/core/templates/webIndexTs.ts +23 -1
  171. package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
  172. package/src/command/providers/CliProvider.ts +1 -1
  173. package/src/core/interfaces/Service.ts +3 -1
  174. package/src/core/providers/TypeProvider.ts +1 -1
  175. package/src/logger/services/Logger.ts +1 -1
  176. package/src/mcp/__tests__/$resource.spec.ts +1 -1
  177. package/src/mcp/__tests__/$tool.spec.ts +1 -1
  178. package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
  179. package/src/orm/__tests__/$repository-tests.ts +1 -0
  180. package/src/orm/__tests__/orm-next-tests.ts +2 -67
  181. package/src/orm/__tests__/orm-next.spec.ts +0 -21
  182. package/src/orm/core/index.shared.ts +0 -2
  183. package/src/orm/core/index.ts +1 -2
  184. package/src/orm/core/primitives/$repository.ts +3 -6
  185. package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
  186. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
  187. package/src/orm/core/services/ModelBuilder.ts +1 -13
  188. package/src/orm/core/services/Repository.ts +1 -42
  189. package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
  190. package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
  191. package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
  192. package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
  193. package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
  194. package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
  195. package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
  196. package/src/react/router/providers/ReactServerProvider.ts +1 -0
  197. package/src/scheduler/providers/CronProvider.ts +1 -1
  198. package/src/security/primitives/$basicAuth.ts +1 -1
  199. package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
  200. package/src/server/core/interfaces/ServerRequest.ts +1 -0
  201. package/src/server/core/providers/ServerProvider.ts +1 -1
  202. package/src/server/core/providers/ServerRouterProvider.ts +2 -2
  203. package/src/server/core/services/HttpClient.ts +1 -1
  204. package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
  205. package/dist/react/testing/chunk-DBEY4PJZ.js +0 -16
  206. package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
  207. package/src/orm/core/helpers/parseQueryString.ts +0 -502
  208. package/src/orm/core/primitives/$view.ts +0 -88
@@ -493,6 +493,214 @@ describe("alepha init", () => {
493
493
  });
494
494
  });
495
495
 
496
+ // ─────────────────────────────────────────────────────────────────────────────
497
+ // SaaS preset (--saas flag)
498
+ // ─────────────────────────────────────────────────────────────────────────────
499
+
500
+ describe("--saas flag", () => {
501
+ it("should imply --shadcn / --tailwind / --react / --api", async () => {
502
+ const { fs, cli, cmd, json } = createTestEnv();
503
+ await setupProject(fs, json);
504
+
505
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
506
+
507
+ // shadcn → components.json + main.css uses tailwind
508
+ expect(fs.wasWritten("/project/components.json")).toBe(true);
509
+ expect(
510
+ fs.wasWrittenMatching("/project/src/main.css", /@import "tailwindcss"/),
511
+ ).toBe(true);
512
+ // tailwind → vite.config.ts
513
+ expect(fs.wasWritten("/project/vite.config.ts")).toBe(true);
514
+ // react → web/ tree
515
+ expect(fs.wasWritten("/project/src/web/AppRouter.ts")).toBe(true);
516
+ expect(fs.wasWritten("/project/src/main.browser.ts")).toBe(true);
517
+ // api → api/ tree
518
+ expect(fs.wasWritten("/project/src/api/index.ts")).toBe(true);
519
+ });
520
+
521
+ it("should wire AlephaApiUsers into api/index.ts", async () => {
522
+ const { fs, cli, cmd, json } = createTestEnv();
523
+ await setupProject(fs, json);
524
+
525
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
526
+
527
+ expect(
528
+ fs.wasWrittenMatching("/project/src/api/index.ts", /AlephaApiUsers/),
529
+ ).toBe(true);
530
+ expect(
531
+ fs.wasWrittenMatching(
532
+ "/project/src/api/index.ts",
533
+ /imports:\s*\[AlephaApiUsers\]/,
534
+ ),
535
+ ).toBe(true);
536
+ });
537
+
538
+ it("should scaffold src/api/providers/RealmProvider.ts with $realm", async () => {
539
+ const { fs, cli, cmd, json } = createTestEnv();
540
+ await setupProject(fs, json);
541
+
542
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
543
+
544
+ expect(fs.wasWritten("/project/src/api/providers/RealmProvider.ts")).toBe(
545
+ true,
546
+ );
547
+ expect(
548
+ fs.wasWrittenMatching(
549
+ "/project/src/api/providers/RealmProvider.ts",
550
+ /\$realm\(/,
551
+ ),
552
+ ).toBe(true);
553
+ expect(
554
+ fs.wasWrittenMatching(
555
+ "/project/src/api/providers/RealmProvider.ts",
556
+ /adminEmails:/,
557
+ ),
558
+ ).toBe(true);
559
+ expect(
560
+ fs.wasWrittenMatching(
561
+ "/project/src/api/providers/RealmProvider.ts",
562
+ /\$permission\(\s*\{[\s\S]*group:\s*"admin"[\s\S]*name:\s*"ui"/,
563
+ ),
564
+ ).toBe(true);
565
+ });
566
+
567
+ it("should register RealmProvider in the API module", async () => {
568
+ const { fs, cli, cmd, json } = createTestEnv();
569
+ await setupProject(fs, json);
570
+
571
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
572
+
573
+ expect(
574
+ fs.wasWrittenMatching(
575
+ "/project/src/api/index.ts",
576
+ /services:\s*\[HelloController,\s*RealmProvider\]/,
577
+ ),
578
+ ).toBe(true);
579
+ });
580
+
581
+ it("should scaffold auth pages + AuthLayout", async () => {
582
+ const { fs, cli, cmd, json } = createTestEnv();
583
+ await setupProject(fs, json);
584
+
585
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
586
+
587
+ expect(
588
+ fs.wasWritten("/project/src/web/components/auth/AuthLayout.tsx"),
589
+ ).toBe(true);
590
+ expect(fs.wasWritten("/project/src/web/components/auth/Login.tsx")).toBe(
591
+ true,
592
+ );
593
+ expect(
594
+ fs.wasWritten("/project/src/web/components/auth/Register.tsx"),
595
+ ).toBe(true);
596
+ expect(
597
+ fs.wasWritten("/project/src/web/components/auth/ResetPassword.tsx"),
598
+ ).toBe(true);
599
+ expect(
600
+ fs.wasWritten("/project/src/web/components/auth/VerifyEmail.tsx"),
601
+ ).toBe(true);
602
+ });
603
+
604
+ it("should scaffold admin AppShell + admin pages", async () => {
605
+ const { fs, cli, cmd, json } = createTestEnv();
606
+ await setupProject(fs, json);
607
+
608
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
609
+
610
+ expect(
611
+ fs.wasWritten("/project/src/web/components/admin/AdminLayout.tsx"),
612
+ ).toBe(true);
613
+ expect(
614
+ fs.wasWrittenMatching(
615
+ "/project/src/web/components/admin/AdminLayout.tsx",
616
+ /AppShell/,
617
+ ),
618
+ ).toBe(true);
619
+ expect(fs.wasWritten("/project/src/web/components/admin/Users.tsx")).toBe(
620
+ true,
621
+ );
622
+ expect(
623
+ fs.wasWritten("/project/src/web/components/admin/Sessions.tsx"),
624
+ ).toBe(true);
625
+ });
626
+
627
+ it("should wire /auth and /admin routes into AppRouter", async () => {
628
+ const { fs, cli, cmd, json } = createTestEnv();
629
+ await setupProject(fs, json);
630
+
631
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
632
+
633
+ expect(
634
+ fs.wasWrittenMatching(
635
+ "/project/src/web/AppRouter.ts",
636
+ /authLayout\s*=\s*\$page/,
637
+ ),
638
+ ).toBe(true);
639
+ expect(
640
+ fs.wasWrittenMatching(
641
+ "/project/src/web/AppRouter.ts",
642
+ /adminLayout\s*=\s*\$page/,
643
+ ),
644
+ ).toBe(true);
645
+ expect(
646
+ fs.wasWrittenMatching(
647
+ "/project/src/web/AppRouter.ts",
648
+ /adminUsers\s*=\s*\$page/,
649
+ ),
650
+ ).toBe(true);
651
+ });
652
+
653
+ it("should default the shadcn preset to b0", async () => {
654
+ const { fs, shell, cli, cmd, json } = createTestEnv();
655
+ await setupProject(fs, json);
656
+
657
+ await cli.run(cmd.init, { argv: "--shadcn", root: "/project" });
658
+
659
+ expect(shell.wasCalledMatching(/shadcn\s+init.*--preset\s+b0\b/)).toBe(
660
+ true,
661
+ );
662
+ });
663
+
664
+ it("should let --shadcn <id> override the preset", async () => {
665
+ const { fs, shell, cli, cmd, json } = createTestEnv();
666
+ await setupProject(fs, json);
667
+
668
+ await cli.run(cmd.init, {
669
+ argv: "--shadcn bOgTgBE1b",
670
+ root: "/project",
671
+ });
672
+
673
+ expect(
674
+ shell.wasCalledMatching(/shadcn\s+init.*--preset\s+bOgTgBE1b\b/),
675
+ ).toBe(true);
676
+ });
677
+
678
+ it("should let --saas <id> override the preset", async () => {
679
+ const { fs, shell, cli, cmd, json } = createTestEnv();
680
+ await setupProject(fs, json);
681
+
682
+ await cli.run(cmd.init, {
683
+ argv: "--saas bOgTgBE1b",
684
+ root: "/project",
685
+ });
686
+
687
+ expect(
688
+ shell.wasCalledMatching(/shadcn\s+init.*--preset\s+bOgTgBE1b\b/),
689
+ ).toBe(true);
690
+ });
691
+
692
+ it("should add the @alepha/saas registry bundle in one shot", async () => {
693
+ const { fs, cli, cmd, shell, json } = createTestEnv();
694
+ await setupProject(fs, json);
695
+
696
+ await cli.run(cmd.init, { argv: "--saas", root: "/project" });
697
+
698
+ expect(shell.wasCalledMatching(/shadcn\s+add\s+@alepha\/saas/)).toBe(
699
+ true,
700
+ );
701
+ });
702
+ });
703
+
496
704
  // ─────────────────────────────────────────────────────────────────────────────
497
705
  // Non-empty directory guard (codegen flags)
498
706
  // ─────────────────────────────────────────────────────────────────────────────
@@ -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).