create-better-t-stack 2.36.3 → 2.37.0-canary.28c5b8e0

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 (112) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/index.d.ts +11 -5
  3. package/dist/index.js +1 -1
  4. package/dist/{src-CN1zi2A-.js → src-CzVr9ZoP.js} +285 -231
  5. package/package.json +1 -1
  6. package/templates/addons/ruler/.ruler/bts.md.hbs +2 -2
  7. package/templates/api/orpc/native/utils/orpc.ts.hbs +2 -2
  8. package/templates/api/orpc/server/base/src/lib/context.ts.hbs +10 -10
  9. package/templates/api/orpc/server/base/src/lib/orpc.ts.hbs +1 -1
  10. package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +2 -2
  11. package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +1 -1
  12. package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +1 -1
  13. package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +1 -1
  14. package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +1 -1
  15. package/templates/api/trpc/native/utils/trpc.ts.hbs +2 -2
  16. package/templates/api/trpc/server/base/src/lib/context.ts.hbs +10 -10
  17. package/templates/api/trpc/server/base/src/lib/trpc.ts.hbs +1 -1
  18. package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +2 -2
  19. package/templates/auth/clerk/convex/backend/convex/auth.config.ts.hbs +12 -0
  20. package/templates/auth/clerk/convex/backend/convex/privateData.ts.hbs +16 -0
  21. package/templates/auth/clerk/convex/native/base/app/(auth)/_layout.tsx.hbs +12 -0
  22. package/templates/auth/clerk/convex/native/base/app/(auth)/sign-in.tsx.hbs +67 -0
  23. package/templates/auth/clerk/convex/native/base/app/(auth)/sign-out.tsx.hbs +110 -0
  24. package/templates/auth/clerk/convex/native/base/components/sign-out-button.tsx.hbs +27 -0
  25. package/templates/auth/clerk/convex/web/react/next/src/app/dashboard/page.tsx.hbs +29 -0
  26. package/templates/auth/clerk/convex/web/react/next/src/middleware.ts.hbs +12 -0
  27. package/templates/auth/clerk/convex/web/react/react-router/src/routes/dashboard.tsx.hbs +32 -0
  28. package/templates/auth/clerk/convex/web/react/tanstack-router/src/routes/dashboard.tsx.hbs +37 -0
  29. package/templates/auth/clerk/convex/web/react/tanstack-start/src/routes/dashboard.tsx.hbs +37 -0
  30. package/templates/auth/clerk/convex/web/react/tanstack-start/src/server.ts.hbs +18 -0
  31. package/templates/backend/convex/packages/backend/package.json.hbs +1 -0
  32. package/templates/backend/server/elysia/src/index.ts.hbs +3 -3
  33. package/templates/backend/server/express/src/index.ts.hbs +6 -6
  34. package/templates/backend/server/fastify/src/index.ts.hbs +4 -4
  35. package/templates/backend/server/hono/src/index.ts.hbs +4 -4
  36. package/templates/backend/server/server-base/src/routers/index.ts.hbs +4 -4
  37. package/templates/deploy/alchemy/alchemy.run.ts.hbs +3 -18
  38. package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +35 -3
  39. package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +28 -0
  40. package/templates/frontend/native/nativewind/package.json.hbs +1 -0
  41. package/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs +32 -0
  42. package/templates/frontend/native/unistyles/app/_layout.tsx.hbs +35 -0
  43. package/templates/frontend/native/unistyles/package.json.hbs +1 -0
  44. package/templates/frontend/nuxt/app/components/Header.vue.hbs +3 -3
  45. package/templates/frontend/react/next/src/app/layout.tsx.hbs +23 -15
  46. package/templates/frontend/react/next/src/components/providers.tsx.hbs +12 -0
  47. package/templates/frontend/react/react-router/src/root.tsx.hbs +28 -1
  48. package/templates/frontend/react/tanstack-router/src/main.tsx.hbs +19 -1
  49. package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +8 -4
  50. package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +52 -5
  51. package/templates/frontend/react/web-base/src/components/header.tsx.hbs +3 -3
  52. package/templates/frontend/solid/src/components/header.tsx.hbs +3 -3
  53. package/templates/frontend/svelte/src/components/Header.svelte.hbs +3 -3
  54. package/templates/deploy/alchemy/wrangler.jsonc.hbs +0 -11
  55. /package/templates/auth/{native → better-auth/native}/native-base/lib/auth-client.ts.hbs +0 -0
  56. /package/templates/auth/{native → better-auth/native}/nativewind/app/(drawer)/index.tsx.hbs +0 -0
  57. /package/templates/auth/{native → better-auth/native}/nativewind/components/sign-in.tsx.hbs +0 -0
  58. /package/templates/auth/{native → better-auth/native}/nativewind/components/sign-up.tsx.hbs +0 -0
  59. /package/templates/auth/{native → better-auth/native}/unistyles/app/(drawer)/index.tsx.hbs +0 -0
  60. /package/templates/auth/{native → better-auth/native}/unistyles/components/sign-in.tsx.hbs +0 -0
  61. /package/templates/auth/{native → better-auth/native}/unistyles/components/sign-up.tsx.hbs +0 -0
  62. /package/templates/auth/{server → better-auth/server}/base/src/lib/auth.ts.hbs +0 -0
  63. /package/templates/auth/{server → better-auth/server}/db/drizzle/mysql/src/db/schema/auth.ts +0 -0
  64. /package/templates/auth/{server → better-auth/server}/db/drizzle/postgres/src/db/schema/auth.ts +0 -0
  65. /package/templates/auth/{server → better-auth/server}/db/drizzle/sqlite/src/db/schema/auth.ts +0 -0
  66. /package/templates/auth/{server → better-auth/server}/db/mongoose/mongodb/src/db/models/auth.model.ts +0 -0
  67. /package/templates/auth/{server → better-auth/server}/db/prisma/mongodb/prisma/schema/auth.prisma +0 -0
  68. /package/templates/auth/{server → better-auth/server}/db/prisma/mysql/prisma/schema/auth.prisma +0 -0
  69. /package/templates/auth/{server → better-auth/server}/db/prisma/postgres/prisma/schema/auth.prisma +0 -0
  70. /package/templates/auth/{server → better-auth/server}/db/prisma/sqlite/prisma/schema/auth.prisma +0 -0
  71. /package/templates/auth/{server → better-auth/server}/next/src/app/api/auth/[...all]/route.ts +0 -0
  72. /package/templates/auth/{web → better-auth/web}/nuxt/app/components/SignInForm.vue +0 -0
  73. /package/templates/auth/{web → better-auth/web}/nuxt/app/components/SignUpForm.vue +0 -0
  74. /package/templates/auth/{web → better-auth/web}/nuxt/app/components/UserMenu.vue +0 -0
  75. /package/templates/auth/{web → better-auth/web}/nuxt/app/middleware/auth.ts +0 -0
  76. /package/templates/auth/{web → better-auth/web}/nuxt/app/pages/dashboard.vue.hbs +0 -0
  77. /package/templates/auth/{web → better-auth/web}/nuxt/app/pages/login.vue +0 -0
  78. /package/templates/auth/{web → better-auth/web}/nuxt/app/plugins/auth-client.ts +0 -0
  79. /package/templates/auth/{web → better-auth/web}/react/base/src/lib/auth-client.ts.hbs +0 -0
  80. /package/templates/auth/{web → better-auth/web}/react/next/src/app/dashboard/page.tsx.hbs +0 -0
  81. /package/templates/auth/{web → better-auth/web}/react/next/src/app/login/page.tsx +0 -0
  82. /package/templates/auth/{web → better-auth/web}/react/next/src/components/sign-in-form.tsx +0 -0
  83. /package/templates/auth/{web → better-auth/web}/react/next/src/components/sign-up-form.tsx +0 -0
  84. /package/templates/auth/{web → better-auth/web}/react/next/src/components/theme-provider.tsx +0 -0
  85. /package/templates/auth/{web → better-auth/web}/react/next/src/components/user-menu.tsx +0 -0
  86. /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/sign-in-form.tsx +0 -0
  87. /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/sign-up-form.tsx +0 -0
  88. /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/user-menu.tsx +0 -0
  89. /package/templates/auth/{web → better-auth/web}/react/react-router/src/routes/dashboard.tsx.hbs +0 -0
  90. /package/templates/auth/{web → better-auth/web}/react/react-router/src/routes/login.tsx +0 -0
  91. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/sign-in-form.tsx +0 -0
  92. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/sign-up-form.tsx +0 -0
  93. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/user-menu.tsx +0 -0
  94. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/routes/dashboard.tsx.hbs +0 -0
  95. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/routes/login.tsx +0 -0
  96. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/sign-in-form.tsx +0 -0
  97. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/sign-up-form.tsx +0 -0
  98. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/user-menu.tsx +0 -0
  99. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/routes/dashboard.tsx.hbs +0 -0
  100. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/routes/login.tsx +0 -0
  101. /package/templates/auth/{web → better-auth/web}/solid/src/components/sign-in-form.tsx +0 -0
  102. /package/templates/auth/{web → better-auth/web}/solid/src/components/sign-up-form.tsx +0 -0
  103. /package/templates/auth/{web → better-auth/web}/solid/src/components/user-menu.tsx.hbs +0 -0
  104. /package/templates/auth/{web → better-auth/web}/solid/src/lib/auth-client.ts +0 -0
  105. /package/templates/auth/{web → better-auth/web}/solid/src/routes/dashboard.tsx.hbs +0 -0
  106. /package/templates/auth/{web → better-auth/web}/solid/src/routes/login.tsx +0 -0
  107. /package/templates/auth/{web → better-auth/web}/svelte/src/components/SignInForm.svelte +0 -0
  108. /package/templates/auth/{web → better-auth/web}/svelte/src/components/SignUpForm.svelte +0 -0
  109. /package/templates/auth/{web → better-auth/web}/svelte/src/components/UserMenu.svelte +0 -0
  110. /package/templates/auth/{web → better-auth/web}/svelte/src/lib/auth-client.ts +0 -0
  111. /package/templates/auth/{web → better-auth/web}/svelte/src/routes/dashboard/+page.svelte.hbs +0 -0
  112. /package/templates/auth/{web → better-auth/web}/svelte/src/routes/login/+page.svelte +0 -0
@@ -35,7 +35,7 @@ const DEFAULT_CONFIG_BASE = {
35
35
  frontend: ["tanstack-router"],
36
36
  database: "sqlite",
37
37
  orm: "drizzle",
38
- auth: true,
38
+ auth: "better-auth",
39
39
  addons: ["turborepo"],
40
40
  examples: [],
41
41
  git: true,
@@ -61,6 +61,10 @@ const DEFAULT_CONFIG = getDefaultConfig();
61
61
  const dependencyVersionMap = {
62
62
  "better-auth": "^1.3.7",
63
63
  "@better-auth/expo": "^1.3.7",
64
+ "@clerk/nextjs": "^6.31.5",
65
+ "@clerk/clerk-react": "^5.45.0",
66
+ "@clerk/tanstack-react-start": "^0.23.1",
67
+ "@clerk/clerk-expo": "^2.14.25",
64
68
  "drizzle-orm": "^0.44.2",
65
69
  "drizzle-kit": "^0.31.2",
66
70
  "@libsql/client": "^0.15.9",
@@ -129,7 +133,7 @@ const dependencyVersionMap = {
129
133
  "nitro-cloudflare-dev": "^0.2.2",
130
134
  "@sveltejs/adapter-cloudflare": "^7.2.1",
131
135
  "@cloudflare/workers-types": "^4.20250822.0",
132
- alchemy: "^0.62.1",
136
+ alchemy: "^0.63.0",
133
137
  nitropack: "^2.12.4",
134
138
  dotenv: "^17.2.1"
135
139
  };
@@ -239,6 +243,11 @@ const APISchema = z.enum([
239
243
  "orpc",
240
244
  "none"
241
245
  ]).describe("API type");
246
+ const AuthSchema = z.enum([
247
+ "better-auth",
248
+ "clerk",
249
+ "none"
250
+ ]).describe("Authentication provider");
242
251
  const ProjectNameSchema = z.string().min(1, "Project name cannot be empty").max(255, "Project name must be less than 255 characters").refine((name) => name === "." || !name.startsWith("."), "Project name cannot start with a dot (except for '.')").refine((name) => name === "." || !name.startsWith("-"), "Project name cannot start with a dash").refine((name) => {
243
252
  const invalidChars = [
244
253
  "<",
@@ -495,7 +504,7 @@ function validateWorkersCompatibility(providedFlags, options, config) {
495
504
  }
496
505
  function coerceBackendPresets(config) {
497
506
  if (config.backend === "convex") {
498
- config.auth = false;
507
+ if (config.auth !== "clerk") config.auth = "none";
499
508
  config.database = "none";
500
509
  config.orm = "none";
501
510
  config.api = "none";
@@ -504,7 +513,7 @@ function coerceBackendPresets(config) {
504
513
  config.examples = ["todo"];
505
514
  }
506
515
  if (config.backend === "none") {
507
- config.auth = false;
516
+ config.auth = "none";
508
517
  config.database = "none";
509
518
  config.orm = "none";
510
519
  config.api = "none";
@@ -516,7 +525,7 @@ function coerceBackendPresets(config) {
516
525
  function incompatibleFlagsForBackend(backend, providedFlags, options) {
517
526
  const list = [];
518
527
  if (backend === "convex") {
519
- if (providedFlags.has("auth") && options.auth === true) list.push("--auth");
528
+ if (providedFlags.has("auth") && options.auth && options.auth !== "none" && options.auth !== "clerk") list.push(`--auth ${options.auth}`);
520
529
  if (providedFlags.has("database") && options.database !== "none") list.push(`--database ${options.database}`);
521
530
  if (providedFlags.has("orm") && options.orm !== "none") list.push(`--orm ${options.orm}`);
522
531
  if (providedFlags.has("api") && options.api !== "none") list.push(`--api ${options.api}`);
@@ -524,7 +533,7 @@ function incompatibleFlagsForBackend(backend, providedFlags, options) {
524
533
  if (providedFlags.has("dbSetup") && options.dbSetup !== "none") list.push(`--db-setup ${options.dbSetup}`);
525
534
  }
526
535
  if (backend === "none") {
527
- if (providedFlags.has("auth") && options.auth === true) list.push("--auth");
536
+ if (providedFlags.has("auth") && options.auth && options.auth !== "none") list.push(`--auth ${options.auth}`);
528
537
  if (providedFlags.has("database") && options.database !== "none") list.push(`--database ${options.database}`);
529
538
  if (providedFlags.has("orm") && options.orm !== "none") list.push(`--orm ${options.orm}`);
530
539
  if (providedFlags.has("api") && options.api !== "none") list.push(`--api ${options.api}`);
@@ -592,7 +601,7 @@ function validateAlchemyCompatibility(webDeploy, serverDeploy, frontends = []) {
592
601
  const isAlchemyWebDeploy = webDeploy === "alchemy";
593
602
  const isAlchemyServerDeploy = serverDeploy === "alchemy";
594
603
  if (isAlchemyWebDeploy || isAlchemyServerDeploy) {
595
- const incompatibleFrontends = frontends.filter((f) => f === "next" || f === "react-router");
604
+ const incompatibleFrontends = frontends.filter((f) => f === "next");
596
605
  if (incompatibleFrontends.length > 0) {
597
606
  const deployType = isAlchemyWebDeploy && isAlchemyServerDeploy ? "web and server deployment" : isAlchemyWebDeploy ? "web deployment" : "server deployment";
598
607
  exitWithError(`Alchemy ${deployType} is temporarily not compatible with ${incompatibleFrontends.join(" and ")} frontend(s). Please choose a different frontend or deployment option.`);
@@ -631,11 +640,32 @@ async function getApiChoice(Api, frontend, backend) {
631
640
  //#endregion
632
641
  //#region src/prompts/auth.ts
633
642
  async function getAuthChoice(auth, hasDatabase, backend) {
634
- if (backend === "convex") return false;
635
- if (!hasDatabase) return false;
636
643
  if (auth !== void 0) return auth;
637
- const response = await confirm({
638
- message: "Add authentication with Better-Auth?",
644
+ if (backend === "convex") {
645
+ const response$1 = await select({
646
+ message: "Select authentication provider",
647
+ options: [{
648
+ value: "clerk",
649
+ label: "Clerk"
650
+ }, {
651
+ value: "none",
652
+ label: "None"
653
+ }],
654
+ initialValue: "clerk"
655
+ });
656
+ if (isCancel(response$1)) return exitCancelled("Operation cancelled");
657
+ return response$1;
658
+ }
659
+ if (!hasDatabase) return "none";
660
+ const response = await select({
661
+ message: "Select authentication provider",
662
+ options: [{
663
+ value: "better-auth",
664
+ label: "Better-Auth"
665
+ }, {
666
+ value: "none",
667
+ label: "None"
668
+ }],
639
669
  initialValue: DEFAULT_CONFIG.auth
640
670
  });
641
671
  if (isCancel(response)) return exitCancelled("Operation cancelled");
@@ -1152,7 +1182,7 @@ function getDeploymentDisplay(deployment) {
1152
1182
  async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []) {
1153
1183
  if (deployment !== void 0) return deployment;
1154
1184
  if (!hasWebFrontend(frontend)) return "none";
1155
- const hasIncompatibleFrontend = frontend.some((f) => f === "next" || f === "react-router");
1185
+ const hasIncompatibleFrontend = frontend.some((f) => f === "next");
1156
1186
  const availableDeployments = hasIncompatibleFrontend ? ["wrangler", "none"] : [
1157
1187
  "wrangler",
1158
1188
  "alchemy",
@@ -1176,7 +1206,7 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
1176
1206
  }
1177
1207
  async function getDeploymentToAdd(frontend, existingDeployment) {
1178
1208
  if (!hasWebFrontend(frontend)) return "none";
1179
- const hasIncompatibleFrontend = frontend.some((f) => f === "next" || f === "react-router");
1209
+ const hasIncompatibleFrontend = frontend.some((f) => f === "next");
1180
1210
  const options = [];
1181
1211
  if (existingDeployment !== "wrangler") {
1182
1212
  const { label, hint } = getDeploymentDisplay("wrangler");
@@ -1235,7 +1265,6 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
1235
1265
  result.database = "none";
1236
1266
  result.orm = "none";
1237
1267
  result.api = "none";
1238
- result.auth = false;
1239
1268
  result.dbSetup = "none";
1240
1269
  result.examples = ["todo"];
1241
1270
  }
@@ -1244,7 +1273,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
1244
1273
  result.database = "none";
1245
1274
  result.orm = "none";
1246
1275
  result.api = "none";
1247
- result.auth = false;
1276
+ result.auth = "none";
1248
1277
  result.dbSetup = "none";
1249
1278
  result.examples = [];
1250
1279
  }
@@ -1345,7 +1374,7 @@ const getLatestCLIVersion = () => {
1345
1374
  */
1346
1375
  function isTelemetryEnabled() {
1347
1376
  const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
1348
- const BTS_TELEMETRY = "1";
1377
+ const BTS_TELEMETRY = "0";
1349
1378
  if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
1350
1379
  if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
1351
1380
  return true;
@@ -1353,8 +1382,8 @@ function isTelemetryEnabled() {
1353
1382
 
1354
1383
  //#endregion
1355
1384
  //#region src/utils/analytics.ts
1356
- const POSTHOG_API_KEY = "phc_8ZUxEwwfKMajJLvxz1daGd931dYbQrwKNficBmsdIrs";
1357
- const POSTHOG_HOST = "https://us.i.posthog.com";
1385
+ const POSTHOG_API_KEY = "random";
1386
+ const POSTHOG_HOST = "random";
1358
1387
  function generateSessionId() {
1359
1388
  const rand = Math.random().toString(36).slice(2);
1360
1389
  const now = Date.now().toString(36);
@@ -1400,10 +1429,7 @@ function displayConfig(config) {
1400
1429
  if (config.api !== void 0) configDisplay.push(`${pc.blue("API:")} ${String(config.api)}`);
1401
1430
  if (config.database !== void 0) configDisplay.push(`${pc.blue("Database:")} ${String(config.database)}`);
1402
1431
  if (config.orm !== void 0) configDisplay.push(`${pc.blue("ORM:")} ${String(config.orm)}`);
1403
- if (config.auth !== void 0) {
1404
- const authText = typeof config.auth === "boolean" ? config.auth ? "Yes" : "No" : String(config.auth);
1405
- configDisplay.push(`${pc.blue("Authentication:")} ${authText}`);
1406
- }
1432
+ if (config.auth !== void 0) configDisplay.push(`${pc.blue("Auth:")} ${String(config.auth)}`);
1407
1433
  if (config.addons !== void 0) {
1408
1434
  const addons = Array.isArray(config.addons) ? config.addons : [config.addons];
1409
1435
  const addonsText = addons.length > 0 && addons[0] !== void 0 ? addons.join(", ") : "none";
@@ -1441,7 +1467,7 @@ function generateReproducibleCommand(config) {
1441
1467
  flags.push(`--database ${config.database}`);
1442
1468
  flags.push(`--orm ${config.orm}`);
1443
1469
  flags.push(`--api ${config.api}`);
1444
- flags.push(config.auth ? "--auth" : "--no-auth");
1470
+ flags.push(`--auth ${config.auth}`);
1445
1471
  if (config.addons && config.addons.length > 0) flags.push(`--addons ${config.addons.join(" ")}`);
1446
1472
  else flags.push("--addons none");
1447
1473
  if (config.examples && config.examples.length > 0) flags.push(`--examples ${config.examples.join(" ")}`);
@@ -1649,8 +1675,8 @@ function validateDatabaseOrmAuth(cfg, flags) {
1649
1675
  if (has("database") && has("orm") && db === "mongodb" && orm && orm !== "mongoose" && orm !== "prisma" && orm !== "none") exitWithError("MongoDB database requires Mongoose or Prisma ORM. Please use '--orm mongoose' or '--orm prisma' or choose a different database.");
1650
1676
  if (has("database") && has("orm") && db && db !== "none" && orm === "none") exitWithError("Database selection requires an ORM. Please choose '--orm drizzle', '--orm prisma', or '--orm mongoose'.");
1651
1677
  if (has("orm") && has("database") && orm && orm !== "none" && db === "none") exitWithError("ORM selection requires a database. Please choose a database or set '--orm none'.");
1652
- if (has("auth") && has("database") && cfg.auth && db === "none") exitWithError("Authentication requires a database. Please choose a database or set '--no-auth'.");
1653
- if (cfg.auth && db === "none") exitWithError("Authentication requires a database. Please choose a database or set '--no-auth'.");
1678
+ if (has("auth") && has("database") && cfg.auth !== "none" && db === "none" && cfg.backend !== "convex") exitWithError("Authentication requires a database. Please choose a database or set '--auth none'.");
1679
+ if (cfg.auth !== "none" && db === "none" && cfg.backend !== "convex") exitWithError("Authentication requires a database. Please choose a database or set '--auth none'.");
1654
1680
  if (orm && orm !== "none" && db === "none") exitWithError("ORM selection requires a database. Please choose a database or set '--orm none'.");
1655
1681
  }
1656
1682
  function validateDatabaseSetup(config, providedFlags) {
@@ -1697,6 +1723,7 @@ function validateDatabaseSetup(config, providedFlags) {
1697
1723
  }
1698
1724
  function validateBackendConstraints(config, providedFlags, options) {
1699
1725
  const { backend } = config;
1726
+ if (config.auth === "clerk" && backend !== "convex") exitWithError("Clerk authentication is only supported with the Convex backend. Please use '--backend convex' or choose a different auth provider.");
1700
1727
  if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none") {
1701
1728
  if (providedFlags.has("runtime") && options.runtime === "none") exitWithError("'--runtime none' is only supported with '--backend convex' or '--backend none'. Please choose 'bun', 'node', or remove the --runtime flag.");
1702
1729
  }
@@ -2151,7 +2178,7 @@ async function setupDbOrmTemplates(projectDir, context) {
2151
2178
  if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, serverAppDir, context);
2152
2179
  }
2153
2180
  async function setupAuthTemplate(projectDir, context) {
2154
- if (context.backend === "convex" || !context.auth) return;
2181
+ if (!context.auth || context.auth === "none") return;
2155
2182
  const serverAppDir = path.join(projectDir, "apps/server");
2156
2183
  const webAppDir = path.join(projectDir, "apps/web");
2157
2184
  const nativeAppDir = path.join(projectDir, "apps/native");
@@ -2170,27 +2197,61 @@ async function setupAuthTemplate(projectDir, context) {
2170
2197
  const hasNativeWind = context.frontend.includes("native-nativewind");
2171
2198
  const hasUnistyles = context.frontend.includes("native-unistyles");
2172
2199
  const hasNative = hasNativeWind || hasUnistyles;
2173
- if (serverAppDirExists) {
2174
- const authServerBaseSrc = path.join(PKG_ROOT, "templates/auth/server/base");
2200
+ const authProvider = context.auth;
2201
+ if (context.backend === "convex" && authProvider === "clerk") {
2202
+ const convexBackendDestDir = path.join(projectDir, "packages/backend");
2203
+ const convexClerkBackendSrc = path.join(PKG_ROOT, "templates/auth/clerk/convex/backend");
2204
+ if (await fs.pathExists(convexClerkBackendSrc)) {
2205
+ await fs.ensureDir(convexBackendDestDir);
2206
+ await processAndCopyFiles("**/*", convexClerkBackendSrc, convexBackendDestDir, context);
2207
+ }
2208
+ if (webAppDirExists) {
2209
+ const reactFramework = context.frontend.find((f) => [
2210
+ "tanstack-router",
2211
+ "react-router",
2212
+ "tanstack-start",
2213
+ "next"
2214
+ ].includes(f));
2215
+ if (reactFramework) {
2216
+ const convexClerkWebSrc = path.join(PKG_ROOT, `templates/auth/clerk/convex/web/react/${reactFramework}`);
2217
+ if (await fs.pathExists(convexClerkWebSrc)) await processAndCopyFiles("**/*", convexClerkWebSrc, webAppDir, context);
2218
+ }
2219
+ }
2220
+ if (nativeAppDirExists) {
2221
+ const convexClerkNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/clerk/convex/native/base");
2222
+ if (await fs.pathExists(convexClerkNativeBaseSrc)) await processAndCopyFiles("**/*", convexClerkNativeBaseSrc, nativeAppDir, context);
2223
+ const hasNativeWind$1 = context.frontend.includes("native-nativewind");
2224
+ const hasUnistyles$1 = context.frontend.includes("native-unistyles");
2225
+ let nativeFrameworkPath = "";
2226
+ if (hasNativeWind$1) nativeFrameworkPath = "nativewind";
2227
+ else if (hasUnistyles$1) nativeFrameworkPath = "unistyles";
2228
+ if (nativeFrameworkPath) {
2229
+ const convexClerkNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/clerk/convex/native/${nativeFrameworkPath}`);
2230
+ if (await fs.pathExists(convexClerkNativeFrameworkSrc)) await processAndCopyFiles("**/*", convexClerkNativeFrameworkSrc, nativeAppDir, context);
2231
+ }
2232
+ }
2233
+ return;
2234
+ }
2235
+ if (serverAppDirExists && context.backend !== "convex") {
2236
+ const authServerBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/base`);
2175
2237
  if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, serverAppDir, context);
2176
2238
  if (context.backend === "next") {
2177
- const authServerNextSrc = path.join(PKG_ROOT, "templates/auth/server/next");
2239
+ const authServerNextSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/next`);
2178
2240
  if (await fs.pathExists(authServerNextSrc)) await processAndCopyFiles("**/*", authServerNextSrc, serverAppDir, context);
2179
2241
  }
2180
2242
  if (context.orm !== "none" && context.database !== "none") {
2181
2243
  const orm = context.orm;
2182
2244
  const db = context.database;
2183
2245
  let authDbSrc = "";
2184
- if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/server/db/drizzle/${db}`);
2185
- else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/server/db/prisma/${db}`);
2186
- else if (orm === "mongoose") authDbSrc = path.join(PKG_ROOT, `templates/auth/server/db/mongoose/${db}`);
2246
+ if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/drizzle/${db}`);
2247
+ else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/prisma/${db}`);
2248
+ else if (orm === "mongoose") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/mongoose/${db}`);
2187
2249
  if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, serverAppDir, context);
2188
- else if (authDbSrc) {}
2189
2250
  }
2190
2251
  }
2191
2252
  if ((hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) && webAppDirExists) {
2192
2253
  if (hasReactWeb) {
2193
- const authWebBaseSrc = path.join(PKG_ROOT, "templates/auth/web/react/base");
2254
+ const authWebBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/react/base`);
2194
2255
  if (await fs.pathExists(authWebBaseSrc)) await processAndCopyFiles("**/*", authWebBaseSrc, webAppDir, context);
2195
2256
  const reactFramework = context.frontend.find((f) => [
2196
2257
  "tanstack-router",
@@ -2199,28 +2260,28 @@ async function setupAuthTemplate(projectDir, context) {
2199
2260
  "next"
2200
2261
  ].includes(f));
2201
2262
  if (reactFramework) {
2202
- const authWebFrameworkSrc = path.join(PKG_ROOT, `templates/auth/web/react/${reactFramework}`);
2263
+ const authWebFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/react/${reactFramework}`);
2203
2264
  if (await fs.pathExists(authWebFrameworkSrc)) await processAndCopyFiles("**/*", authWebFrameworkSrc, webAppDir, context);
2204
2265
  }
2205
2266
  } else if (hasNuxtWeb) {
2206
- const authWebNuxtSrc = path.join(PKG_ROOT, "templates/auth/web/nuxt");
2267
+ const authWebNuxtSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/nuxt`);
2207
2268
  if (await fs.pathExists(authWebNuxtSrc)) await processAndCopyFiles("**/*", authWebNuxtSrc, webAppDir, context);
2208
2269
  } else if (hasSvelteWeb) {
2209
- const authWebSvelteSrc = path.join(PKG_ROOT, "templates/auth/web/svelte");
2270
+ const authWebSvelteSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/svelte`);
2210
2271
  if (await fs.pathExists(authWebSvelteSrc)) await processAndCopyFiles("**/*", authWebSvelteSrc, webAppDir, context);
2211
2272
  } else if (hasSolidWeb) {
2212
- const authWebSolidSrc = path.join(PKG_ROOT, "templates/auth/web/solid");
2273
+ const authWebSolidSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/solid`);
2213
2274
  if (await fs.pathExists(authWebSolidSrc)) await processAndCopyFiles("**/*", authWebSolidSrc, webAppDir, context);
2214
2275
  }
2215
2276
  }
2216
2277
  if (hasNative && nativeAppDirExists) {
2217
- const authNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/native/native-base");
2278
+ const authNativeBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/native-base`);
2218
2279
  if (await fs.pathExists(authNativeBaseSrc)) await processAndCopyFiles("**/*", authNativeBaseSrc, nativeAppDir, context);
2219
2280
  let nativeFrameworkAuthPath = "";
2220
2281
  if (hasNativeWind) nativeFrameworkAuthPath = "nativewind";
2221
2282
  else if (hasUnistyles) nativeFrameworkAuthPath = "unistyles";
2222
2283
  if (nativeFrameworkAuthPath) {
2223
- const authNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/native/${nativeFrameworkAuthPath}`);
2284
+ const authNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/${nativeFrameworkAuthPath}`);
2224
2285
  if (await fs.pathExists(authNativeFrameworkSrc)) await processAndCopyFiles("**/*", authNativeFrameworkSrc, nativeAppDir, context);
2225
2286
  }
2226
2287
  }
@@ -2350,10 +2411,7 @@ async function setupDeploymentTemplates(projectDir, context) {
2350
2411
  if (await fs.pathExists(alchemyTemplateSrc)) {
2351
2412
  await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, projectDir, context);
2352
2413
  const serverAppDir = path.join(projectDir, "apps/server");
2353
- if (await fs.pathExists(serverAppDir)) {
2354
- await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2355
- await processAndCopyFiles("wrangler.jsonc.hbs", alchemyTemplateSrc, serverAppDir, context);
2356
- }
2414
+ if (await fs.pathExists(serverAppDir)) await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2357
2415
  }
2358
2416
  } else {
2359
2417
  if (context.webDeploy === "alchemy") {
@@ -2367,7 +2425,6 @@ async function setupDeploymentTemplates(projectDir, context) {
2367
2425
  if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(serverAppDir)) {
2368
2426
  await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2369
2427
  await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2370
- await processAndCopyFiles("wrangler.jsonc.hbs", alchemyTemplateSrc, serverAppDir, context);
2371
2428
  }
2372
2429
  }
2373
2430
  }
@@ -3000,11 +3057,9 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager) {
3000
3057
  const packageJson = await fs.readJson(packageJsonPath);
3001
3058
  packageJson.scripts = {
3002
3059
  ...packageJson.scripts,
3003
- dev: "wrangler dev --port=3000",
3004
- build: "wrangler deploy --dry-run",
3060
+ dev: "alchemy dev",
3005
3061
  deploy: "alchemy deploy",
3006
- destroy: "alchemy destroy",
3007
- "alchemy:dev": "alchemy dev"
3062
+ destroy: "alchemy destroy"
3008
3063
  };
3009
3064
  await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
3010
3065
  }
@@ -3012,7 +3067,7 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager) {
3012
3067
 
3013
3068
  //#endregion
3014
3069
  //#region src/helpers/deployment/alchemy/alchemy-next-setup.ts
3015
- async function setupNextAlchemyDeploy(projectDir, _packageManager) {
3070
+ async function setupNextAlchemyDeploy(projectDir, _packageManager, options) {
3016
3071
  const webAppDir = path.join(projectDir, "apps/web");
3017
3072
  if (!await fs.pathExists(webAppDir)) return;
3018
3073
  await addPackageDependency({
@@ -3022,11 +3077,11 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager) {
3022
3077
  const pkgPath = path.join(webAppDir, "package.json");
3023
3078
  if (await fs.pathExists(pkgPath)) {
3024
3079
  const pkg = await fs.readJson(pkgPath);
3025
- pkg.scripts = {
3080
+ if (!options?.skipAppScripts) pkg.scripts = {
3026
3081
  ...pkg.scripts,
3027
3082
  deploy: "alchemy deploy",
3028
3083
  destroy: "alchemy destroy",
3029
- "alchemy:dev": "alchemy dev"
3084
+ dev: "alchemy dev"
3030
3085
  };
3031
3086
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3032
3087
  }
@@ -3034,7 +3089,7 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager) {
3034
3089
 
3035
3090
  //#endregion
3036
3091
  //#region src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts
3037
- async function setupNuxtAlchemyDeploy(projectDir, _packageManager) {
3092
+ async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
3038
3093
  const webAppDir = path.join(projectDir, "apps/web");
3039
3094
  if (!await fs.pathExists(webAppDir)) return;
3040
3095
  await addPackageDependency({
@@ -3048,11 +3103,11 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager) {
3048
3103
  const pkgPath = path.join(webAppDir, "package.json");
3049
3104
  if (await fs.pathExists(pkgPath)) {
3050
3105
  const pkg = await fs.readJson(pkgPath);
3051
- pkg.scripts = {
3106
+ if (!options?.skipAppScripts) pkg.scripts = {
3052
3107
  ...pkg.scripts,
3053
3108
  deploy: "alchemy deploy",
3054
3109
  destroy: "alchemy destroy",
3055
- "alchemy:dev": "alchemy dev"
3110
+ dev: "alchemy dev"
3056
3111
  };
3057
3112
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3058
3113
  }
@@ -3102,112 +3157,29 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager) {
3102
3157
 
3103
3158
  //#endregion
3104
3159
  //#region src/helpers/deployment/alchemy/alchemy-react-router-setup.ts
3105
- async function setupReactRouterAlchemyDeploy(projectDir, _packageManager) {
3160
+ async function setupReactRouterAlchemyDeploy(projectDir, _packageManager, options) {
3106
3161
  const webAppDir = path.join(projectDir, "apps/web");
3107
3162
  if (!await fs.pathExists(webAppDir)) return;
3108
3163
  await addPackageDependency({
3109
- devDependencies: [
3110
- "alchemy",
3111
- "@cloudflare/vite-plugin",
3112
- "dotenv"
3113
- ],
3164
+ devDependencies: ["alchemy", "dotenv"],
3114
3165
  projectDir: webAppDir
3115
3166
  });
3116
3167
  const pkgPath = path.join(webAppDir, "package.json");
3117
3168
  if (await fs.pathExists(pkgPath)) {
3118
3169
  const pkg = await fs.readJson(pkgPath);
3119
- pkg.scripts = {
3170
+ if (!options?.skipAppScripts) pkg.scripts = {
3120
3171
  ...pkg.scripts,
3121
3172
  deploy: "alchemy deploy",
3122
3173
  destroy: "alchemy destroy",
3123
- "alchemy:dev": "alchemy dev"
3174
+ dev: "alchemy dev"
3124
3175
  };
3125
3176
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3126
3177
  }
3127
- const viteConfigPath = path.join(webAppDir, "vite.config.ts");
3128
- if (await fs.pathExists(viteConfigPath)) try {
3129
- const project = new Project({ manipulationSettings: {
3130
- indentationText: IndentationText.TwoSpaces,
3131
- quoteKind: QuoteKind.Double
3132
- } });
3133
- project.addSourceFileAtPath(viteConfigPath);
3134
- const sourceFile = project.getSourceFileOrThrow(viteConfigPath);
3135
- const alchemyImport = sourceFile.getImportDeclaration("alchemy/cloudflare/react-router");
3136
- if (!alchemyImport) sourceFile.addImportDeclaration({
3137
- moduleSpecifier: "alchemy/cloudflare/react-router",
3138
- defaultImport: "alchemy"
3139
- });
3140
- const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
3141
- if (!exportAssignment) return;
3142
- const defineConfigCall = exportAssignment.getExpression();
3143
- if (!Node.isCallExpression(defineConfigCall) || defineConfigCall.getExpression().getText() !== "defineConfig") return;
3144
- let configObject = defineConfigCall.getArguments()[0];
3145
- if (!configObject) configObject = defineConfigCall.addArgument("{}");
3146
- if (Node.isObjectLiteralExpression(configObject)) {
3147
- const pluginsProperty = configObject.getProperty("plugins");
3148
- if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
3149
- const initializer = pluginsProperty.getInitializer();
3150
- if (Node.isArrayLiteralExpression(initializer)) {
3151
- const hasCloudflarePlugin = initializer.getElements().some((el) => el.getText().includes("cloudflare("));
3152
- if (!hasCloudflarePlugin) initializer.addElement("alchemy()");
3153
- }
3154
- } else if (!pluginsProperty) configObject.addPropertyAssignment({
3155
- name: "plugins",
3156
- initializer: "[alchemy()]"
3157
- });
3158
- }
3159
- await project.save();
3160
- } catch (error) {
3161
- console.warn("Failed to update vite.config.ts:", error);
3162
- }
3163
- const reactRouterConfigPath = path.join(webAppDir, "react-router.config.ts");
3164
- if (await fs.pathExists(reactRouterConfigPath)) try {
3165
- const project = new Project({ manipulationSettings: {
3166
- indentationText: IndentationText.TwoSpaces,
3167
- quoteKind: QuoteKind.Double
3168
- } });
3169
- project.addSourceFileAtPath(reactRouterConfigPath);
3170
- const sourceFile = project.getSourceFileOrThrow(reactRouterConfigPath);
3171
- const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
3172
- if (!exportAssignment) return;
3173
- const configExpression = exportAssignment.getExpression();
3174
- let configObject;
3175
- if (Node.isObjectLiteralExpression(configExpression)) configObject = configExpression;
3176
- else if (Node.isSatisfiesExpression(configExpression)) {
3177
- const expression = configExpression.getExpression();
3178
- if (Node.isObjectLiteralExpression(expression)) configObject = expression;
3179
- }
3180
- if (!configObject || !Node.isObjectLiteralExpression(configObject)) return;
3181
- const futureProperty = configObject.getProperty("future");
3182
- if (!futureProperty) configObject.addPropertyAssignment({
3183
- name: "future",
3184
- initializer: `{
3185
- unstable_viteEnvironmentApi: true,
3186
- }`
3187
- });
3188
- else if (Node.isPropertyAssignment(futureProperty)) {
3189
- const futureInitializer = futureProperty.getInitializer();
3190
- if (Node.isObjectLiteralExpression(futureInitializer)) {
3191
- const viteEnvApiProp = futureInitializer.getProperty("unstable_viteEnvironmentApi");
3192
- if (!viteEnvApiProp) futureInitializer.addPropertyAssignment({
3193
- name: "unstable_viteEnvironmentApi",
3194
- initializer: "true"
3195
- });
3196
- else if (Node.isPropertyAssignment(viteEnvApiProp)) {
3197
- const value = viteEnvApiProp.getInitializer()?.getText();
3198
- if (value === "false") viteEnvApiProp.setInitializer("true");
3199
- }
3200
- }
3201
- }
3202
- await project.save();
3203
- } catch (error) {
3204
- console.warn("Failed to update react-router.config.ts:", error);
3205
- }
3206
3178
  }
3207
3179
 
3208
3180
  //#endregion
3209
3181
  //#region src/helpers/deployment/alchemy/alchemy-solid-setup.ts
3210
- async function setupSolidAlchemyDeploy(projectDir, _packageManager) {
3182
+ async function setupSolidAlchemyDeploy(projectDir, _packageManager, options) {
3211
3183
  const webAppDir = path.join(projectDir, "apps/web");
3212
3184
  if (!await fs.pathExists(webAppDir)) return;
3213
3185
  await addPackageDependency({
@@ -3217,11 +3189,11 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager) {
3217
3189
  const pkgPath = path.join(webAppDir, "package.json");
3218
3190
  if (await fs.pathExists(pkgPath)) {
3219
3191
  const pkg = await fs.readJson(pkgPath);
3220
- pkg.scripts = {
3192
+ if (!options?.skipAppScripts) pkg.scripts = {
3221
3193
  ...pkg.scripts,
3222
3194
  deploy: "alchemy deploy",
3223
3195
  destroy: "alchemy destroy",
3224
- "alchemy:dev": "alchemy dev"
3196
+ dev: "alchemy dev"
3225
3197
  };
3226
3198
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3227
3199
  }
@@ -3229,7 +3201,7 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager) {
3229
3201
 
3230
3202
  //#endregion
3231
3203
  //#region src/helpers/deployment/alchemy/alchemy-svelte-setup.ts
3232
- async function setupSvelteAlchemyDeploy(projectDir, _packageManager) {
3204
+ async function setupSvelteAlchemyDeploy(projectDir, _packageManager, options) {
3233
3205
  const webAppDir = path.join(projectDir, "apps/web");
3234
3206
  if (!await fs.pathExists(webAppDir)) return;
3235
3207
  await addPackageDependency({
@@ -3243,11 +3215,11 @@ async function setupSvelteAlchemyDeploy(projectDir, _packageManager) {
3243
3215
  const pkgPath = path.join(webAppDir, "package.json");
3244
3216
  if (await fs.pathExists(pkgPath)) {
3245
3217
  const pkg = await fs.readJson(pkgPath);
3246
- pkg.scripts = {
3218
+ if (!options?.skipAppScripts) pkg.scripts = {
3247
3219
  ...pkg.scripts,
3248
3220
  deploy: "alchemy deploy",
3249
3221
  destroy: "alchemy destroy",
3250
- "alchemy:dev": "alchemy dev"
3222
+ dev: "alchemy dev"
3251
3223
  };
3252
3224
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3253
3225
  }
@@ -3300,7 +3272,7 @@ function updateAdapterInConfig(configObject) {
3300
3272
 
3301
3273
  //#endregion
3302
3274
  //#region src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts
3303
- async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager) {
3275
+ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager, options) {
3304
3276
  const webAppDir = path.join(projectDir, "apps/web");
3305
3277
  if (!await fs.pathExists(webAppDir)) return;
3306
3278
  await addPackageDependency({
@@ -3310,11 +3282,11 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager) {
3310
3282
  const pkgPath = path.join(webAppDir, "package.json");
3311
3283
  if (await fs.pathExists(pkgPath)) {
3312
3284
  const pkg = await fs.readJson(pkgPath);
3313
- pkg.scripts = {
3285
+ if (!options?.skipAppScripts) pkg.scripts = {
3314
3286
  ...pkg.scripts,
3315
3287
  deploy: "alchemy deploy",
3316
3288
  destroy: "alchemy destroy",
3317
- "alchemy:dev": "alchemy dev"
3289
+ dev: "alchemy dev"
3318
3290
  };
3319
3291
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3320
3292
  }
@@ -3322,7 +3294,7 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager) {
3322
3294
 
3323
3295
  //#endregion
3324
3296
  //#region src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts
3325
- async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager) {
3297
+ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, options) {
3326
3298
  const webAppDir = path.join(projectDir, "apps/web");
3327
3299
  if (!await fs.pathExists(webAppDir)) return;
3328
3300
  await addPackageDependency({
@@ -3336,11 +3308,11 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager) {
3336
3308
  const pkgPath = path.join(webAppDir, "package.json");
3337
3309
  if (await fs.pathExists(pkgPath)) {
3338
3310
  const pkg = await fs.readJson(pkgPath);
3339
- pkg.scripts = {
3311
+ if (!options?.skipAppScripts) pkg.scripts = {
3340
3312
  ...pkg.scripts,
3341
3313
  deploy: "alchemy deploy",
3342
3314
  destroy: "alchemy destroy",
3343
- "alchemy:dev": "alchemy dev"
3315
+ dev: "alchemy dev"
3344
3316
  };
3345
3317
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3346
3318
  }
@@ -3456,7 +3428,7 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
3456
3428
  ...pkg.scripts,
3457
3429
  deploy: "alchemy deploy",
3458
3430
  destroy: "alchemy destroy",
3459
- "alchemy:dev": "alchemy dev"
3431
+ dev: "alchemy dev"
3460
3432
  };
3461
3433
  await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
3462
3434
  }
@@ -3470,13 +3442,13 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
3470
3442
  const isTanstackStart = frontend.includes("tanstack-start");
3471
3443
  const isReactRouter = frontend.includes("react-router");
3472
3444
  const isSolid = frontend.includes("solid");
3473
- if (isNext) await setupNextAlchemyDeploy(projectDir, packageManager);
3474
- else if (isNuxt) await setupNuxtAlchemyDeploy(projectDir, packageManager);
3475
- else if (isSvelte) await setupSvelteAlchemyDeploy(projectDir, packageManager);
3476
- else if (isTanstackStart) await setupTanStackStartAlchemyDeploy(projectDir, packageManager);
3477
- else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
3478
- else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager);
3479
- else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager);
3445
+ if (isNext) await setupNextAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3446
+ else if (isNuxt) await setupNuxtAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3447
+ else if (isSvelte) await setupSvelteAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3448
+ else if (isTanstackStart) await setupTanStackStartAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3449
+ else if (isTanstackRouter) await setupTanStackRouterAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3450
+ else if (isReactRouter) await setupReactRouterAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3451
+ else if (isSolid) await setupSolidAlchemyDeploy(projectDir, packageManager, { skipAppScripts: true });
3480
3452
  }
3481
3453
 
3482
3454
  //#endregion
@@ -3838,58 +3810,6 @@ async function formatProjectWithBiome(projectDir) {
3838
3810
  } catch {}
3839
3811
  }
3840
3812
 
3841
- //#endregion
3842
- //#region src/helpers/addons/auth-setup.ts
3843
- async function setupAuth(config) {
3844
- const { auth, frontend, backend, projectDir } = config;
3845
- if (backend === "convex" || !auth) return;
3846
- const serverDir = path.join(projectDir, "apps/server");
3847
- const clientDir = path.join(projectDir, "apps/web");
3848
- const nativeDir = path.join(projectDir, "apps/native");
3849
- const clientDirExists = await fs.pathExists(clientDir);
3850
- const nativeDirExists = await fs.pathExists(nativeDir);
3851
- const serverDirExists = await fs.pathExists(serverDir);
3852
- try {
3853
- if (serverDirExists) await addPackageDependency({
3854
- dependencies: ["better-auth"],
3855
- projectDir: serverDir
3856
- });
3857
- const hasWebFrontend$1 = frontend.some((f) => [
3858
- "react-router",
3859
- "tanstack-router",
3860
- "tanstack-start",
3861
- "next",
3862
- "nuxt",
3863
- "svelte",
3864
- "solid"
3865
- ].includes(f));
3866
- if (hasWebFrontend$1 && clientDirExists) await addPackageDependency({
3867
- dependencies: ["better-auth"],
3868
- projectDir: clientDir
3869
- });
3870
- if ((frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) && nativeDirExists) {
3871
- await addPackageDependency({
3872
- dependencies: ["better-auth", "@better-auth/expo"],
3873
- projectDir: nativeDir
3874
- });
3875
- if (serverDirExists) await addPackageDependency({
3876
- dependencies: ["@better-auth/expo"],
3877
- projectDir: serverDir
3878
- });
3879
- }
3880
- } catch (error) {
3881
- consola.error(pc.red("Failed to configure authentication dependencies"));
3882
- if (error instanceof Error) consola.error(pc.red(error.message));
3883
- }
3884
- }
3885
- function generateAuthSecret(length = 32) {
3886
- const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
3887
- let result = "";
3888
- const charactersLength = 62;
3889
- for (let i = 0; i < length; i++) result += characters.charAt(Math.floor(Math.random() * charactersLength));
3890
- return result;
3891
- }
3892
-
3893
3813
  //#endregion
3894
3814
  //#region src/helpers/addons/examples-setup.ts
3895
3815
  async function setupExamples(config) {
@@ -4139,6 +4059,88 @@ async function setupBackendDependencies(config) {
4139
4059
  });
4140
4060
  }
4141
4061
 
4062
+ //#endregion
4063
+ //#region src/helpers/core/auth-setup.ts
4064
+ async function setupAuth(config) {
4065
+ const { auth, frontend, backend, projectDir } = config;
4066
+ if (!auth || auth === "none") return;
4067
+ const serverDir = path.join(projectDir, "apps/server");
4068
+ const clientDir = path.join(projectDir, "apps/web");
4069
+ const nativeDir = path.join(projectDir, "apps/native");
4070
+ const clientDirExists = await fs.pathExists(clientDir);
4071
+ const nativeDirExists = await fs.pathExists(nativeDir);
4072
+ const serverDirExists = await fs.pathExists(serverDir);
4073
+ try {
4074
+ if (backend === "convex") {
4075
+ if (auth === "clerk" && clientDirExists) {
4076
+ const hasNextJs = frontend.includes("next");
4077
+ const hasTanStackStart = frontend.includes("tanstack-start");
4078
+ const hasViteReactOther = frontend.some((f) => ["tanstack-router", "react-router"].includes(f));
4079
+ if (hasNextJs) await addPackageDependency({
4080
+ dependencies: ["@clerk/nextjs"],
4081
+ projectDir: clientDir
4082
+ });
4083
+ else if (hasTanStackStart) await addPackageDependency({
4084
+ dependencies: ["@clerk/tanstack-react-start"],
4085
+ projectDir: clientDir
4086
+ });
4087
+ else if (hasViteReactOther) await addPackageDependency({
4088
+ dependencies: ["@clerk/clerk-react"],
4089
+ projectDir: clientDir
4090
+ });
4091
+ }
4092
+ const hasNativeWind = frontend.includes("native-nativewind");
4093
+ const hasUnistyles = frontend.includes("native-unistyles");
4094
+ if (auth === "clerk" && nativeDirExists && (hasNativeWind || hasUnistyles)) await addPackageDependency({
4095
+ dependencies: ["@clerk/clerk-expo"],
4096
+ projectDir: nativeDir
4097
+ });
4098
+ return;
4099
+ }
4100
+ if (serverDirExists && auth === "better-auth") await addPackageDependency({
4101
+ dependencies: ["better-auth"],
4102
+ projectDir: serverDir
4103
+ });
4104
+ const hasWebFrontend$1 = frontend.some((f) => [
4105
+ "react-router",
4106
+ "tanstack-router",
4107
+ "tanstack-start",
4108
+ "next",
4109
+ "nuxt",
4110
+ "svelte",
4111
+ "solid"
4112
+ ].includes(f));
4113
+ if (hasWebFrontend$1 && clientDirExists) {
4114
+ if (auth === "better-auth") await addPackageDependency({
4115
+ dependencies: ["better-auth"],
4116
+ projectDir: clientDir
4117
+ });
4118
+ }
4119
+ if ((frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) && nativeDirExists) {
4120
+ if (auth === "better-auth") {
4121
+ await addPackageDependency({
4122
+ dependencies: ["better-auth", "@better-auth/expo"],
4123
+ projectDir: nativeDir
4124
+ });
4125
+ if (serverDirExists) await addPackageDependency({
4126
+ dependencies: ["@better-auth/expo"],
4127
+ projectDir: serverDir
4128
+ });
4129
+ }
4130
+ }
4131
+ } catch (error) {
4132
+ consola.error(pc.red("Failed to configure authentication dependencies"));
4133
+ if (error instanceof Error) consola.error(pc.red(error.message));
4134
+ }
4135
+ }
4136
+ function generateAuthSecret(length = 32) {
4137
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
4138
+ let result = "";
4139
+ const charactersLength = 62;
4140
+ for (let i = 0; i < length; i++) result += characters.charAt(Math.floor(Math.random() * charactersLength));
4141
+ return result;
4142
+ }
4143
+
4142
4144
  //#endregion
4143
4145
  //#region src/helpers/core/env-setup.ts
4144
4146
  async function addEnvVariablesToFile(filePath, variables) {
@@ -4217,6 +4219,33 @@ async function setupEnvironmentVariables(config) {
4217
4219
  value: serverUrl,
4218
4220
  condition: true
4219
4221
  }];
4222
+ if (backend === "convex" && auth === "clerk") {
4223
+ if (hasNextJs) clientVars.push({
4224
+ key: "NEXT_PUBLIC_CLERK_FRONTEND_API_URL",
4225
+ value: "",
4226
+ condition: true
4227
+ }, {
4228
+ key: "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY",
4229
+ value: "",
4230
+ condition: true
4231
+ }, {
4232
+ key: "CLERK_SECRET_KEY",
4233
+ value: "",
4234
+ condition: true
4235
+ });
4236
+ else if (hasReactRouter || hasTanStackRouter || hasTanStackStart) {
4237
+ clientVars.push({
4238
+ key: "VITE_CLERK_PUBLISHABLE_KEY",
4239
+ value: "",
4240
+ condition: true
4241
+ });
4242
+ if (hasTanStackStart) clientVars.push({
4243
+ key: "CLERK_SECRET_KEY",
4244
+ value: "",
4245
+ condition: true
4246
+ });
4247
+ }
4248
+ }
4220
4249
  await addEnvVariablesToFile(path.join(clientDir, ".env"), clientVars);
4221
4250
  }
4222
4251
  }
@@ -4234,6 +4263,11 @@ async function setupEnvironmentVariables(config) {
4234
4263
  value: serverUrl,
4235
4264
  condition: true
4236
4265
  }];
4266
+ if (backend === "convex" && auth === "clerk") nativeVars.push({
4267
+ key: "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY",
4268
+ value: "",
4269
+ condition: true
4270
+ });
4237
4271
  await addEnvVariablesToFile(path.join(nativeDir, ".env"), nativeVars);
4238
4272
  }
4239
4273
  }
@@ -5282,7 +5316,7 @@ async function createReadme(projectDir, options) {
5282
5316
  }
5283
5317
  }
5284
5318
  function generateReadmeContent(options) {
5285
- const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc" } = options;
5319
+ const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc", webDeploy, serverDeploy } = options;
5286
5320
  const isConvex = backend === "convex";
5287
5321
  const hasReactRouter = frontend.includes("react-router");
5288
5322
  const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
@@ -5315,7 +5349,7 @@ This project uses Convex as a backend. You'll need to set up Convex before runni
5315
5349
  ${packageManagerRunCmd} dev:setup
5316
5350
  \`\`\`
5317
5351
 
5318
- Follow the prompts to create a new Convex project and connect it to your application.` : generateDatabaseSetup(database, auth, packageManagerRunCmd, orm, options.dbSetup)}
5352
+ Follow the prompts to create a new Convex project and connect it to your application.` : generateDatabaseSetup(database, auth, packageManagerRunCmd, orm, options.dbSetup, options.serverDeploy)}
5319
5353
 
5320
5354
  Then, run the development server:
5321
5355
 
@@ -5327,6 +5361,8 @@ ${generateRunningInstructions(frontend, backend, webPort, hasNative, isConvex)}
5327
5361
 
5328
5362
  ${addons.includes("pwa") && hasReactRouter ? "\n## PWA Support with React Router v7\n\nThere is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809\n" : ""}
5329
5363
 
5364
+ ${generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy)}
5365
+
5330
5366
  ## Project Structure
5331
5367
 
5332
5368
  \`\`\`
@@ -5461,7 +5497,10 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
5461
5497
  const dbName = database === "sqlite" ? "SQLite/Turso" : database === "postgres" ? "PostgreSQL" : database === "mysql" ? "MySQL" : database === "mongodb" ? "MongoDB" : "Database";
5462
5498
  addonsList.push(`- **${ormName}** - TypeScript-first ORM`, `- **${dbName}** - Database engine`);
5463
5499
  }
5464
- if (auth && !isConvex) addonsList.push("- **Authentication** - Email & password authentication with Better Auth");
5500
+ if (auth !== "none" && !isConvex) {
5501
+ const authLabel = auth === "clerk" ? "Clerk" : "Better-Auth";
5502
+ addonsList.push(`- **Authentication** - ${authLabel}`);
5503
+ }
5465
5504
  for (const addon of addons) if (addon === "pwa") addonsList.push("- **PWA** - Progressive Web App support");
5466
5505
  else if (addon === "tauri") addonsList.push("- **Tauri** - Build native desktop applications");
5467
5506
  else if (addon === "biome") addonsList.push("- **Biome** - Linting and formatting");
@@ -5470,13 +5509,13 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
5470
5509
  else if (addon === "turborepo") addonsList.push("- **Turborepo** - Optimized monorepo build system");
5471
5510
  return addonsList.join("\n");
5472
5511
  }
5473
- function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup) {
5512
+ function generateDatabaseSetup(database, _auth, packageManagerRunCmd, orm, dbSetup, serverDeploy) {
5474
5513
  if (database === "none") return "";
5475
5514
  let setup = "## Database Setup\n\n";
5476
5515
  if (database === "sqlite") setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : orm === "prisma" ? " with Prisma" : ` with ${orm}`}.
5477
5516
 
5478
5517
  1. Start the local SQLite database:
5479
- ${dbSetup === "d1" ? "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." : `\`\`\`bash
5518
+ ${dbSetup === "d1" ? serverDeploy === "alchemy" ? "D1 local development and migrations are handled automatically by Alchemy during dev and deploy." : "Local development for a Cloudflare D1 database will already be running as part of the `wrangler dev` command." : `\`\`\`bash
5480
5519
  cd apps/server && ${packageManagerRunCmd} db:local
5481
5520
  \`\`\`
5482
5521
  `}
@@ -5546,6 +5585,21 @@ function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNati
5546
5585
  - \`cd apps/docs && ${packageManagerRunCmd} build\`: Build documentation site`;
5547
5586
  return scripts;
5548
5587
  }
5588
+ function generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy) {
5589
+ const lines = [];
5590
+ if (webDeploy === "alchemy" || serverDeploy === "alchemy") {
5591
+ lines.push("## Deployment (Alchemy)");
5592
+ if (webDeploy === "alchemy" && serverDeploy !== "alchemy") lines.push(`- Web dev: cd apps/web && ${packageManagerRunCmd} dev`, `- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`, `- Web destroy: cd apps/web && ${packageManagerRunCmd} destroy`);
5593
+ if (serverDeploy === "alchemy" && webDeploy !== "alchemy") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`, `- Server destroy: cd apps/server && ${packageManagerRunCmd} destroy`);
5594
+ if (webDeploy === "alchemy" && serverDeploy === "alchemy") lines.push(`- Dev: ${packageManagerRunCmd} dev`, `- Deploy: ${packageManagerRunCmd} deploy`, `- Destroy: ${packageManagerRunCmd} destroy`);
5595
+ }
5596
+ if (webDeploy === "wrangler" || serverDeploy === "wrangler") {
5597
+ lines.push("\n## Deployment (Cloudflare Wrangler)");
5598
+ if (webDeploy === "wrangler") lines.push(`- Web deploy: cd apps/web && ${packageManagerRunCmd} deploy`);
5599
+ if (serverDeploy === "wrangler") lines.push(`- Server dev: cd apps/server && ${packageManagerRunCmd} dev`, `- Server deploy: cd apps/server && ${packageManagerRunCmd} deploy`);
5600
+ }
5601
+ return lines.length ? `\n${lines.join("\n")}\n` : "";
5602
+ }
5549
5603
 
5550
5604
  //#endregion
5551
5605
  //#region src/helpers/core/git.ts
@@ -5761,9 +5815,9 @@ function getWranglerDeployInstructions(runCmd, webDeploy, serverDeploy) {
5761
5815
  }
5762
5816
  function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
5763
5817
  const instructions = [];
5764
- if (webDeploy === "alchemy" && serverDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} alchemy:dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`);
5765
- else if (serverDeploy === "alchemy" && webDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy server with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/server && ${runCmd} alchemy:dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/server && ${runCmd} destroy`}`);
5766
- else if (webDeploy === "alchemy" && serverDeploy === "alchemy") instructions.push(`${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd} alchemy:dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
5818
+ if (webDeploy === "alchemy" && serverDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy web with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/web && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/web && ${runCmd} destroy`}`);
5819
+ else if (serverDeploy === "alchemy" && webDeploy !== "alchemy") instructions.push(`${pc.bold("Deploy server with Alchemy:")}\n${pc.cyan("•")} Dev: ${`cd apps/server && ${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`cd apps/server && ${runCmd} destroy`}`);
5820
+ else if (webDeploy === "alchemy" && serverDeploy === "alchemy") instructions.push(`${pc.bold("Deploy with Alchemy:")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
5767
5821
  return instructions.length ? `\n${instructions.join("\n")}` : "";
5768
5822
  }
5769
5823
 
@@ -5961,8 +6015,8 @@ async function createProject(options) {
5961
6015
  if (!isConvex) {
5962
6016
  await setupDbOrmTemplates(projectDir, options);
5963
6017
  await setupDockerComposeTemplates(projectDir, options);
5964
- await setupAuthTemplate(projectDir, options);
5965
6018
  }
6019
+ await setupAuthTemplate(projectDir, options);
5966
6020
  if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
5967
6021
  await setupAddonsTemplate(projectDir, options);
5968
6022
  await setupDeploymentTemplates(projectDir, options);
@@ -5974,12 +6028,12 @@ async function createProject(options) {
5974
6028
  if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
5975
6029
  }
5976
6030
  if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
5977
- if (!isConvex && options.auth) await setupAuth(options);
6031
+ if (options.auth && options.auth !== "none") await setupAuth(options);
5978
6032
  await handleExtras(projectDir, options);
5979
- await setupWebDeploy(options);
5980
- await setupServerDeploy(options);
5981
6033
  await setupEnvironmentVariables(options);
5982
6034
  await updatePackageConfigurations(projectDir, options);
6035
+ await setupWebDeploy(options);
6036
+ await setupServerDeploy(options);
5983
6037
  await createReadme(projectDir, options);
5984
6038
  await writeBtsConfig(options);
5985
6039
  await formatProjectWithBiome(projectDir);
@@ -6053,7 +6107,7 @@ async function createProjectHandler(input) {
6053
6107
  frontend: [],
6054
6108
  addons: [],
6055
6109
  examples: [],
6056
- auth: false,
6110
+ auth: "none",
6057
6111
  git: false,
6058
6112
  packageManager: "npm",
6059
6113
  install: false,
@@ -6088,8 +6142,8 @@ async function createProjectHandler(input) {
6088
6142
  };
6089
6143
  coerceBackendPresets(config);
6090
6144
  validateConfigCompatibility(config, providedFlags, cliInput);
6091
- if (config.backend === "convex") log.info("Due to '--backend convex' flag, the following options have been automatically set: auth=false, database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo");
6092
- else if (config.backend === "none") log.info("Due to '--backend none', the following options have been automatically set: --auth=false, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none");
6145
+ if (config.backend === "convex") log.info("Due to '--backend convex' flag, the following options have been automatically set: auth=none, database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo");
6146
+ else if (config.backend === "none") log.info("Due to '--backend none', the following options have been automatically set: --auth none, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none");
6093
6147
  log.info(pc.yellow("Using default/flag options (config prompts skipped):"));
6094
6148
  log.message(displayConfig(config));
6095
6149
  log.message("");
@@ -6295,7 +6349,7 @@ const router = t.router({
6295
6349
  verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
6296
6350
  database: DatabaseSchema.optional(),
6297
6351
  orm: ORMSchema.optional(),
6298
- auth: z.boolean().optional(),
6352
+ auth: AuthSchema.optional(),
6299
6353
  frontend: z.array(FrontendSchema).optional(),
6300
6354
  addons: z.array(AddonsSchema).optional(),
6301
6355
  examples: z.array(ExamplesSchema).optional(),
@@ -6386,7 +6440,7 @@ function createBtsCli() {
6386
6440
  * backend: "hono",
6387
6441
  * database: "sqlite",
6388
6442
  * orm: "drizzle",
6389
- * auth: true,
6443
+ * auth: "better-auth",
6390
6444
  * addons: ["biome", "turborepo"],
6391
6445
  * packageManager: "bun",
6392
6446
  * install: false,