create-better-t-stack 2.23.1 → 2.24.1

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/dist/index.js CHANGED
@@ -130,6 +130,15 @@ const ADDON_COMPATIBILITY = {
130
130
  starlight: [],
131
131
  none: []
132
132
  };
133
+ const WEB_FRAMEWORKS = [
134
+ "tanstack-router",
135
+ "react-router",
136
+ "tanstack-start",
137
+ "next",
138
+ "nuxt",
139
+ "svelte",
140
+ "solid"
141
+ ];
133
142
 
134
143
  //#endregion
135
144
  //#region src/types.ts
@@ -834,14 +843,9 @@ async function getRuntimeChoice(runtime, backend) {
834
843
 
835
844
  //#endregion
836
845
  //#region src/prompts/web-deploy.ts
837
- const WORKERS_COMPATIBLE_FRONTENDS = [
838
- "tanstack-router",
839
- "react-router",
840
- "solid",
841
- "next",
842
- "nuxt",
843
- "svelte"
844
- ];
846
+ function hasWebFrontend(frontends) {
847
+ return frontends.some((f) => WEB_FRAMEWORKS.includes(f));
848
+ }
845
849
  function getDeploymentDisplay(deployment) {
846
850
  if (deployment === "workers") return {
847
851
  label: "Cloudflare Workers",
@@ -854,8 +858,7 @@ function getDeploymentDisplay(deployment) {
854
858
  }
855
859
  async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []) {
856
860
  if (deployment !== void 0) return deployment;
857
- const hasCompatibleFrontend = frontend.some((f) => WORKERS_COMPATIBLE_FRONTENDS.includes(f));
858
- if (!hasCompatibleFrontend) return "none";
861
+ if (!hasWebFrontend(frontend)) return "none";
859
862
  const options = [{
860
863
  value: "workers",
861
864
  label: "Cloudflare Workers",
@@ -877,8 +880,9 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
877
880
  return response;
878
881
  }
879
882
  async function getDeploymentToAdd(frontend, existingDeployment) {
883
+ if (!hasWebFrontend(frontend)) return "none";
880
884
  const options = [];
881
- if (frontend.some((f) => WORKERS_COMPATIBLE_FRONTENDS.includes(f)) && existingDeployment !== "workers") {
885
+ if (existingDeployment !== "workers") {
882
886
  const { label, hint } = getDeploymentDisplay("workers");
883
887
  options.push({
884
888
  value: "workers",
@@ -1322,7 +1326,7 @@ function processAndValidateFlags(options, providedFlags, projectName) {
1322
1326
  config.frontend = [];
1323
1327
  } else {
1324
1328
  const validOptions = options.frontend.filter((f) => f !== "none");
1325
- const webFrontends = validOptions.filter((f) => f === "tanstack-router" || f === "react-router" || f === "tanstack-start" || f === "next" || f === "nuxt" || f === "svelte" || f === "solid");
1329
+ const webFrontends = validOptions.filter((f) => WEB_FRAMEWORKS.includes(f));
1326
1330
  const nativeFrontends = validOptions.filter((f) => f === "native-nativewind" || f === "native-unistyles");
1327
1331
  if (webFrontends.length > 1) {
1328
1332
  consola$1.fatal("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid");
@@ -1483,12 +1487,10 @@ function processAndValidateFlags(options, providedFlags, projectName) {
1483
1487
  consola$1.fatal("MongoDB database is not compatible with Cloudflare Workers runtime. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.");
1484
1488
  process.exit(1);
1485
1489
  }
1486
- if (config.webDeploy === "workers" && config.frontend && config.frontend.length > 0) {
1487
- const incompatibleFrontends = config.frontend.filter((f) => f === "tanstack-start");
1488
- if (incompatibleFrontends.length > 0) {
1489
- consola$1.fatal(`The following frontends are not compatible with '--web-deploy workers': ${incompatibleFrontends.join(", ")}. Please choose a different frontend or remove '--web-deploy workers'.`);
1490
- process.exit(1);
1491
- }
1490
+ const hasWebFrontendFlag = (config.frontend ?? []).some((f) => WEB_FRAMEWORKS.includes(f));
1491
+ if (config.webDeploy && config.webDeploy !== "none" && !hasWebFrontendFlag) {
1492
+ consola$1.fatal("'--web-deploy' requires a web frontend. Please select a web frontend or set '--web-deploy none'.");
1493
+ process.exit(1);
1492
1494
  }
1493
1495
  return config;
1494
1496
  }
@@ -2283,6 +2285,7 @@ async function setupDeploymentTemplates(projectDir, context) {
2283
2285
  const frontends = context.frontend;
2284
2286
  const templateMap = {
2285
2287
  "tanstack-router": "react/tanstack-router",
2288
+ "tanstack-start": "react/tanstack-start",
2286
2289
  "react-router": "react/react-router",
2287
2290
  solid: "solid",
2288
2291
  next: "react/next",
@@ -2450,6 +2453,44 @@ async function setupSvelteWorkersDeploy(projectDir, packageManager) {
2450
2453
  }
2451
2454
  }
2452
2455
 
2456
+ //#endregion
2457
+ //#region src/helpers/setup/workers-tanstack-start-setup.ts
2458
+ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
2459
+ const webAppDir = path.join(projectDir, "apps/web");
2460
+ if (!await fs.pathExists(webAppDir)) return;
2461
+ await addPackageDependency({
2462
+ devDependencies: ["wrangler"],
2463
+ projectDir: webAppDir
2464
+ });
2465
+ const pkgPath = path.join(webAppDir, "package.json");
2466
+ if (await fs.pathExists(pkgPath)) {
2467
+ const pkg = await fs.readJson(pkgPath);
2468
+ pkg.scripts = {
2469
+ ...pkg.scripts,
2470
+ deploy: `${packageManager} run build && wrangler deploy`,
2471
+ "cf-typegen": "wrangler types --env-interface Env"
2472
+ };
2473
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
2474
+ }
2475
+ const viteConfigPath = path.join(webAppDir, "vite.config.ts");
2476
+ if (!await fs.pathExists(viteConfigPath)) return;
2477
+ const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
2478
+ if (!sourceFile) return;
2479
+ const defineCall = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).find((expr) => {
2480
+ const expression = expr.getExpression();
2481
+ return Node.isIdentifier(expression) && expression.getText() === "defineConfig";
2482
+ });
2483
+ if (!defineCall) return;
2484
+ const configObj = defineCall.getArguments()[0];
2485
+ if (!configObj) return;
2486
+ const pluginsArray = ensureArrayProperty(configObj, "plugins");
2487
+ const tanstackPluginIndex = pluginsArray.getElements().findIndex((el) => el.getText().includes("tanstackStart("));
2488
+ const tanstackPluginText = "tanstackStart({ target: \"cloudflare-module\" })";
2489
+ if (tanstackPluginIndex === -1) pluginsArray.addElement(tanstackPluginText);
2490
+ else pluginsArray.getElements()[tanstackPluginIndex].replaceWithText(tanstackPluginText);
2491
+ await tsProject.save();
2492
+ }
2493
+
2453
2494
  //#endregion
2454
2495
  //#region src/helpers/setup/workers-vite-setup.ts
2455
2496
  async function setupWorkersVitePlugin(projectDir) {
@@ -2492,11 +2533,13 @@ async function setupWebDeploy(config) {
2492
2533
  const isNuxt = frontend.includes("nuxt");
2493
2534
  const isSvelte = frontend.includes("svelte");
2494
2535
  const isTanstackRouter = frontend.includes("tanstack-router");
2536
+ const isTanstackStart = frontend.includes("tanstack-start");
2495
2537
  const isReactRouter = frontend.includes("react-router");
2496
2538
  const isSolid = frontend.includes("solid");
2497
2539
  if (isNext) await setupNextWorkersDeploy(projectDir, packageManager);
2498
2540
  else if (isNuxt) await setupNuxtWorkersDeploy(projectDir, packageManager);
2499
2541
  else if (isSvelte) await setupSvelteWorkersDeploy(projectDir, packageManager);
2542
+ else if (isTanstackStart) await setupTanstackStartWorkersDeploy(projectDir, packageManager);
2500
2543
  else if (isTanstackRouter || isReactRouter || isSolid) await setupWorkersWebDeploy(projectDir, packageManager);
2501
2544
  }
2502
2545
  async function setupWorkersWebDeploy(projectDir, pkgManager) {
@@ -2550,17 +2593,6 @@ async function addDeploymentToProject(input) {
2550
2593
  const detectedConfig = await detectProjectConfig(projectDir);
2551
2594
  if (!detectedConfig) exitWithError("Could not detect the project configuration. Please ensure this is a valid Better-T Stack project.");
2552
2595
  if (detectedConfig.webDeploy === input.webDeploy) exitWithError(`${input.webDeploy} deployment is already configured for this project.`);
2553
- if (input.webDeploy === "workers") {
2554
- const compatibleFrontends = [
2555
- "tanstack-router",
2556
- "react-router",
2557
- "solid",
2558
- "next",
2559
- "svelte"
2560
- ];
2561
- const hasCompatible = detectedConfig.frontend?.some((f) => compatibleFrontends.includes(f));
2562
- if (!hasCompatible) exitWithError("Cloudflare Workers deployment requires a compatible web frontend (tanstack-router, react-router, solid, next, or svelte).");
2563
- }
2564
2596
  const config = {
2565
2597
  projectName: detectedConfig.projectName || path.basename(projectDir),
2566
2598
  projectDir,
@@ -2814,7 +2846,7 @@ async function setupAuth(config) {
2814
2846
  dependencies: ["better-auth"],
2815
2847
  projectDir: serverDir
2816
2848
  });
2817
- const hasWebFrontend = frontend.some((f) => [
2849
+ const hasWebFrontend$1 = frontend.some((f) => [
2818
2850
  "react-router",
2819
2851
  "tanstack-router",
2820
2852
  "tanstack-start",
@@ -2823,7 +2855,7 @@ async function setupAuth(config) {
2823
2855
  "svelte",
2824
2856
  "solid"
2825
2857
  ].includes(f));
2826
- if (hasWebFrontend && clientDirExists) await addPackageDependency({
2858
+ if (hasWebFrontend$1 && clientDirExists) await addPackageDependency({
2827
2859
  dependencies: ["better-auth"],
2828
2860
  projectDir: clientDir
2829
2861
  });
@@ -2946,8 +2978,8 @@ async function setupEnvironmentVariables(config) {
2946
2978
  const hasNuxt = frontend.includes("nuxt");
2947
2979
  const hasSvelte = frontend.includes("svelte");
2948
2980
  const hasSolid = frontend.includes("solid");
2949
- const hasWebFrontend = hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt || hasSolid || hasSvelte;
2950
- if (hasWebFrontend) {
2981
+ const hasWebFrontend$1 = hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt || hasSolid || hasSvelte;
2982
+ if (hasWebFrontend$1) {
2951
2983
  const clientDir = path.join(projectDir, "apps/web");
2952
2984
  if (await fs.pathExists(clientDir)) {
2953
2985
  let envVarName = "VITE_SERVER_URL";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "2.23.1",
3
+ "version": "2.24.1",
4
4
  "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -68,7 +68,7 @@ import { drizzleAdapter } from "better-auth/adapters/drizzle";
68
68
  {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
69
69
  import { expo } from "@better-auth/expo";
70
70
  {{/if}}
71
- import { db } from "@/db";
71
+ import { db } from "../db";
72
72
  import * as schema from "../db/schema/auth";
73
73
  import { env } from "cloudflare:workers";
74
74
 
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "../../node_modules/wrangler/config-schema.json",
3
+ "name": "{{projectName}}",
4
+ "main": ".output/server/index.mjs",
5
+ "compatibility_date": "2025-07-05",
6
+ "compatibility_flags": ["nodejs_compat"],
7
+ "assets": {
8
+ "directory": ".output/public",
9
+ },
10
+ "observability": {
11
+ "enabled": true,
12
+ },
13
+ // "kv_namespaces": [
14
+ // {
15
+ // "binding": "CACHE",
16
+ // "id": "<Your KV ID>",
17
+ // },
18
+ // ],
19
+ }
20
+
@@ -12,7 +12,7 @@ web-build/
12
12
  # expo router
13
13
  expo-env.d.ts
14
14
 
15
-
15
+ .env
16
16
 
17
17
  ios
18
18
  android
@@ -9,40 +9,40 @@
9
9
  "web": "expo start --web"
10
10
  },
11
11
  "dependencies": {
12
- "@expo/vector-icons": "^14.0.0",
13
- "@react-navigation/bottom-tabs": "^7.0.5",
14
- "@react-navigation/drawer": "^7.0.0",
15
- "@react-navigation/native": "^7.0.3",
12
+ "@expo/vector-icons": "^14.1.0",
13
+ "@react-navigation/bottom-tabs": "^7.3.10",
14
+ "@react-navigation/drawer": "^7.3.9",
15
+ "@react-navigation/native": "^7.1.6",
16
16
  {{#if (includes examples "ai")}}
17
17
  "@stardazed/streams-text-encoding": "^1.0.2",
18
18
  "@ungap/structured-clone": "^1.3.0",
19
19
  {{/if}}
20
- "@tanstack/react-form": "^1.0.5",
21
- "babel-plugin-react-compiler": "^19.0.0-beta-af1b7da-20250417",
22
- "expo": "^53.0.8",
23
- "expo-constants": "~17.1.4",
24
- "expo-linking": "~7.1.4",
25
- "expo-router": "~5.0.3",
20
+ "@tanstack/react-form": "^1.14.0",
21
+ "babel-plugin-react-compiler": "^19.1.0-rc.2",
22
+ "expo": "^53.0.17",
23
+ "expo-constants": "~17.1.7",
24
+ "expo-linking": "~7.1.7",
25
+ "expo-router": "~5.1.3",
26
26
  "expo-secure-store": "~14.2.3",
27
27
  "expo-status-bar": "~2.2.3",
28
- "expo-system-ui": "~5.0.6",
29
- "expo-dev-client": "~5.1.8",
30
- "expo-web-browser": "~14.1.6",
28
+ "expo-system-ui": "~5.0.10",
29
+ "expo-dev-client": "~5.2.4",
30
+ "expo-web-browser": "~14.2.0",
31
31
  "react": "19.0.0",
32
32
  "react-dom": "19.0.0",
33
- "react-native": "0.79.2",
33
+ "react-native": "0.79.5",
34
34
  "react-native-edge-to-edge": "1.6.0",
35
35
  "react-native-gesture-handler": "~2.24.0",
36
- "react-native-nitro-modules": "0.25.2",
36
+ "react-native-nitro-modules": "0.26.3",
37
37
  "react-native-reanimated": "~3.17.4",
38
38
  "react-native-safe-area-context": "5.4.0",
39
- "react-native-screens": "~4.10.0",
40
- "react-native-unistyles": "^3.0.0-rc.5",
39
+ "react-native-screens": "~4.11.1",
40
+ "react-native-unistyles": "^3.0.0",
41
41
  "react-native-web": "^0.20.0"
42
42
  },
43
43
  "devDependencies": {
44
- "ajv": "^8.12.0",
45
- "@babel/core": "^7.20.0",
44
+ "ajv": "^8.17.1",
45
+ "@babel/core": "^7.28.0",
46
46
  "@types/react": "~19.0.10",
47
47
  "typescript": "~5.8.3"
48
48
  },
@@ -19,6 +19,8 @@
19
19
  .vinxi
20
20
  .output
21
21
  .react-router/
22
+ .tanstack/
23
+ .nitro/
22
24
 
23
25
  # Deployment
24
26
  .vercel