create-better-fullstack 2.1.5 → 2.1.7

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/dist/{add-handler-BNSL6HdM.mjs → add-handler-ztNjzoMN.mjs} +52 -6
  2. package/dist/addons-setup-DnLjAzTw.mjs +7 -0
  3. package/dist/{addons-setup-CyrP1IV-.mjs → addons-setup-LaAj43NP.mjs} +10 -24
  4. package/dist/analytics-DVltG11u.mjs +170 -0
  5. package/dist/{errors-Cyol8zbN.mjs → bts-config-DQVWvPDs.mjs} +72 -149
  6. package/dist/cli.mjs +2 -2
  7. package/dist/{templates-CnTOtKjm.mjs → config-processing-D9-F2Us9.mjs} +57 -2
  8. package/dist/{doctor-DBoq7bZ9.mjs → doctor-a4ca3SMd.mjs} +3 -2
  9. package/dist/errors-ns_o2OKg.mjs +86 -0
  10. package/dist/{file-formatter-B3dsev2l.mjs → file-formatter-gvmrpd-g.mjs} +78 -6
  11. package/dist/gen-CCClL7Ve.mjs +274 -0
  12. package/dist/{generated-checks-C8hn9w2i.mjs → generated-checks-BV9jol5h.mjs} +1 -1
  13. package/dist/index.d.mts +162 -64
  14. package/dist/index.mjs +17 -8
  15. package/dist/{install-dependencies-CgNh-aOy.mjs → install-dependencies-RoUyaE8o.mjs} +80 -21
  16. package/dist/mcp-492OkjcS.mjs +11 -0
  17. package/dist/mcp-entry.mjs +205 -30
  18. package/dist/prompt-environment-BR0Kkw2W.mjs +26 -0
  19. package/dist/registry-DSf2CEaU.mjs +408 -0
  20. package/dist/{run-BYse4yJy.mjs → run-D9I7NdES.mjs} +2081 -464
  21. package/dist/run-buK4aZS8.mjs +15 -0
  22. package/dist/scaffold-manifest-DGRyepdb.mjs +4 -0
  23. package/dist/scaffold-manifest-Dyi0voqE.mjs +135 -0
  24. package/dist/update-DJ8CI5KW.mjs +401 -0
  25. package/package.json +3 -3
  26. package/dist/addons-setup-DyMm42a5.mjs +0 -5
  27. package/dist/mcp-CsW3i66c.mjs +0 -6
  28. package/dist/run-_cf_sFwM.mjs +0 -10
  29. /package/dist/{update-deps-D5OG0KmJ.mjs → update-deps-aD-iQw4U.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import "./errors-Cyol8zbN.mjs";
3
- import { a as createBtsCli, c as history, d as telemetry, 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-BYse4yJy.mjs";
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-D9I7NdES.mjs";
4
4
  import "./render-title-zvyKC1ej.mjs";
5
- import "./addons-setup-CyrP1IV-.mjs";
6
- import "./file-formatter-B3dsev2l.mjs";
7
- import "./install-dependencies-CgNh-aOy.mjs";
8
- import "./generated-checks-C8hn9w2i.mjs";
5
+ import "./errors-ns_o2OKg.mjs";
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";
9
14
  import { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, generateVirtualProject } from "@better-fullstack/template-generator";
10
15
 
11
16
  //#region src/index.ts
@@ -36,6 +41,7 @@ async function createVirtual(options) {
36
41
  const ecosystem = options.ecosystem || "typescript";
37
42
  const isReactNative = ecosystem === "react-native";
38
43
  const frontend = options.frontend || (isReactNative ? ["native-bare"] : ["tanstack-router"]);
44
+ const backend = options.backend || (isReactNative ? "none" : "hono");
39
45
  const hasNativeFrontend = frontend.some((item) => item === "native-bare" || item === "native-uniwind" || item === "native-unistyles");
40
46
  const config = {
41
47
  ecosystem,
@@ -44,7 +50,7 @@ async function createVirtual(options) {
44
50
  relativePath: "./virtual",
45
51
  database: options.database || "none",
46
52
  orm: options.orm || "none",
47
- backend: options.backend || (isReactNative ? "none" : "hono"),
53
+ backend,
48
54
  runtime: options.runtime || (isReactNative ? "none" : "bun"),
49
55
  frontend,
50
56
  addons: options.addons || [],
@@ -56,6 +62,7 @@ async function createVirtual(options) {
56
62
  effect: options.effect || "none",
57
63
  git: options.git ?? false,
58
64
  packageManager: options.packageManager || "bun",
65
+ workspaceShape: options.workspaceShape || "monorepo",
59
66
  versionChannel: options.versionChannel || "stable",
60
67
  install: false,
61
68
  dbSetup: options.dbSetup || "none",
@@ -139,6 +146,7 @@ async function createVirtual(options) {
139
146
  goConfig: options.goConfig || "none",
140
147
  goObservability: options.goObservability || "none",
141
148
  javaWebFramework: options.javaWebFramework || (options.ecosystem === "java" ? "spring-boot" : "none"),
149
+ javaLanguage: options.javaLanguage || "java",
142
150
  javaBuildTool: options.javaBuildTool || (options.ecosystem === "java" ? "maven" : "none"),
143
151
  javaOrm: options.javaOrm || "none",
144
152
  javaAuth: options.javaAuth || "none",
@@ -176,6 +184,7 @@ async function createVirtual(options) {
176
184
  aiDocs: options.aiDocs || ["claude-md", "agents-md"]
177
185
  };
178
186
  if (options.stackParts) config.stackParts = options.stackParts;
187
+ applyEffectBackendDefaults(config, new Set(Object.keys(options)));
179
188
  const { generateVirtualProject: generate, EMBEDDED_TEMPLATES: EMBEDDED_TEMPLATES$2 } = await import("@better-fullstack/template-generator");
180
189
  const result = await generate({
181
190
  config,
@@ -198,4 +207,4 @@ async function createVirtual(options) {
198
207
  }
199
208
 
200
209
  //#endregion
201
- export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, check, create, createBtsCli, createVirtual, docs, doctor, generateVirtualProject, history, router, sponsors, telemetry };
210
+ export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, check, create, createBtsCli, createVirtual, docs, doctor, generateVirtualProject, history, router, sponsors, telemetry, update };
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { A as types_exports, d as setLastPromptShownUI, r as exitCancelled, s as isFirstPrompt, u as setIsFirstPrompt$1, y as DEFAULT_CONFIG } from "./errors-Cyol8zbN.mjs";
3
- import { g as validateAddonCompatibility, o as getCompatibleAddons } from "./file-formatter-B3dsev2l.mjs";
2
+ import { b as types_exports, g as DEFAULT_CONFIG } from "./bts-config-DQVWvPDs.mjs";
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
5
  import { log, spinner } from "@clack/prompts";
5
6
  import pc from "picocolors";
6
7
  import fs from "fs-extra";
@@ -496,6 +497,16 @@ const PRERELEASE_TAG_PRIORITY = [
496
497
  ];
497
498
  const REGISTRY_FETCH_TIMEOUT_MS = 1e4;
498
499
  const REGISTRY_CONCURRENCY = 10;
500
+ const SYNCHRONIZED_VERSION_FAMILIES = [{
501
+ name: "oRPC",
502
+ packages: [
503
+ "@orpc/server",
504
+ "@orpc/client",
505
+ "@orpc/openapi",
506
+ "@orpc/zod",
507
+ "@orpc/tanstack-query"
508
+ ]
509
+ }];
499
510
  function mapWithConcurrency(items, fn, concurrency) {
500
511
  const results = Array.from({ length: items.length });
501
512
  let index = 0;
@@ -507,6 +518,19 @@ function mapWithConcurrency(items, fn, concurrency) {
507
518
  }
508
519
  return Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker())).then(() => results);
509
520
  }
521
+ function getVersionSections(packageJson) {
522
+ const sections = [];
523
+ for (const sectionName of ["dependencies", "devDependencies"]) {
524
+ const section = packageJson[sectionName];
525
+ if (section && typeof section === "object" && !Array.isArray(section)) sections.push(section);
526
+ }
527
+ const workspaces = packageJson.workspaces;
528
+ if (workspaces && typeof workspaces === "object" && !Array.isArray(workspaces)) {
529
+ const catalog = workspaces.catalog;
530
+ if (catalog && typeof catalog === "object" && !Array.isArray(catalog)) sections.push(catalog);
531
+ }
532
+ return sections;
533
+ }
510
534
  function parseVersion(value) {
511
535
  const normalized = value.replace(/^[^\d]*/, "");
512
536
  const dashIdx = normalized.indexOf("-");
@@ -552,6 +576,10 @@ function getVersionPrefix(version) {
552
576
  function applyVersionPrefix(currentVersion, resolvedVersion) {
553
577
  return `${getVersionPrefix(currentVersion)}${resolvedVersion}`;
554
578
  }
579
+ function shouldApplyResolvedVersion(currentVersion, resolvedVersion, channel) {
580
+ if (channel !== "beta") return true;
581
+ return compareVersions(resolvedVersion, currentVersion) >= 0;
582
+ }
555
583
  function isRegistrySemverSpec(version) {
556
584
  return /^[~^]?\d/.test(version);
557
585
  }
@@ -580,10 +608,40 @@ function selectRegistryVersionForChannel(packageInfo, channel) {
580
608
  if (prereleases.length > 0) return prereleases.sort((left, right) => compareVersions(right, left))[0] ?? null;
581
609
  return tags.latest ?? null;
582
610
  }
583
- async function resolveRegistryVersion(packageName, channel) {
584
- const version = selectRegistryVersionForChannel(await fetchPackageInfo(packageName), channel);
585
- if (!version) throw new Error(`No ${channel} version available for ${packageName}`);
586
- return version;
611
+ function getVersionsForChannel(packageInfo, channel) {
612
+ const versions = Object.keys(packageInfo.versions ?? {});
613
+ if (channel === "latest") return versions.filter((version) => !isPrerelease(version));
614
+ const prereleases = versions.filter(isPrerelease);
615
+ return prereleases.length > 0 ? prereleases : versions.filter((version) => !isPrerelease(version));
616
+ }
617
+ function resolveSharedFamilyVersion(packageInfos, channel) {
618
+ if (packageInfos.length === 0) return null;
619
+ const firstInfo = packageInfos[0];
620
+ if (!firstInfo) return null;
621
+ let commonVersions = new Set(getVersionsForChannel(firstInfo, channel));
622
+ const remainingInfos = packageInfos.slice(1);
623
+ for (const packageInfo of remainingInfos) {
624
+ const availableVersions = new Set(getVersionsForChannel(packageInfo, channel));
625
+ commonVersions = new Set([...commonVersions].filter((version) => availableVersions.has(version)));
626
+ }
627
+ return [...commonVersions].sort((left, right) => compareVersions(right, left))[0] ?? null;
628
+ }
629
+ function applySynchronizedFamilyVersions(resolvedVersions, packageInfos, channel) {
630
+ for (const family of SYNCHRONIZED_VERSION_FAMILIES) {
631
+ const selectedPackages = family.packages.filter((packageName) => resolvedVersions.has(packageName));
632
+ if (selectedPackages.length < 2) continue;
633
+ const selectedPackageInfos = selectedPackages.flatMap((packageName) => {
634
+ const packageInfo = packageInfos.get(packageName);
635
+ return packageInfo ? [packageInfo] : [];
636
+ });
637
+ if (selectedPackageInfos.length !== selectedPackages.length) continue;
638
+ const sharedVersion = resolveSharedFamilyVersion(selectedPackageInfos, channel);
639
+ if (!sharedVersion) {
640
+ log.warn(`Failed to resolve shared ${channel} version for ${family.name} packages`);
641
+ continue;
642
+ }
643
+ for (const packageName of selectedPackages) resolvedVersions.set(packageName, sharedVersion);
644
+ }
587
645
  }
588
646
  async function collectPackageJsonPaths(projectDir) {
589
647
  const results = [];
@@ -609,35 +667,36 @@ async function applyDependencyVersionChannel(projectDir, channel) {
609
667
  const packageNames = /* @__PURE__ */ new Set();
610
668
  for (const packageJsonPath of packageJsonPaths) {
611
669
  const packageJson = await fs.readJson(packageJsonPath);
612
- for (const [depName, depVersion] of Object.entries(packageJson.dependencies ?? {})) if (typeof depVersion === "string" && isRegistrySemverSpec(depVersion)) packageNames.add(depName);
613
- for (const [depName, depVersion] of Object.entries(packageJson.devDependencies ?? {})) if (typeof depVersion === "string" && isRegistrySemverSpec(depVersion)) packageNames.add(depName);
670
+ for (const section of getVersionSections(packageJson)) for (const [depName, depVersion] of Object.entries(section)) if (typeof depVersion === "string" && isRegistrySemverSpec(depVersion)) packageNames.add(depName);
614
671
  }
615
672
  if (packageNames.size === 0) return;
616
673
  const resolvedVersions = /* @__PURE__ */ new Map();
674
+ const packageInfos = /* @__PURE__ */ new Map();
617
675
  await mapWithConcurrency([...packageNames], async (packageName) => {
618
676
  try {
619
- const resolvedVersion = await resolveRegistryVersion(packageName, channel);
677
+ const packageInfo = await fetchPackageInfo(packageName);
678
+ const resolvedVersion = selectRegistryVersionForChannel(packageInfo, channel);
679
+ if (!resolvedVersion) throw new Error(`No ${channel} version available for ${packageName}`);
680
+ packageInfos.set(packageName, packageInfo);
620
681
  resolvedVersions.set(packageName, resolvedVersion);
621
682
  } catch (error) {
622
683
  log.warn(`Failed to resolve ${channel} version for ${packageName}: ${error instanceof Error ? error.message : String(error)}`);
623
684
  }
624
685
  }, REGISTRY_CONCURRENCY);
625
686
  if (resolvedVersions.size === 0) return;
687
+ applySynchronizedFamilyVersions(resolvedVersions, packageInfos, channel);
626
688
  for (const packageJsonPath of packageJsonPaths) {
627
689
  const packageJson = await fs.readJson(packageJsonPath);
628
690
  let changed = false;
629
- for (const sectionName of ["dependencies", "devDependencies"]) {
630
- const section = packageJson[sectionName];
631
- if (!section) continue;
632
- for (const [packageName, currentVersion] of Object.entries(section)) {
633
- if (!isRegistrySemverSpec(currentVersion)) continue;
634
- const resolvedVersion = resolvedVersions.get(packageName);
635
- if (!resolvedVersion) continue;
636
- const nextVersion = applyVersionPrefix(currentVersion, resolvedVersion);
637
- if (nextVersion !== currentVersion) {
638
- section[packageName] = nextVersion;
639
- changed = true;
640
- }
691
+ for (const section of getVersionSections(packageJson)) for (const [packageName, currentVersion] of Object.entries(section)) {
692
+ if (!isRegistrySemverSpec(currentVersion)) continue;
693
+ const resolvedVersion = resolvedVersions.get(packageName);
694
+ if (!resolvedVersion) continue;
695
+ if (!shouldApplyResolvedVersion(currentVersion, resolvedVersion, channel)) continue;
696
+ const nextVersion = applyVersionPrefix(currentVersion, resolvedVersion);
697
+ if (nextVersion !== currentVersion) {
698
+ section[packageName] = nextVersion;
699
+ changed = true;
641
700
  }
642
701
  }
643
702
  if (changed) await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import "./bts-config-DQVWvPDs.mjs";
3
+ import "./errors-ns_o2OKg.mjs";
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";
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
+
11
+ export { recommendStackFromBrief, startMcpServer };