create-better-fullstack 2.0.3 → 2.1.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/{add-handler-BQN6pwGJ.mjs → add-handler-BjTmOwEN.mjs} +11 -9
- package/dist/addons-setup-CSmj5ClW.mjs +6 -0
- package/dist/{addons-setup-HSghQS7c.mjs → addons-setup-uSvqHagW.mjs} +4 -83
- package/dist/{bts-config-Bg1Qea9Y.mjs → bts-config-InNcw1aJ.mjs} +90 -68
- package/dist/cli.mjs +2 -2
- package/dist/doctor-Bm9qvkya.mjs +281 -0
- package/dist/errors-ns_o2OKg.mjs +86 -0
- package/dist/generated-checks-CUhFFfVo.mjs +91 -0
- package/dist/index.d.mts +85 -29
- package/dist/index.mjs +10 -6
- package/dist/{install-dependencies-D0Z1dZEx.mjs → install-dependencies-CDjTNvIV.mjs} +120 -49
- package/dist/{mcp-58r70ZcL.mjs → mcp-BaLHDRdC.mjs} +1 -1
- package/dist/mcp-entry.mjs +601 -137
- package/dist/render-title-zvyKC1ej.mjs +34 -0
- package/dist/{run-BhcXBjxh.mjs → run-Cqy-n1iT.mjs} +548 -658
- package/dist/run-DYWSKowD.mjs +10 -0
- package/dist/templates-B351F1yX.mjs +489 -0
- package/package.json +5 -4
- package/dist/addons-setup-CV5uZyhH.mjs +0 -5
- package/dist/run-DCxVLUMS.mjs +0 -7
- /package/dist/{update-deps-CLebIM70.mjs → update-deps-D5OG0KmJ.mjs} +0 -0
|
@@ -1,46 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { c as DEFAULT_CONFIG, y as types_exports } from "./bts-config-InNcw1aJ.mjs";
|
|
3
|
+
import { c as isSilent, d as setLastPromptShownUI, i as exitWithError, r as exitCancelled, s as isFirstPrompt, t as CLIError, u as setIsFirstPrompt$1 } from "./errors-ns_o2OKg.mjs";
|
|
4
4
|
import { log, spinner } from "@clack/prompts";
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
import fs from "fs-extra";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { allowedApisForFrontends, getAIFrontendCompatibilityIssue, getApiFrontendCompatibilityIssue, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getUnsupportedWebDeployFrontend, hasDockerComposeCompatibleFrontend, hasWebStyling, isBackendUtilsCompatibleBackend, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
|
|
9
|
-
import gradient from "gradient-string";
|
|
10
9
|
import consola from "consola";
|
|
11
10
|
import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
|
|
12
11
|
import { $ } from "execa";
|
|
13
12
|
|
|
14
|
-
//#region src/utils/render-title.ts
|
|
15
|
-
const TITLE_TEXT = `
|
|
16
|
-
██████╗ ███████╗████████╗████████╗███████╗██████╗
|
|
17
|
-
██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗
|
|
18
|
-
██████╔╝█████╗ ██║ ██║ █████╗ ██████╔╝
|
|
19
|
-
██╔══██╗██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗
|
|
20
|
-
██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║
|
|
21
|
-
╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
|
|
22
|
-
|
|
23
|
-
███████╗██╗ ██╗██╗ ██╗ ███████╗████████╗ █████╗ ██████╗██╗ ██╗
|
|
24
|
-
██╔════╝██║ ██║██║ ██║ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝
|
|
25
|
-
█████╗ ██║ ██║██║ ██║ ███████╗ ██║ ███████║██║ █████╔╝
|
|
26
|
-
██╔══╝ ██║ ██║██║ ██║ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗
|
|
27
|
-
██║ ╚██████╔╝███████╗███████╗███████║ ██║ ██║ ██║╚██████╗██║ ██╗
|
|
28
|
-
╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
|
|
29
|
-
`;
|
|
30
|
-
const monochromeTheme = {
|
|
31
|
-
white: "#FFFFFF",
|
|
32
|
-
lightGray: "#E5E5E5",
|
|
33
|
-
gray: "#A3A3A3",
|
|
34
|
-
darkGray: "#737373"
|
|
35
|
-
};
|
|
36
|
-
const renderTitle = () => {
|
|
37
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
38
|
-
const titleLines = TITLE_TEXT.split("\n");
|
|
39
|
-
if (terminalWidth < Math.max(...titleLines.map((line) => line.length))) console.log(gradient(Object.values(monochromeTheme)).multiline(`Better Fullstack`));
|
|
40
|
-
else console.log(gradient(Object.values(monochromeTheme)).multiline(TITLE_TEXT));
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
//#endregion
|
|
44
13
|
//#region src/utils/error-formatter.ts
|
|
45
14
|
function getCategoryTitle(category) {
|
|
46
15
|
return {
|
|
@@ -241,34 +210,46 @@ function validateAddonCompatibility$1(addon, frontend, _auth, backend, runtime,
|
|
|
241
210
|
reason: "Backend Utils requires a Hono, Express, Fastify, Elysia, feTS, or NestJS backend"
|
|
242
211
|
};
|
|
243
212
|
}
|
|
244
|
-
if (addon === "docker-compose") {
|
|
213
|
+
if (addon === "docker-compose" || addon === "devcontainer") {
|
|
214
|
+
const label = addon === "devcontainer" ? "DevContainer" : "docker-compose";
|
|
215
|
+
const title = addon === "devcontainer" ? "DevContainer" : "Docker Compose";
|
|
245
216
|
if (backend === "convex") return {
|
|
246
217
|
isCompatible: false,
|
|
247
|
-
reason:
|
|
218
|
+
reason: `${label} is not compatible with Convex backend (managed service)`
|
|
248
219
|
};
|
|
249
220
|
if (runtime === "workers") return {
|
|
250
221
|
isCompatible: false,
|
|
251
|
-
reason:
|
|
222
|
+
reason: `${label} is not compatible with Cloudflare Workers runtime`
|
|
223
|
+
};
|
|
224
|
+
if (ecosystem !== void 0 && ![
|
|
225
|
+
"typescript",
|
|
226
|
+
"python",
|
|
227
|
+
"go",
|
|
228
|
+
"rust",
|
|
229
|
+
"java"
|
|
230
|
+
].includes(ecosystem)) return {
|
|
231
|
+
isCompatible: false,
|
|
232
|
+
reason: `${title} currently supports TypeScript, Python, Go, Rust, or Java projects`
|
|
252
233
|
};
|
|
253
234
|
if (ecosystem === "typescript" && !hasDockerComposeCompatibleFrontend(frontend)) return {
|
|
254
235
|
isCompatible: false,
|
|
255
|
-
reason:
|
|
236
|
+
reason: `${title} currently supports Next.js, Vinext, TanStack Router, React Router, React Vite, Solid, or Astro`
|
|
256
237
|
};
|
|
257
238
|
if (ecosystem === "typescript" && backend === "self" && !frontend.includes("next") && !frontend.includes("vinext")) return {
|
|
258
239
|
isCompatible: false,
|
|
259
|
-
reason:
|
|
240
|
+
reason: `${title} self-backend support currently requires Next.js or Vinext`
|
|
260
241
|
};
|
|
261
242
|
if (ecosystem === "rust" && rustFrontend && rustFrontend !== "none") return {
|
|
262
243
|
isCompatible: false,
|
|
263
|
-
reason:
|
|
244
|
+
reason: `${title} for Rust currently supports server-only projects`
|
|
264
245
|
};
|
|
265
246
|
if (ecosystem === "java" && javaWebFramework && javaWebFramework !== "spring-boot") return {
|
|
266
247
|
isCompatible: false,
|
|
267
|
-
reason:
|
|
248
|
+
reason: `${title} for Java currently requires Spring Boot`
|
|
268
249
|
};
|
|
269
250
|
if (ecosystem === "python" && database && database !== "none" && database !== "sqlite" && database !== "postgres") return {
|
|
270
251
|
isCompatible: false,
|
|
271
|
-
reason:
|
|
252
|
+
reason: `${title} for Python ORM projects currently supports SQLite defaults or Postgres`
|
|
272
253
|
};
|
|
273
254
|
}
|
|
274
255
|
return { isCompatible: true };
|
|
@@ -732,10 +713,18 @@ function getAddonDisplay(addon) {
|
|
|
732
713
|
label = "Backend Utils";
|
|
733
714
|
hint = "asyncHandler, ApiResponse & global error handler for your server";
|
|
734
715
|
break;
|
|
716
|
+
case "devcontainer":
|
|
717
|
+
label = "DevContainer";
|
|
718
|
+
hint = "VS Code container config with stack-aware ports and extensions";
|
|
719
|
+
break;
|
|
735
720
|
case "docker-compose":
|
|
736
721
|
label = "Docker Compose";
|
|
737
722
|
hint = "Containerize your app for deployment";
|
|
738
723
|
break;
|
|
724
|
+
case "github-actions":
|
|
725
|
+
label = "GitHub Actions";
|
|
726
|
+
hint = "Ship a CI workflow (install, lint, type-check, build)";
|
|
727
|
+
break;
|
|
739
728
|
default:
|
|
740
729
|
label = addon;
|
|
741
730
|
hint = `Add ${addon}`;
|
|
@@ -749,6 +738,7 @@ const ADDON_GROUPS = {
|
|
|
749
738
|
Tooling: [
|
|
750
739
|
"turborepo",
|
|
751
740
|
"nx",
|
|
741
|
+
"github-actions",
|
|
752
742
|
"biome",
|
|
753
743
|
"oxlint",
|
|
754
744
|
"ultracite",
|
|
@@ -762,6 +752,7 @@ const ADDON_GROUPS = {
|
|
|
762
752
|
"opentui",
|
|
763
753
|
"wxt",
|
|
764
754
|
"ruler",
|
|
755
|
+
"devcontainer",
|
|
765
756
|
"docker-compose"
|
|
766
757
|
],
|
|
767
758
|
Integrations: [
|
|
@@ -1021,6 +1012,9 @@ async function applyDependencyVersionChannel(projectDir, channel) {
|
|
|
1021
1012
|
|
|
1022
1013
|
//#endregion
|
|
1023
1014
|
//#region src/helpers/core/install-dependencies.ts
|
|
1015
|
+
function toErrorMessage(error) {
|
|
1016
|
+
return error instanceof Error ? error.message : String(error);
|
|
1017
|
+
}
|
|
1024
1018
|
function getInstallEnvironment(packageManager) {
|
|
1025
1019
|
if (packageManager === "yarn") return {
|
|
1026
1020
|
YARN_ENABLE_HARDENED_MODE: "0",
|
|
@@ -1033,6 +1027,7 @@ function getInstallArgs(packageManager) {
|
|
|
1033
1027
|
}
|
|
1034
1028
|
async function installDependencies({ projectDir, packageManager }) {
|
|
1035
1029
|
const s = spinner();
|
|
1030
|
+
const step = "Install dependencies";
|
|
1036
1031
|
try {
|
|
1037
1032
|
s.start(`Running ${packageManager} install...`);
|
|
1038
1033
|
const installArgs = getInstallArgs(packageManager);
|
|
@@ -1045,13 +1040,24 @@ async function installDependencies({ projectDir, packageManager }) {
|
|
|
1045
1040
|
stderr: "inherit"
|
|
1046
1041
|
})`${packageManager} ${installArgs}`;
|
|
1047
1042
|
s.stop("Dependencies installed successfully");
|
|
1043
|
+
return {
|
|
1044
|
+
step,
|
|
1045
|
+
success: true
|
|
1046
|
+
};
|
|
1048
1047
|
} catch (error) {
|
|
1049
1048
|
s.stop(pc.red("Failed to install dependencies"));
|
|
1050
|
-
|
|
1049
|
+
const errorMessage = toErrorMessage(error);
|
|
1050
|
+
consola.error(pc.red(`Installation error: ${errorMessage}`));
|
|
1051
|
+
return {
|
|
1052
|
+
step,
|
|
1053
|
+
success: false,
|
|
1054
|
+
errorMessage
|
|
1055
|
+
};
|
|
1051
1056
|
}
|
|
1052
1057
|
}
|
|
1053
1058
|
async function runCargoBuild({ projectDir }) {
|
|
1054
1059
|
const s = spinner();
|
|
1060
|
+
const step = "Cargo build";
|
|
1055
1061
|
try {
|
|
1056
1062
|
s.start("Running cargo build...");
|
|
1057
1063
|
await $({
|
|
@@ -1059,13 +1065,24 @@ async function runCargoBuild({ projectDir }) {
|
|
|
1059
1065
|
stderr: "inherit"
|
|
1060
1066
|
})`cargo build`;
|
|
1061
1067
|
s.stop("Cargo build completed");
|
|
1068
|
+
return {
|
|
1069
|
+
step,
|
|
1070
|
+
success: true
|
|
1071
|
+
};
|
|
1062
1072
|
} catch (error) {
|
|
1063
1073
|
s.stop(pc.red("Cargo build failed"));
|
|
1064
|
-
|
|
1074
|
+
const errorMessage = toErrorMessage(error);
|
|
1075
|
+
consola.error(pc.red(`Cargo build error: ${errorMessage}`));
|
|
1076
|
+
return {
|
|
1077
|
+
step,
|
|
1078
|
+
success: false,
|
|
1079
|
+
errorMessage
|
|
1080
|
+
};
|
|
1065
1081
|
}
|
|
1066
1082
|
}
|
|
1067
1083
|
async function runUvSync({ projectDir }) {
|
|
1068
1084
|
const s = spinner();
|
|
1085
|
+
const step = "uv sync (Python dependencies)";
|
|
1069
1086
|
try {
|
|
1070
1087
|
s.start("Running uv sync...");
|
|
1071
1088
|
await $({
|
|
@@ -1073,13 +1090,24 @@ async function runUvSync({ projectDir }) {
|
|
|
1073
1090
|
stderr: "inherit"
|
|
1074
1091
|
})`uv sync`;
|
|
1075
1092
|
s.stop("Python dependencies installed successfully");
|
|
1093
|
+
return {
|
|
1094
|
+
step,
|
|
1095
|
+
success: true
|
|
1096
|
+
};
|
|
1076
1097
|
} catch (error) {
|
|
1077
1098
|
s.stop(pc.red("uv sync failed"));
|
|
1078
|
-
|
|
1099
|
+
const errorMessage = toErrorMessage(error);
|
|
1100
|
+
consola.error(pc.red(`uv sync error: ${errorMessage}`));
|
|
1101
|
+
return {
|
|
1102
|
+
step,
|
|
1103
|
+
success: false,
|
|
1104
|
+
errorMessage
|
|
1105
|
+
};
|
|
1079
1106
|
}
|
|
1080
1107
|
}
|
|
1081
1108
|
async function runGoModTidy({ projectDir }) {
|
|
1082
1109
|
const s = spinner();
|
|
1110
|
+
const step = "go mod tidy";
|
|
1083
1111
|
try {
|
|
1084
1112
|
s.start("Running go mod tidy...");
|
|
1085
1113
|
await $({
|
|
@@ -1087,14 +1115,25 @@ async function runGoModTidy({ projectDir }) {
|
|
|
1087
1115
|
stderr: "inherit"
|
|
1088
1116
|
})`go mod tidy`;
|
|
1089
1117
|
s.stop("Go dependencies installed successfully");
|
|
1118
|
+
return {
|
|
1119
|
+
step,
|
|
1120
|
+
success: true
|
|
1121
|
+
};
|
|
1090
1122
|
} catch (error) {
|
|
1091
1123
|
s.stop(pc.red("go mod tidy failed"));
|
|
1092
|
-
|
|
1124
|
+
const errorMessage = toErrorMessage(error);
|
|
1125
|
+
consola.error(pc.red(`go mod tidy error: ${errorMessage}`));
|
|
1126
|
+
return {
|
|
1127
|
+
step,
|
|
1128
|
+
success: false,
|
|
1129
|
+
errorMessage
|
|
1130
|
+
};
|
|
1093
1131
|
}
|
|
1094
1132
|
}
|
|
1095
1133
|
async function runMavenTests({ projectDir }) {
|
|
1096
1134
|
const s = spinner();
|
|
1097
1135
|
const mvnw = process.platform === "win32" ? "mvnw.cmd" : "./mvnw";
|
|
1136
|
+
const step = "Maven tests";
|
|
1098
1137
|
try {
|
|
1099
1138
|
s.start("Running Maven tests...");
|
|
1100
1139
|
await $({
|
|
@@ -1102,14 +1141,25 @@ async function runMavenTests({ projectDir }) {
|
|
|
1102
1141
|
stderr: "inherit"
|
|
1103
1142
|
})`${mvnw} test`;
|
|
1104
1143
|
s.stop("Maven tests completed");
|
|
1144
|
+
return {
|
|
1145
|
+
step,
|
|
1146
|
+
success: true
|
|
1147
|
+
};
|
|
1105
1148
|
} catch (error) {
|
|
1106
1149
|
s.stop(pc.red("Maven tests failed"));
|
|
1107
|
-
|
|
1150
|
+
const errorMessage = toErrorMessage(error);
|
|
1151
|
+
consola.error(pc.red(`Maven test error: ${errorMessage}`));
|
|
1152
|
+
return {
|
|
1153
|
+
step,
|
|
1154
|
+
success: false,
|
|
1155
|
+
errorMessage
|
|
1156
|
+
};
|
|
1108
1157
|
}
|
|
1109
1158
|
}
|
|
1110
1159
|
async function runGradleTests({ projectDir }) {
|
|
1111
1160
|
const s = spinner();
|
|
1112
1161
|
const gradlew = process.platform === "win32" ? "gradlew.bat" : "./gradlew";
|
|
1162
|
+
const step = "Gradle tests";
|
|
1113
1163
|
try {
|
|
1114
1164
|
s.start("Running Gradle tests...");
|
|
1115
1165
|
await $({
|
|
@@ -1117,13 +1167,24 @@ async function runGradleTests({ projectDir }) {
|
|
|
1117
1167
|
stderr: "inherit"
|
|
1118
1168
|
})`${gradlew} test`;
|
|
1119
1169
|
s.stop("Gradle tests completed");
|
|
1170
|
+
return {
|
|
1171
|
+
step,
|
|
1172
|
+
success: true
|
|
1173
|
+
};
|
|
1120
1174
|
} catch (error) {
|
|
1121
1175
|
s.stop(pc.red("Gradle tests failed"));
|
|
1122
|
-
|
|
1176
|
+
const errorMessage = toErrorMessage(error);
|
|
1177
|
+
consola.error(pc.red(`Gradle test error: ${errorMessage}`));
|
|
1178
|
+
return {
|
|
1179
|
+
step,
|
|
1180
|
+
success: false,
|
|
1181
|
+
errorMessage
|
|
1182
|
+
};
|
|
1123
1183
|
}
|
|
1124
1184
|
}
|
|
1125
1185
|
async function runMixCompile({ projectDir }) {
|
|
1126
1186
|
const s = spinner();
|
|
1187
|
+
const step = "mix deps.get / compile";
|
|
1127
1188
|
try {
|
|
1128
1189
|
s.start("Running mix deps.get and mix compile...");
|
|
1129
1190
|
await $({
|
|
@@ -1135,11 +1196,21 @@ async function runMixCompile({ projectDir }) {
|
|
|
1135
1196
|
stderr: "inherit"
|
|
1136
1197
|
})`mix compile`;
|
|
1137
1198
|
s.stop("Elixir dependencies installed and project compiled");
|
|
1199
|
+
return {
|
|
1200
|
+
step,
|
|
1201
|
+
success: true
|
|
1202
|
+
};
|
|
1138
1203
|
} catch (error) {
|
|
1139
1204
|
s.stop(pc.red("mix compile failed"));
|
|
1140
|
-
|
|
1205
|
+
const errorMessage = toErrorMessage(error);
|
|
1206
|
+
consola.error(pc.red(`Mix error: ${errorMessage}`));
|
|
1207
|
+
return {
|
|
1208
|
+
step,
|
|
1209
|
+
success: false,
|
|
1210
|
+
errorMessage
|
|
1211
|
+
};
|
|
1141
1212
|
}
|
|
1142
1213
|
}
|
|
1143
1214
|
|
|
1144
1215
|
//#endregion
|
|
1145
|
-
export { validateAddonsAgainstFrontends as A, validateWorkersCompatibility as B, isExampleAIAllowed$1 as C, requiresChatSdkVercelAI as D, isWebFrontend$1 as E, validateServerDeployRequiresBackend as F, incompatibilityError as H, validateUILibraryCSSFrameworkCompatibility as I, validateUILibraryFrontendCompatibility as L, validateExamplesCompatibility as M, validatePaymentsCompatibility as N, splitFrontends$1 as O, validateSelfBackendCompatibility as P, validateWebDeployFrontendTemplates as R, hasWebStyling$1 as S, isFrontendAllowedWithBackend$1 as T, missingRequirementError as U, constraintError as V,
|
|
1216
|
+
export { validateAddonsAgainstFrontends as A, validateWorkersCompatibility as B, isExampleAIAllowed$1 as C, requiresChatSdkVercelAI as D, isWebFrontend$1 as E, validateServerDeployRequiresBackend as F, incompatibilityError as H, validateUILibraryCSSFrameworkCompatibility as I, validateUILibraryFrontendCompatibility as L, validateExamplesCompatibility as M, validatePaymentsCompatibility as N, splitFrontends$1 as O, validateSelfBackendCompatibility as P, validateWebDeployFrontendTemplates as R, hasWebStyling$1 as S, isFrontendAllowedWithBackend$1 as T, missingRequirementError as U, constraintError as V, isGoBack as _, runMavenTests as a, getCompatibleCSSFrameworks$1 as b, applyDependencyVersionChannel as c, isCancel$1 as d, navigableConfirm as f, GO_BACK_SYMBOL as g, setIsFirstPrompt as h, runGradleTests as i, validateApiFrontendCompatibility as j, validateAIFrontendCompatibility as k, getAddonsChoice as l, navigableSelect as m, runCargoBuild as n, runMixCompile as o, navigableMultiselect as p, runGoModTidy as r, runUvSync as s, installDependencies as t, getAddonsToAdd as u, allowedApisForFrontends$1 as v, isExampleChatSdkAllowed$1 as w, getCompatibleUILibraries$1 as x, ensureSingleWebAndNative as y, validateWebDeployRequiresWebFrontend as z };
|