create-better-fullstack 2.1.5 → 2.1.6
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-BNSL6HdM.mjs → add-handler-CuPmSJRM.mjs} +13 -5
- package/dist/{addons-setup-CyrP1IV-.mjs → addons-setup-C_lxdJqU.mjs} +8 -1
- package/dist/addons-setup-DEPfsn6z.mjs +6 -0
- package/dist/{errors-Cyol8zbN.mjs → bts-config-BceXPcpI.mjs} +3 -84
- package/dist/cli.mjs +2 -2
- package/dist/{templates-CnTOtKjm.mjs → config-processing-B_1wTe3g.mjs} +57 -2
- package/dist/{doctor-DBoq7bZ9.mjs → doctor-DucDyWfl.mjs} +3 -2
- package/dist/errors-ns_o2OKg.mjs +86 -0
- package/dist/{file-formatter-B3dsev2l.mjs → file-formatter-XU6ti05V.mjs} +66 -6
- package/dist/gen-DWx3Xu_K.mjs +274 -0
- package/dist/{generated-checks-C8hn9w2i.mjs → generated-checks-Dt4Xqp1x.mjs} +1 -1
- package/dist/index.d.mts +171 -79
- package/dist/index.mjs +15 -8
- package/dist/{install-dependencies-CgNh-aOy.mjs → install-dependencies-DHoYa3P-.mjs} +75 -21
- package/dist/mcp-D9O5zgAA.mjs +8 -0
- package/dist/mcp-entry.mjs +153 -16
- package/dist/registry-CxeEOPot.mjs +394 -0
- package/dist/run-3AkXloH1.mjs +13 -0
- package/dist/{run-BYse4yJy.mjs → run-D80ZtSO8.mjs} +361 -88
- package/dist/scaffold-manifest-GV1fbhpD.mjs +123 -0
- package/dist/update-C9_x2yBF.mjs +401 -0
- package/package.json +3 -3
- package/dist/addons-setup-DyMm42a5.mjs +0 -5
- package/dist/mcp-CsW3i66c.mjs +0 -6
- package/dist/run-_cf_sFwM.mjs +0 -10
- /package/dist/{update-deps-D5OG0KmJ.mjs → update-deps-DLZAuT3V.mjs} +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { a as updateBtsConfig, r as readBtsConfig, u as getDefaultConfig } from "./bts-config-BceXPcpI.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
|
-
import { t as
|
|
5
|
-
import "./
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
4
|
+
import { c as isSilent, l as runWithContextAsync, n as UserCancelledError, t as CLIError } from "./errors-ns_o2OKg.mjs";
|
|
5
|
+
import { t as setupAddons } from "./addons-setup-C_lxdJqU.mjs";
|
|
6
|
+
import "./file-formatter-XU6ti05V.mjs";
|
|
7
|
+
import { c as applyDependencyVersionChannel, t as installDependencies, u as getAddonsToAdd } from "./install-dependencies-DHoYa3P-.mjs";
|
|
8
|
+
import { o as applyStackUpdate, u as planStackUpdate } from "./mcp-entry.mjs";
|
|
8
9
|
import { intro, log, outro } from "@clack/prompts";
|
|
9
10
|
import pc from "picocolors";
|
|
10
11
|
import fs from "fs-extra";
|
|
@@ -55,6 +56,13 @@ function logStackUpdateSummary(plan, dryRun) {
|
|
|
55
56
|
const envCount = countEnvChanges(plan);
|
|
56
57
|
if (envCount > 0) log.info(pc.dim(`Env vars: ${formatCount(envCount, "addition")}`));
|
|
57
58
|
for (const adjustment of plan.compatibilityAdjustments) log.info(pc.dim(`Adjusted: ${adjustment}`));
|
|
59
|
+
if (plan.architectureChanges.length > 0) {
|
|
60
|
+
const swaps = plan.architectureChanges.map((change) => `${change.key}: ${change.from} -> ${change.to}`).join(", ");
|
|
61
|
+
log.warn(pc.yellow(`Architecture change: ${swaps}`));
|
|
62
|
+
log.info(pc.dim("Data and schema are NOT migrated automatically. Migration checklist:"));
|
|
63
|
+
for (const step of plan.migrationSteps) log.info(pc.dim(` - ${step}`));
|
|
64
|
+
if (dryRun && plan.requiresArchitectureAck) log.warn(pc.yellow("Re-run with --acknowledge-architecture-change to apply this architecture change."));
|
|
65
|
+
}
|
|
58
66
|
for (const blocker of plan.manualReviewBlockers) log.warn(pc.yellow(`Manual review: ${blocker}`));
|
|
59
67
|
}
|
|
60
68
|
function buildAddonSetupConfig(projectDir, projectName, currentConfig, plan, addonsToSetup) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { r as readBtsConfig } from "./bts-config-BceXPcpI.mjs";
|
|
3
|
+
import { c as isSilent, r as exitCancelled } from "./errors-ns_o2OKg.mjs";
|
|
3
4
|
import { autocompleteMultiselect, group, isCancel, log, multiselect, select, spinner } from "@clack/prompts";
|
|
4
5
|
import pc from "picocolors";
|
|
5
6
|
import fs from "fs-extra";
|
|
@@ -396,6 +397,12 @@ function getRecommendedMcpServers(config) {
|
|
|
396
397
|
name: "polar",
|
|
397
398
|
target: "https://mcp.polar.sh/mcp/polar-mcp"
|
|
398
399
|
});
|
|
400
|
+
if (config.payments === "revenuecat") servers.push({
|
|
401
|
+
key: "revenuecat",
|
|
402
|
+
label: "RevenueCat",
|
|
403
|
+
name: "revenuecat",
|
|
404
|
+
target: "https://mcp.revenuecat.ai/mcp"
|
|
405
|
+
});
|
|
399
406
|
return servers;
|
|
400
407
|
}
|
|
401
408
|
function filterAgentsForScope(scope) {
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as __reExport } from "./chunk-CCII7kTE.mjs";
|
|
3
|
-
import { cancel } from "@clack/prompts";
|
|
4
|
-
import pc from "picocolors";
|
|
5
3
|
import fs from "fs-extra";
|
|
6
4
|
import path from "node:path";
|
|
7
5
|
import * as JSONC from "jsonc-parser";
|
|
8
6
|
import { createCliDefaultProjectConfigBase } from "@better-fullstack/types";
|
|
9
7
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
11
|
-
import consola from "consola";
|
|
12
8
|
|
|
13
9
|
//#region src/types.ts
|
|
14
10
|
var types_exports = {};
|
|
@@ -462,6 +458,7 @@ function buildBtsConfigForPersistence(projectConfig, metadata = {}) {
|
|
|
462
458
|
testing: persistedConfig.testing,
|
|
463
459
|
packageManager: persistedConfig.packageManager,
|
|
464
460
|
versionChannel: persistedConfig.versionChannel,
|
|
461
|
+
workspaceShape: persistedConfig.workspaceShape === "single-app" ? "single-app" : void 0,
|
|
465
462
|
dbSetup: persistedConfig.dbSetup,
|
|
466
463
|
api: persistedConfig.api,
|
|
467
464
|
webDeploy: persistedConfig.webDeploy,
|
|
@@ -617,6 +614,7 @@ async function writeBtsConfig(projectConfig, metadata = {}) {
|
|
|
617
614
|
testing: btsConfig.testing,
|
|
618
615
|
packageManager: btsConfig.packageManager,
|
|
619
616
|
versionChannel: btsConfig.versionChannel,
|
|
617
|
+
workspaceShape: btsConfig.workspaceShape,
|
|
620
618
|
dbSetup: btsConfig.dbSetup,
|
|
621
619
|
api: btsConfig.api,
|
|
622
620
|
webDeploy: btsConfig.webDeploy,
|
|
@@ -814,83 +812,4 @@ async function updateBtsConfig(projectDir, updates) {
|
|
|
814
812
|
}
|
|
815
813
|
|
|
816
814
|
//#endregion
|
|
817
|
-
|
|
818
|
-
const cliStorage = new AsyncLocalStorage();
|
|
819
|
-
function defaultContext() {
|
|
820
|
-
return {
|
|
821
|
-
navigation: {
|
|
822
|
-
isFirstPrompt: false,
|
|
823
|
-
lastPromptShownUI: false
|
|
824
|
-
},
|
|
825
|
-
silent: false
|
|
826
|
-
};
|
|
827
|
-
}
|
|
828
|
-
function getContext() {
|
|
829
|
-
const ctx = cliStorage.getStore();
|
|
830
|
-
if (!ctx) return defaultContext();
|
|
831
|
-
return ctx;
|
|
832
|
-
}
|
|
833
|
-
function tryGetContext() {
|
|
834
|
-
return cliStorage.getStore();
|
|
835
|
-
}
|
|
836
|
-
function isSilent() {
|
|
837
|
-
return getContext().silent;
|
|
838
|
-
}
|
|
839
|
-
function isFirstPrompt() {
|
|
840
|
-
return getContext().navigation.isFirstPrompt;
|
|
841
|
-
}
|
|
842
|
-
function didLastPromptShowUI() {
|
|
843
|
-
return getContext().navigation.lastPromptShownUI;
|
|
844
|
-
}
|
|
845
|
-
function setIsFirstPrompt(value) {
|
|
846
|
-
const ctx = tryGetContext();
|
|
847
|
-
if (ctx) ctx.navigation.isFirstPrompt = value;
|
|
848
|
-
}
|
|
849
|
-
function setLastPromptShownUI(value) {
|
|
850
|
-
const ctx = tryGetContext();
|
|
851
|
-
if (ctx) ctx.navigation.lastPromptShownUI = value;
|
|
852
|
-
}
|
|
853
|
-
async function runWithContextAsync(options, fn) {
|
|
854
|
-
const ctx = {
|
|
855
|
-
navigation: {
|
|
856
|
-
isFirstPrompt: false,
|
|
857
|
-
lastPromptShownUI: false
|
|
858
|
-
},
|
|
859
|
-
silent: options.silent ?? false
|
|
860
|
-
};
|
|
861
|
-
return cliStorage.run(ctx, fn);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
//#endregion
|
|
865
|
-
//#region src/utils/errors.ts
|
|
866
|
-
var UserCancelledError = class extends Error {
|
|
867
|
-
constructor(message = "Operation cancelled") {
|
|
868
|
-
super(message);
|
|
869
|
-
this.name = "UserCancelledError";
|
|
870
|
-
}
|
|
871
|
-
};
|
|
872
|
-
var CLIError = class extends Error {
|
|
873
|
-
constructor(message) {
|
|
874
|
-
super(message);
|
|
875
|
-
this.name = "CLIError";
|
|
876
|
-
}
|
|
877
|
-
};
|
|
878
|
-
function exitWithError(message) {
|
|
879
|
-
if (isSilent()) throw new CLIError(message);
|
|
880
|
-
consola.error(pc.red(message));
|
|
881
|
-
process.exit(1);
|
|
882
|
-
}
|
|
883
|
-
function exitCancelled(message = "Operation cancelled") {
|
|
884
|
-
if (isSilent()) throw new UserCancelledError(message);
|
|
885
|
-
cancel(pc.red(message));
|
|
886
|
-
process.exit(1);
|
|
887
|
-
}
|
|
888
|
-
function handleError(error, fallbackMessage) {
|
|
889
|
-
const message = error instanceof Error ? error.message : fallbackMessage || String(error);
|
|
890
|
-
if (isSilent()) throw error instanceof Error ? error : new Error(message);
|
|
891
|
-
consola.error(pc.red(message));
|
|
892
|
-
process.exit(1);
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
//#endregion
|
|
896
|
-
export { types_exports as A, getEffectiveStack as C, getGraphSummary as D, getGraphPart as E, getPrimaryGraphPart as O, getUserPkgManager as S, getGraphBackendUrl as T, writeBtsConfig as _, handleError as a, DEFAULT_UI_LIBRARY_BY_FRONTEND as b, isSilent as c, setLastPromptShownUI as d, buildBtsConfigForPersistence as f, updateBtsConfig as g, readBtsConfigFromFile as h, exitWithError as i, hasGraphPart as k, runWithContextAsync as l, readBtsConfig as m, UserCancelledError as n, didLastPromptShowUI as o, previewBtsConfigUpdate as p, exitCancelled as r, isFirstPrompt as s, CLIError as t, setIsFirstPrompt as u, getLatestCLIVersion as v, getGraphBackendDeployInstructions as w, getDefaultConfig as x, DEFAULT_CONFIG as y };
|
|
815
|
+
export { getPrimaryGraphPart as _, updateBtsConfig as a, DEFAULT_CONFIG as c, getUserPkgManager as d, getEffectiveStack as f, getGraphSummary as g, getGraphPart as h, readBtsConfigFromFile as i, DEFAULT_UI_LIBRARY_BY_FRONTEND as l, getGraphBackendUrl as m, previewBtsConfigUpdate as n, writeBtsConfig as o, getGraphBackendDeployInstructions as p, readBtsConfig as r, getLatestCLIVersion as s, buildBtsConfigForPersistence as t, getDefaultConfig as u, hasGraphPart as v, types_exports as y };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
//#region src/cli.ts
|
|
3
|
-
if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-
|
|
4
|
-
else import("./run-
|
|
3
|
+
if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-D9O5zgAA.mjs").then((m) => m.startMcpServer());
|
|
4
|
+
else import("./run-3AkXloH1.mjs").then((m) => m.createBtsCli().run());
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { y as types_exports } from "./bts-config-BceXPcpI.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { cliInputToProjectConfigPartial } from "@better-fullstack/types/stack-translation";
|
|
3
5
|
|
|
4
6
|
//#region src/utils/generate-reproducible-command.ts
|
|
5
7
|
function getBaseCommand(packageManager) {
|
|
@@ -21,6 +23,7 @@ function appendCommonFlags(flags, config) {
|
|
|
21
23
|
else flags.push("--ai-docs none");
|
|
22
24
|
flags.push(config.git ? "--git" : "--no-git");
|
|
23
25
|
flags.push(`--package-manager ${config.packageManager}`);
|
|
26
|
+
if (config.workspaceShape && config.workspaceShape !== "monorepo") flags.push(`--workspace-shape ${config.workspaceShape}`);
|
|
24
27
|
if (config.versionChannel !== "stable") flags.push(`--version-channel ${config.versionChannel}`);
|
|
25
28
|
flags.push(config.install ? "--install" : "--no-install");
|
|
26
29
|
}
|
|
@@ -326,6 +329,7 @@ function getGoFlags(config) {
|
|
|
326
329
|
function getJavaFlags(config) {
|
|
327
330
|
const flags = ["--ecosystem java"];
|
|
328
331
|
flags.push(`--java-web-framework ${config.javaWebFramework}`);
|
|
332
|
+
if (config.javaLanguage === "kotlin") flags.push(`--java-language ${config.javaLanguage}`);
|
|
329
333
|
flags.push(`--java-build-tool ${config.javaBuildTool}`);
|
|
330
334
|
flags.push(`--java-orm ${config.javaOrm}`);
|
|
331
335
|
flags.push(`--java-auth ${config.javaAuth}`);
|
|
@@ -460,6 +464,21 @@ const TEMPLATE_PRESETS = {
|
|
|
460
464
|
webDeploy: "none",
|
|
461
465
|
serverDeploy: "none"
|
|
462
466
|
},
|
|
467
|
+
saas: {
|
|
468
|
+
database: "postgres",
|
|
469
|
+
orm: "drizzle",
|
|
470
|
+
backend: "self",
|
|
471
|
+
runtime: "none",
|
|
472
|
+
frontend: ["next"],
|
|
473
|
+
api: "trpc",
|
|
474
|
+
auth: "better-auth-organizations",
|
|
475
|
+
payments: "creem",
|
|
476
|
+
addons: ["turborepo"],
|
|
477
|
+
examples: ["none"],
|
|
478
|
+
dbSetup: "none",
|
|
479
|
+
webDeploy: "none",
|
|
480
|
+
serverDeploy: "none"
|
|
481
|
+
},
|
|
463
482
|
uniwind: {
|
|
464
483
|
database: "none",
|
|
465
484
|
orm: "none",
|
|
@@ -488,10 +507,46 @@ function getTemplateDescription(template) {
|
|
|
488
507
|
mern: "MongoDB + Express + React + Node.js - Classic MERN stack",
|
|
489
508
|
pern: "PostgreSQL + Express + React + Node.js - Popular PERN stack",
|
|
490
509
|
t3: "T3 Stack - Next.js + tRPC + Prisma + PostgreSQL + Better Auth",
|
|
510
|
+
saas: "SaaS Starter - Next.js + tRPC + Drizzle + PostgreSQL + Better Auth Organizations + Creem billing",
|
|
491
511
|
uniwind: "Expo + Uniwind native app with no backend services",
|
|
492
512
|
none: "No template - Full customization"
|
|
493
513
|
}[template] || "";
|
|
494
514
|
}
|
|
495
515
|
|
|
496
516
|
//#endregion
|
|
497
|
-
|
|
517
|
+
//#region src/utils/config-processing.ts
|
|
518
|
+
function deriveProjectName(projectName, projectDirectory) {
|
|
519
|
+
if (projectName) return projectName;
|
|
520
|
+
if (projectDirectory) return path.basename(path.resolve(process.cwd(), projectDirectory));
|
|
521
|
+
return "";
|
|
522
|
+
}
|
|
523
|
+
function processFlags(options, projectName) {
|
|
524
|
+
const derivedName = deriveProjectName(projectName, options.projectDirectory);
|
|
525
|
+
return cliInputToProjectConfigPartial(options, projectName || derivedName);
|
|
526
|
+
}
|
|
527
|
+
function applyEffectBackendDefaults(config, providedFlags = /* @__PURE__ */ new Set()) {
|
|
528
|
+
if (config.backend !== "effect") return config;
|
|
529
|
+
if (!providedFlags.has("effect")) config.effect = "effect-full";
|
|
530
|
+
if (!providedFlags.has("validation")) config.validation = "effect-schema";
|
|
531
|
+
return config;
|
|
532
|
+
}
|
|
533
|
+
function getProvidedFlags(options) {
|
|
534
|
+
return new Set(Object.keys(options).filter((key) => options[key] !== void 0));
|
|
535
|
+
}
|
|
536
|
+
function validateNoneExclusivity(options, optionName) {
|
|
537
|
+
if (!options || options.length === 0) return;
|
|
538
|
+
if (options.includes("none") && options.length > 1) throw new Error(`Cannot combine 'none' with other ${optionName}.`);
|
|
539
|
+
}
|
|
540
|
+
function validateArrayOptions(options) {
|
|
541
|
+
validateNoneExclusivity(options.frontend, "frontend options");
|
|
542
|
+
validateNoneExclusivity(options.addons, "addons");
|
|
543
|
+
validateNoneExclusivity(options.examples, "examples");
|
|
544
|
+
validateNoneExclusivity(options.aiDocs, "ai docs");
|
|
545
|
+
validateNoneExclusivity(options.rustLibraries, "rust libraries");
|
|
546
|
+
validateNoneExclusivity(options.pythonAi, "python ai libraries");
|
|
547
|
+
validateNoneExclusivity(options.javaLibraries, "java libraries");
|
|
548
|
+
validateNoneExclusivity(options.javaTestingLibraries, "java testing libraries");
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
//#endregion
|
|
552
|
+
export { getTemplateConfig as a, validateArrayOptions as i, getProvidedFlags as n, getTemplateDescription as o, processFlags as r, generateReproducibleCommand as s, applyEffectBackendDefaults as t };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { r as readBtsConfig } from "./bts-config-BceXPcpI.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { a as handleError } from "./errors-ns_o2OKg.mjs";
|
|
5
|
+
import { t as runGeneratedChecks } from "./generated-checks-Dt4Xqp1x.mjs";
|
|
5
6
|
import { intro, log, spinner } from "@clack/prompts";
|
|
6
7
|
import pc from "picocolors";
|
|
7
8
|
import fs from "fs-extra";
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cancel } from "@clack/prompts";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
import consola from "consola";
|
|
6
|
+
|
|
7
|
+
//#region src/utils/context.ts
|
|
8
|
+
const cliStorage = new AsyncLocalStorage();
|
|
9
|
+
function defaultContext() {
|
|
10
|
+
return {
|
|
11
|
+
navigation: {
|
|
12
|
+
isFirstPrompt: false,
|
|
13
|
+
lastPromptShownUI: false
|
|
14
|
+
},
|
|
15
|
+
silent: false
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function getContext() {
|
|
19
|
+
const ctx = cliStorage.getStore();
|
|
20
|
+
if (!ctx) return defaultContext();
|
|
21
|
+
return ctx;
|
|
22
|
+
}
|
|
23
|
+
function tryGetContext() {
|
|
24
|
+
return cliStorage.getStore();
|
|
25
|
+
}
|
|
26
|
+
function isSilent() {
|
|
27
|
+
return getContext().silent;
|
|
28
|
+
}
|
|
29
|
+
function isFirstPrompt() {
|
|
30
|
+
return getContext().navigation.isFirstPrompt;
|
|
31
|
+
}
|
|
32
|
+
function didLastPromptShowUI() {
|
|
33
|
+
return getContext().navigation.lastPromptShownUI;
|
|
34
|
+
}
|
|
35
|
+
function setIsFirstPrompt(value) {
|
|
36
|
+
const ctx = tryGetContext();
|
|
37
|
+
if (ctx) ctx.navigation.isFirstPrompt = value;
|
|
38
|
+
}
|
|
39
|
+
function setLastPromptShownUI(value) {
|
|
40
|
+
const ctx = tryGetContext();
|
|
41
|
+
if (ctx) ctx.navigation.lastPromptShownUI = value;
|
|
42
|
+
}
|
|
43
|
+
async function runWithContextAsync(options, fn) {
|
|
44
|
+
const ctx = {
|
|
45
|
+
navigation: {
|
|
46
|
+
isFirstPrompt: false,
|
|
47
|
+
lastPromptShownUI: false
|
|
48
|
+
},
|
|
49
|
+
silent: options.silent ?? false
|
|
50
|
+
};
|
|
51
|
+
return cliStorage.run(ctx, fn);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/utils/errors.ts
|
|
56
|
+
var UserCancelledError = class extends Error {
|
|
57
|
+
constructor(message = "Operation cancelled") {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "UserCancelledError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var CLIError = class extends Error {
|
|
63
|
+
constructor(message) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = "CLIError";
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function exitWithError(message) {
|
|
69
|
+
if (isSilent()) throw new CLIError(message);
|
|
70
|
+
consola.error(pc.red(message));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
function exitCancelled(message = "Operation cancelled") {
|
|
74
|
+
if (isSilent()) throw new UserCancelledError(message);
|
|
75
|
+
cancel(pc.red(message));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
function handleError(error, fallbackMessage) {
|
|
79
|
+
const message = error instanceof Error ? error.message : fallbackMessage || String(error);
|
|
80
|
+
if (isSilent()) throw error instanceof Error ? error : new Error(message);
|
|
81
|
+
consola.error(pc.red(message));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
export { handleError as a, isSilent as c, setLastPromptShownUI as d, exitWithError as i, runWithContextAsync as l, UserCancelledError as n, didLastPromptShowUI as o, exitCancelled as r, isFirstPrompt as s, CLIError as t, setIsFirstPrompt as u };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { y as types_exports } from "./bts-config-BceXPcpI.mjs";
|
|
3
|
+
import { c as isSilent, i as exitWithError, t as CLIError } from "./errors-ns_o2OKg.mjs";
|
|
3
4
|
import pc from "picocolors";
|
|
4
5
|
import z from "zod";
|
|
5
6
|
import fs from "fs-extra";
|
|
@@ -59,6 +60,7 @@ const CreateCommandOptionsSchema = z.object({
|
|
|
59
60
|
examples: z.array(types_exports.ExamplesSchema).optional(),
|
|
60
61
|
git: z.boolean().optional(),
|
|
61
62
|
packageManager: types_exports.PackageManagerSchema.optional(),
|
|
63
|
+
workspaceShape: types_exports.WorkspaceShapeSchema.optional().describe("Workspace layout: monorepo (default) or single-app (flat root app; only for a thin self app)"),
|
|
62
64
|
install: z.boolean().optional(),
|
|
63
65
|
versionChannel: types_exports.VersionChannelSchema.optional().describe("Dependency version channel (stable, latest, beta)"),
|
|
64
66
|
dbSetup: types_exports.DatabaseSetupSchema.optional(),
|
|
@@ -121,6 +123,7 @@ const CreateCommandOptionsSchema = z.object({
|
|
|
121
123
|
goConfig: types_exports.GoConfigSchema.optional().describe("Go config management (viper, koanf)"),
|
|
122
124
|
goObservability: types_exports.GoObservabilitySchema.optional().describe("Go observability (opentelemetry)"),
|
|
123
125
|
javaWebFramework: types_exports.JavaWebFrameworkSchema.optional().describe("Java web framework (spring-boot, quarkus, none)"),
|
|
126
|
+
javaLanguage: types_exports.JavaLanguageSchema.optional().describe("JVM language (java, kotlin)"),
|
|
124
127
|
javaBuildTool: types_exports.JavaBuildToolSchema.optional().describe("Java build tool (maven, gradle, none)"),
|
|
125
128
|
javaOrm: types_exports.JavaOrmSchema.optional().describe("Java ORM/database (spring-data-jpa)"),
|
|
126
129
|
javaAuth: types_exports.JavaAuthSchema.optional().describe("Java auth (spring-security)"),
|
|
@@ -426,6 +429,10 @@ function validatePaymentsCompatibility(payments, auth, _backend, frontends = [])
|
|
|
426
429
|
const { web } = splitFrontends$1(frontends);
|
|
427
430
|
if (web.length === 0 && frontends.length > 0) exitWithError("Polar payments requires a web frontend or no frontend. Please select a web frontend or choose a different payments provider.");
|
|
428
431
|
}
|
|
432
|
+
if (payments === "revenuecat") {
|
|
433
|
+
const { native } = splitFrontends$1(frontends);
|
|
434
|
+
if (native.length === 0) exitWithError("RevenueCat payments requires a native frontend. Please select a native frontend or choose a different payments provider.");
|
|
435
|
+
}
|
|
429
436
|
}
|
|
430
437
|
function validateExamplesCompatibility(examples, backend, frontend, runtime, ai) {
|
|
431
438
|
const examplesArr = examples ?? [];
|
|
@@ -677,6 +684,14 @@ function validatePeerDependencies(config) {
|
|
|
677
684
|
|
|
678
685
|
//#endregion
|
|
679
686
|
//#region src/utils/config-validation.ts
|
|
687
|
+
const INTLAYER_COMPATIBLE_FRONTENDS = new Set([
|
|
688
|
+
"next",
|
|
689
|
+
"vinext",
|
|
690
|
+
"tanstack-router",
|
|
691
|
+
"tanstack-start",
|
|
692
|
+
"react-router",
|
|
693
|
+
"react-vite"
|
|
694
|
+
]);
|
|
680
695
|
function validateDatabaseOrmAuth(cfg, flags) {
|
|
681
696
|
const db = cfg.database;
|
|
682
697
|
const orm = cfg.orm;
|
|
@@ -938,7 +953,8 @@ function validateBackendNoneConstraints(config, providedFlags) {
|
|
|
938
953
|
if (has("database") && config.database !== "none") exitWithError("Backend 'none' requires '--database none'. Please remove the --database flag or set it to 'none'.");
|
|
939
954
|
if (has("orm") && config.orm !== "none") exitWithError("Backend 'none' requires '--orm none'. Please remove the --orm flag or set it to 'none'.");
|
|
940
955
|
if (has("api") && config.api !== "none") exitWithError("Backend 'none' requires '--api none'. Please remove the --api flag or set it to 'none'.");
|
|
941
|
-
|
|
956
|
+
const isNativeRevenueCat = config.payments === "revenuecat" && splitFrontends$1(config.frontend ?? []).native.length > 0;
|
|
957
|
+
if (has("payments") && config.payments !== "none" && !isNativeRevenueCat) exitWithError("Backend 'none' requires '--payments none'. Please remove the --payments flag or set it to 'none'.");
|
|
942
958
|
if (has("dbSetup") && config.dbSetup !== "none") exitWithError("Backend 'none' requires '--db-setup none'. Please remove the --db-setup flag or set it to 'none'.");
|
|
943
959
|
if (has("serverDeploy") && config.serverDeploy !== "none") exitWithError("Backend 'none' requires '--server-deploy none'. Please remove the --server-deploy flag or set it to 'none'.");
|
|
944
960
|
}
|
|
@@ -1019,23 +1035,44 @@ function validateApiConstraints(config, _options) {
|
|
|
1019
1035
|
});
|
|
1020
1036
|
if (!config.backend || ![
|
|
1021
1037
|
"hono",
|
|
1038
|
+
"effect",
|
|
1022
1039
|
"express",
|
|
1023
1040
|
"fastify",
|
|
1024
1041
|
"elysia"
|
|
1025
1042
|
].includes(config.backend)) incompatibilityError({
|
|
1026
|
-
message: `${apiDisplayName} currently supports Hono, Express, Fastify, and Elysia backends.`,
|
|
1043
|
+
message: `${apiDisplayName} currently supports Hono, Effect, Express, Fastify, and Elysia backends.`,
|
|
1027
1044
|
provided: {
|
|
1028
1045
|
api: config.api,
|
|
1029
1046
|
backend: config.backend ?? "none"
|
|
1030
1047
|
},
|
|
1031
1048
|
suggestions: [
|
|
1032
1049
|
"Use --backend hono",
|
|
1050
|
+
"Use --backend effect",
|
|
1033
1051
|
"Use --backend express",
|
|
1034
1052
|
"Use --backend fastify",
|
|
1035
1053
|
"Use --backend elysia"
|
|
1036
1054
|
]
|
|
1037
1055
|
});
|
|
1038
1056
|
}
|
|
1057
|
+
function validateEffectBackendConstraints(config) {
|
|
1058
|
+
if (config.backend !== "effect") return;
|
|
1059
|
+
if (config.effect !== "effect-full") missingRequirementError({
|
|
1060
|
+
message: "Effect backend requires Effect Platform + SQL services.",
|
|
1061
|
+
provided: {
|
|
1062
|
+
backend: "effect",
|
|
1063
|
+
effect: config.effect ?? "none"
|
|
1064
|
+
},
|
|
1065
|
+
suggestions: ["Use --effect effect-full"]
|
|
1066
|
+
});
|
|
1067
|
+
if (config.validation !== "effect-schema") missingRequirementError({
|
|
1068
|
+
message: "Effect backend requires Effect Schema validation.",
|
|
1069
|
+
provided: {
|
|
1070
|
+
backend: "effect",
|
|
1071
|
+
validation: config.validation ?? "none"
|
|
1072
|
+
},
|
|
1073
|
+
suggestions: ["Use --validation effect-schema"]
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1039
1076
|
function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set()) {
|
|
1040
1077
|
if (config.ecosystem !== "java") return;
|
|
1041
1078
|
const hasSpringBoot = config.javaWebFramework === "spring-boot";
|
|
@@ -1043,7 +1080,8 @@ function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set
|
|
|
1043
1080
|
const hasNoBuildTool = config.javaBuildTool === "none";
|
|
1044
1081
|
const hasJavaLibraries = (config.javaLibraries ?? []).some((library) => library !== "none");
|
|
1045
1082
|
const hasJavaTestingLibraries = (config.javaTestingLibraries ?? []).some((library) => library !== "none");
|
|
1046
|
-
const
|
|
1083
|
+
const hasJavaApi = (config.javaApi ?? "none") !== "none";
|
|
1084
|
+
const hasSpringOnlyFeatures = config.javaOrm !== "none" || config.javaAuth !== "none" || hasJavaLibraries || hasJavaApi;
|
|
1047
1085
|
if (hasNoBuildTool && hasJavaWebFramework) incompatibilityError({
|
|
1048
1086
|
message: "Java web frameworks require Maven or Gradle in the Java scaffold.",
|
|
1049
1087
|
provided: {
|
|
@@ -1059,9 +1097,10 @@ function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set
|
|
|
1059
1097
|
"java-build-tool": config.javaBuildTool ?? "none",
|
|
1060
1098
|
"java-orm": config.javaOrm ?? "none",
|
|
1061
1099
|
"java-auth": config.javaAuth ?? "none",
|
|
1100
|
+
"java-api": config.javaApi ?? "none",
|
|
1062
1101
|
"java-libraries": (config.javaLibraries ?? []).join(" ") || "none"
|
|
1063
1102
|
},
|
|
1064
|
-
suggestions: ["Use --java-web-framework spring-boot and a real build tool for Spring features", "Clear --java-orm, --java-auth, and --java-libraries when using plain Java or Quarkus"]
|
|
1103
|
+
suggestions: ["Use --java-web-framework spring-boot and a real build tool for Spring features", "Clear --java-orm, --java-auth, --java-api, and --java-libraries when using plain Java or Quarkus"]
|
|
1065
1104
|
});
|
|
1066
1105
|
if (hasNoBuildTool && hasJavaTestingLibraries) incompatibilityError({
|
|
1067
1106
|
message: "Java testing libraries require Maven or Gradle to manage test dependencies.",
|
|
@@ -1241,7 +1280,11 @@ function validateRateLimitConstraints(config) {
|
|
|
1241
1280
|
function validateSearchConstraints(config) {
|
|
1242
1281
|
if (!config.search || config.search === "none") return;
|
|
1243
1282
|
const ecosystem = config.ecosystem ?? "typescript";
|
|
1244
|
-
|
|
1283
|
+
const allowedSearch = {
|
|
1284
|
+
go: ["meilisearch", "bleve"],
|
|
1285
|
+
python: ["meilisearch", "elasticsearch"]
|
|
1286
|
+
}[ecosystem] ?? ["meilisearch"];
|
|
1287
|
+
if (ecosystem !== "typescript" && !allowedSearch.includes(config.search)) incompatibilityError({
|
|
1245
1288
|
message: "Only Meilisearch search is available for non-TypeScript ecosystems.",
|
|
1246
1289
|
provided: {
|
|
1247
1290
|
ecosystem,
|
|
@@ -1288,6 +1331,19 @@ function validatePythonApiConstraints(config) {
|
|
|
1288
1331
|
suggestions: ["Use --python-web-framework django with --python-api django-rest-framework or django-ninja", "Set --python-api none for FastAPI, Flask, Litestar, or no Python web framework"]
|
|
1289
1332
|
});
|
|
1290
1333
|
}
|
|
1334
|
+
function validateI18nConstraints(config) {
|
|
1335
|
+
if (config.i18n !== "intlayer") return;
|
|
1336
|
+
const { web } = splitFrontends$1(config.frontend ?? []);
|
|
1337
|
+
const unsupportedFrontend = web.find((frontend) => !INTLAYER_COMPATIBLE_FRONTENDS.has(frontend));
|
|
1338
|
+
if (web.length === 0 || unsupportedFrontend) incompatibilityError({
|
|
1339
|
+
message: "Intlayer i18n is currently wired only for Next.js, Vinext, TanStack Router/Start, React Router, and React + Vite frontends.",
|
|
1340
|
+
provided: {
|
|
1341
|
+
frontend: web.join(" ") || "none",
|
|
1342
|
+
i18n: "intlayer"
|
|
1343
|
+
},
|
|
1344
|
+
suggestions: ["Use --frontend next, vinext, tanstack-router, tanstack-start, react-router, or react-vite", "Set --i18n none or choose another i18n provider for this frontend"]
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1291
1347
|
function validateFullConfig(config, providedFlags, options) {
|
|
1292
1348
|
if (config.stackParts && !options.yolo) {
|
|
1293
1349
|
const graphValidation = (0, types_exports.validateStackParts)(config.stackParts);
|
|
@@ -1302,6 +1358,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1302
1358
|
validateEncoreConstraints(config, providedFlags);
|
|
1303
1359
|
validateAdonisJSConstraints(config, providedFlags);
|
|
1304
1360
|
validateBackendConstraints(config, providedFlags, options);
|
|
1361
|
+
validateEffectBackendConstraints(config);
|
|
1305
1362
|
validateFrontendConstraints(config, providedFlags);
|
|
1306
1363
|
validateApiConstraints(config, options);
|
|
1307
1364
|
validatePythonApiConstraints(config);
|
|
@@ -1312,6 +1369,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1312
1369
|
validateSearchConstraints(config);
|
|
1313
1370
|
validateJavaConstraints(config, providedFlags);
|
|
1314
1371
|
validateElixirConstraints(config);
|
|
1372
|
+
validateI18nConstraints(config);
|
|
1315
1373
|
const hasGraphBackend = config.stackParts?.some((part) => part.role === "backend" && !part.ownerPartId && part.source !== "provided" && part.ecosystem !== "typescript" && part.ecosystem !== "react-native" && part.ecosystem !== "universal");
|
|
1316
1374
|
if (!(providedFlags.has("serverDeploy") && !options.yes && !options.part?.length && options.ecosystem === void 0 && options.backend === void 0 && config.stackParts === void 0)) validateServerDeployRequiresBackend(config.serverDeploy, config.backend, Boolean(hasGraphBackend));
|
|
1317
1375
|
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
@@ -1368,6 +1426,7 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
1368
1426
|
}
|
|
1369
1427
|
validateEcosystemAuthCompatibility(config);
|
|
1370
1428
|
validateDatabaseOrmAuth(config);
|
|
1429
|
+
validateEffectBackendConstraints(config);
|
|
1371
1430
|
if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
|
|
1372
1431
|
validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
|
|
1373
1432
|
validatePythonApiConstraints(config);
|
|
@@ -1378,6 +1437,7 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
1378
1437
|
validateSearchConstraints(config);
|
|
1379
1438
|
validateJavaConstraints(config);
|
|
1380
1439
|
validateElixirConstraints(config);
|
|
1440
|
+
validateI18nConstraints(config);
|
|
1381
1441
|
validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
|
|
1382
1442
|
if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database);
|
|
1383
1443
|
validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
|