create-better-fullstack 2.0.2 → 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.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import "./bts-config-InNcw1aJ.mjs";
3
+ import { a as docs, c as sponsors, i as createBtsCli, l as telemetry, n as builder, o as history, r as create, s as router, t as add } from "./run-Cqy-n1iT.mjs";
4
+ import "./render-title-zvyKC1ej.mjs";
5
+ import "./errors-ns_o2OKg.mjs";
6
+ import "./addons-setup-uSvqHagW.mjs";
7
+ import "./install-dependencies-CDjTNvIV.mjs";
8
+ import "./generated-checks-CUhFFfVo.mjs";
9
+
10
+ export { createBtsCli };
@@ -0,0 +1,489 @@
1
+ #!/usr/bin/env node
2
+ import { v as hasGraphPart, y as types_exports } from "./bts-config-InNcw1aJ.mjs";
3
+
4
+ //#region src/utils/generate-reproducible-command.ts
5
+ function getBaseCommand(packageManager) {
6
+ switch (packageManager) {
7
+ case "bun": return "bun create better-fullstack@latest";
8
+ case "pnpm": return "pnpm create better-fullstack@latest";
9
+ case "yarn": return "yarn create better-fullstack@latest";
10
+ case "npm":
11
+ default: return "npx create-better-fullstack@latest";
12
+ }
13
+ }
14
+ function formatArrayFlag(flag, values) {
15
+ const normalizedValues = values.filter((value) => value !== "none");
16
+ if (normalizedValues.length === 0) return `--${flag} none`;
17
+ return `--${flag} ${normalizedValues.join(" ")}`;
18
+ }
19
+ function appendCommonFlags(flags, config) {
20
+ if (config.aiDocs && config.aiDocs.length > 0) flags.push(formatArrayFlag("ai-docs", config.aiDocs));
21
+ else flags.push("--ai-docs none");
22
+ flags.push(config.git ? "--git" : "--no-git");
23
+ flags.push(`--package-manager ${config.packageManager}`);
24
+ if (config.versionChannel !== "stable") flags.push(`--version-channel ${config.versionChannel}`);
25
+ flags.push(config.install ? "--install" : "--no-install");
26
+ }
27
+ function hasGraphPrimaryPart(config, role, ecosystem) {
28
+ return config.stackParts?.some((part) => part.source !== "provided" && part.role === role && !part.ownerPartId && (!ecosystem || part.ecosystem === ecosystem));
29
+ }
30
+ function hasOwnedGraphPart(config, ownerRole, role, ecosystem, toolId) {
31
+ const owner = config.stackParts?.find((part) => part.source !== "provided" && part.role === ownerRole && !part.ownerPartId && (!ecosystem || part.ecosystem === ecosystem));
32
+ if (!owner) return false;
33
+ return Boolean(config.stackParts?.some((part) => part.source !== "provided" && part.role === role && part.ownerPartId === owner.id && (!ecosystem || part.ecosystem === ecosystem) && (!toolId || part.toolId === toolId)));
34
+ }
35
+ function hasGraphAddonPart(config, addon) {
36
+ const binding = (0, types_exports.getAddonStackPartBinding)(addon);
37
+ if (!binding) return false;
38
+ if (!binding.ownerRole) return Boolean(config.stackParts?.some((part) => part.source !== "provided" && part.role === binding.role && part.ecosystem === binding.ecosystem && part.toolId === addon && !part.ownerPartId));
39
+ const owner = config.stackParts?.find((part) => part.source !== "provided" && part.role === binding.ownerRole && !part.ownerPartId && part.ecosystem === binding.ecosystem);
40
+ if (!owner) return false;
41
+ return Boolean(config.stackParts?.some((part) => part.source !== "provided" && part.role === binding.role && part.ecosystem === binding.ecosystem && part.toolId === addon && part.ownerPartId === owner.id));
42
+ }
43
+ function hasGraphExamplePart(config, example) {
44
+ return Boolean(config.stackParts?.some((part) => part.source !== "provided" && part.role === "examples" && part.ecosystem === "universal" && part.toolId === example && !part.ownerPartId));
45
+ }
46
+ function hasGraphArrayParts(config, values, hasPart) {
47
+ const normalizedValues = values.filter((value) => value !== "none");
48
+ return normalizedValues.length > 0 && normalizedValues.every((value) => hasPart(config, value));
49
+ }
50
+ function appendChangedStringFlag(flags, flag, value, defaultValue) {
51
+ if (value !== defaultValue) flags.push(`--${flag} ${value}`);
52
+ }
53
+ function appendChangedGraphStringFlag(flags, config, role, ecosystem, flag, value, defaultValue) {
54
+ if (hasGraphPart(config, role, ecosystem)) return;
55
+ appendChangedStringFlag(flags, flag, value, defaultValue);
56
+ }
57
+ function appendChangedOwnedGraphStringFlag(flags, config, ownerRole, role, ecosystem, flag, value, defaultValue) {
58
+ if (hasOwnedGraphPart(config, ownerRole, role, ecosystem, value)) return;
59
+ appendChangedStringFlag(flags, flag, value, defaultValue);
60
+ }
61
+ function hasOwnedGraphArrayParts(config, ownerRole, role, ecosystem, values) {
62
+ const normalizedValues = values.filter((value) => value !== "none");
63
+ if (normalizedValues.length === 0) return false;
64
+ return normalizedValues.every((value) => hasOwnedGraphPart(config, ownerRole, role, ecosystem, value));
65
+ }
66
+ function appendChangedOwnedGraphArrayFlag(flags, config, ownerRole, role, ecosystem, flag, values, defaultValues) {
67
+ if (hasOwnedGraphArrayParts(config, ownerRole, role, ecosystem, values)) return;
68
+ appendChangedArrayFlag(flags, flag, values, defaultValues);
69
+ }
70
+ function appendChangedArrayFlag(flags, flag, values, defaultValues) {
71
+ if (values.length !== defaultValues.length || values.some((value, index) => value !== defaultValues[index])) flags.push(formatArrayFlag(flag, values));
72
+ }
73
+ function appendAstroIntegrationFlag(flags, config) {
74
+ if (config.frontend.includes("astro") && config.astroIntegration !== "none") flags.push(`--astro-integration ${config.astroIntegration}`);
75
+ }
76
+ function appendGraphExtraFlags(flags, config) {
77
+ if (!hasGraphArrayParts(config, config.addons, hasGraphAddonPart)) appendChangedArrayFlag(flags, "addons", config.addons, ["turborepo"]);
78
+ if (!hasGraphArrayParts(config, config.examples, hasGraphExamplePart)) appendChangedArrayFlag(flags, "examples", config.examples, []);
79
+ if (hasGraphPrimaryPart(config, "database")) appendChangedOwnedGraphStringFlag(flags, config, "database", "dbSetup", "universal", "db-setup", config.dbSetup, "none");
80
+ else appendChangedStringFlag(flags, "db-setup", config.dbSetup, "none");
81
+ if (hasGraphPrimaryPart(config, "frontend", "typescript")) {
82
+ appendAstroIntegrationFlag(flags, config);
83
+ appendChangedOwnedGraphStringFlag(flags, config, "frontend", "deploy", "typescript", "web-deploy", config.webDeploy, "none");
84
+ appendChangedGraphStringFlag(flags, config, "css", "typescript", "css-framework", config.cssFramework, "tailwind");
85
+ appendChangedGraphStringFlag(flags, config, "ui", "typescript", "ui-library", config.uiLibrary, "shadcn-ui");
86
+ if (config.uiLibrary === "shadcn-ui") {
87
+ appendChangedStringFlag(flags, "shadcn-base", config.shadcnBase ?? "radix", "radix");
88
+ appendChangedStringFlag(flags, "shadcn-style", config.shadcnStyle ?? "nova", "nova");
89
+ appendChangedStringFlag(flags, "shadcn-icon-library", config.shadcnIconLibrary ?? "lucide", "lucide");
90
+ appendChangedStringFlag(flags, "shadcn-color-theme", config.shadcnColorTheme ?? "neutral", "neutral");
91
+ appendChangedStringFlag(flags, "shadcn-base-color", config.shadcnBaseColor ?? "neutral", "neutral");
92
+ appendChangedStringFlag(flags, "shadcn-font", config.shadcnFont ?? "inter", "inter");
93
+ appendChangedStringFlag(flags, "shadcn-radius", config.shadcnRadius ?? "default", "default");
94
+ }
95
+ appendChangedGraphStringFlag(flags, config, "stateManagement", "typescript", "state-management", config.stateManagement, "none");
96
+ appendChangedGraphStringFlag(flags, config, "forms", "typescript", "forms", config.forms, "react-hook-form");
97
+ appendChangedStringFlag(flags, "validation", config.validation, "zod");
98
+ appendChangedStringFlag(flags, "testing", config.testing, "vitest");
99
+ appendChangedGraphStringFlag(flags, config, "animation", "typescript", "animation", config.animation, "none");
100
+ appendChangedGraphStringFlag(flags, config, "fileUpload", "typescript", "file-upload", config.fileUpload, "none");
101
+ appendChangedGraphStringFlag(flags, config, "i18n", "typescript", "i18n", config.i18n, "none");
102
+ appendChangedGraphStringFlag(flags, config, "analytics", "typescript", "analytics", config.analytics, "none");
103
+ }
104
+ if (hasGraphPrimaryPart(config, "frontend", "typescript") || hasGraphPrimaryPart(config, "backend", "typescript")) {
105
+ if (hasGraphPrimaryPart(config, "backend", "typescript")) {
106
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "runtime", "typescript", "runtime", config.runtime, "bun");
107
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "deploy", "typescript", "server-deploy", config.serverDeploy, "none");
108
+ } else appendChangedStringFlag(flags, "server-deploy", config.serverDeploy, "none");
109
+ appendChangedGraphStringFlag(flags, config, "payments", "typescript", "payments", config.payments, "none");
110
+ appendChangedGraphStringFlag(flags, config, "email", "typescript", "email", config.email, "none");
111
+ appendChangedStringFlag(flags, "effect", config.effect, "none");
112
+ appendChangedGraphStringFlag(flags, config, "ai", "typescript", "ai", config.ai, "none");
113
+ appendChangedGraphStringFlag(flags, config, "realtime", "typescript", "realtime", config.realtime, "none");
114
+ appendChangedGraphStringFlag(flags, config, "jobQueue", "typescript", "job-queue", config.jobQueue, "none");
115
+ appendChangedGraphStringFlag(flags, config, "logging", "typescript", "logging", config.logging, "none");
116
+ appendChangedGraphStringFlag(flags, config, "observability", "typescript", "observability", config.observability, "none");
117
+ appendChangedGraphStringFlag(flags, config, "featureFlags", "typescript", "feature-flags", config.featureFlags, "none");
118
+ appendChangedGraphStringFlag(flags, config, "caching", "typescript", "caching", config.caching, "none");
119
+ appendChangedGraphStringFlag(flags, config, "rateLimit", "typescript", "rate-limit", config.rateLimit, "none");
120
+ appendChangedGraphStringFlag(flags, config, "cms", "typescript", "cms", config.cms, "none");
121
+ appendChangedGraphStringFlag(flags, config, "search", "typescript", "search", config.search, "none");
122
+ appendChangedGraphStringFlag(flags, config, "vectorDb", "typescript", "vectorDb", config.vectorDb, "none");
123
+ appendChangedGraphStringFlag(flags, config, "fileStorage", "typescript", "file-storage", config.fileStorage, "none");
124
+ }
125
+ if (hasGraphPrimaryPart(config, "mobile")) {
126
+ appendChangedOwnedGraphStringFlag(flags, config, "mobile", "navigation", "react-native", "mobile-navigation", config.mobileNavigation, "expo-router");
127
+ appendChangedOwnedGraphStringFlag(flags, config, "mobile", "ui", "react-native", "mobile-ui", config.mobileUI, "none");
128
+ appendChangedOwnedGraphStringFlag(flags, config, "mobile", "storage", "react-native", "mobile-storage", config.mobileStorage, "none");
129
+ appendChangedOwnedGraphStringFlag(flags, config, "mobile", "testing", "react-native", "mobile-testing", config.mobileTesting, "none");
130
+ appendChangedStringFlag(flags, "mobile-push", config.mobilePush, "none");
131
+ appendChangedStringFlag(flags, "mobile-ota", config.mobileOTA, "none");
132
+ appendChangedStringFlag(flags, "mobile-deep-linking", config.mobileDeepLinking, "none");
133
+ }
134
+ if (hasGraphPrimaryPart(config, "frontend", "rust")) appendChangedStringFlag(flags, "rust-frontend", config.rustFrontend, "none");
135
+ if (hasGraphPrimaryPart(config, "backend", "rust")) {
136
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "cli", "rust", "rust-cli", config.rustCli, "none");
137
+ appendChangedOwnedGraphArrayFlag(flags, config, "backend", "libraries", "rust", "rust-libraries", config.rustLibraries, []);
138
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "logging", "rust", "rust-logging", config.rustLogging, "tracing");
139
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "errorHandling", "rust", "rust-error-handling", config.rustErrorHandling, "anyhow-thiserror");
140
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "caching", "rust", "rust-caching", config.rustCaching, "none");
141
+ }
142
+ if (hasGraphPrimaryPart(config, "backend", "python")) {
143
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "validation", "python", "python-validation", config.pythonValidation, "none");
144
+ appendChangedOwnedGraphArrayFlag(flags, config, "backend", "ai", "python", "python-ai", config.pythonAi, []);
145
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "jobQueue", "python", "python-task-queue", config.pythonTaskQueue, "none");
146
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "api", "python", "python-graphql", config.pythonGraphql, "none");
147
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "codeQuality", "python", "python-quality", config.pythonQuality, "none");
148
+ }
149
+ if (hasGraphPrimaryPart(config, "backend", "go")) {
150
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "cli", "go", "go-cli", config.goCli, "none");
151
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "logging", "go", "go-logging", config.goLogging, "none");
152
+ }
153
+ if (hasGraphPrimaryPart(config, "backend", "java")) {
154
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "buildTool", "java", "java-build-tool", config.javaBuildTool, "maven");
155
+ appendChangedOwnedGraphArrayFlag(flags, config, "backend", "libraries", "java", "java-libraries", config.javaLibraries, []);
156
+ appendChangedOwnedGraphArrayFlag(flags, config, "backend", "testing", "java", "java-testing-libraries", config.javaTestingLibraries, ["junit5"]);
157
+ }
158
+ if (hasGraphPrimaryPart(config, "backend", "elixir")) {
159
+ appendChangedGraphStringFlag(flags, config, "realtime", "elixir", "elixir-realtime", config.elixirRealtime, "channels");
160
+ appendChangedGraphStringFlag(flags, config, "jobQueue", "elixir", "elixir-jobs", config.elixirJobs, "none");
161
+ appendChangedGraphStringFlag(flags, config, "validation", "elixir", "elixir-validation", config.elixirValidation, "ecto-changesets");
162
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "httpClient", "elixir", "elixir-http", config.elixirHttp, "req");
163
+ appendChangedStringFlag(flags, "elixir-json", config.elixirJson, "jason");
164
+ appendChangedGraphStringFlag(flags, config, "email", "elixir", "elixir-email", config.elixirEmail, "none");
165
+ appendChangedGraphStringFlag(flags, config, "caching", "elixir", "elixir-caching", config.elixirCaching, "none");
166
+ appendChangedGraphStringFlag(flags, config, "observability", "elixir", "elixir-observability", config.elixirObservability, "telemetry");
167
+ appendChangedGraphStringFlag(flags, config, "testing", "elixir", "elixir-testing", config.elixirTesting, "ex_unit");
168
+ appendChangedOwnedGraphStringFlag(flags, config, "backend", "codeQuality", "elixir", "elixir-quality", config.elixirQuality, "credo");
169
+ appendChangedGraphStringFlag(flags, config, "deploy", "elixir", "elixir-deploy", config.elixirDeploy, "none");
170
+ }
171
+ }
172
+ function appendSharedNonTypeScriptFlags(flags, config) {
173
+ flags.push(`--email ${config.email}`);
174
+ flags.push(`--observability ${config.observability}`);
175
+ flags.push(`--caching ${config.caching}`);
176
+ flags.push(`--search ${config.search}`);
177
+ flags.push(formatArrayFlag("addons", config.addons));
178
+ flags.push(formatArrayFlag("examples", config.examples));
179
+ flags.push(`--db-setup ${config.dbSetup}`);
180
+ flags.push(`--web-deploy ${config.webDeploy}`);
181
+ flags.push(`--server-deploy ${config.serverDeploy}`);
182
+ }
183
+ function getTypeScriptFlags(config) {
184
+ const flags = [];
185
+ if (config.frontend && config.frontend.length > 0) flags.push(`--frontend ${config.frontend.join(" ")}`);
186
+ else flags.push("--frontend none");
187
+ appendAstroIntegrationFlag(flags, config);
188
+ flags.push(`--backend ${config.backend}`);
189
+ flags.push(`--runtime ${config.runtime}`);
190
+ flags.push(`--database ${config.database}`);
191
+ flags.push(`--orm ${config.orm}`);
192
+ flags.push(`--api ${config.api}`);
193
+ flags.push(`--auth ${config.auth}`);
194
+ flags.push(`--payments ${config.payments}`);
195
+ flags.push(`--email ${config.email}`);
196
+ flags.push(`--file-upload ${config.fileUpload}`);
197
+ flags.push(`--effect ${config.effect}`);
198
+ flags.push(`--css-framework ${config.cssFramework}`);
199
+ flags.push(`--ui-library ${config.uiLibrary}`);
200
+ if (config.uiLibrary === "shadcn-ui") {
201
+ flags.push(`--shadcn-base ${config.shadcnBase}`);
202
+ flags.push(`--shadcn-style ${config.shadcnStyle}`);
203
+ flags.push(`--shadcn-icon-library ${config.shadcnIconLibrary}`);
204
+ flags.push(`--shadcn-color-theme ${config.shadcnColorTheme}`);
205
+ flags.push(`--shadcn-base-color ${config.shadcnBaseColor}`);
206
+ flags.push(`--shadcn-font ${config.shadcnFont}`);
207
+ flags.push(`--shadcn-radius ${config.shadcnRadius}`);
208
+ }
209
+ flags.push(`--ai ${config.ai}`);
210
+ flags.push(`--state-management ${config.stateManagement}`);
211
+ flags.push(`--forms ${config.forms}`);
212
+ flags.push(`--validation ${config.validation}`);
213
+ flags.push(`--testing ${config.testing}`);
214
+ flags.push(`--animation ${config.animation}`);
215
+ flags.push(`--realtime ${config.realtime}`);
216
+ flags.push(`--job-queue ${config.jobQueue}`);
217
+ flags.push(`--logging ${config.logging}`);
218
+ flags.push(`--observability ${config.observability}`);
219
+ flags.push(`--feature-flags ${config.featureFlags}`);
220
+ flags.push(`--caching ${config.caching}`);
221
+ flags.push(`--rate-limit ${config.rateLimit}`);
222
+ flags.push(`--i18n ${config.i18n}`);
223
+ flags.push(`--cms ${config.cms}`);
224
+ flags.push(`--search ${config.search}`);
225
+ flags.push(`--vector-db ${config.vectorDb}`);
226
+ flags.push(`--file-storage ${config.fileStorage}`);
227
+ flags.push(`--mobile-navigation ${config.mobileNavigation}`);
228
+ flags.push(`--mobile-ui ${config.mobileUI}`);
229
+ flags.push(`--mobile-storage ${config.mobileStorage}`);
230
+ flags.push(`--mobile-testing ${config.mobileTesting}`);
231
+ flags.push(`--mobile-push ${config.mobilePush}`);
232
+ flags.push(`--mobile-ota ${config.mobileOTA}`);
233
+ flags.push(`--mobile-deep-linking ${config.mobileDeepLinking}`);
234
+ if (config.addons && config.addons.length > 0) flags.push(`--addons ${config.addons.join(" ")}`);
235
+ else flags.push("--addons none");
236
+ if (config.examples && config.examples.length > 0) flags.push(`--examples ${config.examples.join(" ")}`);
237
+ else flags.push("--examples none");
238
+ flags.push(`--db-setup ${config.dbSetup}`);
239
+ flags.push(`--web-deploy ${config.webDeploy}`);
240
+ flags.push(`--server-deploy ${config.serverDeploy}`);
241
+ appendCommonFlags(flags, config);
242
+ return flags;
243
+ }
244
+ function getReactNativeFlags(config) {
245
+ const flags = ["--ecosystem react-native"];
246
+ if (config.frontend && config.frontend.length > 0) flags.push(`--frontend ${config.frontend.join(" ")}`);
247
+ else flags.push("--frontend native-bare");
248
+ flags.push(`--auth ${config.auth}`);
249
+ flags.push(`--mobile-navigation ${config.mobileNavigation}`);
250
+ flags.push(`--mobile-ui ${config.mobileUI}`);
251
+ flags.push(`--mobile-storage ${config.mobileStorage}`);
252
+ flags.push(`--mobile-testing ${config.mobileTesting}`);
253
+ flags.push(`--mobile-push ${config.mobilePush}`);
254
+ flags.push(`--mobile-ota ${config.mobileOTA}`);
255
+ flags.push(`--mobile-deep-linking ${config.mobileDeepLinking}`);
256
+ appendCommonFlags(flags, config);
257
+ return flags;
258
+ }
259
+ function getRustFlags(config) {
260
+ const flags = ["--ecosystem rust"];
261
+ flags.push(`--rust-web-framework ${config.rustWebFramework}`);
262
+ flags.push(`--rust-frontend ${config.rustFrontend}`);
263
+ flags.push(`--rust-orm ${config.rustOrm}`);
264
+ flags.push(`--rust-api ${config.rustApi}`);
265
+ flags.push(`--rust-cli ${config.rustCli}`);
266
+ flags.push(formatArrayFlag("rust-libraries", config.rustLibraries));
267
+ flags.push(`--rust-logging ${config.rustLogging}`);
268
+ flags.push(`--rust-error-handling ${config.rustErrorHandling}`);
269
+ flags.push(`--rust-caching ${config.rustCaching}`);
270
+ flags.push(`--rust-auth ${config.rustAuth}`);
271
+ flags.push(`--rust-realtime ${config.rustRealtime}`);
272
+ flags.push(`--rust-message-queue ${config.rustMessageQueue}`);
273
+ flags.push(`--rust-observability ${config.rustObservability}`);
274
+ flags.push(`--rust-templating ${config.rustTemplating}`);
275
+ appendSharedNonTypeScriptFlags(flags, config);
276
+ appendCommonFlags(flags, config);
277
+ return flags;
278
+ }
279
+ function getPythonFlags(config) {
280
+ const flags = ["--ecosystem python"];
281
+ flags.push(`--python-web-framework ${config.pythonWebFramework}`);
282
+ flags.push(`--python-orm ${config.pythonOrm}`);
283
+ flags.push(`--python-validation ${config.pythonValidation}`);
284
+ flags.push(formatArrayFlag("python-ai", config.pythonAi));
285
+ flags.push(`--python-auth ${config.pythonAuth}`);
286
+ flags.push(`--python-api ${config.pythonApi}`);
287
+ flags.push(`--python-task-queue ${config.pythonTaskQueue}`);
288
+ flags.push(`--python-graphql ${config.pythonGraphql}`);
289
+ flags.push(`--python-quality ${config.pythonQuality}`);
290
+ flags.push(formatArrayFlag("python-testing", config.pythonTesting));
291
+ flags.push(`--python-caching ${config.pythonCaching}`);
292
+ flags.push(`--python-realtime ${config.pythonRealtime}`);
293
+ flags.push(`--python-observability ${config.pythonObservability}`);
294
+ flags.push(formatArrayFlag("python-cli", config.pythonCli));
295
+ appendSharedNonTypeScriptFlags(flags, config);
296
+ appendCommonFlags(flags, config);
297
+ return flags;
298
+ }
299
+ function getGoFlags(config) {
300
+ const flags = ["--ecosystem go"];
301
+ flags.push(`--go-web-framework ${config.goWebFramework}`);
302
+ flags.push(`--go-orm ${config.goOrm}`);
303
+ flags.push(`--go-api ${config.goApi}`);
304
+ flags.push(`--go-cli ${config.goCli}`);
305
+ flags.push(`--go-logging ${config.goLogging}`);
306
+ flags.push(`--go-auth ${config.goAuth}`);
307
+ flags.push(formatArrayFlag("go-testing", config.goTesting));
308
+ flags.push(`--go-realtime ${config.goRealtime}`);
309
+ flags.push(`--go-message-queue ${config.goMessageQueue}`);
310
+ flags.push(`--go-caching ${config.goCaching}`);
311
+ flags.push(`--go-config ${config.goConfig}`);
312
+ flags.push(`--go-observability ${config.goObservability}`);
313
+ flags.push(`--auth ${config.auth}`);
314
+ appendSharedNonTypeScriptFlags(flags, config);
315
+ appendCommonFlags(flags, config);
316
+ return flags;
317
+ }
318
+ function getJavaFlags(config) {
319
+ const flags = ["--ecosystem java"];
320
+ flags.push(`--java-web-framework ${config.javaWebFramework}`);
321
+ flags.push(`--java-build-tool ${config.javaBuildTool}`);
322
+ flags.push(`--java-orm ${config.javaOrm}`);
323
+ flags.push(`--java-auth ${config.javaAuth}`);
324
+ flags.push(`--java-api ${config.javaApi}`);
325
+ flags.push(`--java-logging ${config.javaLogging}`);
326
+ flags.push(formatArrayFlag("java-libraries", config.javaLibraries));
327
+ flags.push(formatArrayFlag("java-testing-libraries", config.javaTestingLibraries));
328
+ appendSharedNonTypeScriptFlags(flags, config);
329
+ appendCommonFlags(flags, config);
330
+ return flags;
331
+ }
332
+ function getDotnetFlags(config) {
333
+ const flags = ["--ecosystem dotnet"];
334
+ flags.push(`--dotnet-web-framework ${config.dotnetWebFramework}`);
335
+ flags.push(`--dotnet-orm ${config.dotnetOrm}`);
336
+ flags.push(`--dotnet-auth ${config.dotnetAuth}`);
337
+ flags.push(`--dotnet-api ${config.dotnetApi}`);
338
+ flags.push(formatArrayFlag("dotnet-testing", config.dotnetTesting));
339
+ flags.push(`--dotnet-job-queue ${config.dotnetJobQueue}`);
340
+ flags.push(`--dotnet-realtime ${config.dotnetRealtime}`);
341
+ flags.push(formatArrayFlag("dotnet-observability", config.dotnetObservability));
342
+ flags.push(`--dotnet-validation ${config.dotnetValidation}`);
343
+ flags.push(`--dotnet-caching ${config.dotnetCaching}`);
344
+ flags.push(`--dotnet-deploy ${config.dotnetDeploy}`);
345
+ appendCommonFlags(flags, config);
346
+ return flags;
347
+ }
348
+ function getElixirFlags(config) {
349
+ const flags = ["--ecosystem elixir"];
350
+ flags.push(`--elixir-web-framework ${config.elixirWebFramework}`);
351
+ flags.push(`--elixir-orm ${config.elixirOrm}`);
352
+ flags.push(`--elixir-auth ${config.elixirAuth}`);
353
+ flags.push(`--elixir-api ${config.elixirApi}`);
354
+ flags.push(`--elixir-realtime ${config.elixirRealtime}`);
355
+ flags.push(`--elixir-jobs ${config.elixirJobs}`);
356
+ flags.push(`--elixir-validation ${config.elixirValidation}`);
357
+ flags.push(`--elixir-http ${config.elixirHttp}`);
358
+ flags.push(`--elixir-json ${config.elixirJson}`);
359
+ flags.push(`--elixir-email ${config.elixirEmail}`);
360
+ flags.push(`--elixir-caching ${config.elixirCaching}`);
361
+ flags.push(`--elixir-observability ${config.elixirObservability}`);
362
+ flags.push(`--elixir-testing ${config.elixirTesting}`);
363
+ flags.push(`--elixir-quality ${config.elixirQuality}`);
364
+ flags.push(`--elixir-deploy ${config.elixirDeploy}`);
365
+ flags.push(formatArrayFlag("elixir-libraries", config.elixirLibraries));
366
+ appendCommonFlags(flags, config);
367
+ return flags;
368
+ }
369
+ function generateReproducibleCommand(config) {
370
+ let flags;
371
+ if (config.stackParts && config.stackParts.length > 0) {
372
+ flags = config.stackParts.filter((part) => part.source !== "provided").map((part) => `--part ${(0, types_exports.formatStackPartSpec)(part, config.stackParts ?? [])}`);
373
+ appendGraphExtraFlags(flags, config);
374
+ appendCommonFlags(flags, config);
375
+ return `${getBaseCommand(config.packageManager)}${config.relativePath ? ` ${config.relativePath}` : ""} ${flags.join(" ")}`;
376
+ }
377
+ switch (config.ecosystem) {
378
+ case "react-native":
379
+ flags = getReactNativeFlags(config);
380
+ break;
381
+ case "rust":
382
+ flags = getRustFlags(config);
383
+ break;
384
+ case "python":
385
+ flags = getPythonFlags(config);
386
+ break;
387
+ case "go":
388
+ flags = getGoFlags(config);
389
+ break;
390
+ case "java":
391
+ flags = getJavaFlags(config);
392
+ break;
393
+ case "dotnet":
394
+ flags = getDotnetFlags(config);
395
+ break;
396
+ case "elixir":
397
+ flags = getElixirFlags(config);
398
+ break;
399
+ case "typescript":
400
+ default:
401
+ flags = getTypeScriptFlags(config);
402
+ break;
403
+ }
404
+ return `${getBaseCommand(config.packageManager)}${config.relativePath ? ` ${config.relativePath}` : ""} ${flags.join(" ")}`;
405
+ }
406
+
407
+ //#endregion
408
+ //#region src/utils/templates.ts
409
+ const TEMPLATE_PRESETS = {
410
+ mern: {
411
+ database: "mongodb",
412
+ orm: "mongoose",
413
+ backend: "express",
414
+ runtime: "node",
415
+ frontend: ["react-router"],
416
+ api: "orpc",
417
+ auth: "better-auth",
418
+ payments: "none",
419
+ addons: ["turborepo"],
420
+ examples: ["none"],
421
+ dbSetup: "mongodb-atlas",
422
+ webDeploy: "none",
423
+ serverDeploy: "none"
424
+ },
425
+ pern: {
426
+ database: "postgres",
427
+ orm: "drizzle",
428
+ backend: "express",
429
+ runtime: "node",
430
+ frontend: ["tanstack-router"],
431
+ api: "trpc",
432
+ auth: "better-auth",
433
+ payments: "none",
434
+ addons: ["turborepo"],
435
+ examples: ["none"],
436
+ dbSetup: "none",
437
+ webDeploy: "none",
438
+ serverDeploy: "none"
439
+ },
440
+ t3: {
441
+ database: "postgres",
442
+ orm: "prisma",
443
+ backend: "self",
444
+ runtime: "none",
445
+ frontend: ["next"],
446
+ api: "trpc",
447
+ auth: "better-auth",
448
+ payments: "none",
449
+ addons: ["biome", "turborepo"],
450
+ examples: ["none"],
451
+ dbSetup: "none",
452
+ webDeploy: "none",
453
+ serverDeploy: "none"
454
+ },
455
+ uniwind: {
456
+ database: "none",
457
+ orm: "none",
458
+ backend: "none",
459
+ runtime: "none",
460
+ frontend: ["native-uniwind"],
461
+ api: "none",
462
+ auth: "none",
463
+ payments: "none",
464
+ addons: ["none"],
465
+ examples: ["none"],
466
+ dbSetup: "none",
467
+ webDeploy: "none",
468
+ serverDeploy: "none"
469
+ },
470
+ none: null
471
+ };
472
+ function getTemplateConfig(template) {
473
+ if (template === "none" || !template) return null;
474
+ const config = TEMPLATE_PRESETS[template];
475
+ if (!config) throw new Error(`Unknown template: ${template}`);
476
+ return config;
477
+ }
478
+ function getTemplateDescription(template) {
479
+ return {
480
+ mern: "MongoDB + Express + React + Node.js - Classic MERN stack",
481
+ pern: "PostgreSQL + Express + React + Node.js - Popular PERN stack",
482
+ t3: "T3 Stack - Next.js + tRPC + Prisma + PostgreSQL + Better Auth",
483
+ uniwind: "Expo + Uniwind native app with no backend services",
484
+ none: "No template - Full customization"
485
+ }[template] || "";
486
+ }
487
+
488
+ //#endregion
489
+ export { getTemplateDescription as n, generateReproducibleCommand as r, getTemplateConfig as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "2.0.2",
3
+ "version": "2.1.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",
@@ -39,6 +39,7 @@
39
39
  "next-intl",
40
40
  "nextjs",
41
41
  "nuxt",
42
+ "paraglide",
42
43
  "payments",
43
44
  "pnpm",
44
45
  "pothos",
@@ -127,11 +128,11 @@
127
128
  "prepublishOnly": "npm run build"
128
129
  },
129
130
  "dependencies": {
130
- "@better-fullstack/template-generator": "^2.0.2",
131
- "@better-fullstack/types": "^2.0.2",
131
+ "@better-fullstack/template-generator": "^2.1.0",
132
+ "@better-fullstack/types": "^2.1.0",
132
133
  "@clack/core": "^0.5.0",
133
- "@clack/prompts": "^1.5.1",
134
- "@orpc/server": "^1.14.5",
134
+ "@clack/prompts": "^1.6.0",
135
+ "@orpc/server": "^1.14.6",
135
136
  "consola": "^3.4.2",
136
137
  "env-paths": "^4.0.0",
137
138
  "execa": "^9.6.1",
@@ -148,7 +149,7 @@
148
149
  "@types/bun": "^1.3.14",
149
150
  "ts-morph": "^27.0.2",
150
151
  "@types/fs-extra": "^11.0.4",
151
- "@types/node": "^25.9.2",
152
+ "@types/node": "^25.9.3",
152
153
  "publint": "^0.3.21",
153
154
  "tsdown": "^0.18.2",
154
155
  "typescript": "^5.9.3"
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./bts-config-Bg1Qea9Y.mjs";
3
- import { t as setupAddons } from "./addons-setup-HSghQS7c.mjs";
4
-
5
- export { setupAddons };
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./bts-config-Bg1Qea9Y.mjs";
3
- import { a as docs, c as sponsors, i as createBtsCli, n as builder, o as history, r as create, s as router, t as add } from "./run-DQlymC4z.mjs";
4
- import "./install-dependencies-D6-GO3BZ.mjs";
5
- import "./addons-setup-HSghQS7c.mjs";
6
-
7
- export { createBtsCli };