create-better-t-stack 3.2.5 → 3.2.6

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/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createBtsCli } from "./src-ljR3uw5T.js";
2
+ import { n as createBtsCli } from "./src-DW5V85iA.js";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { builder, createBtsCli, docs, init, router, sponsors } from "./src-ljR3uw5T.js";
2
+ import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-DW5V85iA.js";
3
3
 
4
4
  export { builder, createBtsCli, docs, init, router, sponsors };
@@ -334,11 +334,9 @@ function isWebFrontend(value) {
334
334
  return WEB_FRAMEWORKS.includes(value);
335
335
  }
336
336
  function splitFrontends(values = []) {
337
- const web = values.filter((f) => isWebFrontend(f));
338
- const native = values.filter((f) => f === "native-nativewind" || f === "native-unistyles");
339
337
  return {
340
- web,
341
- native
338
+ web: values.filter((f) => isWebFrontend(f)),
339
+ native: values.filter((f) => f === "native-nativewind" || f === "native-unistyles")
342
340
  };
343
341
  }
344
342
  function ensureSingleWebAndNative(frontends) {
@@ -411,13 +409,10 @@ function validateServerDeployRequiresBackend(serverDeploy, backend) {
411
409
  function validateAddonCompatibility(addon, frontend, _auth) {
412
410
  const compatibleFrontends = ADDON_COMPATIBILITY[addon];
413
411
  if (compatibleFrontends.length > 0) {
414
- if (!frontend.some((f) => compatibleFrontends.includes(f))) {
415
- const frontendList = compatibleFrontends.join(", ");
416
- return {
417
- isCompatible: false,
418
- reason: `${addon} addon requires one of these frontends: ${frontendList}`
419
- };
420
- }
412
+ if (!frontend.some((f) => compatibleFrontends.includes(f))) return {
413
+ isCompatible: false,
414
+ reason: `${addon} addon requires one of these frontends: ${compatibleFrontends.join(", ")}`
415
+ };
421
416
  }
422
417
  return { isCompatible: true };
423
418
  }
@@ -546,11 +541,10 @@ async function getAddonsChoice(addons, frontends, auth) {
546
541
  Object.keys(groupedOptions).forEach((group$1) => {
547
542
  if (groupedOptions[group$1].length === 0) delete groupedOptions[group$1];
548
543
  });
549
- const initialValues = DEFAULT_CONFIG.addons.filter((addonValue) => Object.values(groupedOptions).some((options) => options.some((opt) => opt.value === addonValue)));
550
544
  const response = await groupMultiselect({
551
545
  message: "Select addons",
552
546
  options: groupedOptions,
553
- initialValues,
547
+ initialValues: DEFAULT_CONFIG.addons.filter((addonValue) => Object.values(groupedOptions).some((options) => options.some((opt) => opt.value === addonValue))),
554
548
  required: false,
555
549
  selectableGroups: false
556
550
  });
@@ -924,46 +918,45 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
924
918
  if (isCancel(frontendTypes)) return exitCancelled("Operation cancelled");
925
919
  const result = [];
926
920
  if (frontendTypes.includes("web")) {
927
- const webOptions = [
928
- {
929
- value: "tanstack-router",
930
- label: "TanStack Router",
931
- hint: "Modern and scalable routing for React Applications"
932
- },
933
- {
934
- value: "react-router",
935
- label: "React Router",
936
- hint: "A user‑obsessed, standards‑focused, multi‑strategy router"
937
- },
938
- {
939
- value: "next",
940
- label: "Next.js",
941
- hint: "The React Framework for the Web"
942
- },
943
- {
944
- value: "nuxt",
945
- label: "Nuxt",
946
- hint: "The Progressive Web Framework for Vue.js"
947
- },
948
- {
949
- value: "svelte",
950
- label: "Svelte",
951
- hint: "web development for the rest of us"
952
- },
953
- {
954
- value: "solid",
955
- label: "Solid",
956
- hint: "Simple and performant reactivity for building user interfaces"
957
- },
958
- {
959
- value: "tanstack-start",
960
- label: "TanStack Start",
961
- hint: "SSR, Server Functions, API Routes and more with TanStack Router"
962
- }
963
- ].filter((option) => isFrontendAllowedWithBackend(option.value, backend, auth));
964
921
  const webFramework = await select({
965
922
  message: "Choose web",
966
- options: webOptions,
923
+ options: [
924
+ {
925
+ value: "tanstack-router",
926
+ label: "TanStack Router",
927
+ hint: "Modern and scalable routing for React Applications"
928
+ },
929
+ {
930
+ value: "react-router",
931
+ label: "React Router",
932
+ hint: "A user‑obsessed, standards‑focused, multi‑strategy router"
933
+ },
934
+ {
935
+ value: "next",
936
+ label: "Next.js",
937
+ hint: "The React Framework for the Web"
938
+ },
939
+ {
940
+ value: "nuxt",
941
+ label: "Nuxt",
942
+ hint: "The Progressive Web Framework for Vue.js"
943
+ },
944
+ {
945
+ value: "svelte",
946
+ label: "Svelte",
947
+ hint: "web development for the rest of us"
948
+ },
949
+ {
950
+ value: "solid",
951
+ label: "Solid",
952
+ hint: "Simple and performant reactivity for building user interfaces"
953
+ },
954
+ {
955
+ value: "tanstack-start",
956
+ label: "TanStack Start",
957
+ hint: "SSR, Server Functions, API Routes and more with TanStack Router"
958
+ }
959
+ ].filter((option) => isFrontendAllowedWithBackend(option.value, backend, auth)),
967
960
  initialValue: DEFAULT_CONFIG.frontend[0]
968
961
  });
969
962
  if (isCancel(webFramework)) return exitCancelled("Operation cancelled");
@@ -1036,10 +1029,9 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
1036
1029
  if (backend === "convex") return "none";
1037
1030
  if (!hasDatabase) return "none";
1038
1031
  if (orm !== void 0) return orm;
1039
- const options = [...database === "mongodb" ? [ormOptions.prisma, ormOptions.mongoose] : [ormOptions.drizzle, ormOptions.prisma]];
1040
1032
  const response = await select({
1041
1033
  message: "Select ORM",
1042
- options,
1034
+ options: [...database === "mongodb" ? [ormOptions.prisma, ormOptions.mongoose] : [ormOptions.drizzle, ormOptions.prisma]],
1043
1035
  initialValue: database === "mongodb" ? "prisma" : runtime === "workers" ? "drizzle" : DEFAULT_CONFIG.orm
1044
1036
  });
1045
1037
  if (isCancel(response)) return exitCancelled("Operation cancelled");
@@ -1050,7 +1042,6 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
1050
1042
  //#region src/prompts/package-manager.ts
1051
1043
  async function getPackageManagerChoice(packageManager) {
1052
1044
  if (packageManager !== void 0) return packageManager;
1053
- const detectedPackageManager = getUserPkgManager();
1054
1045
  const response = await select({
1055
1046
  message: "Choose package manager",
1056
1047
  options: [
@@ -1070,7 +1061,7 @@ async function getPackageManagerChoice(packageManager) {
1070
1061
  hint: "All-in-one JavaScript runtime & toolkit"
1071
1062
  }
1072
1063
  ],
1073
- initialValue: detectedPackageManager
1064
+ initialValue: getUserPkgManager()
1074
1065
  });
1075
1066
  if (isCancel(response)) return exitCancelled("Operation cancelled");
1076
1067
  return response;
@@ -1219,21 +1210,20 @@ function getDeploymentDisplay(deployment) {
1219
1210
  async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []) {
1220
1211
  if (deployment !== void 0) return deployment;
1221
1212
  if (!hasWebFrontend(frontend)) return "none";
1222
- const options = [
1223
- "wrangler",
1224
- "alchemy",
1225
- "none"
1226
- ].map((deploy) => {
1227
- const { label, hint } = getDeploymentDisplay(deploy);
1228
- return {
1229
- value: deploy,
1230
- label,
1231
- hint
1232
- };
1233
- });
1234
1213
  const response = await select({
1235
1214
  message: "Select web deployment",
1236
- options,
1215
+ options: [
1216
+ "wrangler",
1217
+ "alchemy",
1218
+ "none"
1219
+ ].map((deploy) => {
1220
+ const { label, hint } = getDeploymentDisplay(deploy);
1221
+ return {
1222
+ value: deploy,
1223
+ label,
1224
+ hint
1225
+ };
1226
+ }),
1237
1227
  initialValue: DEFAULT_CONFIG.webDeploy
1238
1228
  });
1239
1229
  if (isCancel(response)) return exitCancelled("Operation cancelled");
@@ -1333,10 +1323,8 @@ function validateDirectoryName(name) {
1333
1323
  async function getProjectName(initialName) {
1334
1324
  if (initialName) {
1335
1325
  if (initialName === ".") return initialName;
1336
- const finalDirName = path.basename(initialName);
1337
- if (!validateDirectoryName(finalDirName)) {
1338
- const projectDir = path.resolve(process.cwd(), initialName);
1339
- if (isPathWithinCwd(projectDir)) return initialName;
1326
+ if (!validateDirectoryName(path.basename(initialName))) {
1327
+ if (isPathWithinCwd(path.resolve(process.cwd(), initialName))) return initialName;
1340
1328
  consola.error(pc.red("Project path must be within current directory"));
1341
1329
  }
1342
1330
  }
@@ -1356,12 +1344,10 @@ async function getProjectName(initialName) {
1356
1344
  defaultValue: defaultName,
1357
1345
  validate: (value) => {
1358
1346
  const nameToUse = String(value ?? "").trim() || defaultName;
1359
- const finalDirName = path.basename(nameToUse);
1360
- const validationError = validateDirectoryName(finalDirName);
1347
+ const validationError = validateDirectoryName(path.basename(nameToUse));
1361
1348
  if (validationError) return validationError;
1362
1349
  if (nameToUse !== ".") {
1363
- const projectDir = path.resolve(process.cwd(), nameToUse);
1364
- if (!isPathWithinCwd(projectDir)) return "Project path must be within current directory";
1350
+ if (!isPathWithinCwd(path.resolve(process.cwd(), nameToUse))) return "Project path must be within current directory";
1365
1351
  }
1366
1352
  }
1367
1353
  });
@@ -1552,11 +1538,9 @@ async function handleDirectoryConflict(currentPathInput, silent = false) {
1552
1538
  finalPathInput: currentPathInput,
1553
1539
  shouldClearDirectory: false
1554
1540
  };
1555
- case "rename": {
1541
+ case "rename":
1556
1542
  log.info("Please choose a different project name or path.");
1557
- const newPathInput = await getProjectName(void 0);
1558
- return await handleDirectoryConflict(newPathInput);
1559
- }
1543
+ return await handleDirectoryConflict(await getProjectName(void 0));
1560
1544
  case "cancel": return exitCancelled("Operation cancelled.");
1561
1545
  }
1562
1546
  }
@@ -1621,8 +1605,7 @@ const catppuccinTheme = {
1621
1605
  const renderTitle = () => {
1622
1606
  const terminalWidth = process.stdout.columns || 80;
1623
1607
  const titleLines = TITLE_TEXT.split("\n");
1624
- const titleWidth = Math.max(...titleLines.map((line) => line.length));
1625
- if (terminalWidth < titleWidth) console.log(gradient(Object.values(catppuccinTheme)).multiline(`
1608
+ if (terminalWidth < Math.max(...titleLines.map((line) => line.length))) console.log(gradient(Object.values(catppuccinTheme)).multiline(`
1626
1609
  ╔══════════════════╗
1627
1610
  ║ Better T Stack ║
1628
1611
  ╚══════════════════╝
@@ -1904,10 +1887,7 @@ function processAndValidateFlags(options, providedFlags, projectName) {
1904
1887
  return config;
1905
1888
  }
1906
1889
  function processProvidedFlagsWithoutValidation(options, projectName) {
1907
- if (!options.yolo) {
1908
- const providedFlags = getProvidedFlags(options);
1909
- validateYesFlagCombination(options, providedFlags);
1910
- }
1890
+ if (!options.yolo) validateYesFlagCombination(options, getProvidedFlags(options));
1911
1891
  const config = processFlags(options, projectName);
1912
1892
  const validatedProjectName = extractAndValidateProjectName(projectName, options.projectDirectory, true);
1913
1893
  if (validatedProjectName) config.projectName = validatedProjectName;
@@ -2088,8 +2068,7 @@ async function setupFumadocs(config) {
2088
2068
  initialValue: "next-mdx"
2089
2069
  });
2090
2070
  if (isCancel(template)) return exitCancelled("Operation cancelled");
2091
- const commandWithArgs = `create-fumadocs-app@latest fumadocs --template ${TEMPLATES[template].value} --src --no-install --pm ${packageManager} --no-eslint --no-git`;
2092
- const fumadocsInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
2071
+ const fumadocsInitCommand = getPackageExecutionCommand(packageManager, `create-fumadocs-app@latest fumadocs --template ${TEMPLATES[template].value} --src --no-install --pm ${packageManager} --no-eslint --no-git`);
2093
2072
  const s = spinner();
2094
2073
  s.start("Setting up Fumadocs...");
2095
2074
  const appsDir = path.join(projectDir, "apps");
@@ -2176,8 +2155,7 @@ async function setupRuler(config) {
2176
2155
  const s = spinner();
2177
2156
  s.start("Applying rules with Ruler...");
2178
2157
  try {
2179
- const rulerApplyCmd = getPackageExecutionCommand(packageManager, `@intellectronica/ruler@latest apply --agents ${selectedEditors.join(",")} --local-only`);
2180
- await execa(rulerApplyCmd, {
2158
+ await execa(getPackageExecutionCommand(packageManager, `@intellectronica/ruler@latest apply --agents ${selectedEditors.join(",")} --local-only`), {
2181
2159
  cwd: projectDir,
2182
2160
  env: { CI: "true" },
2183
2161
  shell: true
@@ -2211,7 +2189,7 @@ async function setupStarlight(config) {
2211
2189
  const s = spinner();
2212
2190
  try {
2213
2191
  s.start("Setting up Starlight docs...");
2214
- const commandWithArgs = `create-astro@latest ${[
2192
+ const starlightInitCommand = getPackageExecutionCommand(packageManager, `create-astro@latest ${[
2215
2193
  "docs",
2216
2194
  "--template",
2217
2195
  "starlight",
@@ -2220,8 +2198,7 @@ async function setupStarlight(config) {
2220
2198
  "tailwind",
2221
2199
  "--no-git",
2222
2200
  "--skip-houston"
2223
- ].join(" ")}`;
2224
- const starlightInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
2201
+ ].join(" ")}`);
2225
2202
  const appsDir = path.join(projectDir, "apps");
2226
2203
  await fs.ensureDir(appsDir);
2227
2204
  await execa(starlightInitCommand, {
@@ -2268,7 +2245,7 @@ async function setupTauri(config) {
2268
2245
  const hasNext = frontend.includes("next");
2269
2246
  const devUrl = hasReactRouter || hasSvelte ? "http://localhost:5173" : hasNext ? "http://localhost:3001" : "http://localhost:3001";
2270
2247
  const frontendDist = hasNuxt ? "../.output/public" : hasSvelte ? "../build" : hasNext ? "../.next" : hasReactRouter ? "../build/client" : "../dist";
2271
- const commandWithArgs = `@tauri-apps/cli@latest ${[
2248
+ await execa(getPackageExecutionCommand(packageManager, `@tauri-apps/cli@latest ${[
2272
2249
  "init",
2273
2250
  `--app-name=${path.basename(projectDir)}`,
2274
2251
  `--window-title=${path.basename(projectDir)}`,
@@ -2276,9 +2253,7 @@ async function setupTauri(config) {
2276
2253
  `--dev-url=${devUrl}`,
2277
2254
  `--before-dev-command="${packageManager} run dev"`,
2278
2255
  `--before-build-command="${packageManager} run build"`
2279
- ].join(" ")}`;
2280
- const tauriInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
2281
- await execa(tauriInitCommand, {
2256
+ ].join(" ")}`), {
2282
2257
  cwd: clientPackageDir,
2283
2258
  env: { CI: "true" },
2284
2259
  shell: true
@@ -2350,8 +2325,7 @@ async function setupUltracite(config, hasHusky) {
2350
2325
  if (editors.length > 0) ultraciteArgs.push("--editors", ...editors);
2351
2326
  if (rules.length > 0) ultraciteArgs.push("--rules", ...rules);
2352
2327
  if (hasHusky) ultraciteArgs.push("--integrations", "husky", "lint-staged");
2353
- const commandWithArgs = `ultracite@latest ${ultraciteArgs.join(" ")} --skip-install`;
2354
- const ultraciteInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
2328
+ const ultraciteInitCommand = getPackageExecutionCommand(packageManager, `ultracite@latest ${ultraciteArgs.join(" ")} --skip-install`);
2355
2329
  const s = spinner();
2356
2330
  s.start("Setting up Ultracite...");
2357
2331
  await execa(ultraciteInitCommand, {
@@ -2738,8 +2712,7 @@ async function processAndCopyFiles(sourcePattern, baseSourceDir, destDir, contex
2738
2712
  }
2739
2713
  }
2740
2714
  async function copyBaseTemplate(projectDir, context) {
2741
- const templateDir = path.join(PKG_ROOT, "templates/base");
2742
- await processAndCopyFiles(["**/*"], templateDir, projectDir, context);
2715
+ await processAndCopyFiles(["**/*"], path.join(PKG_ROOT, "templates/base"), projectDir, context);
2743
2716
  }
2744
2717
  async function setupFrontendTemplates(projectDir, context) {
2745
2718
  const hasReactWeb = context.frontend.some((f) => [
@@ -3191,8 +3164,7 @@ async function setupDeploymentTemplates(projectDir, context) {
3191
3164
  if (context.webDeploy === "alchemy" && (context.serverDeploy === "alchemy" || isBackendSelf)) {
3192
3165
  if (await fs.pathExists(alchemyTemplateSrc)) {
3193
3166
  const webAppDir = path.join(projectDir, "apps/web");
3194
- const destDir = isBackendSelf && await fs.pathExists(webAppDir) ? webAppDir : projectDir;
3195
- await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, destDir, context);
3167
+ await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, isBackendSelf && await fs.pathExists(webAppDir) ? webAppDir : projectDir, context);
3196
3168
  await addEnvDtsToPackages(projectDir, context, alchemyTemplateSrc);
3197
3169
  }
3198
3170
  } else {
@@ -3289,16 +3261,14 @@ async function addAddonsToProject(input) {
3289
3261
  await setupAddonsTemplate(projectDir, config);
3290
3262
  await setupAddons(config, true);
3291
3263
  const currentAddons = detectedConfig.addons || [];
3292
- const mergedAddons = [...new Set([...currentAddons, ...input.addons])];
3293
- await updateBtsConfig(projectDir, { addons: mergedAddons });
3264
+ await updateBtsConfig(projectDir, { addons: [...new Set([...currentAddons, ...input.addons])] });
3294
3265
  if (config.install) await installDependencies({
3295
3266
  projectDir,
3296
3267
  packageManager: config.packageManager
3297
3268
  });
3298
3269
  else if (!input.suppressInstallMessage) log.info(pc.yellow(`Run ${pc.bold(`${config.packageManager} install`)} to install dependencies`));
3299
3270
  } catch (error) {
3300
- const message = error instanceof Error ? error.message : String(error);
3301
- exitWithError(`Error adding addons: ${message}`);
3271
+ exitWithError(`Error adding addons: ${error instanceof Error ? error.message : String(error)}`);
3302
3272
  }
3303
3273
  }
3304
3274
 
@@ -3342,8 +3312,7 @@ async function generateCloudflareWorkerTypes({ serverDir, packageManager }) {
3342
3312
  const s = spinner();
3343
3313
  try {
3344
3314
  s.start("Generating Cloudflare Workers types...");
3345
- const runCmd = getPackageExecutionCommand(packageManager, "wrangler types --env-interface CloudflareBindings");
3346
- await execa(runCmd, {
3315
+ await execa(getPackageExecutionCommand(packageManager, "wrangler types --env-interface CloudflareBindings"), {
3347
3316
  cwd: serverDir,
3348
3317
  shell: true
3349
3318
  });
@@ -4017,8 +3986,7 @@ async function addDeploymentToProject(input) {
4017
3986
  });
4018
3987
  else if (!input.suppressInstallMessage) log.info(pc.yellow(`Run ${pc.bold(`${config.packageManager} install`)} to install dependencies`));
4019
3988
  } catch (error) {
4020
- const message = error instanceof Error ? error.message : String(error);
4021
- exitWithError(`Error adding deployment: ${message}`);
3989
+ exitWithError(`Error adding deployment: ${error instanceof Error ? error.message : String(error)}`);
4022
3990
  }
4023
3991
  }
4024
3992
 
@@ -4446,8 +4414,7 @@ async function setupBetterAuthPlugins(projectDir, config) {
4446
4414
  if (betterAuthCall) {
4447
4415
  const configObject = betterAuthCall.getArguments()[0];
4448
4416
  if (configObject && configObject.getKind() === SyntaxKind.ObjectLiteralExpression) {
4449
- const objLiteral = configObject.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
4450
- const pluginsArray = ensureArrayProperty(objLiteral, "plugins");
4417
+ const pluginsArray = ensureArrayProperty(configObject.asKindOrThrow(SyntaxKind.ObjectLiteralExpression), "plugins");
4451
4418
  pluginsToAdd.forEach((plugin) => {
4452
4419
  pluginsArray.addElement(plugin);
4453
4420
  });
@@ -4685,11 +4652,9 @@ async function setupEnvironmentVariables(config) {
4685
4652
  const clientDir = path.join(projectDir, "apps/web");
4686
4653
  if (await fs.pathExists(clientDir)) {
4687
4654
  const baseVar = getClientServerVar(frontend, backend);
4688
- const envVarName = backend === "convex" ? getConvexVar(frontend) : baseVar.key;
4689
- const serverUrl = backend === "convex" ? "https://<YOUR_CONVEX_URL>" : baseVar.value;
4690
4655
  const clientVars = [{
4691
- key: envVarName,
4692
- value: serverUrl,
4656
+ key: backend === "convex" ? getConvexVar(frontend) : baseVar.key,
4657
+ value: backend === "convex" ? "https://<YOUR_CONVEX_URL>" : baseVar.value,
4693
4658
  condition: backend === "convex" ? true : baseVar.write
4694
4659
  }];
4695
4660
  if (backend === "convex" && auth === "clerk") {
@@ -4864,14 +4829,12 @@ ${hasWeb ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}
4864
4829
  } else if (await fs.pathExists(serverDir)) await addEnvVariablesToFile(path.join(serverDir, ".env"), serverVars);
4865
4830
  const isUnifiedAlchemy = webDeploy === "alchemy" && serverDeploy === "alchemy";
4866
4831
  const isIndividualAlchemy = webDeploy === "alchemy" || serverDeploy === "alchemy";
4867
- if (isUnifiedAlchemy) {
4868
- const rootEnvPath = path.join(projectDir, ".env");
4869
- await addEnvVariablesToFile(rootEnvPath, [{
4870
- key: "ALCHEMY_PASSWORD",
4871
- value: "please-change-this",
4872
- condition: true
4873
- }]);
4874
- } else if (isIndividualAlchemy) {
4832
+ if (isUnifiedAlchemy) await addEnvVariablesToFile(path.join(projectDir, ".env"), [{
4833
+ key: "ALCHEMY_PASSWORD",
4834
+ value: "please-change-this",
4835
+ condition: true
4836
+ }]);
4837
+ else if (isIndividualAlchemy) {
4875
4838
  if (webDeploy === "alchemy") {
4876
4839
  const webDir = path.join(projectDir, "apps/web");
4877
4840
  if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), [{
@@ -4933,10 +4896,9 @@ async function setupCloudflareD1(config) {
4933
4896
  try {
4934
4897
  await addEnvVariablesToFile(envPath, variables);
4935
4898
  } catch (_err) {}
4936
- const serverDir = path.join(projectDir, backend === "self" ? "apps/web" : "apps/server");
4937
4899
  await addPackageDependency({
4938
4900
  dependencies: ["@prisma/adapter-d1"],
4939
- projectDir: serverDir
4901
+ projectDir: path.join(projectDir, backend === "self" ? "apps/web" : "apps/server")
4940
4902
  });
4941
4903
  }
4942
4904
  }
@@ -4954,13 +4916,11 @@ async function setupDockerCompose(config) {
4954
4916
  }
4955
4917
  async function writeEnvFile$4(projectDir, database, projectName, backend) {
4956
4918
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
4957
- const envPath = path.join(projectDir, targetApp, ".env");
4958
- const variables = [{
4919
+ await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
4959
4920
  key: "DATABASE_URL",
4960
4921
  value: getDatabaseUrl(database, projectName),
4961
4922
  condition: true
4962
- }];
4963
- await addEnvVariablesToFile(envPath, variables);
4923
+ }]);
4964
4924
  }
4965
4925
  function getDatabaseUrl(database, projectName) {
4966
4926
  switch (database) {
@@ -5030,13 +4990,11 @@ async function initMongoDBAtlas(serverDir) {
5030
4990
  async function writeEnvFile$3(projectDir, backend, config) {
5031
4991
  try {
5032
4992
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
5033
- const envPath = path.join(projectDir, targetApp, ".env");
5034
- const variables = [{
4993
+ await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
5035
4994
  key: "DATABASE_URL",
5036
4995
  value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
5037
4996
  condition: true
5038
- }];
5039
- await addEnvVariablesToFile(envPath, variables);
4997
+ }]);
5040
4998
  } catch (_error) {
5041
4999
  consola.error("Failed to update environment configuration");
5042
5000
  }
@@ -5159,8 +5117,7 @@ async function executeNeonCommand(packageManager, commandArgsString, spinnerText
5159
5117
  }
5160
5118
  async function createNeonProject(projectName, regionId, packageManager) {
5161
5119
  try {
5162
- const commandArgsString = `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`;
5163
- const { stdout } = await executeNeonCommand(packageManager, commandArgsString, `Creating Neon project "${projectName}"...`);
5120
+ const { stdout } = await executeNeonCommand(packageManager, `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`, `Creating Neon project "${projectName}"...`);
5164
5121
  const response = JSON.parse(stdout);
5165
5122
  if (response.project && response.connection_uris && response.connection_uris.length > 0) {
5166
5123
  const projectId = response.project.id;
@@ -5181,13 +5138,11 @@ async function createNeonProject(projectName, regionId, packageManager) {
5181
5138
  }
5182
5139
  async function writeEnvFile$2(projectDir, backend, config) {
5183
5140
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
5184
- const envPath = path.join(projectDir, targetApp, ".env");
5185
- const variables = [{
5141
+ await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
5186
5142
  key: "DATABASE_URL",
5187
5143
  value: config?.connectionString ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
5188
5144
  condition: true
5189
- }];
5190
- await addEnvVariablesToFile(envPath, variables);
5145
+ }]);
5191
5146
  return true;
5192
5147
  }
5193
5148
  async function setupWithNeonDb(projectDir, packageManager, backend) {
@@ -5197,8 +5152,7 @@ async function setupWithNeonDb(projectDir, packageManager, backend) {
5197
5152
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
5198
5153
  const targetDir = path.join(projectDir, targetApp);
5199
5154
  await fs.ensureDir(targetDir);
5200
- const packageCmd = getPackageExecutionCommand(packageManager, "neondb@latest --yes");
5201
- await execa(packageCmd, {
5155
+ await execa(getPackageExecutionCommand(packageManager, "neondb@latest --yes"), {
5202
5156
  shell: true,
5203
5157
  cwd: targetDir
5204
5158
  });
@@ -5416,8 +5370,7 @@ async function initPrismaDatabase(serverDir, packageManager) {
5416
5370
  const prismaDir = path.join(serverDir, "prisma");
5417
5371
  await fs.ensureDir(prismaDir);
5418
5372
  log.info("Starting Prisma PostgreSQL setup.");
5419
- const prismaInitCommand = getPackageExecutionCommand(packageManager, "prisma init --db");
5420
- await execa(prismaInitCommand, {
5373
+ await execa(getPackageExecutionCommand(packageManager, "prisma init --db"), {
5421
5374
  cwd: serverDir,
5422
5375
  stdio: "inherit",
5423
5376
  shell: true
@@ -5478,10 +5431,9 @@ DATABASE_URL="your_database_url"`);
5478
5431
  }
5479
5432
  async function addPrismaAccelerateExtension(projectDir) {
5480
5433
  try {
5481
- const dbPackageDir = path.join(projectDir, "packages/db");
5482
5434
  await addPackageDependency({
5483
5435
  dependencies: ["@prisma/extension-accelerate"],
5484
- projectDir: dbPackageDir
5436
+ projectDir: path.join(projectDir, "packages/db")
5485
5437
  });
5486
5438
  return true;
5487
5439
  } catch (_error) {
@@ -5592,8 +5544,7 @@ function extractDbUrl(output) {
5592
5544
  async function initializeSupabase(serverDir, packageManager) {
5593
5545
  log.info("Initializing Supabase project...");
5594
5546
  try {
5595
- const supabaseInitCommand = getPackageExecutionCommand(packageManager, "supabase init");
5596
- await execa(supabaseInitCommand, {
5547
+ await execa(getPackageExecutionCommand(packageManager, "supabase init"), {
5597
5548
  cwd: serverDir,
5598
5549
  stdio: "inherit",
5599
5550
  shell: true
@@ -5784,13 +5735,12 @@ async function selectTursoGroup() {
5784
5735
  log.info(`Using the only available group: ${pc.blue(groups[0].name)}`);
5785
5736
  return groups[0].name;
5786
5737
  }
5787
- const groupOptions = groups.map((group$1) => ({
5788
- value: group$1.name,
5789
- label: `${group$1.name} (${group$1.locations})`
5790
- }));
5791
5738
  const selectedGroup = await select({
5792
5739
  message: "Select a Turso database group:",
5793
- options: groupOptions
5740
+ options: groups.map((group$1) => ({
5741
+ value: group$1.name,
5742
+ label: `${group$1.name} (${group$1.locations})`
5743
+ }))
5794
5744
  });
5795
5745
  if (isCancel(selectedGroup)) return exitCancelled("Operation cancelled");
5796
5746
  return selectedGroup;
@@ -5821,8 +5771,7 @@ async function createTursoDatabase(dbName, groupName) {
5821
5771
  }
5822
5772
  async function writeEnvFile(projectDir, backend, config) {
5823
5773
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
5824
- const envPath = path.join(projectDir, targetApp, ".env");
5825
- const variables = [{
5774
+ await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
5826
5775
  key: "DATABASE_URL",
5827
5776
  value: config?.dbUrl ?? "",
5828
5777
  condition: true
@@ -5830,8 +5779,7 @@ async function writeEnvFile(projectDir, backend, config) {
5830
5779
  key: "DATABASE_AUTH_TOKEN",
5831
5780
  value: config?.authToken ?? "",
5832
5781
  condition: true
5833
- }];
5834
- await addEnvVariablesToFile(envPath, variables);
5782
+ }]);
5835
5783
  }
5836
5784
  function displayManualSetupInstructions() {
5837
5785
  log.info(`Manual Turso Setup Instructions:
@@ -5912,8 +5860,7 @@ async function setupTurso(config, cliInput) {
5912
5860
  if (isCancel(dbNameResponse)) return exitCancelled("Operation cancelled");
5913
5861
  dbName = dbNameResponse;
5914
5862
  try {
5915
- const config$1 = await createTursoDatabase(dbName, selectedGroup);
5916
- await writeEnvFile(projectDir, backend, config$1);
5863
+ await writeEnvFile(projectDir, backend, await createTursoDatabase(dbName, selectedGroup));
5917
5864
  success = true;
5918
5865
  } catch (error) {
5919
5866
  if (error instanceof Error && error.message === "DATABASE_EXISTS") {
@@ -7083,7 +7030,6 @@ async function createProjectHandler(input) {
7083
7030
  shouldClearDirectory = result.shouldClearDirectory;
7084
7031
  }
7085
7032
  } catch (error) {
7086
- const elapsedTimeMs$1 = Date.now() - startTime;
7087
7033
  return {
7088
7034
  success: false,
7089
7035
  projectConfig: {
@@ -7109,7 +7055,7 @@ async function createProjectHandler(input) {
7109
7055
  },
7110
7056
  reproducibleCommand: "",
7111
7057
  timeScaffolded,
7112
- elapsedTimeMs: elapsedTimeMs$1,
7058
+ elapsedTimeMs: Date.now() - startTime,
7113
7059
  projectDirectory: "",
7114
7060
  relativePath: "",
7115
7061
  error: error instanceof Error ? error.message : String(error)
@@ -7361,11 +7307,10 @@ const router = os.router({
7361
7307
  manualDb: z$1.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup")
7362
7308
  })])).handler(async ({ input }) => {
7363
7309
  const [projectName, options] = input;
7364
- const combinedInput = {
7310
+ const result = await createProjectHandler({
7365
7311
  projectName,
7366
7312
  ...options
7367
- };
7368
- const result = await createProjectHandler(combinedInput);
7313
+ });
7369
7314
  if (options.verbose) return result;
7370
7315
  }),
7371
7316
  add: os.meta({ description: "Add addons or deployment configurations to an existing Better-T-Stack project" }).input(z$1.tuple([z$1.object({
@@ -7383,8 +7328,7 @@ const router = os.router({
7383
7328
  try {
7384
7329
  renderTitle();
7385
7330
  intro(pc.magenta("Better-T-Stack Sponsors"));
7386
- const sponsors$1 = await fetchSponsors();
7387
- displaySponsors(sponsors$1);
7331
+ displaySponsors(await fetchSponsors());
7388
7332
  } catch (error) {
7389
7333
  handleError(error, "Failed to display sponsors");
7390
7334
  }
@@ -7472,4 +7416,4 @@ async function builder() {
7472
7416
  }
7473
7417
 
7474
7418
  //#endregion
7475
- export { builder, createBtsCli, docs, init, router, sponsors };
7419
+ export { router as a, init as i, createBtsCli as n, sponsors as o, docs as r, builder as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.2.5",
3
+ "version": "3.2.6",
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",
@@ -67,9 +67,9 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@biomejs/js-api": "^3.0.0",
70
- "@biomejs/wasm-nodejs": "^2.2.4",
71
- "@clack/prompts": "^1.0.0-alpha.5",
72
- "@orpc/server": "^1.9.0",
70
+ "@biomejs/wasm-nodejs": "^2.2.6",
71
+ "@clack/prompts": "^1.0.0-alpha.6",
72
+ "@orpc/server": "^1.10.0",
73
73
  "consola": "^3.4.2",
74
74
  "execa": "^9.6.0",
75
75
  "fs-extra": "^11.3.2",
@@ -78,18 +78,18 @@
78
78
  "jsonc-parser": "^3.3.1",
79
79
  "picocolors": "^1.1.1",
80
80
  "tinyglobby": "^0.2.15",
81
- "trpc-cli": "^0.11.0",
82
- "ts-morph": "^27.0.0",
83
- "yaml": "^2.7.0",
84
- "zod": "^4.1.11"
81
+ "trpc-cli": "^0.12.0",
82
+ "ts-morph": "^27.0.2",
83
+ "yaml": "^2.8.1",
84
+ "zod": "^4.1.12"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@types/fs-extra": "^11.0.4",
88
- "@types/node": "^24.5.2",
88
+ "@types/node": "^24.9.1",
89
89
  "@vitest/ui": "^3.2.4",
90
- "publint": "^0.3.13",
91
- "tsdown": "^0.15.4",
92
- "typescript": "^5.9.2",
90
+ "publint": "^0.3.15",
91
+ "tsdown": "^0.15.9",
92
+ "typescript": "^5.9.3",
93
93
  "vitest": "^3.2.4"
94
94
  }
95
95
  }