create-better-fullstack 2.1.8 → 2.3.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 (29) hide show
  1. package/README.md +4 -4
  2. package/dist/{add-handler-ztNjzoMN.mjs → add-handler-z4NCxoq6.mjs} +9 -8
  3. package/dist/addons-setup-COE1e1db.mjs +7 -0
  4. package/dist/{addons-setup-LaAj43NP.mjs → addons-setup-DKtiNexf.mjs} +1 -1
  5. package/dist/{analytics-DVltG11u.mjs → analytics-BD8hZvIj.mjs} +1 -1
  6. package/dist/{bts-config-DQVWvPDs.mjs → bts-config-Bwd6GB7B.mjs} +59 -0
  7. package/dist/cli.mjs +2 -2
  8. package/dist/command-exists-DtX9ldL8.mjs +15 -0
  9. package/dist/{config-processing-D9-F2Us9.mjs → config-processing-B-RT_mVE.mjs} +32 -3
  10. package/dist/{doctor-a4ca3SMd.mjs → doctor-LmNs-hDr.mjs} +4 -3
  11. package/dist/{file-formatter-gvmrpd-g.mjs → file-formatter-DxF56-mO.mjs} +550 -24
  12. package/dist/{gen-CCClL7Ve.mjs → gen-CQfQU0uZ.mjs} +1 -1
  13. package/dist/{generated-checks-BV9jol5h.mjs → generated-checks-BUcI5VM2.mjs} +55 -22
  14. package/dist/index.d.mts +741 -211
  15. package/dist/index.mjs +30 -9
  16. package/dist/{install-dependencies-RoUyaE8o.mjs → install-dependencies-CJiUklm3.mjs} +132 -23
  17. package/dist/{mcp-492OkjcS.mjs → mcp-BBammItk.mjs} +5 -5
  18. package/dist/mcp-entry.mjs +76 -236
  19. package/dist/{registry-DSf2CEaU.mjs → registry-D0JfLCoH.mjs} +1 -1
  20. package/dist/{run-T6g1jkfy.mjs → run-BAIeghcU.mjs} +1948 -318
  21. package/dist/run-CAl4L4uU.mjs +16 -0
  22. package/dist/scaffold-manifest-CQwvyttq.mjs +4 -0
  23. package/dist/{scaffold-manifest-Dyi0voqE.mjs → scaffold-manifest-Dr3Anmlf.mjs} +34 -5
  24. package/dist/{update-DJ8CI5KW.mjs → update-CnrBdWrh.mjs} +182 -25
  25. package/package.json +24 -7
  26. package/dist/addons-setup-DnLjAzTw.mjs +0 -7
  27. package/dist/run-CD8f7PHh.mjs +0 -15
  28. package/dist/scaffold-manifest-DGRyepdb.mjs +0 -4
  29. /package/dist/{update-deps-aD-iQw4U.mjs → update-deps-G3FgqBlW.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import "./bts-config-DQVWvPDs.mjs";
3
- import { a as createBtsCli, c as history, d as telemetry, f as update, i as create, l as router, n as builder, o as docs, r as check, s as doctor, t as add, u as sponsors } from "./run-T6g1jkfy.mjs";
2
+ import "./bts-config-Bwd6GB7B.mjs";
3
+ import { a as createBtsCli, c as history, d as telemetry, f as update, i as create, l as router, n as builder, o as docs, r as check, s as doctor, t as add, u as sponsors } from "./run-BAIeghcU.mjs";
4
4
  import "./render-title-zvyKC1ej.mjs";
5
5
  import "./errors-ns_o2OKg.mjs";
6
6
  import "./prompt-environment-BR0Kkw2W.mjs";
7
- import "./analytics-DVltG11u.mjs";
8
- import "./file-formatter-gvmrpd-g.mjs";
9
- import "./install-dependencies-RoUyaE8o.mjs";
10
- import "./generated-checks-BV9jol5h.mjs";
11
- import { t as applyEffectBackendDefaults } from "./config-processing-D9-F2Us9.mjs";
12
- import "./scaffold-manifest-Dyi0voqE.mjs";
13
- import "./addons-setup-LaAj43NP.mjs";
7
+ import "./analytics-BD8hZvIj.mjs";
8
+ import "./file-formatter-DxF56-mO.mjs";
9
+ import "./install-dependencies-CJiUklm3.mjs";
10
+ import "./command-exists-DtX9ldL8.mjs";
11
+ import { t as applyEffectBackendDefaults } from "./config-processing-B-RT_mVE.mjs";
12
+ import "./generated-checks-BUcI5VM2.mjs";
13
+ import "./scaffold-manifest-Dr3Anmlf.mjs";
14
+ import "./addons-setup-DKtiNexf.mjs";
14
15
  import { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, generateVirtualProject } from "@better-fullstack/template-generator";
15
16
 
16
17
  //#region src/index.ts
@@ -98,6 +99,7 @@ async function createVirtual(options) {
98
99
  mobilePush: options.mobilePush || "none",
99
100
  mobileOTA: options.mobileOTA || "none",
100
101
  mobileDeepLinking: options.mobileDeepLinking || (hasNativeFrontend ? "expo-linking" : "none"),
102
+ mobileLibraries: options.mobileLibraries || [],
101
103
  cms: options.cms || "none",
102
104
  caching: options.caching || "none",
103
105
  rateLimit: options.rateLimit || "none",
@@ -133,6 +135,13 @@ async function createVirtual(options) {
133
135
  pythonRealtime: options.pythonRealtime || "none",
134
136
  pythonObservability: options.pythonObservability || "none",
135
137
  pythonCli: options.pythonCli || [],
138
+ pythonCloudSdk: options.pythonCloudSdk || "none",
139
+ pythonHttpClient: options.pythonHttpClient || "none",
140
+ pythonData: options.pythonData || [],
141
+ pythonMedia: options.pythonMedia || "none",
142
+ pythonServer: options.pythonServer || "none",
143
+ pythonPackageManager: options.pythonPackageManager || "uv",
144
+ pythonMessageQueue: options.pythonMessageQueue || "none",
136
145
  goWebFramework: options.goWebFramework || "none",
137
146
  goOrm: options.goOrm || "none",
138
147
  goApi: options.goApi || "none",
@@ -145,6 +154,12 @@ async function createVirtual(options) {
145
154
  goCaching: options.goCaching || "none",
146
155
  goConfig: options.goConfig || "none",
147
156
  goObservability: options.goObservability || "none",
157
+ goValidation: options.goValidation || "none",
158
+ goQuality: options.goQuality || "none",
159
+ goMigrations: options.goMigrations || "none",
160
+ goTemplating: options.goTemplating || "none",
161
+ goProtoTooling: options.goProtoTooling || "none",
162
+ goDI: options.goDI || "none",
148
163
  javaWebFramework: options.javaWebFramework || (options.ecosystem === "java" ? "spring-boot" : "none"),
149
164
  javaLanguage: options.javaLanguage || "java",
150
165
  javaBuildTool: options.javaBuildTool || (options.ecosystem === "java" ? "maven" : "none"),
@@ -165,6 +180,7 @@ async function createVirtual(options) {
165
180
  dotnetValidation: options.dotnetValidation || "none",
166
181
  dotnetCaching: options.dotnetCaching || "none",
167
182
  dotnetDeploy: options.dotnetDeploy || (options.ecosystem === "dotnet" ? "docker" : "none"),
183
+ dotnetLibraries: options.dotnetLibraries || [],
168
184
  elixirWebFramework: options.elixirWebFramework || (options.ecosystem === "elixir" ? "phoenix" : "none"),
169
185
  elixirOrm: options.elixirOrm || (options.ecosystem === "elixir" ? "ecto-sql" : "none"),
170
186
  elixirAuth: options.elixirAuth || "none",
@@ -179,6 +195,11 @@ async function createVirtual(options) {
179
195
  elixirObservability: options.elixirObservability || (options.ecosystem === "elixir" ? "telemetry" : "none"),
180
196
  elixirTesting: options.elixirTesting || (options.ecosystem === "elixir" ? "ex_unit" : "none"),
181
197
  elixirQuality: options.elixirQuality || (options.ecosystem === "elixir" ? "credo" : "none"),
198
+ elixirI18n: options.elixirI18n || "none",
199
+ elixirHttpServer: options.elixirHttpServer || (options.ecosystem === "elixir" ? "cowboy" : "none"),
200
+ elixirApplicationFramework: options.elixirApplicationFramework || "none",
201
+ elixirDocumentation: options.elixirDocumentation || "none",
202
+ elixirClustering: options.elixirClustering || "none",
182
203
  elixirDeploy: options.elixirDeploy || "none",
183
204
  elixirLibraries: options.elixirLibraries || [],
184
205
  aiDocs: options.aiDocs || ["claude-md", "agents-md"]
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { b as types_exports, g as DEFAULT_CONFIG } from "./bts-config-DQVWvPDs.mjs";
2
+ import { b as types_exports, g as DEFAULT_CONFIG } from "./bts-config-Bwd6GB7B.mjs";
3
3
  import { d as setLastPromptShownUI, r as exitCancelled, s as isFirstPrompt, u as setIsFirstPrompt$1 } from "./errors-ns_o2OKg.mjs";
4
- import { g as validateAddonCompatibility, o as getCompatibleAddons } from "./file-formatter-gvmrpd-g.mjs";
4
+ import { S as validateAddonCompatibility, f as getCompatibleAddons } from "./file-formatter-DxF56-mO.mjs";
5
+ import { t as commandExists } from "./command-exists-DtX9ldL8.mjs";
5
6
  import { log, spinner } from "@clack/prompts";
6
7
  import pc from "picocolors";
7
8
  import fs from "fs-extra";
@@ -360,6 +361,42 @@ function getAddonDisplay(addon) {
360
361
  label = "GitHub Actions";
361
362
  hint = "Ship a CI workflow (install, lint, type-check, build)";
362
363
  break;
364
+ case "eslint":
365
+ label = "ESLint";
366
+ hint = "Pluggable JavaScript and TypeScript linting with flat config";
367
+ break;
368
+ case "prettier":
369
+ label = "Prettier";
370
+ hint = "Opinionated formatting for code, JSON, Markdown, and styles";
371
+ break;
372
+ case "axios":
373
+ label = "Axios";
374
+ hint = "HTTP client with interceptors, cancellation, and typed responses";
375
+ break;
376
+ case "firebase":
377
+ label = "Firebase JS SDK";
378
+ hint = "Firebase app, Auth, Firestore, and Storage client setup";
379
+ break;
380
+ case "graphql-codegen":
381
+ label = "GraphQL Code Generator";
382
+ hint = "Generate typed GraphQL documents and client helpers";
383
+ break;
384
+ case "openapi-typescript":
385
+ label = "openapi-typescript";
386
+ hint = "Generate runtime-free TypeScript types from OpenAPI schemas";
387
+ break;
388
+ case "apollo-client":
389
+ label = "Apollo Client";
390
+ hint = "GraphQL client with normalized caching and framework integrations";
391
+ break;
392
+ case "electron":
393
+ label = "Electron";
394
+ hint = "Package compatible Vite frontends as desktop applications";
395
+ break;
396
+ case "capacitor":
397
+ label = "Capacitor";
398
+ hint = "Ship compatible Vite frontends to iOS and Android";
399
+ break;
363
400
  default:
364
401
  label = addon;
365
402
  hint = `Add ${addon}`;
@@ -375,6 +412,8 @@ const ADDON_GROUPS = {
375
412
  "nx",
376
413
  "github-actions",
377
414
  "biome",
415
+ "eslint",
416
+ "prettier",
378
417
  "oxlint",
379
418
  "ultracite",
380
419
  "husky",
@@ -382,10 +421,6 @@ const ADDON_GROUPS = {
382
421
  ],
383
422
  Documentation: ["starlight", "fumadocs"],
384
423
  Extensions: [
385
- "pwa",
386
- "tauri",
387
- "opentui",
388
- "wxt",
389
424
  "ruler",
390
425
  "devcontainer",
391
426
  "docker-compose"
@@ -393,10 +428,14 @@ const ADDON_GROUPS = {
393
428
  Integrations: [
394
429
  "msw",
395
430
  "storybook",
396
- "backend-utils"
431
+ "backend-utils",
432
+ "axios",
433
+ "firebase"
397
434
  ],
435
+ "API Tooling": ["graphql-codegen", "openapi-typescript"],
398
436
  "AI Agents": ["mcp", "skills"],
399
- "Data Fetching": ["swr"],
437
+ "App Platforms": [...types_exports.APP_PLATFORM_ADDON_VALUES],
438
+ "Data Fetching": ["swr", "apollo-client"],
400
439
  TanStack: [
401
440
  "tanstack-query",
402
441
  "tanstack-table",
@@ -411,19 +450,49 @@ function createGroupedAddonOptions() {
411
450
  function getAddonGroup(addon) {
412
451
  return Object.entries(ADDON_GROUPS).find(([, addons]) => addons.includes(addon))?.[0];
413
452
  }
414
- function validateAddonCompatibilityForPrompt(addon, frontends, auth, backend, runtime) {
415
- return validateAddonCompatibility(addon, frontends, auth, backend, runtime);
453
+ function validateAddonCompatibilityForPrompt(addon, frontends, auth, backend, runtime, api) {
454
+ return validateAddonCompatibility(addon, frontends, auth, backend, runtime, void 0, void 0, void 0, void 0, api);
455
+ }
456
+ function getCompatibleAddonsForPrompt(allAddons, frontends, existingAddons = [], auth, backend, runtime, api) {
457
+ return getCompatibleAddons(allAddons, frontends, existingAddons, auth, backend, runtime, api);
416
458
  }
417
- function getCompatibleAddonsForPrompt(allAddons, frontends, existingAddons = [], auth, backend, runtime) {
418
- return getCompatibleAddons(allAddons, frontends, existingAddons, auth, backend, runtime);
459
+ const APP_PLATFORM_ADDONS = new Set(types_exports.APP_PLATFORM_ADDON_VALUES);
460
+ /**
461
+ * Dedicated multiselect for app platforms (Electron, Tauri, Capacitor, PWA,
462
+ * WXT, OpenTUI). Selections merge into `config.addons`; when `--addons` is
463
+ * passed the flag already carries any platforms, so this returns [] to avoid
464
+ * double-collecting.
465
+ */
466
+ async function getAppPlatformsChoice(addons, frontends) {
467
+ if (addons !== void 0) return [];
468
+ const options = [];
469
+ for (const platform of types_exports.APP_PLATFORM_ADDON_VALUES) {
470
+ const { isCompatible } = validateAddonCompatibilityForPrompt(platform, frontends || []);
471
+ if (!isCompatible) continue;
472
+ const { label, hint } = getAddonDisplay(platform);
473
+ options.push({
474
+ value: platform,
475
+ label,
476
+ hint
477
+ });
478
+ }
479
+ if (options.length === 0) return [];
480
+ const response = await navigableMultiselect({
481
+ message: "Select app platforms (desktop, mobile, extension)",
482
+ options,
483
+ initialValues: [],
484
+ required: false
485
+ });
486
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
487
+ return response;
419
488
  }
420
- async function getAddonsChoice(addons, frontends, auth, backend, runtime) {
489
+ async function getAddonsChoice(addons, frontends, auth, backend, runtime, api) {
421
490
  if (addons !== void 0) return addons;
422
- const allAddons = types_exports.AddonsSchema.options.filter((addon) => addon !== "none");
491
+ const allAddons = types_exports.AddonsSchema.options.filter((addon) => addon !== "none" && !APP_PLATFORM_ADDONS.has(addon));
423
492
  const groupedOptions = createGroupedAddonOptions();
424
493
  const frontendsArray = frontends || [];
425
494
  for (const addon of allAddons) {
426
- const { isCompatible } = validateAddonCompatibilityForPrompt(addon, frontendsArray, auth, backend, runtime);
495
+ const { isCompatible } = validateAddonCompatibilityForPrompt(addon, frontendsArray, auth, backend, runtime, api);
427
496
  if (!isCompatible) continue;
428
497
  const { label, hint } = getAddonDisplay(addon);
429
498
  const option = {
@@ -452,10 +521,10 @@ async function getAddonsChoice(addons, frontends, auth, backend, runtime) {
452
521
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
453
522
  return response;
454
523
  }
455
- async function getAddonsToAdd(frontend, existingAddons = [], auth, backend, runtime) {
524
+ async function getAddonsToAdd(frontend, existingAddons = [], auth, backend, runtime, api) {
456
525
  const groupedOptions = createGroupedAddonOptions();
457
526
  const frontendArray = frontend || [];
458
- const compatibleAddons = getCompatibleAddonsForPrompt(types_exports.AddonsSchema.options.filter((addon) => addon !== "none"), frontendArray, existingAddons, auth, backend, runtime);
527
+ const compatibleAddons = getCompatibleAddonsForPrompt(types_exports.AddonsSchema.options.filter((addon) => addon !== "none"), frontendArray, existingAddons, auth, backend, runtime, api);
459
528
  for (const addon of compatibleAddons) {
460
529
  const { label, hint } = getAddonDisplay(addon);
461
530
  const option = {
@@ -775,22 +844,62 @@ async function runCargoBuild({ projectDir }) {
775
844
  }
776
845
  async function runUvSync({ projectDir }) {
777
846
  const s = spinner();
778
- const step = "uv sync (Python dependencies)";
847
+ const step = "uv sync --extra dev (Python dependencies)";
779
848
  try {
780
- s.start("Running uv sync...");
849
+ s.start("Running uv sync --extra dev...");
781
850
  await $({
782
851
  cwd: projectDir,
783
852
  stderr: "inherit"
784
- })`uv sync`;
853
+ })`uv sync --extra dev`;
854
+ s.stop("Python dependencies installed successfully");
855
+ return {
856
+ step,
857
+ success: true
858
+ };
859
+ } catch (error) {
860
+ s.stop(pc.red("uv sync --extra dev failed"));
861
+ const errorMessage = toErrorMessage(error);
862
+ consola.error(pc.red(`uv sync --extra dev error: ${errorMessage}`));
863
+ return {
864
+ step,
865
+ success: false,
866
+ errorMessage
867
+ };
868
+ }
869
+ }
870
+ async function runPythonInstall({ projectDir, packageManager }) {
871
+ if (packageManager === "uv") return runUvSync({ projectDir });
872
+ const s = spinner();
873
+ const step = `${packageManager} install (Python dependencies)`;
874
+ try {
875
+ if (packageManager === "poetry") {
876
+ s.start("Running poetry install...");
877
+ await $({
878
+ cwd: projectDir,
879
+ stderr: "inherit"
880
+ })`poetry install --extras dev`;
881
+ } else {
882
+ s.start("Creating a virtual environment and installing with pip...");
883
+ const python = await commandExists("python") ? "python" : "python3";
884
+ await $({
885
+ cwd: projectDir,
886
+ stderr: "inherit"
887
+ })`${python} -m venv .venv`;
888
+ const pip = process.platform === "win32" ? ".venv/Scripts/pip.exe" : ".venv/bin/pip";
889
+ await $({
890
+ cwd: projectDir,
891
+ stderr: "inherit"
892
+ })`${pip} install -e .[dev]`;
893
+ }
785
894
  s.stop("Python dependencies installed successfully");
786
895
  return {
787
896
  step,
788
897
  success: true
789
898
  };
790
899
  } catch (error) {
791
- s.stop(pc.red("uv sync failed"));
900
+ s.stop(pc.red("Python dependency installation failed"));
792
901
  const errorMessage = toErrorMessage(error);
793
- consola.error(pc.red(`uv sync error: ${errorMessage}`));
902
+ consola.error(pc.red(`Python installation error: ${errorMessage}`));
794
903
  return {
795
904
  step,
796
905
  success: false,
@@ -906,4 +1015,4 @@ async function runMixCompile({ projectDir }) {
906
1015
  }
907
1016
 
908
1017
  //#endregion
909
- export { isGoBack as _, runMavenTests as a, applyDependencyVersionChannel as c, isCancel$1 as d, navigableConfirm as f, GO_BACK_SYMBOL as g, setIsFirstPrompt as h, runGradleTests as i, 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 };
1018
+ export { GO_BACK_SYMBOL as _, runMavenTests as a, applyDependencyVersionChannel as c, getAppPlatformsChoice as d, isCancel$1 as f, setIsFirstPrompt as g, navigableSelect as h, runGradleTests as i, getAddonsChoice as l, navigableMultiselect as m, runCargoBuild as n, runMixCompile as o, navigableConfirm as p, runGoModTidy as r, runPythonInstall as s, installDependencies as t, getAddonsToAdd as u, isGoBack as v };
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import "./bts-config-DQVWvPDs.mjs";
2
+ import "./bts-config-Bwd6GB7B.mjs";
3
3
  import "./errors-ns_o2OKg.mjs";
4
4
  import "./prompt-environment-BR0Kkw2W.mjs";
5
- import "./analytics-DVltG11u.mjs";
6
- import "./file-formatter-gvmrpd-g.mjs";
7
- import "./config-processing-D9-F2Us9.mjs";
8
- import "./scaffold-manifest-Dyi0voqE.mjs";
5
+ import "./analytics-BD8hZvIj.mjs";
6
+ import "./file-formatter-DxF56-mO.mjs";
7
+ import "./config-processing-B-RT_mVE.mjs";
8
+ import "./scaffold-manifest-Dr3Anmlf.mjs";
9
9
  import { a as startMcpServer, i as recommendStackFromBrief, n as MCP_STACK_UPDATE_SCHEMA, r as getMcpGraphPreview, t as MCP_PLAN_CREATE_SCHEMA } from "./mcp-entry.mjs";
10
10
 
11
11
  export { recommendStackFromBrief, startMcpServer };