create-better-fullstack 2.0.0 → 2.0.2
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-BPAZM8Zo.mjs +149 -0
- package/dist/addons-setup-CV5uZyhH.mjs +5 -0
- package/dist/{addons-setup-DHoByttt.mjs → addons-setup-HSghQS7c.mjs} +29 -33
- package/dist/bts-config-Bg1Qea9Y.mjs +737 -0
- package/dist/cli.mjs +2 -2
- package/dist/index.d.mts +404 -96
- package/dist/index.mjs +38 -11545
- package/dist/install-dependencies-D6-GO3BZ.mjs +1139 -0
- package/dist/mcp-58r70ZcL.mjs +5 -0
- package/dist/mcp-entry.mjs +377 -543
- package/dist/run-DQlymC4z.mjs +11546 -0
- package/dist/run-QRBymn-p.mjs +7 -0
- package/dist/update-deps-CLebIM70.mjs +189 -0
- package/package.json +7 -10
- package/dist/addons-setup-Ca069cmy.mjs +0 -5
- package/dist/bts-config-BMniWIbd.mjs +0 -497
- package/dist/mcp-YvDMaVXB.mjs +0 -5
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { g as getDefaultConfig, n as readBtsConfig, r as updateBtsConfig } from "./bts-config-Bg1Qea9Y.mjs";
|
|
3
|
+
import { W as renderTitle, c as applyDependencyVersionChannel, t as installDependencies, u as getAddonsToAdd } from "./install-dependencies-D6-GO3BZ.mjs";
|
|
4
|
+
import { a as CLIError, f as isSilent, o as UserCancelledError, p as runWithContextAsync, t as setupAddons } from "./addons-setup-HSghQS7c.mjs";
|
|
5
|
+
import { intro, log, outro } from "@clack/prompts";
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
import fs from "fs-extra";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { EMBEDDED_TEMPLATES, VirtualFileSystem, processAddonTemplates, processAddonsDeps } from "@better-fullstack/template-generator";
|
|
10
|
+
import { writeTreeToFilesystem } from "@better-fullstack/template-generator/fs-writer";
|
|
11
|
+
|
|
12
|
+
//#region src/helpers/core/add-handler.ts
|
|
13
|
+
async function addHandler(input, options = {}) {
|
|
14
|
+
const { silent = false } = options;
|
|
15
|
+
return runWithContextAsync({ silent }, async () => {
|
|
16
|
+
try {
|
|
17
|
+
return await addHandlerInternal(input);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error instanceof UserCancelledError) {
|
|
20
|
+
if (isSilent()) return {
|
|
21
|
+
success: false,
|
|
22
|
+
addedAddons: [],
|
|
23
|
+
projectDir: "",
|
|
24
|
+
error: error.message
|
|
25
|
+
};
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (error instanceof CLIError) {
|
|
29
|
+
if (isSilent()) return {
|
|
30
|
+
success: false,
|
|
31
|
+
addedAddons: [],
|
|
32
|
+
projectDir: "",
|
|
33
|
+
error: error.message
|
|
34
|
+
};
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
if (isSilent()) return {
|
|
38
|
+
success: false,
|
|
39
|
+
addedAddons: [],
|
|
40
|
+
projectDir: "",
|
|
41
|
+
error: error instanceof Error ? error.message : String(error)
|
|
42
|
+
};
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async function addHandlerInternal(input) {
|
|
48
|
+
const projectDir = path.resolve(input.projectDir || process.cwd());
|
|
49
|
+
if (!isSilent()) {
|
|
50
|
+
renderTitle();
|
|
51
|
+
intro(pc.magenta("Add addons to your Better Fullstack project"));
|
|
52
|
+
}
|
|
53
|
+
const btsConfig = await readBtsConfig(projectDir);
|
|
54
|
+
if (!btsConfig) throw new CLIError(`No Better Fullstack project found in ${projectDir}. Make sure bts.jsonc exists.`);
|
|
55
|
+
const projectName = path.basename(projectDir);
|
|
56
|
+
if (!isSilent()) log.info(pc.dim(`Detected project: ${projectName}`));
|
|
57
|
+
const existingAddons = btsConfig.addons || [];
|
|
58
|
+
let addonsToAdd = [];
|
|
59
|
+
if (input.addons && input.addons.length > 0) addonsToAdd = input.addons.filter((addon) => addon !== "none" && !existingAddons.includes(addon));
|
|
60
|
+
else addonsToAdd = (await getAddonsToAdd(btsConfig.frontend || [], existingAddons, btsConfig.auth)).filter((addon) => addon !== "none");
|
|
61
|
+
if (addonsToAdd.length === 0) {
|
|
62
|
+
if (!isSilent()) {
|
|
63
|
+
log.info(pc.dim("No new addons selected."));
|
|
64
|
+
outro(pc.magenta("Nothing to add."));
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
success: true,
|
|
68
|
+
addedAddons: [],
|
|
69
|
+
projectDir
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (!isSilent()) log.info(pc.cyan(`Adding addons: ${addonsToAdd.join(", ")}`));
|
|
73
|
+
const baseConfig = getDefaultConfig();
|
|
74
|
+
const config = {
|
|
75
|
+
...baseConfig,
|
|
76
|
+
...btsConfig,
|
|
77
|
+
projectName,
|
|
78
|
+
projectDir,
|
|
79
|
+
relativePath: ".",
|
|
80
|
+
packageManager: input.packageManager || btsConfig.packageManager || baseConfig.packageManager,
|
|
81
|
+
addons: addonsToAdd,
|
|
82
|
+
frontend: btsConfig.frontend || baseConfig.frontend,
|
|
83
|
+
examples: btsConfig.examples || [],
|
|
84
|
+
rustLibraries: btsConfig.rustLibraries || [],
|
|
85
|
+
pythonAi: btsConfig.pythonAi || [],
|
|
86
|
+
aiDocs: btsConfig.aiDocs || []
|
|
87
|
+
};
|
|
88
|
+
const vfs = new VirtualFileSystem();
|
|
89
|
+
const packageJsonPaths = await collectPackageJsonPaths(projectDir);
|
|
90
|
+
for (const pkgPath of packageJsonPaths) {
|
|
91
|
+
const fullPath = path.join(projectDir, pkgPath);
|
|
92
|
+
const content = await fs.readFile(fullPath, "utf-8");
|
|
93
|
+
vfs.writeFile(pkgPath, content);
|
|
94
|
+
}
|
|
95
|
+
await processAddonTemplates(vfs, EMBEDDED_TEMPLATES, config);
|
|
96
|
+
processAddonsDeps(vfs, config);
|
|
97
|
+
await writeTreeToFilesystem({
|
|
98
|
+
root: vfs.toTree(projectName),
|
|
99
|
+
fileCount: vfs.getFileCount(),
|
|
100
|
+
directoryCount: vfs.getDirectoryCount(),
|
|
101
|
+
config
|
|
102
|
+
}, projectDir);
|
|
103
|
+
const setupWarnings = await setupAddons(config);
|
|
104
|
+
await applyDependencyVersionChannel(projectDir, config.versionChannel);
|
|
105
|
+
const configUpdates = { addons: [...new Set([...existingAddons, ...addonsToAdd])] };
|
|
106
|
+
if (input.webDeploy !== void 0) configUpdates.webDeploy = input.webDeploy;
|
|
107
|
+
if (input.serverDeploy !== void 0) configUpdates.serverDeploy = input.serverDeploy;
|
|
108
|
+
await updateBtsConfig(projectDir, configUpdates);
|
|
109
|
+
if (input.install) await installDependencies({
|
|
110
|
+
projectDir,
|
|
111
|
+
packageManager: config.packageManager
|
|
112
|
+
});
|
|
113
|
+
if (!isSilent()) {
|
|
114
|
+
log.success(pc.green(`Successfully added: ${addonsToAdd.join(", ")}`));
|
|
115
|
+
for (const warning of setupWarnings) log.warn(pc.yellow(warning));
|
|
116
|
+
if (!input.install) {
|
|
117
|
+
const installCmd = config.packageManager === "npm" ? "npm install" : `${config.packageManager} install`;
|
|
118
|
+
log.info(pc.yellow(`Run '${installCmd}' to install new dependencies.`));
|
|
119
|
+
}
|
|
120
|
+
outro(pc.magenta("Addons added successfully!"));
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
addedAddons: addonsToAdd,
|
|
125
|
+
projectDir,
|
|
126
|
+
setupWarnings: setupWarnings.length > 0 ? setupWarnings : void 0
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function collectPackageJsonPaths(projectDir) {
|
|
130
|
+
const results = [];
|
|
131
|
+
async function walk(currentDir) {
|
|
132
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".turbo") continue;
|
|
135
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
136
|
+
if (entry.isDirectory()) {
|
|
137
|
+
await walk(fullPath);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (entry.isFile() && entry.name === "package.json") results.push(path.relative(projectDir, fullPath).replaceAll(path.sep, "/"));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await walk(projectDir);
|
|
144
|
+
if (!results.includes("package.json") && await fs.pathExists(path.join(projectDir, "package.json"))) results.push("package.json");
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
//#endregion
|
|
149
|
+
export { addHandler };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { n as readBtsConfig } from "./bts-config-Bg1Qea9Y.mjs";
|
|
3
3
|
import { autocompleteMultiselect, cancel, group, isCancel, log, multiselect, select, spinner } from "@clack/prompts";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import fs from "fs-extra";
|
|
@@ -16,8 +16,7 @@ function defaultContext() {
|
|
|
16
16
|
isFirstPrompt: false,
|
|
17
17
|
lastPromptShownUI: false
|
|
18
18
|
},
|
|
19
|
-
silent: false
|
|
20
|
-
verbose: false
|
|
19
|
+
silent: false
|
|
21
20
|
};
|
|
22
21
|
}
|
|
23
22
|
function getContext() {
|
|
@@ -51,11 +50,7 @@ async function runWithContextAsync(options, fn) {
|
|
|
51
50
|
isFirstPrompt: false,
|
|
52
51
|
lastPromptShownUI: false
|
|
53
52
|
},
|
|
54
|
-
silent: options.silent ?? false
|
|
55
|
-
verbose: options.verbose ?? false,
|
|
56
|
-
projectDir: options.projectDir,
|
|
57
|
-
projectName: options.projectName,
|
|
58
|
-
packageManager: options.packageManager
|
|
53
|
+
silent: options.silent ?? false
|
|
59
54
|
};
|
|
60
55
|
return cliStorage.run(ctx, fn);
|
|
61
56
|
}
|
|
@@ -91,10 +86,33 @@ function handleError(error, fallbackMessage) {
|
|
|
91
86
|
process.exit(1);
|
|
92
87
|
}
|
|
93
88
|
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/utils/prompt-environment.ts
|
|
91
|
+
function hasOwnProperty(value, property) {
|
|
92
|
+
return Object.prototype.hasOwnProperty.call(value, property);
|
|
93
|
+
}
|
|
94
|
+
function resolveCiValue(environment) {
|
|
95
|
+
if (environment && hasOwnProperty(environment, "ci")) return environment.ci;
|
|
96
|
+
return process.env.CI;
|
|
97
|
+
}
|
|
98
|
+
function isCiEnvironment(value) {
|
|
99
|
+
if (!value) return false;
|
|
100
|
+
const normalizedValue = value.trim().toLowerCase();
|
|
101
|
+
return normalizedValue !== "" && normalizedValue !== "0" && normalizedValue !== "false";
|
|
102
|
+
}
|
|
103
|
+
function canPromptInteractively(environment = {}) {
|
|
104
|
+
const silent = environment.silent ?? isSilent();
|
|
105
|
+
const stdinIsTTY = environment.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
106
|
+
const stdoutIsTTY = environment.stdoutIsTTY ?? process.stdout.isTTY === true;
|
|
107
|
+
const ci = resolveCiValue(environment);
|
|
108
|
+
return !silent && stdinIsTTY && stdoutIsTTY && !isCiEnvironment(ci);
|
|
109
|
+
}
|
|
110
|
+
|
|
94
111
|
//#endregion
|
|
95
112
|
//#region src/utils/add-package-deps.ts
|
|
96
113
|
const addPackageDependency = async (opts) => {
|
|
97
114
|
const { dependencies = [], devDependencies = [], customDependencies = {}, customDevDependencies = {}, projectDir } = opts;
|
|
115
|
+
const { dependencyVersionMap } = await import("@better-fullstack/template-generator");
|
|
98
116
|
const pkgJsonPath = path.join(projectDir, "package.json");
|
|
99
117
|
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
100
118
|
if (!pkgJson.dependencies) pkgJson.dependencies = {};
|
|
@@ -178,28 +196,6 @@ function getPackageRunnerPrefix(packageManager) {
|
|
|
178
196
|
}
|
|
179
197
|
}
|
|
180
198
|
|
|
181
|
-
//#endregion
|
|
182
|
-
//#region src/utils/prompt-environment.ts
|
|
183
|
-
function hasOwnProperty(value, property) {
|
|
184
|
-
return Object.prototype.hasOwnProperty.call(value, property);
|
|
185
|
-
}
|
|
186
|
-
function resolveCiValue(environment) {
|
|
187
|
-
if (environment && hasOwnProperty(environment, "ci")) return environment.ci;
|
|
188
|
-
return process.env.CI;
|
|
189
|
-
}
|
|
190
|
-
function isCiEnvironment(value) {
|
|
191
|
-
if (!value) return false;
|
|
192
|
-
const normalizedValue = value.trim().toLowerCase();
|
|
193
|
-
return normalizedValue !== "" && normalizedValue !== "0" && normalizedValue !== "false";
|
|
194
|
-
}
|
|
195
|
-
function canPromptInteractively(environment = {}) {
|
|
196
|
-
const silent = environment.silent ?? isSilent();
|
|
197
|
-
const stdinIsTTY = environment.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
198
|
-
const stdoutIsTTY = environment.stdoutIsTTY ?? process.stdout.isTTY === true;
|
|
199
|
-
const ci = resolveCiValue(environment);
|
|
200
|
-
return !silent && stdinIsTTY && stdoutIsTTY && !isCiEnvironment(ci);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
199
|
//#endregion
|
|
204
200
|
//#region src/helpers/addons/interactive-selection.ts
|
|
205
201
|
function shouldPromptForAddonSelection(environment = {}) {
|
|
@@ -456,7 +452,7 @@ function getRecommendedMcpServers(config) {
|
|
|
456
452
|
name: "supabase",
|
|
457
453
|
target: "https://mcp.supabase.com/mcp"
|
|
458
454
|
});
|
|
459
|
-
if (config.auth === "better-auth") servers.push({
|
|
455
|
+
if (config.auth === "better-auth" || config.auth === "better-auth-organizations") servers.push({
|
|
460
456
|
key: "better-auth",
|
|
461
457
|
label: "Better Auth",
|
|
462
458
|
name: "better-auth",
|
|
@@ -851,7 +847,7 @@ function getRecommendedSourceKeys(config) {
|
|
|
851
847
|
if (frontend.includes("nuxt")) sources.push("nuxt/ui");
|
|
852
848
|
if (frontend.includes("native-uniwind")) sources.push("heroui-inc/heroui");
|
|
853
849
|
if (hasNativeFrontend(frontend)) sources.push("expo/skills");
|
|
854
|
-
if (auth === "better-auth") sources.push("better-auth/skills");
|
|
850
|
+
if (auth === "better-auth" || auth === "better-auth-organizations") sources.push("better-auth/skills");
|
|
855
851
|
if (dbSetup === "neon") sources.push("neondatabase/agent-skills");
|
|
856
852
|
if (dbSetup === "supabase") sources.push("supabase/agent-skills");
|
|
857
853
|
if (dbSetup === "planetscale") sources.push("planetscale/database-skills");
|
|
@@ -1416,4 +1412,4 @@ async function setupLefthook(projectDir) {
|
|
|
1416
1412
|
}
|
|
1417
1413
|
|
|
1418
1414
|
//#endregion
|
|
1419
|
-
export {
|
|
1415
|
+
export { CLIError as a, exitWithError as c, isFirstPrompt as d, isSilent as f, setLastPromptShownUI as h, canPromptInteractively as i, handleError as l, setIsFirstPrompt as m, getPackageExecutionArgs as n, UserCancelledError as o, runWithContextAsync as p, addPackageDependency as r, exitCancelled as s, setupAddons as t, didLastPromptShowUI as u };
|