create-better-t-stack 3.35.2 → 3.36.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
@@ -68,8 +68,8 @@ Options:
68
68
  --install Install dependencies
69
69
  --no-install Skip installing dependencies
70
70
  --db-setup <setup> Database setup (turso, d1, neon, supabase, prisma-postgres, planetscale, mongodb-atlas, docker, none)
71
- --web-deploy <setup> Web deployment (cloudflare, docker, none)
72
- --server-deploy <setup> Server deployment (cloudflare, docker, none)
71
+ --web-deploy <setup> Web deployment (cloudflare, docker, vercel, none)
72
+ --server-deploy <setup> Server deployment (cloudflare, docker, vercel, none)
73
73
  --backend <framework> Backend framework (hono, express, fastify, elysia, convex, self, none)
74
74
  --runtime <runtime> Runtime (bun, node, workers, none)
75
75
  --api <type> API type (trpc, orpc, none)
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-CTOHjSfr.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-CAiTgv6S.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
@@ -184,8 +184,8 @@ declare const router: _$_trpc_server0.TRPCBuiltRouter<{
184
184
  backend?: "none" | "hono" | "express" | "fastify" | "elysia" | "convex" | "self" | undefined;
185
185
  runtime?: "none" | "bun" | "node" | "workers" | undefined;
186
186
  api?: "none" | "trpc" | "orpc" | undefined;
187
- webDeploy?: "none" | "docker" | "cloudflare" | undefined;
188
- serverDeploy?: "none" | "docker" | "cloudflare" | undefined;
187
+ webDeploy?: "none" | "docker" | "cloudflare" | "vercel" | undefined;
188
+ serverDeploy?: "none" | "docker" | "cloudflare" | "vercel" | undefined;
189
189
  directoryConflict?: "merge" | "overwrite" | "increment" | "error" | undefined;
190
190
  renderTitle?: boolean | undefined;
191
191
  disableAnalytics?: boolean | undefined;
@@ -249,7 +249,7 @@ declare const router: _$_trpc_server0.TRPCBuiltRouter<{
249
249
  ultracite?: {
250
250
  linter?: "biome" | "oxlint" | "eslint" | undefined;
251
251
  editors?: ("void" | "antigravity" | "cursor" | "vscode" | "zed" | "windsurf" | "trae" | "codebuddy" | "bob" | "kiro")[] | undefined;
252
- agents?: ("cline" | "codex" | "opencode" | "goose" | "amp" | "pi" | "qoder" | "droid" | "zencoder" | "mcpjam" | "bob" | "universal" | "claude" | "jules" | "replit" | "devin" | "lovable" | "ona" | "openclaw" | "continue" | "snowflake-cortex" | "deepagents" | "kimi-cli" | "mux" | "adal" | "copilot" | "aider" | "firebase-studio" | "open-hands" | "gemini" | "junie" | "augmentcode" | "kilo-code" | "roo-code" | "warp" | "crush" | "qwen" | "amazon-q-cli" | "firebender" | "cursor-cli" | "mistral-vibe" | "vercel")[] | undefined;
252
+ agents?: ("vercel" | "cline" | "codex" | "opencode" | "goose" | "amp" | "pi" | "qoder" | "droid" | "zencoder" | "mcpjam" | "bob" | "universal" | "claude" | "jules" | "replit" | "devin" | "lovable" | "ona" | "openclaw" | "continue" | "snowflake-cortex" | "deepagents" | "kimi-cli" | "mux" | "adal" | "copilot" | "aider" | "firebase-studio" | "open-hands" | "gemini" | "junie" | "augmentcode" | "kilo-code" | "roo-code" | "warp" | "crush" | "qwen" | "amazon-q-cli" | "firebender" | "cursor-cli" | "mistral-vibe")[] | undefined;
253
253
  hooks?: ("cursor" | "windsurf" | "codebuddy" | "claude" | "copilot")[] | undefined;
254
254
  } | undefined;
255
255
  } | undefined;
@@ -283,8 +283,8 @@ declare const router: _$_trpc_server0.TRPCBuiltRouter<{
283
283
  backend?: "none" | "hono" | "express" | "fastify" | "elysia" | "convex" | "self" | undefined;
284
284
  runtime?: "none" | "bun" | "node" | "workers" | undefined;
285
285
  api?: "none" | "trpc" | "orpc" | undefined;
286
- webDeploy?: "none" | "docker" | "cloudflare" | undefined;
287
- serverDeploy?: "none" | "docker" | "cloudflare" | undefined;
286
+ webDeploy?: "none" | "docker" | "cloudflare" | "vercel" | undefined;
287
+ serverDeploy?: "none" | "docker" | "cloudflare" | "vercel" | undefined;
288
288
  directoryConflict?: "merge" | "overwrite" | "increment" | "error" | undefined;
289
289
  renderTitle?: boolean | undefined;
290
290
  disableAnalytics?: boolean | undefined;
@@ -359,12 +359,12 @@ declare const router: _$_trpc_server0.TRPCBuiltRouter<{
359
359
  ultracite?: {
360
360
  linter?: "biome" | "oxlint" | "eslint" | undefined;
361
361
  editors?: ("void" | "antigravity" | "cursor" | "vscode" | "zed" | "windsurf" | "trae" | "codebuddy" | "bob" | "kiro")[] | undefined;
362
- agents?: ("cline" | "codex" | "opencode" | "goose" | "amp" | "pi" | "qoder" | "droid" | "zencoder" | "mcpjam" | "bob" | "universal" | "claude" | "jules" | "replit" | "devin" | "lovable" | "ona" | "openclaw" | "continue" | "snowflake-cortex" | "deepagents" | "kimi-cli" | "mux" | "adal" | "copilot" | "aider" | "firebase-studio" | "open-hands" | "gemini" | "junie" | "augmentcode" | "kilo-code" | "roo-code" | "warp" | "crush" | "qwen" | "amazon-q-cli" | "firebender" | "cursor-cli" | "mistral-vibe" | "vercel")[] | undefined;
362
+ agents?: ("vercel" | "cline" | "codex" | "opencode" | "goose" | "amp" | "pi" | "qoder" | "droid" | "zencoder" | "mcpjam" | "bob" | "universal" | "claude" | "jules" | "replit" | "devin" | "lovable" | "ona" | "openclaw" | "continue" | "snowflake-cortex" | "deepagents" | "kimi-cli" | "mux" | "adal" | "copilot" | "aider" | "firebase-studio" | "open-hands" | "gemini" | "junie" | "augmentcode" | "kilo-code" | "roo-code" | "warp" | "crush" | "qwen" | "amazon-q-cli" | "firebender" | "cursor-cli" | "mistral-vibe")[] | undefined;
363
363
  hooks?: ("cursor" | "windsurf" | "codebuddy" | "claude" | "copilot")[] | undefined;
364
364
  } | undefined;
365
365
  } | undefined;
366
- webDeploy?: "none" | "docker" | "cloudflare" | undefined;
367
- serverDeploy?: "none" | "docker" | "cloudflare" | undefined;
366
+ webDeploy?: "none" | "docker" | "cloudflare" | "vercel" | undefined;
367
+ serverDeploy?: "none" | "docker" | "cloudflare" | "vercel" | undefined;
368
368
  projectDir?: string | undefined;
369
369
  install?: boolean | undefined;
370
370
  packageManager?: "bun" | "npm" | "pnpm" | 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-CTOHjSfr.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-CAiTgv6S.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 };
@@ -883,11 +883,36 @@ function validateDockerServerDeploy(serverDeploy, backend, runtime) {
883
883
  if (runtime === "workers") return validationErr$1("'--server-deploy docker' is not compatible with '--runtime workers'. Use '--runtime bun' or '--runtime node', or choose '--server-deploy cloudflare'.");
884
884
  return Result.ok(void 0);
885
885
  }
886
+ function validateVercelServerDeploy(serverDeploy, backend, runtime) {
887
+ if (serverDeploy !== "vercel") return Result.ok(void 0);
888
+ if (backend === "convex" || backend === "self") return validationErr$1("'--server-deploy vercel' requires a separate server backend (hono, express, fastify, elysia). For a fullstack 'self' backend, use '--web-deploy vercel' instead.");
889
+ if (runtime === "workers") return validationErr$1("'--server-deploy vercel' is not compatible with '--runtime workers'. Use '--runtime bun' or '--runtime node', or choose '--server-deploy cloudflare'.");
890
+ return Result.ok(void 0);
891
+ }
892
+ const DOCKER_SERVER_OUTPUT_FRONTENDS = [
893
+ "next",
894
+ "svelte",
895
+ "astro",
896
+ "react-router"
897
+ ];
898
+ function validateDockerWebDeployDesktopAddons(webDeploy, addons, frontend, backend, auth) {
899
+ if (webDeploy !== "docker" || !addons || !frontend) return Result.ok(void 0);
900
+ const desktopAddons = addons.filter((addon) => STATIC_DESKTOP_ADDONS.includes(addon));
901
+ if (desktopAddons.length === 0) return Result.ok(void 0);
902
+ const affected = frontend.find((f) => DOCKER_SERVER_OUTPUT_FRONTENDS.includes(f));
903
+ if (!affected) return Result.ok(void 0);
904
+ if (affected === "next" && !desktopAddons.includes("tauri") && backend === "convex" && auth === "better-auth") return Result.ok(void 0);
905
+ return validationErr$1(`'--web-deploy docker' is not compatible with the ${desktopAddons.join(", ")} addon on '${affected}' because desktop addons switch the web build to a static export, which the docker image cannot serve. Remove the addon or use a static-serving frontend (tanstack-router, solid).`);
906
+ }
886
907
  function validateAddonCompatibility(addon, frontend, auth, backend, runtime) {
887
908
  if (addon === "evlog" && !supportsEvlogAddon(frontend, backend, runtime)) return {
888
909
  isCompatible: false,
889
910
  reason: evlogCompatibilityMessage
890
911
  };
912
+ if (STATIC_DESKTOP_ADDONS.includes(addon) && auth === "clerk" && frontend.includes("react-router")) return {
913
+ isCompatible: false,
914
+ reason: `${addon} addon forces React Router into a static export, but Clerk on React Router requires SSR middleware. Remove the addon or use a different auth/frontend.`
915
+ };
891
916
  if (backend === "self" && STATIC_DESKTOP_ADDONS.includes(addon)) return {
892
917
  isCompatible: false,
893
918
  reason: `${addon} addon requires a separate backend or no backend because backend 'self' emits server routes that cannot be bundled as static desktop assets.`
@@ -4680,6 +4705,8 @@ function validateFullConfig(config, providedFlags, options) {
4680
4705
  yield* validateApiConstraints(config, options);
4681
4706
  yield* validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
4682
4707
  yield* validateDockerServerDeploy(config.serverDeploy, config.backend, config.runtime);
4708
+ yield* validateVercelServerDeploy(config.serverDeploy, config.backend, config.runtime);
4709
+ yield* validateDockerWebDeployDesktopAddons(config.webDeploy, config.addons, config.frontend, config.backend, config.auth);
4683
4710
  yield* validateSelfBackendCompatibility(providedFlags, options, config);
4684
4711
  yield* validateWorkersCompatibility(providedFlags, options, config);
4685
4712
  if (config.runtime === "workers" && config.serverDeploy === "none") yield* validationErr("Cloudflare Workers runtime requires a server deployment. Please choose 'cloudflare' for --server-deploy.");
@@ -4836,6 +4863,10 @@ function getDeploymentDisplay$1(deployment) {
4836
4863
  label: "Docker",
4837
4864
  hint: "Self-host with a Dockerfile and docker-compose.yml"
4838
4865
  };
4866
+ if (deployment === "vercel") return {
4867
+ label: "Vercel",
4868
+ hint: "Deploy to Vercel with Services"
4869
+ };
4839
4870
  return {
4840
4871
  label: deployment,
4841
4872
  hint: `Add ${deployment} deployment`
@@ -4846,7 +4877,11 @@ async function getServerDeploymentChoice(deployment, runtime, backend, _webDeplo
4846
4877
  if (!backend || !SERVER_APP_BACKENDS.includes(backend)) return "none";
4847
4878
  if (runtime === "workers") return "cloudflare";
4848
4879
  if (runtime !== "bun" && runtime !== "node") return "none";
4849
- const options = ["docker", "none"].map((deploy) => {
4880
+ const options = [
4881
+ "docker",
4882
+ "vercel",
4883
+ "none"
4884
+ ].map((deploy) => {
4850
4885
  const { label, hint } = deploy === "none" ? {
4851
4886
  label: "None",
4852
4887
  hint: "Skip deployment setup"
@@ -4879,6 +4914,10 @@ function getDeploymentDisplay(deployment) {
4879
4914
  label: "Docker",
4880
4915
  hint: "Self-host with a Dockerfile and docker-compose.yml"
4881
4916
  };
4917
+ if (deployment === "vercel") return {
4918
+ label: "Vercel",
4919
+ hint: "Deploy to Vercel with Services"
4920
+ };
4882
4921
  return {
4883
4922
  label: deployment,
4884
4923
  hint: `Add ${deployment} deployment`
@@ -4891,6 +4930,7 @@ async function getDeploymentChoice(deployment, _runtime, backend, frontend = [],
4891
4930
  const options = [
4892
4931
  "cloudflare",
4893
4932
  "docker",
4933
+ "vercel",
4894
4934
  "none"
4895
4935
  ].map((deploy) => {
4896
4936
  const { label, hint } = getDeploymentDisplay(deploy);
@@ -6947,11 +6987,11 @@ async function displayPostInstallInstructions(config) {
6947
6987
  if (vitePlusNativeHooksInstructions) output += `\n${vitePlusNativeHooksInstructions.trim()}\n`;
6948
6988
  if (lintingInstructions) output += `\n${lintingInstructions.trim()}\n`;
6949
6989
  if (pwaInstructions) output += `\n${pwaInstructions.trim()}\n`;
6950
- if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
6951
6990
  if (starlightInstructions) output += `\n${starlightInstructions.trim()}\n`;
6952
6991
  if (clerkInstructions) output += `\n${clerkInstructions.trim()}\n`;
6953
6992
  if (betterAuthConvexInstructions) output += `\n${betterAuthConvexInstructions.trim()}\n`;
6954
6993
  if (polarInstructions) output += `\n${polarInstructions.trim()}\n`;
6994
+ if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
6955
6995
  if (noOrmWarning) output += `\n${noOrmWarning.trim()}\n`;
6956
6996
  if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
6957
6997
  const sponsorsResult = await fetchSponsorsQuietly();
@@ -7118,13 +7158,25 @@ function getPolarInstructions(backend, packageManager) {
7118
7158
  function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend) {
7119
7159
  const instructions = [];
7120
7160
  const isBackendSelf = backend === "self";
7121
- if (webDeploy === "cloudflare" && serverDeploy !== "cloudflare" && !isBackendSelf) instructions.push(`${pc.bold("Deploy web with Cloudflare (Alchemy):")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
7122
- else if (serverDeploy === "cloudflare" && webDeploy !== "cloudflare" && !isBackendSelf) instructions.push(`${pc.bold("Deploy server with Cloudflare (Alchemy):")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
7123
- else if (webDeploy === "cloudflare" && (serverDeploy === "cloudflare" || isBackendSelf)) instructions.push(`${pc.bold("Deploy with Cloudflare (Alchemy):")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
7161
+ if (webDeploy === "cloudflare" && serverDeploy !== "cloudflare" && !isBackendSelf) {
7162
+ const cfDeploy = serverDeploy === "vercel" ? "deploy:web" : "deploy";
7163
+ instructions.push(`${pc.bold("Deploy web with Cloudflare (Alchemy):")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} ${cfDeploy}`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
7164
+ } else if (serverDeploy === "cloudflare" && webDeploy !== "cloudflare" && !isBackendSelf) {
7165
+ const cfDeploy = webDeploy === "vercel" ? "deploy:server" : "deploy";
7166
+ instructions.push(`${pc.bold("Deploy server with Cloudflare (Alchemy):")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} ${cfDeploy}`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
7167
+ } else if (webDeploy === "cloudflare" && (serverDeploy === "cloudflare" || isBackendSelf)) instructions.push(`${pc.bold("Deploy with Cloudflare (Alchemy):")}\n${pc.cyan("•")} Dev: ${`${runCmd} dev`}\n${pc.cyan("•")} Deploy: ${`${runCmd} deploy`}\n${pc.cyan("•")} Destroy: ${`${runCmd} destroy`}`);
7124
7168
  if (webDeploy === "docker" || serverDeploy === "docker") {
7125
7169
  const dockerTargets = webDeploy === "docker" && serverDeploy === "docker" ? "web + server" : webDeploy === "docker" ? "web" : "server";
7126
7170
  instructions.push(`${pc.bold(`Deploy ${dockerTargets} with Docker Compose:`)}\n${pc.cyan("•")} Start: ${`${runCmd} docker:up`}\n${pc.cyan("•")} Logs: ${`${runCmd} docker:logs`}\n${pc.cyan("•")} Stop: ${`${runCmd} docker:down`}\n${pc.cyan("•")} Config: docker-compose.yml`);
7127
7171
  }
7172
+ if (webDeploy === "vercel" || serverDeploy === "vercel") {
7173
+ const mixedWithCloudflare = webDeploy === "cloudflare" || serverDeploy === "cloudflare";
7174
+ const vercelSetupScript = "deploy:setup";
7175
+ const vercelEnvScript = "env:production";
7176
+ const vercelDeployScript = mixedWithCloudflare ? webDeploy === "vercel" ? "deploy:web:prod" : "deploy:server:prod" : "deploy:prod";
7177
+ const vercelTargets = webDeploy === "vercel" && (serverDeploy === "vercel" || isBackendSelf) ? "web + server" : webDeploy === "vercel" ? "web" : "server";
7178
+ instructions.push(`${pc.bold(`Deploy ${vercelTargets} with Vercel Services:`)}\n${pc.cyan("•")} Link project: ${`${runCmd} ${vercelSetupScript}`}\n${pc.cyan("•")} Sync env (before first deploy): ${`${runCmd} ${vercelEnvScript}`}\n${pc.cyan("•")} Deploy: ${`${runCmd} ${vercelDeployScript}`}\n${pc.cyan("•")} Guide: https://www.better-t-stack.dev/docs/guides/vercel`);
7179
+ }
7128
7180
  return instructions.length ? `\n${instructions.join("\n")}` : "";
7129
7181
  }
7130
7182
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.35.2",
3
+ "version": "3.36.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.35.2",
73
- "@better-t-stack/types": "^3.35.2",
72
+ "@better-t-stack/template-generator": "^3.36.0",
73
+ "@better-t-stack/types": "^3.36.0",
74
74
  "@clack/core": "^1.4.1",
75
75
  "@clack/prompts": "^1.5.1",
76
76
  "@modelcontextprotocol/sdk": "1.29.0",