vela 0.15.5 → 0.15.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/bin.js +177 -154
- package/dist/bin.js.map +4 -4
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -21,7 +21,7 @@ import pc46 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.15.
|
|
24
|
+
version: "0.15.6",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -73,7 +73,7 @@ var package_default = {
|
|
|
73
73
|
pocketbase: "^0.28.0",
|
|
74
74
|
"pocketbase-server": "^0.40.5-beta.5",
|
|
75
75
|
stripe: "^22.6.2",
|
|
76
|
-
sv: "~1.
|
|
76
|
+
sv: "~1.1.1",
|
|
77
77
|
svelte: "^5.56.10",
|
|
78
78
|
tar: "^7.5.22",
|
|
79
79
|
tinyexec: "^1.3.0",
|
|
@@ -601,10 +601,10 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
|
|
|
601
601
|
// src/commands/bless.ts
|
|
602
602
|
import fs18 from "node:fs";
|
|
603
603
|
import path16 from "node:path";
|
|
604
|
-
import
|
|
604
|
+
import process9 from "node:process";
|
|
605
605
|
import * as v4 from "valibot";
|
|
606
606
|
import { Command } from "commander";
|
|
607
|
-
import * as
|
|
607
|
+
import * as p6 from "@clack/prompts";
|
|
608
608
|
import pc3 from "picocolors";
|
|
609
609
|
import { resolveCommand as resolveCommand2 } from "package-manager-detector";
|
|
610
610
|
|
|
@@ -1533,9 +1533,122 @@ function quoteEnvValue(value) {
|
|
|
1533
1533
|
}
|
|
1534
1534
|
|
|
1535
1535
|
// src/lib/superuser.ts
|
|
1536
|
-
import
|
|
1536
|
+
import process8 from "node:process";
|
|
1537
1537
|
import * as v3 from "valibot";
|
|
1538
|
+
import * as p4 from "@clack/prompts";
|
|
1539
|
+
|
|
1540
|
+
// src/lib/providers.ts
|
|
1541
|
+
import process7 from "node:process";
|
|
1538
1542
|
import * as p3 from "@clack/prompts";
|
|
1543
|
+
import { bySlug } from "@velastack/patterns";
|
|
1544
|
+
function capabilityName(slug2) {
|
|
1545
|
+
return slug2.replace(/^enable-/, "");
|
|
1546
|
+
}
|
|
1547
|
+
function choices(providers) {
|
|
1548
|
+
return `--provider <${providers.map((provider) => provider.id).join("|")}>`;
|
|
1549
|
+
}
|
|
1550
|
+
function unknownProviderMessage(name, raw, providers) {
|
|
1551
|
+
return [
|
|
1552
|
+
`Unknown provider "${raw}" for ${name}.`,
|
|
1553
|
+
"",
|
|
1554
|
+
"Available providers:",
|
|
1555
|
+
...providers.map((provider) => ` ${provider.id}`)
|
|
1556
|
+
].join("\n");
|
|
1557
|
+
}
|
|
1558
|
+
function decideProvider(request) {
|
|
1559
|
+
const { patternName, providers, flagValue, interactive } = request;
|
|
1560
|
+
if (flagValue !== void 0) {
|
|
1561
|
+
const provider = providers.find((candidate) => candidate.id === flagValue);
|
|
1562
|
+
if (!provider) {
|
|
1563
|
+
return { kind: "error", message: unknownProviderMessage(patternName, flagValue, providers) };
|
|
1564
|
+
}
|
|
1565
|
+
return { kind: "use", provider };
|
|
1566
|
+
}
|
|
1567
|
+
if (interactive) return { kind: "prompt" };
|
|
1568
|
+
return {
|
|
1569
|
+
kind: "error",
|
|
1570
|
+
message: `Choose ${article(patternName)} ${patternName} provider: pass ${choices(providers)}. There is no terminal to ask on.`
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
function article(word) {
|
|
1574
|
+
return /^[aeiou]/i.test(word) ? "an" : "a";
|
|
1575
|
+
}
|
|
1576
|
+
function isInteractive() {
|
|
1577
|
+
return Boolean(process7.stdout.isTTY) && !process7.env.CI;
|
|
1578
|
+
}
|
|
1579
|
+
function providerFlagInArgv(argv) {
|
|
1580
|
+
return argv.some((arg) => arg === "--provider" || arg.startsWith("--provider="));
|
|
1581
|
+
}
|
|
1582
|
+
function checkProviderInput(pattern, argv, input) {
|
|
1583
|
+
const providers = pattern.providers ?? [];
|
|
1584
|
+
if (providers.length > 0) {
|
|
1585
|
+
if (typeof input.provider !== "string" || input.provider.length === 0) {
|
|
1586
|
+
throw new Error(`${pattern.title} needs a provider. Pass ${choices(providers)}.`);
|
|
1587
|
+
}
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
if (providerFlagInArgv(argv)) {
|
|
1591
|
+
throw new Error(`${pattern.title} does not support --provider.`);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
async function resolveProvider(slug2, flagValue) {
|
|
1595
|
+
const pattern = bySlug[slug2];
|
|
1596
|
+
const providers = pattern.providers ?? [];
|
|
1597
|
+
if (providers.length === 0) {
|
|
1598
|
+
throw new Error(`${pattern.title} does not support --provider.`);
|
|
1599
|
+
}
|
|
1600
|
+
const patternName = capabilityName(slug2);
|
|
1601
|
+
const decision = decideProvider({
|
|
1602
|
+
patternName,
|
|
1603
|
+
providers,
|
|
1604
|
+
flagValue,
|
|
1605
|
+
interactive: isInteractive()
|
|
1606
|
+
});
|
|
1607
|
+
if (decision.kind === "error") throw new Error(decision.message);
|
|
1608
|
+
if (decision.kind === "use") return decision.provider;
|
|
1609
|
+
const selected = await p3.select({
|
|
1610
|
+
message: `Select ${patternName} provider`,
|
|
1611
|
+
options: providers.map((provider) => ({ value: provider.id, label: provider.label }))
|
|
1612
|
+
});
|
|
1613
|
+
if (p3.isCancel(selected)) {
|
|
1614
|
+
p3.cancel("Operation cancelled.");
|
|
1615
|
+
process7.exit(0);
|
|
1616
|
+
}
|
|
1617
|
+
return providers.find((provider) => provider.id === selected);
|
|
1618
|
+
}
|
|
1619
|
+
async function collectProviderEnv(provider) {
|
|
1620
|
+
const values = {};
|
|
1621
|
+
const interactive = isInteractive();
|
|
1622
|
+
for (const variable of provider.env ?? []) {
|
|
1623
|
+
const existing = process7.env[variable.key];
|
|
1624
|
+
if (existing) {
|
|
1625
|
+
values[variable.key] = existing;
|
|
1626
|
+
continue;
|
|
1627
|
+
}
|
|
1628
|
+
if (!interactive) {
|
|
1629
|
+
values[variable.key] = variable.default ?? "";
|
|
1630
|
+
continue;
|
|
1631
|
+
}
|
|
1632
|
+
const value = variable.secret ? await p3.password({
|
|
1633
|
+
message: variable.placeholder ? `${variable.label} (${variable.placeholder})` : variable.label
|
|
1634
|
+
}) : await p3.text({
|
|
1635
|
+
message: variable.label,
|
|
1636
|
+
placeholder: variable.placeholder,
|
|
1637
|
+
initialValue: variable.default
|
|
1638
|
+
});
|
|
1639
|
+
if (p3.isCancel(value)) {
|
|
1640
|
+
p3.cancel("Operation cancelled.");
|
|
1641
|
+
process7.exit(0);
|
|
1642
|
+
}
|
|
1643
|
+
values[variable.key] = (value ?? "").trim();
|
|
1644
|
+
}
|
|
1645
|
+
return values;
|
|
1646
|
+
}
|
|
1647
|
+
function missingEnvKeys(provider, values) {
|
|
1648
|
+
return (provider.env ?? []).filter((variable) => !(values[variable.key] ?? "").trim() && !variable.default).map((variable) => variable.key);
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
// src/lib/superuser.ts
|
|
1539
1652
|
var emailFlag = v3.optional(v3.pipe(v3.string(), v3.email("must be a valid email address")));
|
|
1540
1653
|
var passwordFlag = v3.optional(
|
|
1541
1654
|
v3.pipe(v3.string(), v3.minLength(8, "must be at least 8 characters long"))
|
|
@@ -1564,17 +1677,23 @@ function decideSuperuser(flags, env2, interactive) {
|
|
|
1564
1677
|
message: `Pass ${missing.join(" and ")} for the PocketBase admin user. There is no terminal to ask on.`
|
|
1565
1678
|
};
|
|
1566
1679
|
}
|
|
1680
|
+
async function requireSuperuser(flags, env2, onCancel2) {
|
|
1681
|
+
const decision = decideSuperuser(flags, env2, isInteractive());
|
|
1682
|
+
if (decision.kind === "error") throw new Error(decision.message);
|
|
1683
|
+
if (decision.kind === "use") return decision.credentials;
|
|
1684
|
+
return promptSuperuser(decision.known, onCancel2);
|
|
1685
|
+
}
|
|
1567
1686
|
function superuserFromEnv() {
|
|
1568
|
-
const email2 =
|
|
1569
|
-
const password9 =
|
|
1687
|
+
const email2 = process8.env.POCKETBASE_SUPERUSER_EMAIL?.trim();
|
|
1688
|
+
const password9 = process8.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
1570
1689
|
return { ...email2 ? { email: email2 } : {}, ...password9 ? { password: password9 } : {} };
|
|
1571
1690
|
}
|
|
1572
1691
|
function promptSuperuser(known, onCancel2) {
|
|
1573
|
-
return
|
|
1692
|
+
return p4.group(
|
|
1574
1693
|
{
|
|
1575
1694
|
email: () => {
|
|
1576
1695
|
if (known.email) return Promise.resolve(known.email);
|
|
1577
|
-
return
|
|
1696
|
+
return p4.text({
|
|
1578
1697
|
message: "Enter an email for the admin user",
|
|
1579
1698
|
initialValue: "admin@example.com",
|
|
1580
1699
|
validate: (value) => !value ? "Email is required" : !value.includes("@") ? "Invalid email" : void 0
|
|
@@ -1582,7 +1701,7 @@ function promptSuperuser(known, onCancel2) {
|
|
|
1582
1701
|
},
|
|
1583
1702
|
password: () => {
|
|
1584
1703
|
if (known.password) return Promise.resolve(known.password);
|
|
1585
|
-
return
|
|
1704
|
+
return p4.password({
|
|
1586
1705
|
message: "Enter a password for the admin user (at least 8 characters)",
|
|
1587
1706
|
validate: (value) => !value ? "Password is required" : value.length < 8 ? "Password must be at least 8 characters long" : void 0
|
|
1588
1707
|
});
|
|
@@ -2490,7 +2609,7 @@ async function ensureEnvDeclarations(root, specs) {
|
|
|
2490
2609
|
}
|
|
2491
2610
|
|
|
2492
2611
|
// src/lib/result-report.ts
|
|
2493
|
-
import * as
|
|
2612
|
+
import * as p5 from "@clack/prompts";
|
|
2494
2613
|
function reportResult(report5) {
|
|
2495
2614
|
const sections = [
|
|
2496
2615
|
["Files created", report5.filesCreated],
|
|
@@ -2514,20 +2633,20 @@ function reportResult(report5) {
|
|
|
2514
2633
|
}
|
|
2515
2634
|
const failures = report5.failures ?? [];
|
|
2516
2635
|
if (body.length > 0) {
|
|
2517
|
-
|
|
2636
|
+
p5.log.success(`${report5.summary}
|
|
2518
2637
|
|
|
2519
2638
|
${body.join("\n")}`);
|
|
2520
2639
|
} else if (failures.length === 0) {
|
|
2521
|
-
|
|
2640
|
+
p5.log.success(report5.summary);
|
|
2522
2641
|
}
|
|
2523
2642
|
for (const failure of failures) {
|
|
2524
2643
|
const headline = failure.status === "not-found" ? `Could not find ${failure.path}` : `Could not update ${failure.path}`;
|
|
2525
|
-
|
|
2644
|
+
p5.log.warn(failure.message ? `${headline}
|
|
2526
2645
|
|
|
2527
2646
|
${failure.message}` : headline);
|
|
2528
2647
|
}
|
|
2529
2648
|
if (report5.nextSteps && report5.nextSteps.length > 0) {
|
|
2530
|
-
|
|
2649
|
+
p5.note(report5.nextSteps.map((s) => `- ${s}`).join("\n"), "Next steps", {
|
|
2531
2650
|
format: (line) => line
|
|
2532
2651
|
});
|
|
2533
2652
|
}
|
|
@@ -2537,7 +2656,11 @@ ${failure.message}` : headline);
|
|
|
2537
2656
|
function optionsSchema() {
|
|
2538
2657
|
const templates = projectTemplateNames({ backend: true });
|
|
2539
2658
|
return v4.strictObject({
|
|
2540
|
-
install
|
|
2659
|
+
// Unset when neither `--install` nor `--no-install` is passed (commander 15).
|
|
2660
|
+
install: v4.optional(
|
|
2661
|
+
v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
2662
|
+
true
|
|
2663
|
+
),
|
|
2541
2664
|
template: v4.optional(v4.picklist(templates, `must be one of: ${templates.join(", ")}`)),
|
|
2542
2665
|
email: emailFlag,
|
|
2543
2666
|
password: passwordFlag,
|
|
@@ -2586,9 +2709,9 @@ async function blessProject(cwdArg, options) {
|
|
|
2586
2709
|
assertKit3(projectPath, "vela bless");
|
|
2587
2710
|
assertNotAlreadyBlessed(projectPath);
|
|
2588
2711
|
const templateDir = findProjectTemplate(options.template ?? DEFAULT_TEMPLATE).dir;
|
|
2589
|
-
const { email: email2, password: password9 } = await
|
|
2590
|
-
|
|
2591
|
-
|
|
2712
|
+
const { email: email2, password: password9 } = await requireSuperuser(options, {}, () => {
|
|
2713
|
+
p6.cancel("Operation cancelled.");
|
|
2714
|
+
process9.exit(0);
|
|
2592
2715
|
});
|
|
2593
2716
|
mergeDependencies(projectPath, templateDir);
|
|
2594
2717
|
copyVelaOnlyFiles(templateDir, projectPath);
|
|
@@ -2599,7 +2722,7 @@ async function blessProject(cwdArg, options) {
|
|
|
2599
2722
|
mergeConfigFiles(projectPath);
|
|
2600
2723
|
mergeAppDts(templateDir, projectPath);
|
|
2601
2724
|
maybeReplaceRoutes(projectPath, templateDir, options);
|
|
2602
|
-
|
|
2725
|
+
p6.log.success("Vela files in place");
|
|
2603
2726
|
let packageManager2;
|
|
2604
2727
|
if (options.install !== false) {
|
|
2605
2728
|
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
@@ -2609,7 +2732,7 @@ async function blessProject(cwdArg, options) {
|
|
|
2609
2732
|
packageManager2 = pm;
|
|
2610
2733
|
}
|
|
2611
2734
|
}
|
|
2612
|
-
|
|
2735
|
+
p6.log.step("Initializing PocketBase...");
|
|
2613
2736
|
await createSuperuser(projectPath, email2, password9);
|
|
2614
2737
|
writeEnvFile(
|
|
2615
2738
|
projectPath,
|
|
@@ -2619,12 +2742,12 @@ async function blessProject(cwdArg, options) {
|
|
|
2619
2742
|
},
|
|
2620
2743
|
["PocketBase superuser credentials \u2014 used by `vela` commands"]
|
|
2621
2744
|
);
|
|
2622
|
-
|
|
2745
|
+
p6.log.success("PocketBase initialized");
|
|
2623
2746
|
printNextSteps(projectPath, packageManager2);
|
|
2624
2747
|
}
|
|
2625
2748
|
function ensureShadcnCss(projectPath) {
|
|
2626
2749
|
if (ensureShadcnImport(path16.join(projectPath, "src", "app.css"))) {
|
|
2627
|
-
|
|
2750
|
+
p6.log.info(
|
|
2628
2751
|
"src/app.css: added the shadcn-svelte/tailwind.css import its registry components rely on."
|
|
2629
2752
|
);
|
|
2630
2753
|
}
|
|
@@ -2632,7 +2755,7 @@ function ensureShadcnCss(projectPath) {
|
|
|
2632
2755
|
function hintComponentsJson(projectPath) {
|
|
2633
2756
|
const config = readComponentsJson(projectPath);
|
|
2634
2757
|
if (!config) return;
|
|
2635
|
-
for (const hint of componentsJsonHints(config))
|
|
2758
|
+
for (const hint of componentsJsonHints(config)) p6.log.warn(hint);
|
|
2636
2759
|
}
|
|
2637
2760
|
function resolveProjectPath(cwdArg) {
|
|
2638
2761
|
const projectPath = path16.resolve(cwdArg);
|
|
@@ -2671,14 +2794,14 @@ function mergeDependencies(projectPath, templateDir) {
|
|
|
2671
2794
|
dropTemplateAdapters(userPkg, templatePkg)
|
|
2672
2795
|
);
|
|
2673
2796
|
const pinned = applyTemplatePins(merged, templatePkg, conflicts);
|
|
2674
|
-
if (ensureLibImports(merged))
|
|
2797
|
+
if (ensureLibImports(merged)) p6.log.info("package.json: added the #lib imports.");
|
|
2675
2798
|
writePackageJson(userPkgPath, merged);
|
|
2676
2799
|
if (pinned.length > 0) {
|
|
2677
|
-
|
|
2800
|
+
p6.log.info(`Pinned what SvelteKit 3 needs exactly:
|
|
2678
2801
|
${pinned.map((l) => ` ${l}`).join("\n")}`);
|
|
2679
2802
|
}
|
|
2680
2803
|
if (added.length > 0) {
|
|
2681
|
-
|
|
2804
|
+
p6.log.info(
|
|
2682
2805
|
`Added ${added.length} entries to package.json (${summarize(added.map((c) => c.name))}).`
|
|
2683
2806
|
);
|
|
2684
2807
|
}
|
|
@@ -2686,14 +2809,14 @@ ${pinned.map((l) => ` ${l}`).join("\n")}`);
|
|
|
2686
2809
|
const lines = replaced.map(
|
|
2687
2810
|
(c) => ` script ${pc3.bold(c.name)}: ${pc3.gray(c.userValue ?? "")} \u2192 ${pc3.cyan(c.templateValue)}`
|
|
2688
2811
|
);
|
|
2689
|
-
|
|
2812
|
+
p6.log.info(`Updated ${replaced.length} script(s):
|
|
2690
2813
|
${lines.join("\n")}`);
|
|
2691
2814
|
}
|
|
2692
2815
|
if (conflicts.length > 0) {
|
|
2693
2816
|
const lines = conflicts.map(
|
|
2694
2817
|
(c) => ` dep ${pc3.bold(c.name)}: kept ${pc3.cyan(c.userValue ?? "")} (template wants ${pc3.gray(c.templateValue)})`
|
|
2695
2818
|
);
|
|
2696
|
-
|
|
2819
|
+
p6.log.warn(`Kept ${conflicts.length} dependency version(s) on conflict:
|
|
2697
2820
|
${lines.join("\n")}`);
|
|
2698
2821
|
}
|
|
2699
2822
|
}
|
|
@@ -2734,9 +2857,9 @@ function applyTemplatePins(merged, template, conflicts) {
|
|
|
2734
2857
|
async function declareEnvVars(projectPath) {
|
|
2735
2858
|
const outcome = await ensureEnvDeclarations(projectPath, VELA_ENV_VARS);
|
|
2736
2859
|
if (outcome.failure) {
|
|
2737
|
-
|
|
2860
|
+
p6.log.warn(`${outcome.file}: ${outcome.failure}`);
|
|
2738
2861
|
} else if (outcome.changed) {
|
|
2739
|
-
|
|
2862
|
+
p6.log.info(`${outcome.file}: declared ${outcome.declared.join(", ")}.`);
|
|
2740
2863
|
}
|
|
2741
2864
|
}
|
|
2742
2865
|
function copyVelaOnlyFiles(templateDir, projectPath) {
|
|
@@ -2765,7 +2888,7 @@ function writeSiteFile(templateDir, projectPath) {
|
|
|
2765
2888
|
const dest = path16.join(projectPath, SITE_FILE);
|
|
2766
2889
|
if (!fs18.existsSync(source)) return;
|
|
2767
2890
|
if (fs18.existsSync(dest)) {
|
|
2768
|
-
|
|
2891
|
+
p6.log.info(
|
|
2769
2892
|
`Kept your ${pc3.bold(SITE_FILE)}. Vela's layouts read ${pc3.cyan("name")} and ${pc3.cyan("url")} from its ${pc3.cyan("site")} export.`
|
|
2770
2893
|
);
|
|
2771
2894
|
return;
|
|
@@ -2780,13 +2903,13 @@ function writeSiteFile(templateDir, projectPath) {
|
|
|
2780
2903
|
cliVersion: package_default.version
|
|
2781
2904
|
})
|
|
2782
2905
|
);
|
|
2783
|
-
|
|
2906
|
+
p6.log.info(`Wrote ${pc3.bold(SITE_FILE)}, naming the app ${pc3.cyan(appName)}. Edit it to rename.`);
|
|
2784
2907
|
}
|
|
2785
2908
|
function reportKeptFiles(kept) {
|
|
2786
2909
|
if (kept.length === 0) return;
|
|
2787
2910
|
const padding = Math.max(...kept.map((f) => f.path.length));
|
|
2788
2911
|
const lines = kept.map((f) => ` ${pc3.bold(f.path.padEnd(padding))} ${pc3.gray(f.adds)}`);
|
|
2789
|
-
|
|
2912
|
+
p6.log.info(
|
|
2790
2913
|
`Kept ${kept.length} file(s) you already had. Merge by hand to pick up what vela adds:
|
|
2791
2914
|
${lines.join("\n")}`
|
|
2792
2915
|
);
|
|
@@ -2814,11 +2937,11 @@ function mergeConfigFiles(projectPath) {
|
|
|
2814
2937
|
];
|
|
2815
2938
|
for (const [name, outcome] of outcomes) {
|
|
2816
2939
|
if (outcome.applied) {
|
|
2817
|
-
|
|
2940
|
+
p6.log.info(`${name}: ${outcome.reason}`);
|
|
2818
2941
|
continue;
|
|
2819
2942
|
}
|
|
2820
2943
|
if (outcome.snippet) {
|
|
2821
|
-
|
|
2944
|
+
p6.log.warn(
|
|
2822
2945
|
`${name}: ${outcome.reason}
|
|
2823
2946
|
${pc3.gray("Add this manually:")}
|
|
2824
2947
|
${pc3.cyan(outcome.snippet)}`
|
|
@@ -2845,7 +2968,7 @@ function mergeAppDts(templateDir, projectPath) {
|
|
|
2845
2968
|
`;
|
|
2846
2969
|
const match = current.match(/declare global\s*\{\s*\n/);
|
|
2847
2970
|
if (!match || match.index === void 0) {
|
|
2848
|
-
|
|
2971
|
+
p6.log.warn(
|
|
2849
2972
|
`src/app.d.ts: non-standard shape \u2014 add this namespace manually:
|
|
2850
2973
|
${pc3.cyan(block)}`
|
|
2851
2974
|
);
|
|
@@ -2857,11 +2980,11 @@ ${pc3.cyan(block)}`
|
|
|
2857
2980
|
}
|
|
2858
2981
|
function maybeReplaceRoutes(projectPath, templateDir, options) {
|
|
2859
2982
|
if (options.skipRoutes) {
|
|
2860
|
-
|
|
2983
|
+
p6.log.info("Skipping src/routes (--skip-routes).");
|
|
2861
2984
|
return;
|
|
2862
2985
|
}
|
|
2863
2986
|
if (!options.forceRoutes && !isVanillaRoutes(projectPath)) {
|
|
2864
|
-
|
|
2987
|
+
p6.log.info("Leaving src/routes alone (looks customized).");
|
|
2865
2988
|
return;
|
|
2866
2989
|
}
|
|
2867
2990
|
const target = path16.join(projectPath, "src", "routes");
|
|
@@ -2871,14 +2994,14 @@ function maybeReplaceRoutes(projectPath, templateDir, options) {
|
|
|
2871
2994
|
recursive: true,
|
|
2872
2995
|
filter: (s) => path16.basename(s) !== ".DS_Store"
|
|
2873
2996
|
});
|
|
2874
|
-
|
|
2997
|
+
p6.log.success("Replaced src/routes with the vela template.");
|
|
2875
2998
|
}
|
|
2876
2999
|
function summarize(names) {
|
|
2877
3000
|
if (names.length <= 4) return names.join(", ");
|
|
2878
3001
|
return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
|
|
2879
3002
|
}
|
|
2880
3003
|
function printNextSteps(projectPath, packageManager2) {
|
|
2881
|
-
const relative = path16.relative(
|
|
3004
|
+
const relative = path16.relative(process9.cwd(), projectPath);
|
|
2882
3005
|
const pm = packageManager2 ?? getUserAgent() ?? "npm";
|
|
2883
3006
|
const nextSteps = [];
|
|
2884
3007
|
if (relative !== "") {
|
|
@@ -2910,117 +3033,6 @@ import { Command as Command3 } from "commander";
|
|
|
2910
3033
|
import * as p10 from "@clack/prompts";
|
|
2911
3034
|
import { detect as detect5, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
2912
3035
|
|
|
2913
|
-
// src/lib/providers.ts
|
|
2914
|
-
import process9 from "node:process";
|
|
2915
|
-
import * as p6 from "@clack/prompts";
|
|
2916
|
-
import { bySlug } from "@velastack/patterns";
|
|
2917
|
-
function capabilityName(slug2) {
|
|
2918
|
-
return slug2.replace(/^enable-/, "");
|
|
2919
|
-
}
|
|
2920
|
-
function choices(providers) {
|
|
2921
|
-
return `--provider <${providers.map((provider) => provider.id).join("|")}>`;
|
|
2922
|
-
}
|
|
2923
|
-
function unknownProviderMessage(name, raw, providers) {
|
|
2924
|
-
return [
|
|
2925
|
-
`Unknown provider "${raw}" for ${name}.`,
|
|
2926
|
-
"",
|
|
2927
|
-
"Available providers:",
|
|
2928
|
-
...providers.map((provider) => ` ${provider.id}`)
|
|
2929
|
-
].join("\n");
|
|
2930
|
-
}
|
|
2931
|
-
function decideProvider(request) {
|
|
2932
|
-
const { patternName, providers, flagValue, interactive } = request;
|
|
2933
|
-
if (flagValue !== void 0) {
|
|
2934
|
-
const provider = providers.find((candidate) => candidate.id === flagValue);
|
|
2935
|
-
if (!provider) {
|
|
2936
|
-
return { kind: "error", message: unknownProviderMessage(patternName, flagValue, providers) };
|
|
2937
|
-
}
|
|
2938
|
-
return { kind: "use", provider };
|
|
2939
|
-
}
|
|
2940
|
-
if (interactive) return { kind: "prompt" };
|
|
2941
|
-
return {
|
|
2942
|
-
kind: "error",
|
|
2943
|
-
message: `Choose ${article(patternName)} ${patternName} provider: pass ${choices(providers)}. There is no terminal to ask on.`
|
|
2944
|
-
};
|
|
2945
|
-
}
|
|
2946
|
-
function article(word) {
|
|
2947
|
-
return /^[aeiou]/i.test(word) ? "an" : "a";
|
|
2948
|
-
}
|
|
2949
|
-
function isInteractive() {
|
|
2950
|
-
return Boolean(process9.stdout.isTTY) && !process9.env.CI;
|
|
2951
|
-
}
|
|
2952
|
-
function providerFlagInArgv(argv) {
|
|
2953
|
-
return argv.some((arg) => arg === "--provider" || arg.startsWith("--provider="));
|
|
2954
|
-
}
|
|
2955
|
-
function checkProviderInput(pattern, argv, input) {
|
|
2956
|
-
const providers = pattern.providers ?? [];
|
|
2957
|
-
if (providers.length > 0) {
|
|
2958
|
-
if (typeof input.provider !== "string" || input.provider.length === 0) {
|
|
2959
|
-
throw new Error(`${pattern.title} needs a provider. Pass ${choices(providers)}.`);
|
|
2960
|
-
}
|
|
2961
|
-
return;
|
|
2962
|
-
}
|
|
2963
|
-
if (providerFlagInArgv(argv)) {
|
|
2964
|
-
throw new Error(`${pattern.title} does not support --provider.`);
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
|
-
async function resolveProvider(slug2, flagValue) {
|
|
2968
|
-
const pattern = bySlug[slug2];
|
|
2969
|
-
const providers = pattern.providers ?? [];
|
|
2970
|
-
if (providers.length === 0) {
|
|
2971
|
-
throw new Error(`${pattern.title} does not support --provider.`);
|
|
2972
|
-
}
|
|
2973
|
-
const patternName = capabilityName(slug2);
|
|
2974
|
-
const decision = decideProvider({
|
|
2975
|
-
patternName,
|
|
2976
|
-
providers,
|
|
2977
|
-
flagValue,
|
|
2978
|
-
interactive: isInteractive()
|
|
2979
|
-
});
|
|
2980
|
-
if (decision.kind === "error") throw new Error(decision.message);
|
|
2981
|
-
if (decision.kind === "use") return decision.provider;
|
|
2982
|
-
const selected = await p6.select({
|
|
2983
|
-
message: `Select ${patternName} provider`,
|
|
2984
|
-
options: providers.map((provider) => ({ value: provider.id, label: provider.label }))
|
|
2985
|
-
});
|
|
2986
|
-
if (p6.isCancel(selected)) {
|
|
2987
|
-
p6.cancel("Operation cancelled.");
|
|
2988
|
-
process9.exit(0);
|
|
2989
|
-
}
|
|
2990
|
-
return providers.find((provider) => provider.id === selected);
|
|
2991
|
-
}
|
|
2992
|
-
async function collectProviderEnv(provider) {
|
|
2993
|
-
const values = {};
|
|
2994
|
-
const interactive = isInteractive();
|
|
2995
|
-
for (const variable of provider.env ?? []) {
|
|
2996
|
-
const existing = process9.env[variable.key];
|
|
2997
|
-
if (existing) {
|
|
2998
|
-
values[variable.key] = existing;
|
|
2999
|
-
continue;
|
|
3000
|
-
}
|
|
3001
|
-
if (!interactive) {
|
|
3002
|
-
values[variable.key] = variable.default ?? "";
|
|
3003
|
-
continue;
|
|
3004
|
-
}
|
|
3005
|
-
const value = variable.secret ? await p6.password({
|
|
3006
|
-
message: variable.placeholder ? `${variable.label} (${variable.placeholder})` : variable.label
|
|
3007
|
-
}) : await p6.text({
|
|
3008
|
-
message: variable.label,
|
|
3009
|
-
placeholder: variable.placeholder,
|
|
3010
|
-
initialValue: variable.default
|
|
3011
|
-
});
|
|
3012
|
-
if (p6.isCancel(value)) {
|
|
3013
|
-
p6.cancel("Operation cancelled.");
|
|
3014
|
-
process9.exit(0);
|
|
3015
|
-
}
|
|
3016
|
-
values[variable.key] = (value ?? "").trim();
|
|
3017
|
-
}
|
|
3018
|
-
return values;
|
|
3019
|
-
}
|
|
3020
|
-
function missingEnvKeys(provider, values) {
|
|
3021
|
-
return (provider.env ?? []).filter((variable) => !(values[variable.key] ?? "").trim() && !variable.default).map((variable) => variable.key);
|
|
3022
|
-
}
|
|
3023
|
-
|
|
3024
3036
|
// src/lib/link-on-create.ts
|
|
3025
3037
|
var FREE_CMS_HINT = "Get a free CMS at https://velastack.dev";
|
|
3026
3038
|
var PROJECT_ID_RE = /^[a-z0-9]{15}$/;
|
|
@@ -5532,7 +5544,13 @@ function optionsSchema2(listing) {
|
|
|
5532
5544
|
choices2 += ` (could not reach the template registry: ${listing.registryError})`;
|
|
5533
5545
|
}
|
|
5534
5546
|
return v5.strictObject({
|
|
5535
|
-
install
|
|
5547
|
+
// `--no-install` and `--install <pm>` share a key, and commander 15 leaves it
|
|
5548
|
+
// unset when neither is passed: installing with the detected package
|
|
5549
|
+
// manager is the default.
|
|
5550
|
+
install: v5.optional(
|
|
5551
|
+
v5.union([v5.boolean(), v5.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
5552
|
+
true
|
|
5553
|
+
),
|
|
5536
5554
|
template: v5.optional(v5.picklist(names, choices2)),
|
|
5537
5555
|
name: v5.optional(v5.pipe(v5.string(), v5.trim(), v5.minLength(1, "must not be empty"))),
|
|
5538
5556
|
email: emailFlag,
|
|
@@ -5688,9 +5706,12 @@ async function resolveCreatableTemplate(template) {
|
|
|
5688
5706
|
return resolved;
|
|
5689
5707
|
}
|
|
5690
5708
|
async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
|
|
5709
|
+
const interactive = isInteractive();
|
|
5691
5710
|
let directory;
|
|
5692
5711
|
if (cwdArg) {
|
|
5693
5712
|
directory = path27.resolve(cwdArg);
|
|
5713
|
+
} else if (!interactive) {
|
|
5714
|
+
throw new Error("Pass the directory to create the project in, e.g. `vela create my-app`.");
|
|
5694
5715
|
} else {
|
|
5695
5716
|
const answer = await p10.text({
|
|
5696
5717
|
message: "Where would you like your project to be created?",
|
|
@@ -5701,6 +5722,7 @@ async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
|
|
|
5701
5722
|
directory = path27.resolve(answer);
|
|
5702
5723
|
}
|
|
5703
5724
|
if (fs29.existsSync(directory) && fs29.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
|
|
5725
|
+
if (!interactive) throw new Error(`${directory} is not empty.`);
|
|
5704
5726
|
const force = await p10.confirm({
|
|
5705
5727
|
message: "Directory not empty. Continue?",
|
|
5706
5728
|
initialValue: false
|
|
@@ -5712,6 +5734,7 @@ async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
|
|
|
5712
5734
|
{
|
|
5713
5735
|
name: () => {
|
|
5714
5736
|
if (options.name) return Promise.resolve(options.name);
|
|
5737
|
+
if (!interactive) return Promise.resolve(dirName || "SvelteKit");
|
|
5715
5738
|
return p10.text({
|
|
5716
5739
|
message: "App name (written to src/lib/site.ts)",
|
|
5717
5740
|
initialValue: dirName || "SvelteKit",
|
|
@@ -5721,7 +5744,7 @@ async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
|
|
|
5721
5744
|
},
|
|
5722
5745
|
{ onCancel: onCancel2 }
|
|
5723
5746
|
);
|
|
5724
|
-
const credentials = template.backend ? await
|
|
5747
|
+
const credentials = template.backend ? await requireSuperuser(options, {}, onCancel2) : void 0;
|
|
5725
5748
|
const link2 = await linkOnCreate(name, template, options, onCancel2);
|
|
5726
5749
|
copyTemplate(resolved, directory);
|
|
5727
5750
|
applyTemplateFiles(directory, {
|