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.
- package/dist/index.mjs +19 -171
- 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
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
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
|
-
|
|
787
|
-
|
|
788
|
-
|
|
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
|
|
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}
|
|
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
|
-
|
|
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.
|
|
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.
|
|
131
|
-
"@better-fullstack/types": "^1.
|
|
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.
|
|
134
|
-
"@orpc/server": "^1.14.
|
|
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.
|
|
149
|
-
"zod": "
|
|
148
|
+
"yaml": "^2.8.4",
|
|
149
|
+
"zod": "4.3.6"
|
|
150
150
|
},
|
|
151
151
|
"devDependencies": {
|
|
152
152
|
"@types/bun": "^1.3.13",
|