create-better-fullstack 1.6.3 → 1.7.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.
Files changed (2) hide show
  1. package/dist/index.mjs +19 -171
  2. package/package.json +7 -7
package/dist/index.mjs CHANGED
@@ -10,7 +10,7 @@ import z from "zod";
10
10
  import envPaths from "env-paths";
11
11
  import fs from "fs-extra";
12
12
  import path from "node:path";
13
- import { allowedApisForFrontends, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getLocalWebDevPort, hasDockerComposeCompatibleFrontend, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
13
+ import { allowedApisForFrontends, getAIFrontendCompatibilityIssue, getApiFrontendCompatibilityIssue, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getLocalWebDevPort, hasDockerComposeCompatibleFrontend, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
14
14
  import { ECOSYSTEM_GROUPS, EMBEDDED_TEMPLATES, EMBEDDED_TEMPLATES as EMBEDDED_TEMPLATES$1, TEMPLATE_COUNT, VirtualFileSystem, VirtualFileSystem as VirtualFileSystem$1, checkAllVersions, generateCliReport, generateVirtualProject, generateVirtualProject as generateVirtualProject$1, listEcosystems, processAddonTemplates, processAddonsDeps, validatePreflightConfig } from "@better-fullstack/template-generator";
15
15
  import gradient from "gradient-string";
16
16
  import path$1 from "path";
@@ -18,6 +18,7 @@ import { writeTreeToFilesystem } from "@better-fullstack/template-generator/fs-w
18
18
  import consola, { consola as consola$1 } from "consola";
19
19
  import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
20
20
  import { $, execa } from "execa";
21
+ import { cliInputToProjectConfigPartial } from "@better-fullstack/types/stack-translation";
21
22
  import os$1 from "node:os";
22
23
  import { format } from "oxfmt";
23
24
 
@@ -602,74 +603,12 @@ function validateWorkersCompatibility(providedFlags, options, config) {
602
603
  });
603
604
  }
604
605
  function validateApiFrontendCompatibility(api, frontends = [], astroIntegration) {
605
- const includesNuxt = frontends.includes("nuxt");
606
- const includesSvelte = frontends.includes("svelte");
607
- const includesSolid = frontends.includes("solid");
608
- const includesAstro = frontends.includes("astro");
609
- const includesQwik = frontends.includes("qwik");
610
- const includesAngular = frontends.includes("angular");
611
- const includesRedwood = frontends.includes("redwood");
612
- const includesFresh = frontends.includes("fresh");
613
- const includesSolidStart = frontends.includes("solid-start");
614
- if ((includesNuxt || includesSvelte || includesSolid || includesSolidStart) && (api === "trpc" || api === "ts-rest" || api === "garph")) {
615
- const apiName = api === "trpc" ? "tRPC" : api === "ts-rest" ? "ts-rest" : "garph";
616
- const incompatibleFrontend = includesNuxt ? "nuxt" : includesSvelte ? "svelte" : includesSolid ? "solid" : "solid-start";
617
- incompatibilityError({
618
- message: `${apiName} API requires React-based frontends.`,
619
- provided: {
620
- api,
621
- frontend: incompatibleFrontend
622
- },
623
- suggestions: [
624
- "Use --api orpc (works with all frontends)",
625
- "Use --api none",
626
- "Choose next, react-router, react-vite, or tanstack-start"
627
- ]
628
- });
629
- }
630
- if (includesQwik && api && api !== "none") incompatibilityError({
631
- message: "Qwik has built-in server capabilities and doesn't support external APIs.",
632
- provided: {
633
- api,
634
- frontend: "qwik"
635
- },
636
- suggestions: ["Use --api none with Qwik"]
637
- });
638
- if (includesAngular && api && api !== "none") incompatibilityError({
639
- message: "Angular has built-in HttpClient and doesn't support external APIs.",
640
- provided: {
641
- api,
642
- frontend: "angular"
643
- },
644
- suggestions: ["Use --api none with Angular"]
645
- });
646
- if (includesRedwood && api && api !== "none") incompatibilityError({
647
- message: "RedwoodJS has built-in GraphQL API and doesn't support external APIs.",
648
- provided: {
649
- api,
650
- frontend: "redwood"
651
- },
652
- suggestions: ["Use --api none with RedwoodJS"]
653
- });
654
- if (includesFresh && api && api !== "none") incompatibilityError({
655
- message: "Fresh has built-in server capabilities and doesn't support external APIs.",
656
- provided: {
657
- api,
658
- frontend: "fresh"
659
- },
660
- suggestions: ["Use --api none with Fresh"]
661
- });
662
- if (includesAstro && astroIntegration && astroIntegration !== "react" && (api === "trpc" || api === "ts-rest" || api === "garph")) incompatibilityError({
663
- message: `${api === "trpc" ? "tRPC" : api === "ts-rest" ? "ts-rest" : "garph"} API requires React integration with Astro.`,
664
- provided: {
665
- api,
666
- "astro-integration": astroIntegration
667
- },
668
- suggestions: [
669
- "Use --api orpc (works with all Astro integrations)",
670
- "Use --api none",
671
- "Use --astro-integration react"
672
- ]
606
+ const issue = getApiFrontendCompatibilityIssue(api, frontends, astroIntegration);
607
+ if (!issue) return;
608
+ incompatibilityError({
609
+ message: issue.message,
610
+ provided: issue.provided ?? {},
611
+ suggestions: issue.suggestions ?? []
673
612
  });
674
613
  }
675
614
  function isFrontendAllowedWithBackend$1(frontend, backend, auth) {
@@ -783,18 +722,9 @@ function validateExamplesCompatibility(examples, backend, frontend, runtime, ai)
783
722
  * Server-side @tanstack/ai core works anywhere, but client adapters only exist for React and Solid.
784
723
  */
785
724
  function validateAIFrontendCompatibility(ai, frontends = []) {
786
- if (!ai || ai !== "tanstack-ai") return;
787
- const compatibleFrontends = [
788
- "tanstack-router",
789
- "react-router",
790
- "react-vite",
791
- "tanstack-start",
792
- "next",
793
- "redwood",
794
- "solid",
795
- "solid-start"
796
- ];
797
- if (!frontends.some((f) => compatibleFrontends.includes(f))) exitWithError("TanStack AI requires React or Solid frontend (no Vue/Svelte/Angular adapter yet). Please use a React-based frontend (Next.js, TanStack Router, React Router, etc.) or Solid.");
725
+ const issue = getAIFrontendCompatibilityIssue(ai, frontends);
726
+ if (!issue) return;
727
+ exitWithError(issue.message);
798
728
  }
799
729
  /**
800
730
  * Validates that a UI library is compatible with the selected frontend(s)
@@ -1482,16 +1412,20 @@ async function applyDependencyVersionChannel(projectDir, channel) {
1482
1412
  //#endregion
1483
1413
  //#region src/helpers/core/install-dependencies.ts
1484
1414
  function getInstallEnvironment(packageManager) {
1485
- if (packageManager !== "yarn") return;
1486
- return {
1415
+ if (packageManager === "yarn") return {
1487
1416
  YARN_ENABLE_HARDENED_MODE: "0",
1488
1417
  YARN_ENABLE_IMMUTABLE_INSTALLS: "false"
1489
1418
  };
1490
1419
  }
1420
+ function getInstallArgs(packageManager) {
1421
+ if (packageManager === "pnpm") return ["install", "--dangerously-allow-all-builds"];
1422
+ return ["install"];
1423
+ }
1491
1424
  async function installDependencies({ projectDir, packageManager }) {
1492
1425
  const s = spinner();
1493
1426
  try {
1494
1427
  s.start(`Running ${packageManager} install...`);
1428
+ const installArgs = getInstallArgs(packageManager);
1495
1429
  await $({
1496
1430
  cwd: projectDir,
1497
1431
  env: {
@@ -1499,7 +1433,7 @@ async function installDependencies({ projectDir, packageManager }) {
1499
1433
  ...getInstallEnvironment(packageManager)
1500
1434
  },
1501
1435
  stderr: "inherit"
1502
- })`${packageManager} install`;
1436
+ })`${packageManager} ${installArgs}`;
1503
1437
  s.stop("Dependencies installed successfully");
1504
1438
  } catch (error) {
1505
1439
  s.stop(pc.red("Failed to install dependencies"));
@@ -6517,100 +6451,14 @@ function getTemplateDescription(template) {
6517
6451
 
6518
6452
  //#endregion
6519
6453
  //#region src/utils/config-processing.ts
6520
- function processArrayOption(options) {
6521
- if (!options || options.length === 0) return [];
6522
- if (options.includes("none")) return [];
6523
- return options.filter((item) => item !== "none");
6524
- }
6525
6454
  function deriveProjectName(projectName, projectDirectory) {
6526
6455
  if (projectName) return projectName;
6527
6456
  if (projectDirectory) return path.basename(path.resolve(process.cwd(), projectDirectory));
6528
6457
  return "";
6529
6458
  }
6530
6459
  function processFlags(options, projectName) {
6531
- const config = {};
6532
- if (options.ecosystem) config.ecosystem = options.ecosystem;
6533
- if (options.api) config.api = options.api;
6534
- if (options.backend) config.backend = options.backend;
6535
- if (options.database) config.database = options.database;
6536
- if (options.orm) config.orm = options.orm;
6537
- if (options.auth !== void 0) config.auth = options.auth;
6538
- if (options.payments !== void 0) config.payments = options.payments;
6539
- if (options.email !== void 0) config.email = options.email;
6540
- if (options.effect !== void 0) config.effect = options.effect;
6541
- if (options.stateManagement !== void 0) config.stateManagement = options.stateManagement;
6542
- if (options.validation !== void 0) config.validation = options.validation;
6543
- if (options.realtime !== void 0) config.realtime = options.realtime;
6544
- if (options.jobQueue !== void 0) config.jobQueue = options.jobQueue;
6545
- if (options.animation !== void 0) config.animation = options.animation;
6546
- if (options.ai !== void 0) config.ai = options.ai;
6547
- if (options.forms !== void 0) config.forms = options.forms;
6548
- if (options.testing !== void 0) config.testing = options.testing;
6549
- if (options.logging !== void 0) config.logging = options.logging;
6550
- if (options.observability !== void 0) config.observability = options.observability;
6551
- if (options.cms !== void 0) config.cms = options.cms;
6552
- if (options.caching !== void 0) config.caching = options.caching;
6553
- if (options.i18n !== void 0) config.i18n = options.i18n;
6554
- if (options.search !== void 0) config.search = options.search;
6555
- if (options.fileStorage !== void 0) config.fileStorage = options.fileStorage;
6556
- if (options.analytics !== void 0) config.analytics = options.analytics;
6557
- if (options.featureFlags !== void 0) config.featureFlags = options.featureFlags;
6558
- if (options.fileUpload !== void 0) config.fileUpload = options.fileUpload;
6559
- if (options.git !== void 0) config.git = options.git;
6560
- if (options.install !== void 0) config.install = options.install;
6561
- if (options.runtime) config.runtime = options.runtime;
6562
- if (options.dbSetup) config.dbSetup = options.dbSetup;
6563
- if (options.packageManager) config.packageManager = options.packageManager;
6564
- if (options.versionChannel) config.versionChannel = options.versionChannel;
6565
- if (options.webDeploy) config.webDeploy = options.webDeploy;
6566
- if (options.serverDeploy) config.serverDeploy = options.serverDeploy;
6567
6460
  const derivedName = deriveProjectName(projectName, options.projectDirectory);
6568
- if (derivedName) config.projectName = projectName || derivedName;
6569
- if (options.frontend && options.frontend.length > 0) config.frontend = processArrayOption(options.frontend);
6570
- if (options.astroIntegration) config.astroIntegration = options.astroIntegration;
6571
- if (options.cssFramework) config.cssFramework = options.cssFramework;
6572
- if (options.uiLibrary) config.uiLibrary = options.uiLibrary;
6573
- if (options.shadcnBase) config.shadcnBase = options.shadcnBase;
6574
- if (options.shadcnStyle) config.shadcnStyle = options.shadcnStyle;
6575
- if (options.shadcnIconLibrary) config.shadcnIconLibrary = options.shadcnIconLibrary;
6576
- if (options.shadcnColorTheme) config.shadcnColorTheme = options.shadcnColorTheme;
6577
- if (options.shadcnBaseColor) config.shadcnBaseColor = options.shadcnBaseColor;
6578
- if (options.shadcnFont) config.shadcnFont = options.shadcnFont;
6579
- if (options.shadcnRadius) config.shadcnRadius = options.shadcnRadius;
6580
- if (options.addons && options.addons.length > 0) config.addons = processArrayOption(options.addons);
6581
- if (options.examples && options.examples.length > 0) config.examples = processArrayOption(options.examples);
6582
- if (options.aiDocs !== void 0) config.aiDocs = processArrayOption(options.aiDocs);
6583
- if (options.rustWebFramework !== void 0) config.rustWebFramework = options.rustWebFramework;
6584
- if (options.rustFrontend !== void 0) config.rustFrontend = options.rustFrontend;
6585
- if (options.rustOrm !== void 0) config.rustOrm = options.rustOrm;
6586
- if (options.rustApi !== void 0) config.rustApi = options.rustApi;
6587
- if (options.rustCli !== void 0) config.rustCli = options.rustCli;
6588
- if (options.rustLibraries !== void 0) config.rustLibraries = processArrayOption(options.rustLibraries);
6589
- if (options.rustLogging !== void 0) config.rustLogging = options.rustLogging;
6590
- if (options.rustErrorHandling !== void 0) config.rustErrorHandling = options.rustErrorHandling;
6591
- if (options.rustCaching !== void 0) config.rustCaching = options.rustCaching;
6592
- if (options.rustAuth !== void 0) config.rustAuth = options.rustAuth;
6593
- if (options.pythonWebFramework !== void 0) config.pythonWebFramework = options.pythonWebFramework;
6594
- if (options.pythonOrm !== void 0) config.pythonOrm = options.pythonOrm;
6595
- if (options.pythonValidation !== void 0) config.pythonValidation = options.pythonValidation;
6596
- if (options.pythonAi !== void 0) config.pythonAi = processArrayOption(options.pythonAi);
6597
- if (options.pythonAuth !== void 0) config.pythonAuth = options.pythonAuth;
6598
- if (options.pythonTaskQueue !== void 0) config.pythonTaskQueue = options.pythonTaskQueue;
6599
- if (options.pythonGraphql !== void 0) config.pythonGraphql = options.pythonGraphql;
6600
- if (options.pythonQuality !== void 0) config.pythonQuality = options.pythonQuality;
6601
- if (options.goWebFramework !== void 0) config.goWebFramework = options.goWebFramework;
6602
- if (options.goOrm !== void 0) config.goOrm = options.goOrm;
6603
- if (options.goApi !== void 0) config.goApi = options.goApi;
6604
- if (options.goCli !== void 0) config.goCli = options.goCli;
6605
- if (options.goLogging !== void 0) config.goLogging = options.goLogging;
6606
- if (options.goAuth !== void 0) config.goAuth = options.goAuth;
6607
- if (options.javaWebFramework !== void 0) config.javaWebFramework = options.javaWebFramework;
6608
- if (options.javaBuildTool !== void 0) config.javaBuildTool = options.javaBuildTool;
6609
- if (options.javaOrm !== void 0) config.javaOrm = options.javaOrm;
6610
- if (options.javaAuth !== void 0) config.javaAuth = options.javaAuth;
6611
- if (options.javaLibraries !== void 0) config.javaLibraries = processArrayOption(options.javaLibraries);
6612
- if (options.javaTestingLibraries !== void 0) config.javaTestingLibraries = processArrayOption(options.javaTestingLibraries);
6613
- return config;
6461
+ return cliInputToProjectConfigPartial(options, projectName || derivedName);
6614
6462
  }
6615
6463
  function getProvidedFlags(options) {
6616
6464
  return new Set(Object.keys(options).filter((key) => options[key] !== void 0));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "1.6.3",
3
+ "version": "1.7.0",
4
4
  "description": "Scaffold production-ready fullstack apps in seconds. Pick your stack from 425 options — the CLI wires everything together.",
5
5
  "keywords": [
6
6
  "algolia",
@@ -127,11 +127,11 @@
127
127
  "prepublishOnly": "npm run build"
128
128
  },
129
129
  "dependencies": {
130
- "@better-fullstack/template-generator": "^1.6.3",
131
- "@better-fullstack/types": "^1.6.3",
130
+ "@better-fullstack/template-generator": "^1.7.0",
131
+ "@better-fullstack/types": "^1.7.0",
132
132
  "@clack/core": "^0.5.0",
133
- "@clack/prompts": "^1.2.0",
134
- "@orpc/server": "^1.14.0",
133
+ "@clack/prompts": "^1.3.0",
134
+ "@orpc/server": "^1.14.1",
135
135
  "consola": "^3.4.2",
136
136
  "env-paths": "^4.0.0",
137
137
  "execa": "^9.6.1",
@@ -145,8 +145,8 @@
145
145
  "@modelcontextprotocol/sdk": "^1.29.0",
146
146
  "trpc-cli": "^0.12.1",
147
147
  "ts-morph": "^27.0.2",
148
- "yaml": "^2.8.3",
149
- "zod": "^4.3.6"
148
+ "yaml": "^2.8.4",
149
+ "zod": "4.3.6"
150
150
  },
151
151
  "devDependencies": {
152
152
  "@types/bun": "^1.3.13",