create-better-t-stack 3.39.2 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,7 +43,7 @@ generated commands.
43
43
  | Category | Options |
44
44
  | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
45
  | **TypeScript** | End-to-end type safety across all parts of your application |
46
- | **Frontend** | • React with TanStack Router<br>• React with React Router<br>• React with TanStack Start (SSR)<br>• Next.js<br>• SvelteKit<br>• Nuxt (Vue)<br>• SolidStart v2 (SSR)<br>• Astro<br>• React Native bare Expo<br>• React Native with NativeWind (via Expo)<br>• React Native with Unistyles (via Expo)<br>• None |
46
+ | **Frontend** | • React with TanStack Router<br>• React with React Router<br>• React with TanStack Start (SSR)<br>• Next.js<br>• SvelteKit<br>• Nuxt (Vue)<br>• Solid (SSR)<br>• Astro<br>• React Native bare Expo<br>• React Native with NativeWind (via Expo)<br>• React Native with Unistyles (via Expo)<br>• None |
47
47
  | **Backend** | • Hono<br>• Express<br>• Elysia<br>• Fastify<br>• Self (fullstack inside the web app)<br>• Convex<br>• None |
48
48
  | **API Layer** | • tRPC (type-safe APIs)<br>• oRPC (OpenAPI-compatible type-safe APIs)<br>• None |
49
49
  | **Runtime** | • Bun<br>• Node.js<br>• Cloudflare Workers<br>• None |
@@ -259,8 +259,8 @@ npx create-better-t-stack --frontend none --backend hono --api trpc --database n
259
259
  - **Cloudflare D1 setup**: Requires `sqlite` and either `--runtime workers --server-deploy cloudflare` or `--backend self --web-deploy cloudflare`. For `backend self`, D1 is supported on `next`, `tanstack-start`, `nuxt`, `svelte`, `solid`, and `astro`.
260
260
  - **Addons 'none'**: Skips all addons.
261
261
  - **Examples 'none'**: Skips all example implementations (todo, AI chat).
262
- - **Nuxt, Svelte, SolidStart, and Astro** frontends are only compatible with the oRPC API layer
263
- - **PWA support** requires TanStack Router, React Router, Next.js, or SolidStart
262
+ - **Nuxt, Svelte, Solid, and Astro** frontends are only compatible with the oRPC API layer
263
+ - **PWA support** requires TanStack Router, React Router, Next.js, or Solid
264
264
  - **Tauri desktop app** requires TanStack Router, React Router, TanStack Start, Next.js, Nuxt, SvelteKit, or Astro
265
265
  - **Electrobun desktop app** requires TanStack Router, React Router, TanStack Start, Next.js, Nuxt, SvelteKit, or Astro. Desktop packaging uses static web assets, so SSR-first frontends need a static/export build before desktop builds will work.
266
266
  - **AI example** is not compatible with Solid or Astro. With Convex backend, it also excludes Nuxt and Svelte.
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-BYgmfow5.mjs";
2
+ import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-DjuxSWWY.mjs";
3
3
  import z from "zod";
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/dist/index.d.mts CHANGED
@@ -186,7 +186,7 @@ declare const router: import("@trpc/server").TRPCBuiltRouter<{
186
186
  disableAnalytics?: boolean | undefined;
187
187
  manualDb?: boolean | undefined;
188
188
  dbSetupOptions?: {
189
- mode?: "manual" | "auto" | undefined;
189
+ mode?: "manual" | "auto" | "alchemy" | undefined;
190
190
  neon?: {
191
191
  method?: "neon" | "neon-new" | "neondb" | "neonctl" | undefined;
192
192
  projectName?: string | undefined;
@@ -249,7 +249,7 @@ declare const router: import("@trpc/server").TRPCBuiltRouter<{
249
249
  } | undefined;
250
250
  } | undefined;
251
251
  dbSetupOptions?: {
252
- mode?: "manual" | "auto" | undefined;
252
+ mode?: "manual" | "auto" | "alchemy" | undefined;
253
253
  neon?: {
254
254
  method?: "neon" | "neon-new" | "neondb" | "neonctl" | undefined;
255
255
  projectName?: string | undefined;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-BYgmfow5.mjs";
2
+ import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-DjuxSWWY.mjs";
3
3
  export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, Result, SchemaNameSchema, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, getSchemaResult, router, sponsors };
@@ -32,7 +32,7 @@ const VALUE_LABELS = {
32
32
  next: "Next.js",
33
33
  nuxt: "Nuxt",
34
34
  svelte: "SvelteKit",
35
- solid: "SolidStart",
35
+ solid: "Solid",
36
36
  astro: "Astro",
37
37
  "native-bare": "Expo (bare)",
38
38
  "native-uniwind": "Expo + Uniwind",
@@ -88,6 +88,9 @@ const VALUE_LABELS = {
88
88
  docker: "Docker",
89
89
  cloudflare: "Cloudflare",
90
90
  vercel: "Vercel",
91
+ alchemy: "Alchemy",
92
+ auto: "Automatic",
93
+ manual: "Manual",
91
94
  npm: "npm",
92
95
  pnpm: "pnpm"
93
96
  };
@@ -132,7 +135,8 @@ function getConfigSections(config) {
132
135
  section("Data", [
133
136
  ["Database", config.database],
134
137
  ["ORM", config.orm],
135
- ["Setup", config.dbSetup]
138
+ ["Setup", config.dbSetup],
139
+ ["Provisioning", config.dbSetupOptions?.mode]
136
140
  ]),
137
141
  section("Product", [
138
142
  ["Auth", config.auth],
@@ -964,11 +968,11 @@ function validateSelfBackendCompatibility(providedFlags, options, config) {
964
968
  const frontends = config.frontend || options.frontend || [];
965
969
  if (backend === "self") {
966
970
  const { web, native } = splitFrontends(frontends);
967
- if (!(web.length === 1 && FULLSTACK_FRONTENDS$1.includes(web[0]))) return validationErr$1("Backend 'self' (fullstack) currently only supports Next.js, TanStack Start, Nuxt, SvelteKit, SolidStart, and Astro frontends. Please use --frontend next, --frontend tanstack-start, --frontend nuxt, --frontend svelte, --frontend solid, or --frontend astro.");
971
+ if (!(web.length === 1 && FULLSTACK_FRONTENDS$1.includes(web[0]))) return validationErr$1("Backend 'self' (fullstack) currently only supports Next.js, TanStack Start, Nuxt, SvelteKit, Solid, and Astro frontends. Please use --frontend next, --frontend tanstack-start, --frontend nuxt, --frontend svelte, --frontend solid, or --frontend astro.");
968
972
  if (native.length > 1) return validationErr$1("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
969
973
  }
970
974
  const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
971
- if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") return validationErr$1("Backend 'self' (fullstack) currently only supports Next.js, TanStack Start, Nuxt, SvelteKit, SolidStart, and Astro frontends. Please use --frontend next, --frontend tanstack-start, --frontend nuxt, --frontend svelte, --frontend solid, --frontend astro, or choose a different backend.");
975
+ if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") return validationErr$1("Backend 'self' (fullstack) currently only supports Next.js, TanStack Start, Nuxt, SvelteKit, Solid, and Astro frontends. Please use --frontend next, --frontend tanstack-start, --frontend nuxt, --frontend svelte, --frontend solid, --frontend astro, or choose a different backend.");
972
976
  return Result.ok(void 0);
973
977
  }
974
978
  function validateWorkersCompatibility(providedFlags, options, config) {
@@ -1074,7 +1078,7 @@ function supportsPrismaWebDeploy(frontend) {
1074
1078
  }
1075
1079
  function validatePrismaWebDeploy(webDeploy, frontend) {
1076
1080
  if (webDeploy !== "prisma" || !frontend) return Result.ok(void 0);
1077
- if (!supportsPrismaWebDeploy(frontend)) return validationErr$1("'--web-deploy prisma' requires a supported server frontend. Choose Next.js, Nuxt, Astro, React Router, TanStack Start, SvelteKit, or SolidStart. TanStack Router is a static SPA, while Prisma Compute requires an executable server artifact.");
1081
+ if (!supportsPrismaWebDeploy(frontend)) return validationErr$1("'--web-deploy prisma' requires a supported server frontend. Choose Next.js, Nuxt, Astro, React Router, TanStack Start, SvelteKit, or Solid. TanStack Router is a static SPA, while Prisma Compute requires an executable server artifact.");
1078
1082
  return Result.ok(void 0);
1079
1083
  }
1080
1084
  function validateCloudflareWebDeployKnownIssues(config) {
@@ -1763,7 +1767,7 @@ function getNodeToolingRequirements(config) {
1763
1767
  addNodeRequirement(requirements, "^22.19.0 || ^24.11.0 || >=26.0.0", "Nuxt 4");
1764
1768
  break;
1765
1769
  case "solid":
1766
- addNodeRequirement(requirements, ">=24.0.0", "SolidStart 2");
1770
+ addNodeRequirement(requirements, ">=24.0.0", "Solid");
1767
1771
  break;
1768
1772
  case "react-router":
1769
1773
  addNodeRequirement(requirements, ">=22.22.0", "React Router 8");
@@ -4888,6 +4892,54 @@ async function addHandlerInternal(input) {
4888
4892
  });
4889
4893
  }
4890
4894
  //#endregion
4895
+ //#region src/helpers/core/db-setup-options.ts
4896
+ function withDbSetupMode(dbSetupOptions, mode) {
4897
+ const resolved = { ...dbSetupOptions };
4898
+ if (mode === void 0) delete resolved.mode;
4899
+ else resolved.mode = mode;
4900
+ return Object.keys(resolved).length === 0 ? void 0 : resolved;
4901
+ }
4902
+ const REMOTE_PROVISIONING_DB_SETUPS = [
4903
+ "turso",
4904
+ "neon",
4905
+ "prisma-postgres",
4906
+ "supabase",
4907
+ "mongodb-atlas"
4908
+ ];
4909
+ function requiresProvisioningGuardrails(dbSetup) {
4910
+ return REMOTE_PROVISIONING_DB_SETUPS.includes(dbSetup);
4911
+ }
4912
+ function resolveDbSetupMode(dbSetup, cliOptions = {}) {
4913
+ if (dbSetup === "none") return;
4914
+ const explicitMode = cliOptions.dbSetupOptions?.mode;
4915
+ if (explicitMode) return explicitMode;
4916
+ if (cliOptions.manualDb === true) return "manual";
4917
+ if (isSilent() && requiresProvisioningGuardrails(dbSetup)) return "manual";
4918
+ }
4919
+ function mergeResolvedDbSetupOptions(dbSetup, dbSetupOptions, cliOptions = {}) {
4920
+ if (dbSetup === "none") return;
4921
+ const resolvedMode = resolveDbSetupMode(dbSetup, {
4922
+ ...cliOptions,
4923
+ dbSetupOptions: dbSetupOptions ?? cliOptions.dbSetupOptions
4924
+ });
4925
+ if (!dbSetupOptions && !resolvedMode) return;
4926
+ return {
4927
+ ...dbSetupOptions,
4928
+ mode: resolvedMode
4929
+ };
4930
+ }
4931
+ function resolveProjectDbSetupOptions(config, cliOptions = {}) {
4932
+ const dbSetupOptions = config.dbSetupOptions ?? cliOptions.dbSetupOptions;
4933
+ if (!(dbSetupOptions?.mode ?? (cliOptions.manualDb === true ? "manual" : void 0)) && (0, types_exports.supportsAlchemyManagedDatabase)(config)) return {
4934
+ ...dbSetupOptions,
4935
+ mode: "alchemy"
4936
+ };
4937
+ return mergeResolvedDbSetupOptions(config.dbSetup, dbSetupOptions, {
4938
+ ...cliOptions,
4939
+ dbSetupOptions
4940
+ });
4941
+ }
4942
+ //#endregion
4891
4943
  //#region src/prompts/api.ts
4892
4944
  async function getApiChoice(Api, frontend, backend, previousValue) {
4893
4945
  if (backend === "convex" || backend === "none") return "none";
@@ -5164,6 +5216,47 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime, p
5164
5216
  if (isCancel$1(response)) throw new UserCancelledError({ message: "Operation cancelled" });
5165
5217
  return response;
5166
5218
  }
5219
+ const providerLabels = {
5220
+ neon: "Neon",
5221
+ planetscale: "PlanetScale",
5222
+ "prisma-postgres": "Prisma Postgres"
5223
+ };
5224
+ async function getDbProvisioningChoice(mode, dbSetup, backend, webDeploy, serverDeploy, previousValue) {
5225
+ if (!dbSetup || !backend || !webDeploy || !serverDeploy) return mode;
5226
+ if (!(0, types_exports.supportsAlchemyManagedDatabase)({
5227
+ backend,
5228
+ dbSetup,
5229
+ webDeploy,
5230
+ serverDeploy
5231
+ })) return mode === "alchemy" ? void 0 : mode;
5232
+ if (mode !== void 0) return mode;
5233
+ const provider = providerLabels[dbSetup];
5234
+ if (!provider) return void 0;
5235
+ const options = [
5236
+ {
5237
+ value: "alchemy",
5238
+ label: "Alchemy",
5239
+ hint: `Provision ${provider} during deploy and inject its credentials`
5240
+ },
5241
+ ...dbSetup === "neon" || dbSetup === "prisma-postgres" ? [{
5242
+ value: "auto",
5243
+ label: "Automatic",
5244
+ hint: `Set up ${provider} now and write its connection credentials`
5245
+ }] : [],
5246
+ {
5247
+ value: "manual",
5248
+ label: "Manual",
5249
+ hint: `Use an existing ${provider} database and configure credentials yourself`
5250
+ }
5251
+ ];
5252
+ const response = await navigableSelect({
5253
+ message: `How should ${provider} be provisioned?`,
5254
+ options,
5255
+ initialValue: preferValidInitial(options, previousValue, "alchemy")
5256
+ });
5257
+ if (isCancel$1(response)) throw new UserCancelledError({ message: "Operation cancelled" });
5258
+ return response;
5259
+ }
5167
5260
  //#endregion
5168
5261
  //#region src/prompts/examples.ts
5169
5262
  async function getExamplesChoice(examples, database, frontends, backend, api, previousValue) {
@@ -5431,6 +5524,20 @@ function validateDatabaseSetup(config, providedFlags) {
5431
5524
  }
5432
5525
  return Result.ok(void 0);
5433
5526
  }
5527
+ function validateDatabaseProvisioningMode(config) {
5528
+ if (config.dbSetup === "planetscale" && config.dbSetupOptions?.mode === "auto") return validationErr("PlanetScale does not support automatic database setup. Use dbSetupOptions.mode 'alchemy' or 'manual'.");
5529
+ if (config.dbSetupOptions?.mode !== "alchemy") return Result.ok(void 0);
5530
+ const { backend, dbSetup, webDeploy, serverDeploy } = config;
5531
+ if (!backend || !dbSetup || !webDeploy || !serverDeploy) return Result.ok(void 0);
5532
+ if (!(0, types_exports.supportsAlchemyManagedDatabase)({
5533
+ backend,
5534
+ dbSetup,
5535
+ webDeploy,
5536
+ serverDeploy,
5537
+ dbSetupOptions: config.dbSetupOptions
5538
+ })) return validationErr("Alchemy database provisioning requires Neon, PlanetScale, or Prisma Postgres and an Alchemy deployment target for the app that consumes the database.");
5539
+ return Result.ok(void 0);
5540
+ }
5434
5541
  function validateConvexConstraints(config, providedFlags) {
5435
5542
  const { backend } = config;
5436
5543
  if (backend !== "convex") return Result.ok(void 0);
@@ -5515,6 +5622,7 @@ function validateFullConfig(config, providedFlags, options) {
5515
5622
  return Result.gen(function* () {
5516
5623
  yield* validateDatabaseOrmAuth(config, providedFlags);
5517
5624
  yield* validateDatabaseSetup(config, providedFlags);
5625
+ yield* validateDatabaseProvisioningMode(config);
5518
5626
  yield* validateConvexConstraints(config, providedFlags);
5519
5627
  yield* validateBackendNoneConstraints(config, providedFlags);
5520
5628
  yield* validateSelfBackendConstraints(config, providedFlags);
@@ -5827,6 +5935,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath, option
5827
5935
  examples: ({ results, previousAnswer }) => getExamplesChoice(flags.examples, results.database, results.frontend, results.backend, results.api, previousAnswer),
5828
5936
  webDeploy: ({ results, previousAnswer }) => getDeploymentChoice(flags.webDeploy, results.runtime, results.backend, results.frontend, results.dbSetup, results.database, results.orm, results.addons, previousAnswer),
5829
5937
  serverDeploy: ({ results, previousAnswer }) => getServerDeploymentChoice(flags.serverDeploy, results.runtime, results.backend, results.webDeploy, previousAnswer),
5938
+ dbSetupMode: ({ results, previousAnswer }) => getDbProvisioningChoice(flags.dbSetupOptions?.mode ?? (options.manualDb === true ? "manual" : void 0), results.dbSetup, results.backend, results.webDeploy, results.serverDeploy, previousAnswer),
5830
5939
  git: ({ previousAnswer }) => getGitChoice(flags.git, previousAnswer),
5831
5940
  packageManager: ({ previousAnswer }) => getPackageManagerChoice(flags.packageManager, previousAnswer),
5832
5941
  install: ({ previousAnswer }) => getinstallChoice(flags.install, previousAnswer)
@@ -5864,6 +5973,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath, option
5864
5973
  prompts: [
5865
5974
  "webDeploy",
5866
5975
  "serverDeploy",
5976
+ "dbSetupMode",
5867
5977
  "git",
5868
5978
  "packageManager",
5869
5979
  "install"
@@ -5879,7 +5989,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath, option
5879
5989
  projectDir,
5880
5990
  relativePath,
5881
5991
  addonOptions: flags.addonOptions,
5882
- dbSetupOptions: flags.dbSetupOptions,
5992
+ dbSetupOptions: withDbSetupMode(flags.dbSetupOptions, result.dbSetupMode),
5883
5993
  frontend: result.frontend,
5884
5994
  backend: result.backend,
5885
5995
  runtime: result.runtime,
@@ -6570,37 +6680,6 @@ async function commandExists(command) {
6570
6680
  return result.isOk() ? result.value : false;
6571
6681
  }
6572
6682
  //#endregion
6573
- //#region src/helpers/core/db-setup-options.ts
6574
- const REMOTE_PROVISIONING_DB_SETUPS = [
6575
- "turso",
6576
- "neon",
6577
- "prisma-postgres",
6578
- "supabase",
6579
- "mongodb-atlas"
6580
- ];
6581
- function requiresProvisioningGuardrails(dbSetup) {
6582
- return REMOTE_PROVISIONING_DB_SETUPS.includes(dbSetup);
6583
- }
6584
- function resolveDbSetupMode(dbSetup, cliOptions = {}) {
6585
- if (dbSetup === "none") return;
6586
- const explicitMode = cliOptions.dbSetupOptions?.mode;
6587
- if (explicitMode) return explicitMode;
6588
- if (cliOptions.manualDb === true) return "manual";
6589
- if (isSilent() && requiresProvisioningGuardrails(dbSetup)) return "manual";
6590
- }
6591
- function mergeResolvedDbSetupOptions(dbSetup, dbSetupOptions, cliOptions = {}) {
6592
- if (dbSetup === "none") return;
6593
- const resolvedMode = resolveDbSetupMode(dbSetup, {
6594
- ...cliOptions,
6595
- dbSetupOptions: dbSetupOptions ?? cliOptions.dbSetupOptions
6596
- });
6597
- if (!dbSetupOptions && !resolvedMode) return;
6598
- return {
6599
- ...dbSetupOptions,
6600
- mode: resolvedMode
6601
- };
6602
- }
6603
- //#endregion
6604
6683
  //#region src/helpers/database-providers/mongodb-atlas-setup.ts
6605
6684
  async function checkAtlasCLI() {
6606
6685
  const exists = await commandExists("atlas");
@@ -7893,7 +7972,7 @@ function getDesktopStaticBuildNote(frontend) {
7893
7972
  return `${pc.yellow("NOTE:")} Desktop builds package static web assets.\n ${staticBuildFrontends.get(staticBuildFrontend)} needs a static/export web build before desktop packaging will work.`;
7894
7973
  }
7895
7974
  async function displayPostInstallInstructions(config) {
7896
- const { api, database, relativePath, packageManager, depsInstalled, orm, addons, runtime, frontend, backend, dbSetup, webDeploy, serverDeploy } = config;
7975
+ const { api, database, relativePath, packageManager, depsInstalled, orm, addons, runtime, frontend, backend, dbSetup, webDeploy, serverDeploy, dbSetupOptions } = config;
7897
7976
  const isConvex = backend === "convex";
7898
7977
  const isBackendSelf = backend === "self";
7899
7978
  const runCmd = packageManager === "npm" ? "npm run" : packageManager === "pnpm" ? "pnpm run" : "bun run";
@@ -7903,7 +7982,7 @@ async function displayPostInstallInstructions(config) {
7903
7982
  const hasVitePlus = addons?.includes("vite-plus");
7904
7983
  const hasVitePlusNativeHooks = hasVitePlus && !hasHusky && !hasLefthook;
7905
7984
  const hasGitHooksOrLinting = addons?.includes("husky") || addons?.includes("biome") || addons?.includes("lefthook") || addons?.includes("oxlint") || hasVitePlus;
7906
- const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, webDeploy, serverDeploy, backend) : "";
7985
+ const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, webDeploy, serverDeploy, backend, dbSetupOptions) : "";
7907
7986
  const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd, frontend) : "";
7908
7987
  const electrobunInstructions = addons?.includes("electrobun") ? getElectrobunInstructions(runCmd, frontend) : "";
7909
7988
  const huskyInstructions = hasHusky ? getHuskyInstructions(runCmd) : "";
@@ -7914,7 +7993,7 @@ async function displayPostInstallInstructions(config) {
7914
7993
  const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
7915
7994
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
7916
7995
  const clerkInstructions = config.auth === "clerk" ? getClerkInstructions(frontend || [], backend, api) : "";
7917
- const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
7996
+ const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend, config.auth, frontend || []);
7918
7997
  const hasWeb = frontend?.some((f) => types_exports.webFrontends.includes(f));
7919
7998
  const hasNative = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles");
7920
7999
  const hasReactRouter = frontend?.includes("react-router");
@@ -8038,7 +8117,7 @@ function getLefthookInstructions(packageManager) {
8038
8117
  function getVitePlusNativeHooksInstructions(runCmd) {
8039
8118
  return `${pc.bold("Vite+ native Git hooks:")}\n${pc.cyan("•")} Optional hook setup: ${`${runCmd} hooks:setup`}\n${pc.dim(" (runs vp config; hooks install into .vite-hooks and use vp staged)")}\n`;
8040
8119
  }
8041
- async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup, webDeploy, serverDeploy, backend) {
8120
+ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup, webDeploy, serverDeploy, backend, dbSetupOptions) {
8042
8121
  const notes = [];
8043
8122
  const commands = [];
8044
8123
  const isD1Alchemy = dbSetup === "d1" && (serverDeploy === "cloudflare" || backend === "self" && webDeploy === "cloudflare");
@@ -8046,7 +8125,8 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
8046
8125
  backend,
8047
8126
  dbSetup,
8048
8127
  webDeploy,
8049
- serverDeploy
8128
+ serverDeploy,
8129
+ dbSetupOptions
8050
8130
  });
8051
8131
  if (dbSetup === "docker") {
8052
8132
  const dockerStatus = await getDockerStatus(database);
@@ -8210,7 +8290,7 @@ function getPolarInstructions(backend, packageManager) {
8210
8290
  const envPath = backend === "self" ? "apps/web/.env" : "apps/server/.env";
8211
8291
  return `${pc.bold("Polar Payments Setup:")}\n${pc.cyan("•")} Get access token & product ID from ${pc.underline("https://sandbox.polar.sh/")}\n${pc.cyan("•")} Set POLAR_ACCESS_TOKEN in ${envPath}`;
8212
8292
  }
8213
- function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend) {
8293
+ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend, auth, frontend) {
8214
8294
  const instructions = [];
8215
8295
  const isBackendSelf = backend === "self";
8216
8296
  const hasAlchemyWeb = (0, types_exports.isAlchemyDeployTarget)(webDeploy);
@@ -8219,7 +8299,12 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend)
8219
8299
  if (hasAlchemyWeb || hasAlchemyServer) {
8220
8300
  const targetParts = [...hasAlchemyWeb ? [`web on ${webDeploy === "cloudflare" ? "Cloudflare" : "Prisma"}`] : [], ...hasAlchemyServer && !isBackendSelf ? [`server on ${serverDeploy === "cloudflare" ? "Cloudflare" : "Prisma"}`] : []];
8221
8301
  const deployScript = webDeploy === "vercel" ? "deploy:server" : serverDeploy === "vercel" ? "deploy:web" : "deploy";
8222
- instructions.push(`${pc.bold(`Deploy with Alchemy (${targetParts.join(" + ")}):`)}\n${pc.cyan("•")} Configure provider login: ${`cd packages/infra && ${alchemyExec} alchemy login --configure`}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} ${deployScript}`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
8302
+ const originSteps = [];
8303
+ const hasWeb = frontend.some((value) => types_exports.webFrontends.includes(value));
8304
+ if (!isBackendSelf && hasAlchemyServer && hasWeb) originSteps.push(`${pc.cyan("•")} Required after the first deploy: set CORS_ORIGIN in apps/server/.env to the deployed web origin, then deploy again`);
8305
+ if (auth === "better-auth" && isBackendSelf && webDeploy === "prisma") originSteps.push(`${pc.cyan("•")} After the first deploy, set BETTER_AUTH_URL in apps/web/.env to the returned web URL, then deploy again`);
8306
+ else if (auth === "better-auth" && !isBackendSelf && serverDeploy === "prisma") originSteps.push(`${pc.cyan("•")} After the first deploy, set BETTER_AUTH_URL in apps/server/.env to the returned server URL, then deploy again`);
8307
+ instructions.push(`${pc.bold(`Deploy with Alchemy (${targetParts.join(" + ")}):`)}\n${pc.cyan("•")} Configure provider login: ${`cd packages/infra && ${alchemyExec} alchemy login --configure`}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} ${deployScript}`}\n${originSteps.join("\n")}${originSteps.length > 0 ? "\n" : ""}${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
8223
8308
  }
8224
8309
  if (webDeploy === "docker" || serverDeploy === "docker") {
8225
8310
  const dockerTargets = webDeploy === "docker" && serverDeploy === "docker" ? "web + server" : webDeploy === "docker" ? "web" : "server";
@@ -8466,7 +8551,10 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
8466
8551
  const isTemplateSetup = input.template && input.template !== "none";
8467
8552
  if (!isSilent() && !isTemplateSetup && Object.keys(otherFlags).length > 0) log.info(pc.dim("Command-line options applied."));
8468
8553
  config = yield* Result.await(Result.tryPromise({
8469
- try: async () => gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput, { skipCompatibilityChecks: cliInput.yolo }),
8554
+ try: async () => gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput, {
8555
+ skipCompatibilityChecks: cliInput.yolo,
8556
+ manualDb: cliInput.manualDb ?? input.manualDb
8557
+ }),
8470
8558
  catch: (cause) => {
8471
8559
  if (cause instanceof UserCancelledError) return cause;
8472
8560
  return new CLIError({
@@ -8476,7 +8564,7 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
8476
8564
  }
8477
8565
  }));
8478
8566
  }
8479
- const effectiveDbSetupOptions = mergeResolvedDbSetupOptions(config.dbSetup, config.dbSetupOptions, {
8567
+ const effectiveDbSetupOptions = resolveProjectDbSetupOptions(config, {
8480
8568
  manualDb: cliInput.manualDb ?? input.manualDb,
8481
8569
  dbSetupOptions: cliInput.dbSetupOptions ?? input.dbSetupOptions
8482
8570
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.39.2",
3
+ "version": "3.40.0",
4
4
  "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
5
5
  "keywords": [
6
6
  "better-auth",
@@ -69,8 +69,8 @@
69
69
  "prepublishOnly": "npm run build"
70
70
  },
71
71
  "dependencies": {
72
- "@better-t-stack/template-generator": "^3.39.2",
73
- "@better-t-stack/types": "^3.39.2",
72
+ "@better-t-stack/template-generator": "^3.40.0",
73
+ "@better-t-stack/types": "^3.40.0",
74
74
  "@clack/core": "^1.4.3",
75
75
  "@clack/prompts": "^1.7.0",
76
76
  "@modelcontextprotocol/sdk": "1.30.0",