create-better-fullstack 1.4.16 → 1.5.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/README.md +1 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +1 -1
- package/dist/{src-BVbxA2WC.mjs → src-DaUU4ThO.mjs} +217 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ Configure your stack visually — pick every option from a UI, preview your choi
|
|
|
38
38
|
--yolo # Scaffold a random stack — good for exploring
|
|
39
39
|
--template <name> # Use a preset (t3, mern, pern, uniwind)
|
|
40
40
|
--ecosystem <lang> # Start in rust, python, or go mode
|
|
41
|
+
--version-channel # Dependency channel: stable, latest, beta
|
|
41
42
|
--no-git # Skip git initialization
|
|
42
43
|
--no-install # Skip dependency installation
|
|
43
44
|
--package-manager # Package manager (bun, pnpm, npm, yarn)
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -278,6 +278,11 @@ declare const router: {
|
|
|
278
278
|
yarn: "yarn";
|
|
279
279
|
}>>;
|
|
280
280
|
install: z.ZodOptional<z.ZodBoolean>;
|
|
281
|
+
versionChannel: z.ZodOptional<z.ZodEnum<{
|
|
282
|
+
stable: "stable";
|
|
283
|
+
latest: "latest";
|
|
284
|
+
beta: "beta";
|
|
285
|
+
}>>;
|
|
281
286
|
dbSetup: z.ZodOptional<z.ZodEnum<{
|
|
282
287
|
none: "none";
|
|
283
288
|
turso: "turso";
|
|
@@ -543,6 +548,7 @@ declare const router: {
|
|
|
543
548
|
payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
|
|
544
549
|
git: boolean;
|
|
545
550
|
packageManager: "bun" | "npm" | "pnpm" | "yarn";
|
|
551
|
+
versionChannel: "stable" | "latest" | "beta";
|
|
546
552
|
install: boolean;
|
|
547
553
|
dbSetup: "none" | "turso" | "neon" | "prisma-postgres" | "planetscale" | "mongodb-atlas" | "supabase" | "upstash" | "d1" | "docker";
|
|
548
554
|
api: "none" | "trpc" | "orpc" | "ts-rest" | "garph";
|
|
@@ -629,6 +635,7 @@ declare const router: {
|
|
|
629
635
|
payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
|
|
630
636
|
git: boolean;
|
|
631
637
|
packageManager: "bun" | "npm" | "pnpm" | "yarn";
|
|
638
|
+
versionChannel: "stable" | "latest" | "beta";
|
|
632
639
|
install: boolean;
|
|
633
640
|
dbSetup: "none" | "turso" | "neon" | "prisma-postgres" | "planetscale" | "mongodb-atlas" | "supabase" | "upstash" | "d1" | "docker";
|
|
634
641
|
api: "none" | "trpc" | "orpc" | "ts-rest" | "garph";
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as builder, c as createVirtual, d as history, f as router, i as add, l as docs, n as TEMPLATE_COUNT, o as create, p as sponsors, r as VirtualFileSystem, s as createBtsCli, t as EMBEDDED_TEMPLATES, u as generateVirtualProject } from "./src-
|
|
2
|
+
import { a as builder, c as createVirtual, d as history, f as router, i as add, l as docs, n as TEMPLATE_COUNT, o as create, p as sponsors, r as VirtualFileSystem, s as createBtsCli, t as EMBEDDED_TEMPLATES, u as generateVirtualProject } from "./src-DaUU4ThO.mjs";
|
|
3
3
|
|
|
4
4
|
export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, history, router, sponsors };
|
|
@@ -67,6 +67,7 @@ const DEFAULT_CONFIG_BASE = {
|
|
|
67
67
|
examples: [],
|
|
68
68
|
git: true,
|
|
69
69
|
install: true,
|
|
70
|
+
versionChannel: "stable",
|
|
70
71
|
dbSetup: "none",
|
|
71
72
|
backend: "hono",
|
|
72
73
|
runtime: "bun",
|
|
@@ -1288,10 +1289,9 @@ const ADDON_GROUPS = {
|
|
|
1288
1289
|
"tauri",
|
|
1289
1290
|
"opentui",
|
|
1290
1291
|
"wxt",
|
|
1291
|
-
"ruler"
|
|
1292
|
-
"msw",
|
|
1293
|
-
"storybook"
|
|
1292
|
+
"ruler"
|
|
1294
1293
|
],
|
|
1294
|
+
Integrations: ["msw", "storybook"],
|
|
1295
1295
|
"AI Agents": ["mcp", "skills"],
|
|
1296
1296
|
TanStack: [
|
|
1297
1297
|
"tanstack-query",
|
|
@@ -1308,6 +1308,7 @@ async function getAddonsChoice(addons, frontends, auth) {
|
|
|
1308
1308
|
Tooling: [],
|
|
1309
1309
|
Documentation: [],
|
|
1310
1310
|
Extensions: [],
|
|
1311
|
+
Integrations: [],
|
|
1311
1312
|
"AI Agents": [],
|
|
1312
1313
|
TanStack: []
|
|
1313
1314
|
};
|
|
@@ -1324,6 +1325,7 @@ async function getAddonsChoice(addons, frontends, auth) {
|
|
|
1324
1325
|
if (ADDON_GROUPS.Tooling.includes(addon)) groupedOptions.Tooling.push(option);
|
|
1325
1326
|
else if (ADDON_GROUPS.Documentation.includes(addon)) groupedOptions.Documentation.push(option);
|
|
1326
1327
|
else if (ADDON_GROUPS.Extensions.includes(addon)) groupedOptions.Extensions.push(option);
|
|
1328
|
+
else if (ADDON_GROUPS.Integrations.includes(addon)) groupedOptions.Integrations.push(option);
|
|
1327
1329
|
else if (ADDON_GROUPS["AI Agents"].includes(addon)) groupedOptions["AI Agents"].push(option);
|
|
1328
1330
|
else if (ADDON_GROUPS.TanStack.includes(addon)) groupedOptions.TanStack.push(option);
|
|
1329
1331
|
}
|
|
@@ -1350,6 +1352,7 @@ async function getAddonsToAdd(frontend, existingAddons = [], auth) {
|
|
|
1350
1352
|
Tooling: [],
|
|
1351
1353
|
Documentation: [],
|
|
1352
1354
|
Extensions: [],
|
|
1355
|
+
Integrations: [],
|
|
1353
1356
|
"AI Agents": [],
|
|
1354
1357
|
TanStack: []
|
|
1355
1358
|
};
|
|
@@ -1365,6 +1368,7 @@ async function getAddonsToAdd(frontend, existingAddons = [], auth) {
|
|
|
1365
1368
|
if (ADDON_GROUPS.Tooling.includes(addon)) groupedOptions.Tooling.push(option);
|
|
1366
1369
|
else if (ADDON_GROUPS.Documentation.includes(addon)) groupedOptions.Documentation.push(option);
|
|
1367
1370
|
else if (ADDON_GROUPS.Extensions.includes(addon)) groupedOptions.Extensions.push(option);
|
|
1371
|
+
else if (ADDON_GROUPS.Integrations.includes(addon)) groupedOptions.Integrations.push(option);
|
|
1368
1372
|
else if (ADDON_GROUPS["AI Agents"].includes(addon)) groupedOptions["AI Agents"].push(option);
|
|
1369
1373
|
else if (ADDON_GROUPS.TanStack.includes(addon)) groupedOptions.TanStack.push(option);
|
|
1370
1374
|
}
|
|
@@ -1413,6 +1417,7 @@ async function writeBtsConfig(projectConfig) {
|
|
|
1413
1417
|
forms: projectConfig.forms,
|
|
1414
1418
|
testing: projectConfig.testing,
|
|
1415
1419
|
packageManager: projectConfig.packageManager,
|
|
1420
|
+
versionChannel: projectConfig.versionChannel,
|
|
1416
1421
|
dbSetup: projectConfig.dbSetup,
|
|
1417
1422
|
api: projectConfig.api,
|
|
1418
1423
|
webDeploy: projectConfig.webDeploy,
|
|
@@ -1472,6 +1477,7 @@ async function writeBtsConfig(projectConfig) {
|
|
|
1472
1477
|
forms: btsConfig.forms,
|
|
1473
1478
|
testing: btsConfig.testing,
|
|
1474
1479
|
packageManager: btsConfig.packageManager,
|
|
1480
|
+
versionChannel: btsConfig.versionChannel,
|
|
1475
1481
|
dbSetup: btsConfig.dbSetup,
|
|
1476
1482
|
api: btsConfig.api,
|
|
1477
1483
|
webDeploy: btsConfig.webDeploy,
|
|
@@ -1558,6 +1564,166 @@ async function updateBtsConfig(projectDir, updates) {
|
|
|
1558
1564
|
} catch {}
|
|
1559
1565
|
}
|
|
1560
1566
|
|
|
1567
|
+
//#endregion
|
|
1568
|
+
//#region src/utils/dependency-version-channel.ts
|
|
1569
|
+
const VERSION_CACHE = /* @__PURE__ */ new Map();
|
|
1570
|
+
const PRERELEASE_TAG_PRIORITY = [
|
|
1571
|
+
"beta",
|
|
1572
|
+
"next",
|
|
1573
|
+
"rc",
|
|
1574
|
+
"canary",
|
|
1575
|
+
"alpha"
|
|
1576
|
+
];
|
|
1577
|
+
const REGISTRY_FETCH_TIMEOUT_MS = 1e4;
|
|
1578
|
+
const REGISTRY_CONCURRENCY = 10;
|
|
1579
|
+
function mapWithConcurrency(items, fn, concurrency) {
|
|
1580
|
+
const results = Array.from({ length: items.length });
|
|
1581
|
+
let index = 0;
|
|
1582
|
+
async function worker() {
|
|
1583
|
+
while (index < items.length) {
|
|
1584
|
+
const i = index++;
|
|
1585
|
+
results[i] = await fn(items[i], i);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
return Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker())).then(() => results);
|
|
1589
|
+
}
|
|
1590
|
+
function parseVersion(value) {
|
|
1591
|
+
const normalized = value.replace(/^[^\d]*/, "");
|
|
1592
|
+
const dashIdx = normalized.indexOf("-");
|
|
1593
|
+
const base = dashIdx === -1 ? normalized : normalized.slice(0, dashIdx);
|
|
1594
|
+
const prerelease = dashIdx === -1 ? "" : normalized.slice(dashIdx + 1);
|
|
1595
|
+
const [major = "0", minor = "0", patch = "0"] = base.split(".");
|
|
1596
|
+
return {
|
|
1597
|
+
major: Number(major) || 0,
|
|
1598
|
+
minor: Number(minor) || 0,
|
|
1599
|
+
patch: Number(patch) || 0,
|
|
1600
|
+
prerelease: prerelease ? prerelease.split(/[.-]/).map((part) => /^\d+$/.test(part) ? Number(part) : part) : []
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
function compareVersions(a, b) {
|
|
1604
|
+
const left = parseVersion(a);
|
|
1605
|
+
const right = parseVersion(b);
|
|
1606
|
+
if (left.major !== right.major) return left.major - right.major;
|
|
1607
|
+
if (left.minor !== right.minor) return left.minor - right.minor;
|
|
1608
|
+
if (left.patch !== right.patch) return left.patch - right.patch;
|
|
1609
|
+
if (left.prerelease.length === 0 && right.prerelease.length === 0) return 0;
|
|
1610
|
+
if (left.prerelease.length === 0) return 1;
|
|
1611
|
+
if (right.prerelease.length === 0) return -1;
|
|
1612
|
+
const maxLength = Math.max(left.prerelease.length, right.prerelease.length);
|
|
1613
|
+
for (let index = 0; index < maxLength; index++) {
|
|
1614
|
+
const leftPart = left.prerelease[index];
|
|
1615
|
+
const rightPart = right.prerelease[index];
|
|
1616
|
+
if (leftPart === void 0) return -1;
|
|
1617
|
+
if (rightPart === void 0) return 1;
|
|
1618
|
+
if (leftPart === rightPart) continue;
|
|
1619
|
+
if (typeof leftPart === "number" && typeof rightPart === "number") return leftPart - rightPart;
|
|
1620
|
+
if (typeof leftPart === "number") return -1;
|
|
1621
|
+
if (typeof rightPart === "number") return 1;
|
|
1622
|
+
return leftPart.localeCompare(rightPart);
|
|
1623
|
+
}
|
|
1624
|
+
return 0;
|
|
1625
|
+
}
|
|
1626
|
+
function isPrerelease(version) {
|
|
1627
|
+
return /-(alpha|beta|rc|next|canary)/i.test(version);
|
|
1628
|
+
}
|
|
1629
|
+
function getVersionPrefix(version) {
|
|
1630
|
+
return version.match(/^[^\d]*/)?.[0] ?? "";
|
|
1631
|
+
}
|
|
1632
|
+
function applyVersionPrefix(currentVersion, resolvedVersion) {
|
|
1633
|
+
return `${getVersionPrefix(currentVersion)}${resolvedVersion}`;
|
|
1634
|
+
}
|
|
1635
|
+
function isRegistrySemverSpec(version) {
|
|
1636
|
+
return /^[~^]?\d/.test(version);
|
|
1637
|
+
}
|
|
1638
|
+
async function fetchPackageInfo(packageName) {
|
|
1639
|
+
const cached = VERSION_CACHE.get(packageName);
|
|
1640
|
+
if (cached) return cached;
|
|
1641
|
+
const encodedName = encodeURIComponent(packageName).replace("%40", "@");
|
|
1642
|
+
const response = await fetch(`https://registry.npmjs.org/${encodedName}`, {
|
|
1643
|
+
headers: { Accept: "application/vnd.npm.install-v1+json" },
|
|
1644
|
+
signal: AbortSignal.timeout(REGISTRY_FETCH_TIMEOUT_MS)
|
|
1645
|
+
});
|
|
1646
|
+
if (!response.ok) throw new Error(`Package ${packageName} not found (${response.status})`);
|
|
1647
|
+
const raw = await response.json();
|
|
1648
|
+
const data = {
|
|
1649
|
+
"dist-tags": raw["dist-tags"],
|
|
1650
|
+
versions: raw["versions"]
|
|
1651
|
+
};
|
|
1652
|
+
VERSION_CACHE.set(packageName, data);
|
|
1653
|
+
return data;
|
|
1654
|
+
}
|
|
1655
|
+
function selectRegistryVersionForChannel(packageInfo, channel) {
|
|
1656
|
+
const tags = packageInfo["dist-tags"] ?? {};
|
|
1657
|
+
if (channel === "latest") return tags.latest ?? null;
|
|
1658
|
+
for (const tag of PRERELEASE_TAG_PRIORITY) if (tags[tag]) return tags[tag];
|
|
1659
|
+
const prereleases = Object.keys(packageInfo.versions ?? {}).filter(isPrerelease);
|
|
1660
|
+
if (prereleases.length > 0) return prereleases.sort((left, right) => compareVersions(right, left))[0] ?? null;
|
|
1661
|
+
return tags.latest ?? null;
|
|
1662
|
+
}
|
|
1663
|
+
async function resolveRegistryVersion(packageName, channel) {
|
|
1664
|
+
const version = selectRegistryVersionForChannel(await fetchPackageInfo(packageName), channel);
|
|
1665
|
+
if (!version) throw new Error(`No ${channel} version available for ${packageName}`);
|
|
1666
|
+
return version;
|
|
1667
|
+
}
|
|
1668
|
+
async function collectPackageJsonPaths$1(projectDir) {
|
|
1669
|
+
const results = [];
|
|
1670
|
+
async function walk(currentDir) {
|
|
1671
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
1672
|
+
for (const entry of entries) {
|
|
1673
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".turbo") continue;
|
|
1674
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
1675
|
+
if (entry.isDirectory()) {
|
|
1676
|
+
await walk(fullPath);
|
|
1677
|
+
continue;
|
|
1678
|
+
}
|
|
1679
|
+
if (entry.isFile() && entry.name === "package.json") results.push(fullPath);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
await walk(projectDir);
|
|
1683
|
+
return results.sort();
|
|
1684
|
+
}
|
|
1685
|
+
async function applyDependencyVersionChannel(projectDir, channel) {
|
|
1686
|
+
if (channel === "stable") return;
|
|
1687
|
+
const packageJsonPaths = await collectPackageJsonPaths$1(projectDir);
|
|
1688
|
+
if (packageJsonPaths.length === 0) return;
|
|
1689
|
+
const packageNames = /* @__PURE__ */ new Set();
|
|
1690
|
+
for (const packageJsonPath of packageJsonPaths) {
|
|
1691
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
1692
|
+
for (const [depName, depVersion] of Object.entries(packageJson.dependencies ?? {})) if (typeof depVersion === "string" && isRegistrySemverSpec(depVersion)) packageNames.add(depName);
|
|
1693
|
+
for (const [depName, depVersion] of Object.entries(packageJson.devDependencies ?? {})) if (typeof depVersion === "string" && isRegistrySemverSpec(depVersion)) packageNames.add(depName);
|
|
1694
|
+
}
|
|
1695
|
+
if (packageNames.size === 0) return;
|
|
1696
|
+
const resolvedVersions = /* @__PURE__ */ new Map();
|
|
1697
|
+
await mapWithConcurrency([...packageNames], async (packageName) => {
|
|
1698
|
+
try {
|
|
1699
|
+
const resolvedVersion = await resolveRegistryVersion(packageName, channel);
|
|
1700
|
+
resolvedVersions.set(packageName, resolvedVersion);
|
|
1701
|
+
} catch (error) {
|
|
1702
|
+
log.warn(`Failed to resolve ${channel} version for ${packageName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1703
|
+
}
|
|
1704
|
+
}, REGISTRY_CONCURRENCY);
|
|
1705
|
+
if (resolvedVersions.size === 0) return;
|
|
1706
|
+
for (const packageJsonPath of packageJsonPaths) {
|
|
1707
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
1708
|
+
let changed = false;
|
|
1709
|
+
for (const sectionName of ["dependencies", "devDependencies"]) {
|
|
1710
|
+
const section = packageJson[sectionName];
|
|
1711
|
+
if (!section) continue;
|
|
1712
|
+
for (const [packageName, currentVersion] of Object.entries(section)) {
|
|
1713
|
+
if (!isRegistrySemverSpec(currentVersion)) continue;
|
|
1714
|
+
const resolvedVersion = resolvedVersions.get(packageName);
|
|
1715
|
+
if (!resolvedVersion) continue;
|
|
1716
|
+
const nextVersion = applyVersionPrefix(currentVersion, resolvedVersion);
|
|
1717
|
+
if (nextVersion !== currentVersion) {
|
|
1718
|
+
section[packageName] = nextVersion;
|
|
1719
|
+
changed = true;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
if (changed) await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1561
1727
|
//#endregion
|
|
1562
1728
|
//#region src/utils/add-package-deps.ts
|
|
1563
1729
|
const addPackageDependency = async (opts) => {
|
|
@@ -2946,6 +3112,7 @@ async function addHandlerInternal(input) {
|
|
|
2946
3112
|
config
|
|
2947
3113
|
}, projectDir);
|
|
2948
3114
|
await setupAddons(config);
|
|
3115
|
+
await applyDependencyVersionChannel(projectDir, config.versionChannel);
|
|
2949
3116
|
const configUpdates = { addons: [...new Set([...existingAddons, ...addonsToAdd])] };
|
|
2950
3117
|
if (input.webDeploy !== void 0) configUpdates.webDeploy = input.webDeploy;
|
|
2951
3118
|
if (input.serverDeploy !== void 0) configUpdates.serverDeploy = input.serverDeploy;
|
|
@@ -5985,6 +6152,35 @@ async function getProjectName(initialName) {
|
|
|
5985
6152
|
return projectPath;
|
|
5986
6153
|
}
|
|
5987
6154
|
|
|
6155
|
+
//#endregion
|
|
6156
|
+
//#region src/prompts/version-channel.ts
|
|
6157
|
+
async function getVersionChannelChoice(versionChannel) {
|
|
6158
|
+
if (versionChannel !== void 0) return versionChannel;
|
|
6159
|
+
const response = await navigableSelect({
|
|
6160
|
+
message: "Choose dependency version channel",
|
|
6161
|
+
options: [
|
|
6162
|
+
{
|
|
6163
|
+
value: "stable",
|
|
6164
|
+
label: "Stable",
|
|
6165
|
+
hint: "Use Better Fullstack's curated pinned versions"
|
|
6166
|
+
},
|
|
6167
|
+
{
|
|
6168
|
+
value: "latest",
|
|
6169
|
+
label: "Latest",
|
|
6170
|
+
hint: "Resolve current npm latest tags during scaffolding"
|
|
6171
|
+
},
|
|
6172
|
+
{
|
|
6173
|
+
value: "beta",
|
|
6174
|
+
label: "Beta",
|
|
6175
|
+
hint: "Prefer npm beta/next prerelease tags when available"
|
|
6176
|
+
}
|
|
6177
|
+
],
|
|
6178
|
+
initialValue: "stable"
|
|
6179
|
+
});
|
|
6180
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
6181
|
+
return response;
|
|
6182
|
+
}
|
|
6183
|
+
|
|
5988
6184
|
//#endregion
|
|
5989
6185
|
//#region src/utils/telemetry.ts
|
|
5990
6186
|
/**
|
|
@@ -6077,6 +6273,7 @@ function displayConfig(config) {
|
|
|
6077
6273
|
configDisplay.push(`${pc.blue("Git Init:")} ${gitText}`);
|
|
6078
6274
|
}
|
|
6079
6275
|
if (config.packageManager !== void 0) configDisplay.push(`${pc.blue("Package Manager:")} ${String(config.packageManager)}`);
|
|
6276
|
+
if (config.versionChannel !== void 0) configDisplay.push(`${pc.blue("Version Channel:")} ${String(config.versionChannel)}`);
|
|
6080
6277
|
if (config.install !== void 0) {
|
|
6081
6278
|
const installText = typeof config.install === "boolean" ? config.install ? "Yes" : "No" : String(config.install);
|
|
6082
6279
|
configDisplay.push(`${pc.blue("Install Dependencies:")} ${installText}`);
|
|
@@ -6109,6 +6306,7 @@ function appendCommonFlags(flags, config) {
|
|
|
6109
6306
|
else flags.push("--ai-docs none");
|
|
6110
6307
|
flags.push(config.git ? "--git" : "--no-git");
|
|
6111
6308
|
flags.push(`--package-manager ${config.packageManager}`);
|
|
6309
|
+
if (config.versionChannel !== "stable") flags.push(`--version-channel ${config.versionChannel}`);
|
|
6112
6310
|
flags.push(config.install ? "--install" : "--no-install");
|
|
6113
6311
|
}
|
|
6114
6312
|
function appendSharedNonTypeScriptFlags(flags, config) {
|
|
@@ -6432,6 +6630,7 @@ function processFlags(options, projectName) {
|
|
|
6432
6630
|
if (options.runtime) config.runtime = options.runtime;
|
|
6433
6631
|
if (options.dbSetup) config.dbSetup = options.dbSetup;
|
|
6434
6632
|
if (options.packageManager) config.packageManager = options.packageManager;
|
|
6633
|
+
if (options.versionChannel) config.versionChannel = options.versionChannel;
|
|
6435
6634
|
if (options.webDeploy) config.webDeploy = options.webDeploy;
|
|
6436
6635
|
if (options.serverDeploy) config.serverDeploy = options.serverDeploy;
|
|
6437
6636
|
const derivedName = deriveProjectName(projectName, options.projectDirectory);
|
|
@@ -8607,6 +8806,7 @@ async function createProject(options, cliInput = {}) {
|
|
|
8607
8806
|
await setPackageManagerVersion(projectDir, options.packageManager);
|
|
8608
8807
|
if (!isConvex && options.database !== "none") await setupDatabase(options, cliInput);
|
|
8609
8808
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
8809
|
+
await applyDependencyVersionChannel(projectDir, options.versionChannel);
|
|
8610
8810
|
await writeBtsConfig(options);
|
|
8611
8811
|
await formatProject(projectDir);
|
|
8612
8812
|
if (!isSilent()) log.success("Project template successfully scaffolded!");
|
|
@@ -8651,6 +8851,10 @@ async function setPackageManagerVersion(projectDir, packageManager) {
|
|
|
8651
8851
|
|
|
8652
8852
|
//#endregion
|
|
8653
8853
|
//#region src/helpers/core/command-handlers.ts
|
|
8854
|
+
function shouldPromptForVersionChannel(input) {
|
|
8855
|
+
if (input.yes || input.versionChannel !== void 0 || isSilent()) return false;
|
|
8856
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true && process.env.CI !== "true";
|
|
8857
|
+
}
|
|
8654
8858
|
async function createProjectHandler(input, options = {}) {
|
|
8655
8859
|
const { silent = false } = options;
|
|
8656
8860
|
return runWithContextAsync({ silent }, async () => {
|
|
@@ -8672,6 +8876,7 @@ async function createProjectHandler(input, options = {}) {
|
|
|
8672
8876
|
}
|
|
8673
8877
|
currentPathInput = defaultName;
|
|
8674
8878
|
} else currentPathInput = await getProjectName(input.projectName);
|
|
8879
|
+
const versionChannel = shouldPromptForVersionChannel(input) ? await getVersionChannelChoice() : input.versionChannel ?? "stable";
|
|
8675
8880
|
let finalPathInput;
|
|
8676
8881
|
let shouldClearDirectory;
|
|
8677
8882
|
try {
|
|
@@ -8707,6 +8912,7 @@ async function createProjectHandler(input, options = {}) {
|
|
|
8707
8912
|
effect: "none",
|
|
8708
8913
|
git: false,
|
|
8709
8914
|
packageManager: "npm",
|
|
8915
|
+
versionChannel: "stable",
|
|
8710
8916
|
install: false,
|
|
8711
8917
|
dbSetup: "none",
|
|
8712
8918
|
api: "none",
|
|
@@ -8791,7 +8997,8 @@ async function createProjectHandler(input, options = {}) {
|
|
|
8791
8997
|
...flagConfig,
|
|
8792
8998
|
projectName: finalBaseName,
|
|
8793
8999
|
projectDir: finalResolvedPath,
|
|
8794
|
-
relativePath: finalPathInput
|
|
9000
|
+
relativePath: finalPathInput,
|
|
9001
|
+
versionChannel
|
|
8795
9002
|
};
|
|
8796
9003
|
validateConfigCompatibility(config, providedFlags, cliInput);
|
|
8797
9004
|
const yesPreflight = validatePreflightConfig(config);
|
|
@@ -8808,7 +9015,10 @@ async function createProjectHandler(input, options = {}) {
|
|
|
8808
9015
|
log.message(displayConfig(otherFlags));
|
|
8809
9016
|
log.message("");
|
|
8810
9017
|
}
|
|
8811
|
-
config =
|
|
9018
|
+
config = {
|
|
9019
|
+
...await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput),
|
|
9020
|
+
versionChannel
|
|
9021
|
+
};
|
|
8812
9022
|
}
|
|
8813
9023
|
const preflight = validatePreflightConfig(config);
|
|
8814
9024
|
if (preflight.hasWarnings && !isSilent()) displayPreflightWarnings(preflight);
|
|
@@ -9002,6 +9212,7 @@ const router = os.router({
|
|
|
9002
9212
|
git: z.boolean().optional(),
|
|
9003
9213
|
packageManager: types_exports.PackageManagerSchema.optional(),
|
|
9004
9214
|
install: z.boolean().optional(),
|
|
9215
|
+
versionChannel: types_exports.VersionChannelSchema.optional().describe("Dependency version channel (stable, latest, beta)"),
|
|
9005
9216
|
dbSetup: types_exports.DatabaseSetupSchema.optional(),
|
|
9006
9217
|
backend: types_exports.BackendSchema.optional(),
|
|
9007
9218
|
runtime: types_exports.RuntimeSchema.optional(),
|
|
@@ -9226,6 +9437,7 @@ async function createVirtual(options) {
|
|
|
9226
9437
|
effect: options.effect || "none",
|
|
9227
9438
|
git: options.git ?? false,
|
|
9228
9439
|
packageManager: options.packageManager || "bun",
|
|
9440
|
+
versionChannel: options.versionChannel || "stable",
|
|
9229
9441
|
install: false,
|
|
9230
9442
|
dbSetup: options.dbSetup || "none",
|
|
9231
9443
|
api: options.api || "trpc",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-fullstack",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Scaffold production-ready fullstack apps in seconds. Pick your stack from 270+ options — the CLI wires everything together.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -108,8 +108,8 @@
|
|
|
108
108
|
"prepublishOnly": "npm run build"
|
|
109
109
|
},
|
|
110
110
|
"dependencies": {
|
|
111
|
-
"@better-fullstack/template-generator": "^1.
|
|
112
|
-
"@better-fullstack/types": "^1.
|
|
111
|
+
"@better-fullstack/template-generator": "^1.5.0",
|
|
112
|
+
"@better-fullstack/types": "^1.5.0",
|
|
113
113
|
"@clack/core": "^0.5.0",
|
|
114
114
|
"@clack/prompts": "^1.1.0",
|
|
115
115
|
"@orpc/server": "^1.13.9",
|