create-better-t-stack 2.33.8-canary.98a850ad → 2.33.9-canary.88769d6d

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-D0MPVT22.js";
2
+ import { createBtsCli } from "./src-Bm5FOLMd.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-D0MPVT22.js";
2
+ import { builder, createBtsCli, docs, init, router, sponsors } from "./src-Bm5FOLMd.js";
3
3
 
4
4
  export { builder, createBtsCli, docs, init, router, sponsors };
@@ -5,7 +5,6 @@ import { createCli, trpcServer } from "trpc-cli";
5
5
  import z from "zod";
6
6
  import path from "node:path";
7
7
  import consola, { consola as consola$1 } from "consola";
8
- import * as fs$1 from "fs-extra";
9
8
  import fs from "fs-extra";
10
9
  import { fileURLToPath } from "node:url";
11
10
  import gradient from "gradient-string";
@@ -137,7 +136,8 @@ const ADDON_COMPATIBILITY = {
137
136
  "react-router",
138
137
  "nuxt",
139
138
  "svelte",
140
- "solid"
139
+ "solid",
140
+ "next"
141
141
  ],
142
142
  biome: [],
143
143
  husky: [],
@@ -565,6 +565,20 @@ function validateWebDeployRequiresWebFrontend(webDeploy, hasWebFrontendFlag) {
565
565
  function validateServerDeployRequiresBackend(serverDeploy, backend) {
566
566
  if (serverDeploy && serverDeploy !== "none" && (!backend || backend === "none")) exitWithError("'--server-deploy' requires a backend. Please select a backend or set '--server-deploy none'.");
567
567
  }
568
+ function validateAddonsAgainstFrontends(addons = [], frontends = []) {
569
+ for (const addon of addons) {
570
+ if (addon === "none") continue;
571
+ const { isCompatible, reason } = validateAddonCompatibility(addon, frontends);
572
+ if (!isCompatible) exitWithError(`Incompatible addon/frontend combination: ${reason}`);
573
+ }
574
+ }
575
+ function validateExamplesCompatibility(examples, backend, database, frontend) {
576
+ const examplesArr = examples ?? [];
577
+ if (examplesArr.length === 0 || examplesArr.includes("none")) return;
578
+ if (examplesArr.includes("todo") && backend !== "convex" && backend !== "none" && database === "none") exitWithError("The 'todo' example requires a database if a backend (other than Convex) is present. Cannot use --examples todo when database is 'none' and a backend is selected.");
579
+ if (examplesArr.includes("ai") && backend === "elysia") exitWithError("The 'ai' example is not compatible with the Elysia backend.");
580
+ if (examplesArr.includes("ai") && (frontend ?? []).includes("solid")) exitWithError("The 'ai' example is not compatible with the Solid frontend.");
581
+ }
568
582
 
569
583
  //#endregion
570
584
  //#region src/prompts/api.ts
@@ -1298,9 +1312,9 @@ async function getProjectName(initialName) {
1298
1312
 
1299
1313
  //#endregion
1300
1314
  //#region src/utils/get-latest-cli-version.ts
1301
- const getLatestCLIVersion = async () => {
1315
+ const getLatestCLIVersion = () => {
1302
1316
  const packageJsonPath = path.join(PKG_ROOT, "package.json");
1303
- const packageJsonContent = await fs.readJSON(packageJsonPath);
1317
+ const packageJsonContent = fs.readJSONSync(packageJsonPath);
1304
1318
  return packageJsonContent.version ?? "1.0.0";
1305
1319
  };
1306
1320
 
@@ -1662,6 +1676,43 @@ function processAndValidateFlags(options, providedFlags, projectName) {
1662
1676
  validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
1663
1677
  return config;
1664
1678
  }
1679
+ function validateConfigCompatibility(config) {
1680
+ const effectiveDatabase = config.database;
1681
+ const effectiveBackend = config.backend;
1682
+ const effectiveFrontend = config.frontend;
1683
+ const effectiveApi = config.api;
1684
+ validateApiFrontendCompatibility(effectiveApi, effectiveFrontend);
1685
+ if (config.addons && config.addons.length > 0) {
1686
+ validateAddonsAgainstFrontends(config.addons, effectiveFrontend);
1687
+ config.addons = [...new Set(config.addons)];
1688
+ }
1689
+ validateExamplesCompatibility(config.examples ?? [], effectiveBackend, effectiveDatabase, effectiveFrontend ?? []);
1690
+ }
1691
+ function processProvidedFlagsWithoutValidation(options, projectName) {
1692
+ const config = {};
1693
+ if (options.api) config.api = options.api;
1694
+ if (options.backend) config.backend = options.backend;
1695
+ if (options.database) config.database = options.database;
1696
+ if (options.orm) config.orm = options.orm;
1697
+ if (options.auth !== void 0) config.auth = options.auth;
1698
+ if (options.git !== void 0) config.git = options.git;
1699
+ if (options.install !== void 0) config.install = options.install;
1700
+ if (options.runtime) config.runtime = options.runtime;
1701
+ if (options.dbSetup) config.dbSetup = options.dbSetup;
1702
+ if (options.packageManager) config.packageManager = options.packageManager;
1703
+ if (options.webDeploy) config.webDeploy = options.webDeploy;
1704
+ const derivedName = deriveProjectName(projectName, options.projectDirectory);
1705
+ if (derivedName) {
1706
+ const nameToValidate = projectName ? path.basename(projectName) : derivedName;
1707
+ const result = ProjectNameSchema.safeParse(nameToValidate);
1708
+ if (!result.success) throw new Error(`Invalid project name: ${result.error.issues[0]?.message}`);
1709
+ config.projectName = projectName || derivedName;
1710
+ }
1711
+ if (options.frontend && options.frontend.length > 0) config.frontend = processArrayOption(options.frontend);
1712
+ if (options.addons && options.addons.length > 0) config.addons = processArrayOption(options.addons);
1713
+ if (options.examples && options.examples.length > 0) config.examples = processArrayOption(options.examples);
1714
+ return config;
1715
+ }
1665
1716
  function getProvidedFlags(options) {
1666
1717
  return new Set(Object.keys(options).filter((key) => options[key] !== void 0));
1667
1718
  }
@@ -2216,20 +2267,16 @@ async function setupDeploymentTemplates(projectDir, context) {
2216
2267
  }
2217
2268
  } else {
2218
2269
  if (context.webDeploy === "alchemy") {
2270
+ const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
2219
2271
  const webAppDir = path.join(projectDir, "apps/web");
2220
- if (await fs.pathExists(webAppDir)) {
2221
- const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
2222
- if (await fs.pathExists(alchemyTemplateSrc)) await processAndCopyFiles("**/*", alchemyTemplateSrc, webAppDir, context);
2223
- }
2272
+ if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(webAppDir)) await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, webAppDir, context);
2224
2273
  }
2225
2274
  if (context.serverDeploy === "alchemy") {
2275
+ const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
2226
2276
  const serverAppDir = path.join(projectDir, "apps/server");
2227
- if (await fs.pathExists(serverAppDir)) {
2228
- const alchemyTemplateSrc = path.join(PKG_ROOT, "templates/deploy/alchemy");
2229
- if (await fs.pathExists(alchemyTemplateSrc)) {
2230
- await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2231
- await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2232
- }
2277
+ if (await fs.pathExists(alchemyTemplateSrc) && await fs.pathExists(serverAppDir)) {
2278
+ await processAndCopyFiles("alchemy.run.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2279
+ await processAndCopyFiles("env.d.ts.hbs", alchemyTemplateSrc, serverAppDir, context);
2233
2280
  }
2234
2281
  }
2235
2282
  }
@@ -2501,7 +2548,7 @@ async function setupUltracite(config, hasHusky) {
2501
2548
  ];
2502
2549
  if (editors.length > 0) ultraciteArgs.push("--editors", ...editors);
2503
2550
  if (rules.length > 0) ultraciteArgs.push("--rules", ...rules);
2504
- if (hasHusky) ultraciteArgs.push("--features", "husky", "lint-staged");
2551
+ if (hasHusky) ultraciteArgs.push("--integrations", "husky", "lint-staged");
2505
2552
  const ultraciteArgsString = ultraciteArgs.join(" ");
2506
2553
  const commandWithArgs = `ultracite@latest ${ultraciteArgsString} --skip-install`;
2507
2554
  const ultraciteInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
@@ -3342,15 +3389,15 @@ async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
3342
3389
  //#region src/helpers/deployment/workers/workers-next-setup.ts
3343
3390
  async function setupNextWorkersDeploy(projectDir, _packageManager) {
3344
3391
  const webAppDir = path.join(projectDir, "apps/web");
3345
- if (!await fs$1.pathExists(webAppDir)) return;
3392
+ if (!await fs.pathExists(webAppDir)) return;
3346
3393
  await addPackageDependency({
3347
3394
  dependencies: ["@opennextjs/cloudflare"],
3348
3395
  devDependencies: ["wrangler"],
3349
3396
  projectDir: webAppDir
3350
3397
  });
3351
3398
  const packageJsonPath = path.join(webAppDir, "package.json");
3352
- if (await fs$1.pathExists(packageJsonPath)) {
3353
- const pkg = await fs$1.readJson(packageJsonPath);
3399
+ if (await fs.pathExists(packageJsonPath)) {
3400
+ const pkg = await fs.readJson(packageJsonPath);
3354
3401
  pkg.scripts = {
3355
3402
  ...pkg.scripts,
3356
3403
  preview: "opennextjs-cloudflare build && opennextjs-cloudflare preview",
@@ -3358,7 +3405,7 @@ async function setupNextWorkersDeploy(projectDir, _packageManager) {
3358
3405
  upload: "opennextjs-cloudflare build && opennextjs-cloudflare upload",
3359
3406
  "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
3360
3407
  };
3361
- await fs$1.writeJson(packageJsonPath, pkg, { spaces: 2 });
3408
+ await fs.writeJson(packageJsonPath, pkg, { spaces: 2 });
3362
3409
  }
3363
3410
  }
3364
3411
 
@@ -5902,15 +5949,9 @@ async function createProjectHandler(input) {
5902
5949
  projectDirectory: input.projectName
5903
5950
  };
5904
5951
  const providedFlags = getProvidedFlags(cliInput);
5905
- const flagConfig = processAndValidateFlags(cliInput, providedFlags, finalBaseName);
5906
- const { projectName: _projectNameFromFlags,...otherFlags } = flagConfig;
5907
- if (!input.yes && Object.keys(otherFlags).length > 0) {
5908
- log.info(pc.yellow("Using these pre-selected options:"));
5909
- log.message(displayConfig(otherFlags));
5910
- log.message("");
5911
- }
5912
5952
  let config;
5913
5953
  if (input.yes) {
5954
+ const flagConfig = processProvidedFlagsWithoutValidation(cliInput, finalBaseName);
5914
5955
  config = {
5915
5956
  ...DEFAULT_CONFIG,
5916
5957
  ...flagConfig,
@@ -5918,12 +5959,22 @@ async function createProjectHandler(input) {
5918
5959
  projectDir: finalResolvedPath,
5919
5960
  relativePath: finalPathInput
5920
5961
  };
5962
+ validateConfigCompatibility(config);
5921
5963
  if (config.backend === "convex") log.info("Due to '--backend convex' flag, the following options have been automatically set: auth=false, database=none, orm=none, api=none, runtime=none, dbSetup=none, examples=todo");
5922
5964
  else if (config.backend === "none") log.info("Due to '--backend none', the following options have been automatically set: --auth=false, --database=none, --orm=none, --api=none, --runtime=none, --db-setup=none, --examples=none");
5923
5965
  log.info(pc.yellow("Using default/flag options (config prompts skipped):"));
5924
5966
  log.message(displayConfig(config));
5925
5967
  log.message("");
5926
- } else config = await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput);
5968
+ } else {
5969
+ const flagConfig = processAndValidateFlags(cliInput, providedFlags, finalBaseName);
5970
+ const { projectName: _projectNameFromFlags,...otherFlags } = flagConfig;
5971
+ if (Object.keys(otherFlags).length > 0) {
5972
+ log.info(pc.yellow("Using these pre-selected options:"));
5973
+ log.message(displayConfig(otherFlags));
5974
+ log.message("");
5975
+ }
5976
+ config = await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput);
5977
+ }
5927
5978
  await createProject(config);
5928
5979
  const reproducibleCommand = generateReproducibleCommand(config);
5929
5980
  log.success(pc.blue(`You can reproduce this setup with the following command:\n${reproducibleCommand}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "2.33.8-canary.98a850ad",
3
+ "version": "2.33.9-canary.88769d6d",
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",