vela 0.11.4 → 0.11.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/README.md +12 -1
- package/dist/bin.js +1282 -785
- package/dist/bin.js.map +4 -4
- package/package.json +17 -5
- package/templates/minimal/package.template.json +1 -1
- package/templates/minimal/vite.config.ts +1 -1
- package/templates/server/apply.sh +71 -30
- package/templates/server/lib.sh +16 -5
- package/templates/server/rollback.sh +2 -2
package/dist/bin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/bin.ts
|
|
4
|
-
import
|
|
4
|
+
import process40 from "node:process";
|
|
5
5
|
|
|
6
6
|
// src/lib/argv.ts
|
|
7
7
|
function normalizeArgv(argv) {
|
|
@@ -11,9 +11,9 @@ function normalizeArgv(argv) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// src/program.ts
|
|
14
|
-
import
|
|
15
|
-
import * as
|
|
16
|
-
import { Command as
|
|
14
|
+
import process39 from "node:process";
|
|
15
|
+
import * as p62 from "@clack/prompts";
|
|
16
|
+
import { Command as Command105 } from "commander";
|
|
17
17
|
import nodePath from "node:path";
|
|
18
18
|
import dotenv2 from "dotenv";
|
|
19
19
|
import pc38 from "picocolors";
|
|
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.11.
|
|
24
|
+
version: "0.11.6",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -57,7 +57,7 @@ var package_default = {
|
|
|
57
57
|
dependencies: {
|
|
58
58
|
"@clack/prompts": "^1.7.0",
|
|
59
59
|
"@faker-js/faker": "^10.6.0",
|
|
60
|
-
"@velastack/patterns": "^0.2.
|
|
60
|
+
"@velastack/patterns": "^0.2.5",
|
|
61
61
|
"@velastack/pocketbase-codegen": "^0.1.0",
|
|
62
62
|
"annotate-json-schema": "^0.1.0",
|
|
63
63
|
commander: "^13.1.0",
|
|
@@ -66,7 +66,7 @@ var package_default = {
|
|
|
66
66
|
dotenv: "^17.4.2",
|
|
67
67
|
"fetch-cookie": "^3.2.0",
|
|
68
68
|
"json-schema-faker": "^0.6.3",
|
|
69
|
-
"magic-string": "^
|
|
69
|
+
"magic-string": "^1.2.3",
|
|
70
70
|
"package-manager-detector": "^1.8.0",
|
|
71
71
|
picocolors: "^1.1.1",
|
|
72
72
|
pocketbase: "^0.28.0",
|
|
@@ -83,10 +83,10 @@ var package_default = {
|
|
|
83
83
|
"@types/node": "^22.0.0",
|
|
84
84
|
esbuild: "^0.28.2",
|
|
85
85
|
prettier: "^3.9.6",
|
|
86
|
+
shellcheck: "^4.1.0",
|
|
86
87
|
typescript: "^5.6.0",
|
|
87
88
|
vite: "^8.2.2",
|
|
88
|
-
vitest: "^4.1.11"
|
|
89
|
-
shellcheck: "^4.1.0"
|
|
89
|
+
vitest: "^4.1.11"
|
|
90
90
|
},
|
|
91
91
|
peerDependencies: {
|
|
92
92
|
"@sveltejs/kit": "^2.57.1",
|
|
@@ -100,6 +100,18 @@ var package_default = {
|
|
|
100
100
|
optional: true
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
+
overrides: {
|
|
104
|
+
"global-agent": "^4.1.3",
|
|
105
|
+
"@xhmikosr/decompress-unzip": {
|
|
106
|
+
"file-type": "^21.3.1"
|
|
107
|
+
},
|
|
108
|
+
"@xhmikosr/decompress-tar": {
|
|
109
|
+
"file-type": "^21.3.1"
|
|
110
|
+
},
|
|
111
|
+
"@felipecrs/decompress-tarxz": {
|
|
112
|
+
"file-type": "^21.3.1"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
103
115
|
keywords: [
|
|
104
116
|
"svelte",
|
|
105
117
|
"sveltekit",
|
|
@@ -291,8 +303,20 @@ function mergePackageJson(user, template) {
|
|
|
291
303
|
}
|
|
292
304
|
return { merged, added, conflicts, replaced };
|
|
293
305
|
}
|
|
294
|
-
function
|
|
295
|
-
|
|
306
|
+
function dropTemplateAdapters(user, template) {
|
|
307
|
+
const isAdapter = (name) => name.startsWith("@sveltejs/adapter-");
|
|
308
|
+
const userHasOne = DEP_KINDS.some((kind) => Object.keys(user[kind] ?? {}).some(isAdapter));
|
|
309
|
+
if (!userHasOne) return template;
|
|
310
|
+
const copy = { ...template };
|
|
311
|
+
for (const kind of DEP_KINDS) {
|
|
312
|
+
const deps = template[kind];
|
|
313
|
+
if (!deps) continue;
|
|
314
|
+
copy[kind] = Object.fromEntries(Object.entries(deps).filter(([name]) => !isAdapter(name)));
|
|
315
|
+
}
|
|
316
|
+
return copy;
|
|
317
|
+
}
|
|
318
|
+
function readPackageJson(path47) {
|
|
319
|
+
return JSON.parse(fs.readFileSync(path47, "utf8"));
|
|
296
320
|
}
|
|
297
321
|
var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
|
|
298
322
|
var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
|
|
@@ -305,12 +329,12 @@ function fillTemplatePlaceholders(raw, values) {
|
|
|
305
329
|
function escapeSingleQuoted(value) {
|
|
306
330
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
307
331
|
}
|
|
308
|
-
function readTemplatePackageJson(
|
|
309
|
-
const raw = fillTemplatePlaceholders(fs.readFileSync(
|
|
332
|
+
function readTemplatePackageJson(path47, values) {
|
|
333
|
+
const raw = fillTemplatePlaceholders(fs.readFileSync(path47, "utf8"), values);
|
|
310
334
|
return JSON.parse(raw);
|
|
311
335
|
}
|
|
312
|
-
function writePackageJson(
|
|
313
|
-
fs.writeFileSync(
|
|
336
|
+
function writePackageJson(path47, pkg) {
|
|
337
|
+
fs.writeFileSync(path47, JSON.stringify(pkg, null, " ") + "\n");
|
|
314
338
|
}
|
|
315
339
|
function toValidPackageName(name) {
|
|
316
340
|
return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
|
|
@@ -569,10 +593,10 @@ function writeCachedIndex(cached2) {
|
|
|
569
593
|
fs5.mkdirSync(cacheRoot(), { recursive: true });
|
|
570
594
|
fs5.writeFileSync(indexCachePath(), JSON.stringify(cached2, null, 2));
|
|
571
595
|
}
|
|
572
|
-
function parseTemplateIndex(
|
|
596
|
+
function parseTemplateIndex(text19, url) {
|
|
573
597
|
let parsed;
|
|
574
598
|
try {
|
|
575
|
-
parsed = JSON.parse(
|
|
599
|
+
parsed = JSON.parse(text19);
|
|
576
600
|
} catch (e) {
|
|
577
601
|
throw new Error(`Template index at ${url} is not valid JSON: ${e.message}`);
|
|
578
602
|
}
|
|
@@ -866,7 +890,7 @@ async function packageManagerPrompt(cwd) {
|
|
|
866
890
|
}
|
|
867
891
|
return pm;
|
|
868
892
|
}
|
|
869
|
-
async function installDependencies(agent, cwd) {
|
|
893
|
+
async function installDependencies(agent, cwd, { exitOnFailure = true } = {}) {
|
|
870
894
|
const task = p2.taskLog({
|
|
871
895
|
title: `Installing dependencies with ${agent}...`,
|
|
872
896
|
limit: Math.ceil(process5.stdout.rows / 2),
|
|
@@ -883,14 +907,16 @@ async function installDependencies(agent, cwd) {
|
|
|
883
907
|
proc.process?.stderr?.on("data", (data) => task.message(data.toString(), { raw: true }));
|
|
884
908
|
await proc;
|
|
885
909
|
task.success("Successfully installed dependencies");
|
|
910
|
+
return true;
|
|
886
911
|
} catch {
|
|
887
912
|
task.error("Failed to install dependencies");
|
|
913
|
+
if (!exitOnFailure) return false;
|
|
888
914
|
p2.cancel("Operation failed.");
|
|
889
915
|
process5.exit(2);
|
|
890
916
|
}
|
|
891
917
|
}
|
|
892
|
-
function addPnpmBuildDependencies(cwd,
|
|
893
|
-
if (!
|
|
918
|
+
function addPnpmBuildDependencies(cwd, packageManager2, allowedPackages) {
|
|
919
|
+
if (!packageManager2 || packageManager2 !== "pnpm") return;
|
|
894
920
|
const pkgPath = path6.join(cwd, "package.json");
|
|
895
921
|
if (!fs7.existsSync(pkgPath)) return;
|
|
896
922
|
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
@@ -1027,11 +1053,11 @@ function getPocketbaseMetadata(cwd) {
|
|
|
1027
1053
|
return null;
|
|
1028
1054
|
}
|
|
1029
1055
|
async function execPackageBin(cwd, args, stdio = "pipe") {
|
|
1030
|
-
const
|
|
1031
|
-
const resolved = resolveCommand(
|
|
1032
|
-
if (!resolved) throw new Error(`Could not resolve command for ${
|
|
1056
|
+
const packageManager2 = (await detect2({ cwd }))?.name ?? "npm";
|
|
1057
|
+
const resolved = resolveCommand(packageManager2, "execute", args);
|
|
1058
|
+
if (!resolved) throw new Error(`Could not resolve command for ${packageManager2}`);
|
|
1033
1059
|
const { command, args: resolvedArgs } = resolved;
|
|
1034
|
-
if (
|
|
1060
|
+
if (packageManager2 === "npm") resolvedArgs.unshift("--yes");
|
|
1035
1061
|
return x(command, resolvedArgs, { nodeOptions: { cwd, stdio }, throwOnError: true });
|
|
1036
1062
|
}
|
|
1037
1063
|
async function withPocketbase(cwd, fn, creds) {
|
|
@@ -1479,7 +1505,14 @@ var GITIGNORE_ENTRIES = [
|
|
|
1479
1505
|
"!.env.example",
|
|
1480
1506
|
"!.env.test",
|
|
1481
1507
|
"vite.config.js.timestamp-*",
|
|
1482
|
-
"vite.config.ts.timestamp-*"
|
|
1508
|
+
"vite.config.ts.timestamp-*",
|
|
1509
|
+
// The local database, minus the parts that are source. Same block as the
|
|
1510
|
+
// template's _gitignore; without it a blessed project commits its SQLite.
|
|
1511
|
+
"/data/*",
|
|
1512
|
+
"!/data/fixtures",
|
|
1513
|
+
"!/data/seeds",
|
|
1514
|
+
"!/data/hooks",
|
|
1515
|
+
"/backups"
|
|
1483
1516
|
];
|
|
1484
1517
|
function mergeGitignore(filePath) {
|
|
1485
1518
|
const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf8") : "";
|
|
@@ -1647,13 +1680,13 @@ async function blessProject(cwdArg, options) {
|
|
|
1647
1680
|
mergeAppDts(templateDir, projectPath);
|
|
1648
1681
|
maybeReplaceRoutes(projectPath, templateDir, options);
|
|
1649
1682
|
p4.log.success("Vela files in place");
|
|
1650
|
-
let
|
|
1683
|
+
let packageManager2;
|
|
1651
1684
|
if (options.install !== false) {
|
|
1652
1685
|
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
1653
1686
|
if (pm) {
|
|
1654
1687
|
addPnpmBuildDependencies(projectPath, pm, ["esbuild", "pocketbase-server"]);
|
|
1655
1688
|
await installDependencies(pm, projectPath);
|
|
1656
|
-
|
|
1689
|
+
packageManager2 = pm;
|
|
1657
1690
|
}
|
|
1658
1691
|
}
|
|
1659
1692
|
p4.log.step("Initializing PocketBase...");
|
|
@@ -1667,7 +1700,7 @@ async function blessProject(cwdArg, options) {
|
|
|
1667
1700
|
["PocketBase superuser credentials \u2014 used by `vela` commands"]
|
|
1668
1701
|
);
|
|
1669
1702
|
p4.log.success("PocketBase initialized");
|
|
1670
|
-
printNextSteps(projectPath,
|
|
1703
|
+
printNextSteps(projectPath, packageManager2);
|
|
1671
1704
|
}
|
|
1672
1705
|
function ensureShadcnCss(projectPath) {
|
|
1673
1706
|
if (ensureShadcnImport(path13.join(projectPath, "src", "app.css"))) {
|
|
@@ -1713,7 +1746,10 @@ function mergeDependencies(projectPath, templateDir) {
|
|
|
1713
1746
|
appName,
|
|
1714
1747
|
cliVersion: package_default.version
|
|
1715
1748
|
});
|
|
1716
|
-
const { merged, added, conflicts, replaced } = mergePackageJson(
|
|
1749
|
+
const { merged, added, conflicts, replaced } = mergePackageJson(
|
|
1750
|
+
userPkg,
|
|
1751
|
+
dropTemplateAdapters(userPkg, templatePkg)
|
|
1752
|
+
);
|
|
1717
1753
|
writePackageJson(userPkgPath, merged);
|
|
1718
1754
|
if (added.length > 0) {
|
|
1719
1755
|
p4.log.info(
|
|
@@ -1851,9 +1887,9 @@ function summarize(names) {
|
|
|
1851
1887
|
if (names.length <= 4) return names.join(", ");
|
|
1852
1888
|
return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
|
|
1853
1889
|
}
|
|
1854
|
-
function printNextSteps(projectPath,
|
|
1890
|
+
function printNextSteps(projectPath, packageManager2) {
|
|
1855
1891
|
const relative = path13.relative(process7.cwd(), projectPath);
|
|
1856
|
-
const pm =
|
|
1892
|
+
const pm = packageManager2 ?? getUserAgent() ?? "npm";
|
|
1857
1893
|
const nextSteps = [];
|
|
1858
1894
|
if (relative !== "") {
|
|
1859
1895
|
const hasSpaces = relative.includes(" ");
|
|
@@ -1885,13 +1921,13 @@ import * as p5 from "@clack/prompts";
|
|
|
1885
1921
|
import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
1886
1922
|
function optionsSchema2(listing) {
|
|
1887
1923
|
const names = listing.templates.map((template) => template.name);
|
|
1888
|
-
let
|
|
1924
|
+
let choices2 = `must be one of: ${templateChoicesMessage(listing.templates)}`;
|
|
1889
1925
|
if (listing.registryError) {
|
|
1890
|
-
|
|
1926
|
+
choices2 += ` (could not reach the template registry: ${listing.registryError})`;
|
|
1891
1927
|
}
|
|
1892
1928
|
return v4.strictObject({
|
|
1893
1929
|
install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
1894
|
-
template: v4.optional(v4.picklist(names,
|
|
1930
|
+
template: v4.optional(v4.picklist(names, choices2)),
|
|
1895
1931
|
name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
|
|
1896
1932
|
email: v4.optional(v4.pipe(v4.string(), v4.email("must be a valid email address"))),
|
|
1897
1933
|
password: v4.optional(v4.pipe(v4.string(), v4.minLength(8, "must be at least 8 characters long")))
|
|
@@ -1901,19 +1937,19 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1901
1937
|
return runCommand(async () => {
|
|
1902
1938
|
const listing = await listAllTemplates();
|
|
1903
1939
|
const options = parseOptions(optionsSchema2(listing), rawOpts);
|
|
1904
|
-
const { directory, packageManager, name, template } = await createProject(
|
|
1940
|
+
const { directory, packageManager: packageManager2, name, template } = await createProject(
|
|
1905
1941
|
projectPath,
|
|
1906
1942
|
options,
|
|
1907
1943
|
listing
|
|
1908
1944
|
);
|
|
1909
1945
|
const relative = path14.relative(process8.cwd(), directory);
|
|
1910
|
-
const pm =
|
|
1946
|
+
const pm = packageManager2 ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
1911
1947
|
const nextSteps = [];
|
|
1912
1948
|
if (relative !== "") {
|
|
1913
1949
|
const hasSpaces = relative.includes(" ");
|
|
1914
1950
|
nextSteps.push(`\`cd ${hasSpaces ? `"${relative}"` : relative}\``);
|
|
1915
1951
|
}
|
|
1916
|
-
if (!
|
|
1952
|
+
if (!packageManager2) {
|
|
1917
1953
|
const resolved = resolveCommand3(pm, "install", []);
|
|
1918
1954
|
if (resolved) {
|
|
1919
1955
|
nextSteps.push(
|
|
@@ -2002,14 +2038,14 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2002
2038
|
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
2003
2039
|
}
|
|
2004
2040
|
p5.log.success("Project created");
|
|
2005
|
-
let
|
|
2041
|
+
let packageManager2;
|
|
2006
2042
|
if (options.install !== false) {
|
|
2007
2043
|
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
2008
2044
|
if (pm) {
|
|
2009
2045
|
const builds = template.backend ? ["esbuild", "pocketbase-server"] : ["esbuild"];
|
|
2010
2046
|
addPnpmBuildDependencies(projectPath, pm, builds);
|
|
2011
2047
|
await installDependencies(pm, projectPath);
|
|
2012
|
-
|
|
2048
|
+
packageManager2 = pm;
|
|
2013
2049
|
}
|
|
2014
2050
|
}
|
|
2015
2051
|
if (credentials) {
|
|
@@ -2035,7 +2071,7 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2035
2071
|
);
|
|
2036
2072
|
p5.log.success("PocketBase initialized");
|
|
2037
2073
|
}
|
|
2038
|
-
return { directory: projectPath, packageManager, name, template };
|
|
2074
|
+
return { directory: projectPath, packageManager: packageManager2, name, template };
|
|
2039
2075
|
}
|
|
2040
2076
|
function promptCredentials(options, onCancel2) {
|
|
2041
2077
|
return p5.group(
|
|
@@ -2065,23 +2101,135 @@ import { Command as Command9 } from "commander";
|
|
|
2065
2101
|
|
|
2066
2102
|
// src/commands/generate/form.ts
|
|
2067
2103
|
import { Command as Command4 } from "commander";
|
|
2068
|
-
import * as
|
|
2104
|
+
import * as p12 from "@clack/prompts";
|
|
2069
2105
|
|
|
2070
2106
|
// src/lib/pattern-runner.ts
|
|
2071
2107
|
import path15 from "node:path";
|
|
2108
|
+
import * as p7 from "@clack/prompts";
|
|
2109
|
+
import { bySlug as bySlug2 } from "@velastack/patterns";
|
|
2110
|
+
|
|
2111
|
+
// src/lib/providers.ts
|
|
2112
|
+
import process9 from "node:process";
|
|
2072
2113
|
import * as p6 from "@clack/prompts";
|
|
2073
2114
|
import { bySlug } from "@velastack/patterns";
|
|
2115
|
+
function capabilityName(slug2) {
|
|
2116
|
+
return slug2.replace(/^enable-/, "");
|
|
2117
|
+
}
|
|
2118
|
+
function choices(providers) {
|
|
2119
|
+
return `--provider <${providers.map((provider) => provider.id).join("|")}>`;
|
|
2120
|
+
}
|
|
2121
|
+
function unknownProviderMessage(name, raw, providers) {
|
|
2122
|
+
return [
|
|
2123
|
+
`Unknown provider "${raw}" for ${name}.`,
|
|
2124
|
+
"",
|
|
2125
|
+
"Available providers:",
|
|
2126
|
+
...providers.map((provider) => ` ${provider.id}`)
|
|
2127
|
+
].join("\n");
|
|
2128
|
+
}
|
|
2129
|
+
function decideProvider(request) {
|
|
2130
|
+
const { patternName, providers, flagValue, interactive } = request;
|
|
2131
|
+
if (flagValue !== void 0) {
|
|
2132
|
+
const provider = providers.find((candidate) => candidate.id === flagValue);
|
|
2133
|
+
if (!provider) {
|
|
2134
|
+
return { kind: "error", message: unknownProviderMessage(patternName, flagValue, providers) };
|
|
2135
|
+
}
|
|
2136
|
+
return { kind: "use", provider };
|
|
2137
|
+
}
|
|
2138
|
+
if (interactive) return { kind: "prompt" };
|
|
2139
|
+
return {
|
|
2140
|
+
kind: "error",
|
|
2141
|
+
message: `Choose ${article(patternName)} ${patternName} provider: pass ${choices(providers)}. There is no terminal to ask on.`
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
function article(word) {
|
|
2145
|
+
return /^[aeiou]/i.test(word) ? "an" : "a";
|
|
2146
|
+
}
|
|
2147
|
+
function isInteractive() {
|
|
2148
|
+
return Boolean(process9.stdout.isTTY) && !process9.env.CI;
|
|
2149
|
+
}
|
|
2150
|
+
function providerFlagInArgv(argv) {
|
|
2151
|
+
return argv.some((arg) => arg === "--provider" || arg.startsWith("--provider="));
|
|
2152
|
+
}
|
|
2153
|
+
function checkProviderInput(pattern, argv, input) {
|
|
2154
|
+
const providers = pattern.providers ?? [];
|
|
2155
|
+
if (providers.length > 0) {
|
|
2156
|
+
if (typeof input.provider !== "string" || input.provider.length === 0) {
|
|
2157
|
+
throw new Error(`${pattern.title} needs a provider. Pass ${choices(providers)}.`);
|
|
2158
|
+
}
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
if (providerFlagInArgv(argv)) {
|
|
2162
|
+
throw new Error(`${pattern.title} does not support --provider.`);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
async function resolveProvider(slug2, flagValue) {
|
|
2166
|
+
const pattern = bySlug[slug2];
|
|
2167
|
+
const providers = pattern.providers ?? [];
|
|
2168
|
+
if (providers.length === 0) {
|
|
2169
|
+
throw new Error(`${pattern.title} does not support --provider.`);
|
|
2170
|
+
}
|
|
2171
|
+
const patternName = capabilityName(slug2);
|
|
2172
|
+
const decision = decideProvider({
|
|
2173
|
+
patternName,
|
|
2174
|
+
providers,
|
|
2175
|
+
flagValue,
|
|
2176
|
+
interactive: isInteractive()
|
|
2177
|
+
});
|
|
2178
|
+
if (decision.kind === "error") throw new Error(decision.message);
|
|
2179
|
+
if (decision.kind === "use") return decision.provider;
|
|
2180
|
+
const selected = await p6.select({
|
|
2181
|
+
message: `Select ${patternName} provider`,
|
|
2182
|
+
options: providers.map((provider) => ({ value: provider.id, label: provider.label }))
|
|
2183
|
+
});
|
|
2184
|
+
if (p6.isCancel(selected)) {
|
|
2185
|
+
p6.cancel("Operation cancelled.");
|
|
2186
|
+
process9.exit(0);
|
|
2187
|
+
}
|
|
2188
|
+
return providers.find((provider) => provider.id === selected);
|
|
2189
|
+
}
|
|
2190
|
+
async function collectProviderEnv(provider) {
|
|
2191
|
+
const values = {};
|
|
2192
|
+
const interactive = isInteractive();
|
|
2193
|
+
for (const variable of provider.env ?? []) {
|
|
2194
|
+
const existing = process9.env[variable.key];
|
|
2195
|
+
if (existing) {
|
|
2196
|
+
values[variable.key] = existing;
|
|
2197
|
+
continue;
|
|
2198
|
+
}
|
|
2199
|
+
if (!interactive) {
|
|
2200
|
+
values[variable.key] = variable.default ?? "";
|
|
2201
|
+
continue;
|
|
2202
|
+
}
|
|
2203
|
+
const value = await p6.text({
|
|
2204
|
+
message: variable.label,
|
|
2205
|
+
placeholder: variable.placeholder,
|
|
2206
|
+
initialValue: variable.default
|
|
2207
|
+
});
|
|
2208
|
+
if (p6.isCancel(value)) {
|
|
2209
|
+
p6.cancel("Operation cancelled.");
|
|
2210
|
+
process9.exit(0);
|
|
2211
|
+
}
|
|
2212
|
+
values[variable.key] = (value ?? "").trim();
|
|
2213
|
+
}
|
|
2214
|
+
return values;
|
|
2215
|
+
}
|
|
2216
|
+
function missingEnvKeys(provider, values) {
|
|
2217
|
+
return (provider.env ?? []).filter((variable) => !(values[variable.key] ?? "").trim() && !variable.default).map((variable) => variable.key);
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
// src/lib/pattern-runner.ts
|
|
2074
2221
|
function toRelative(root, filePath) {
|
|
2075
2222
|
return path15.isAbsolute(filePath) ? path15.relative(root, filePath) : filePath;
|
|
2076
2223
|
}
|
|
2077
2224
|
var isSuccess = (f) => (f.status ?? "success") === "success";
|
|
2078
2225
|
async function runPattern(slug2, argv, input, report4) {
|
|
2079
|
-
const pattern =
|
|
2226
|
+
const pattern = bySlug2[slug2];
|
|
2080
2227
|
if (!pattern) {
|
|
2081
2228
|
throw new Error(`Unknown pattern: ${slug2}`);
|
|
2082
2229
|
}
|
|
2230
|
+
checkProviderInput(pattern, argv, input);
|
|
2083
2231
|
const { workspaceRootDir, features } = await getWorkspace();
|
|
2084
|
-
const log45 =
|
|
2232
|
+
const log45 = p7.taskLog({ title: report4.task.title });
|
|
2085
2233
|
let result;
|
|
2086
2234
|
try {
|
|
2087
2235
|
result = await pattern.generate({
|
|
@@ -2120,7 +2268,7 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
2120
2268
|
const deleted = result.deletes.filter(isSuccess);
|
|
2121
2269
|
const totalChanges = created.length + modified.length + deleted.length + result.components.length + result.packages.length + result.collections.length;
|
|
2122
2270
|
if (totalChanges === 0 && failures.length === 0) {
|
|
2123
|
-
|
|
2271
|
+
p7.log.info(`${pattern.title ?? slug2} produced no changes.`);
|
|
2124
2272
|
return;
|
|
2125
2273
|
}
|
|
2126
2274
|
reportResult({
|
|
@@ -2141,7 +2289,7 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
2141
2289
|
// src/lib/ai-flow.ts
|
|
2142
2290
|
import fs18 from "node:fs";
|
|
2143
2291
|
import path17 from "node:path";
|
|
2144
|
-
import * as
|
|
2292
|
+
import * as p11 from "@clack/prompts";
|
|
2145
2293
|
import pc4 from "picocolors";
|
|
2146
2294
|
|
|
2147
2295
|
// src/lib/project-config.ts
|
|
@@ -2214,14 +2362,14 @@ var aiSchema = (workspaceRootDir, body) => aiPost(workspaceRootDir, "schema", bo
|
|
|
2214
2362
|
var aiForm = (workspaceRootDir, body) => aiPost(workspaceRootDir, "form", body);
|
|
2215
2363
|
|
|
2216
2364
|
// src/lib/ai-loop.ts
|
|
2217
|
-
import * as
|
|
2365
|
+
import * as p8 from "@clack/prompts";
|
|
2218
2366
|
async function aiLoop(opts) {
|
|
2219
2367
|
let prompt = opts.initialPrompt;
|
|
2220
2368
|
let history = [];
|
|
2221
2369
|
let attempt = 0;
|
|
2222
2370
|
while (true) {
|
|
2223
2371
|
attempt++;
|
|
2224
|
-
const spinner7 =
|
|
2372
|
+
const spinner7 = p8.spinner();
|
|
2225
2373
|
spinner7.start(`${opts.stageLabel} (${attempt > 1 ? "iteration " + attempt : "first pass"})\u2026`);
|
|
2226
2374
|
let result;
|
|
2227
2375
|
let turn;
|
|
@@ -2235,12 +2383,12 @@ async function aiLoop(opts) {
|
|
|
2235
2383
|
throw e;
|
|
2236
2384
|
}
|
|
2237
2385
|
opts.renderPreview(result);
|
|
2238
|
-
const next = await
|
|
2386
|
+
const next = await p8.text({
|
|
2239
2387
|
message: "Refine the result, or press Enter to apply.",
|
|
2240
2388
|
placeholder: opts.refinePlaceholder,
|
|
2241
2389
|
defaultValue: ""
|
|
2242
2390
|
});
|
|
2243
|
-
if (
|
|
2391
|
+
if (p8.isCancel(next)) return null;
|
|
2244
2392
|
const trimmed = (typeof next === "string" ? next : "").trim();
|
|
2245
2393
|
if (trimmed === "") return result;
|
|
2246
2394
|
history = turn;
|
|
@@ -2249,7 +2397,7 @@ async function aiLoop(opts) {
|
|
|
2249
2397
|
}
|
|
2250
2398
|
|
|
2251
2399
|
// src/lib/ai-existing-models.ts
|
|
2252
|
-
import * as
|
|
2400
|
+
import * as p9 from "@clack/prompts";
|
|
2253
2401
|
async function loadExistingModels(workspaceRootDir) {
|
|
2254
2402
|
let result = [];
|
|
2255
2403
|
try {
|
|
@@ -2274,7 +2422,7 @@ async function loadExistingModels(workspaceRootDir) {
|
|
|
2274
2422
|
});
|
|
2275
2423
|
} catch (e) {
|
|
2276
2424
|
const msg = e instanceof Error ? e.message : String(e);
|
|
2277
|
-
|
|
2425
|
+
p9.log.warn(
|
|
2278
2426
|
`Could not load existing schema from PocketBase (${msg}). The AI agent will design without that context.`
|
|
2279
2427
|
);
|
|
2280
2428
|
return [];
|
|
@@ -2283,7 +2431,7 @@ async function loadExistingModels(workspaceRootDir) {
|
|
|
2283
2431
|
}
|
|
2284
2432
|
|
|
2285
2433
|
// src/lib/ai-to-argv.ts
|
|
2286
|
-
import * as
|
|
2434
|
+
import * as p10 from "@clack/prompts";
|
|
2287
2435
|
var PRIMITIVE_TYPES = /* @__PURE__ */ new Set(["text", "number", "bool", "email", "date", "url", "file"]);
|
|
2288
2436
|
function singularize(name) {
|
|
2289
2437
|
if (name.endsWith("ies") && name.length > 3) return `${name.slice(0, -3)}y`;
|
|
@@ -2306,7 +2454,7 @@ function collectionSpecToArgv(spec) {
|
|
|
2306
2454
|
for (const field of spec.fields) {
|
|
2307
2455
|
const type = typeArg(field);
|
|
2308
2456
|
if (type === null) {
|
|
2309
|
-
|
|
2457
|
+
p10.log.warn(
|
|
2310
2458
|
`Skipping field "${field.name}" (type "${field.type}" cannot be represented as a pattern argument)`
|
|
2311
2459
|
);
|
|
2312
2460
|
continue;
|
|
@@ -2409,10 +2557,10 @@ function renderModel(spec) {
|
|
|
2409
2557
|
const tail = extra.length > 0 ? " " + pc4.dim(extra.join(" ")) : "";
|
|
2410
2558
|
lines.push(` ${f.name.padEnd(nameWidth)} ${f.type.padEnd(typeWidth)} ${required}${tail}`);
|
|
2411
2559
|
}
|
|
2412
|
-
|
|
2560
|
+
p11.log.message(lines.join("\n"));
|
|
2413
2561
|
}
|
|
2414
2562
|
function renderLayout(layout) {
|
|
2415
|
-
|
|
2563
|
+
p11.log.message(renderGrid(layout));
|
|
2416
2564
|
}
|
|
2417
2565
|
async function runSchemaStage(opts) {
|
|
2418
2566
|
const { workspaceRootDir } = await getWorkspace();
|
|
@@ -2476,12 +2624,12 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2476
2624
|
}
|
|
2477
2625
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "form" });
|
|
2478
2626
|
if (!stage2) {
|
|
2479
|
-
|
|
2627
|
+
p12.cancel("Aborted before any files were written.");
|
|
2480
2628
|
return;
|
|
2481
2629
|
}
|
|
2482
2630
|
const layout = await runLayoutStage(stage2.workspaceRootDir, stage2.model);
|
|
2483
2631
|
if (!layout) {
|
|
2484
|
-
|
|
2632
|
+
p12.cancel("Aborted before any files were written.");
|
|
2485
2633
|
return;
|
|
2486
2634
|
}
|
|
2487
2635
|
argv = specToArgv(stage2.model);
|
|
@@ -2523,7 +2671,7 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2523
2671
|
|
|
2524
2672
|
// src/commands/generate/schema.ts
|
|
2525
2673
|
import { Command as Command5 } from "commander";
|
|
2526
|
-
import * as
|
|
2674
|
+
import * as p13 from "@clack/prompts";
|
|
2527
2675
|
var schema = new Command5("schema").description("generate a schema from a model").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--ai <description>", "design the schema with AI from a natural-language description").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2528
2676
|
(model, fields, options) => runCommand(async () => {
|
|
2529
2677
|
let argv;
|
|
@@ -2534,7 +2682,7 @@ var schema = new Command5("schema").description("generate a schema from a model"
|
|
|
2534
2682
|
}
|
|
2535
2683
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "schema" });
|
|
2536
2684
|
if (!stage2) {
|
|
2537
|
-
|
|
2685
|
+
p13.cancel("Aborted before any files were written.");
|
|
2538
2686
|
return;
|
|
2539
2687
|
}
|
|
2540
2688
|
argv = specToArgv(stage2.model);
|
|
@@ -2594,7 +2742,7 @@ var resource = new Command6("resource").description("generate a resource (model
|
|
|
2594
2742
|
|
|
2595
2743
|
// src/commands/generate/scaffold.ts
|
|
2596
2744
|
import { Command as Command7 } from "commander";
|
|
2597
|
-
import * as
|
|
2745
|
+
import * as p14 from "@clack/prompts";
|
|
2598
2746
|
var scaffold = new Command7("scaffold").description("generate a full CRUD scaffold (model, forms, list, detail)").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--remote", "generate a scaffold backed by a remote PocketBase collection").option(
|
|
2599
2747
|
"--route <route>",
|
|
2600
2748
|
'place the scaffold at a custom route (e.g. "(app)/[team_id]/projects"). Defaults to the pluralized model name under (app)/(public).'
|
|
@@ -2612,12 +2760,12 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2612
2760
|
}
|
|
2613
2761
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "scaffold" });
|
|
2614
2762
|
if (!stage2) {
|
|
2615
|
-
|
|
2763
|
+
p14.cancel("Aborted before any files were written.");
|
|
2616
2764
|
return;
|
|
2617
2765
|
}
|
|
2618
2766
|
const layout = await runLayoutStage(stage2.workspaceRootDir, stage2.model);
|
|
2619
2767
|
if (!layout) {
|
|
2620
|
-
|
|
2768
|
+
p14.cancel("Aborted before any files were written.");
|
|
2621
2769
|
return;
|
|
2622
2770
|
}
|
|
2623
2771
|
argv = specToArgv(stage2.model);
|
|
@@ -2687,11 +2835,42 @@ var migration = new Command8("migration").description("generate a migration for
|
|
|
2687
2835
|
var generate = new Command9("generate").description("generate scaffolding for database models and forms").configureHelp(helpConfig).addCommand(form).addCommand(schema).addCommand(resource).addCommand(scaffold).addCommand(migration);
|
|
2688
2836
|
|
|
2689
2837
|
// src/commands/enable.ts
|
|
2690
|
-
import { Command as
|
|
2838
|
+
import { Command as Command25 } from "commander";
|
|
2691
2839
|
|
|
2692
|
-
// src/commands/enable/
|
|
2840
|
+
// src/commands/enable/analytics.ts
|
|
2693
2841
|
import { Command as Command10 } from "commander";
|
|
2694
|
-
var
|
|
2842
|
+
var analytics = new Command10("analytics").description("enable web analytics (Plausible, Google Analytics or PostHog)").option("--provider <provider>", "analytics provider: plausible, google or posthog").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2843
|
+
(opts, cmd) => runCommand(async () => {
|
|
2844
|
+
const provider = await resolveProvider("enable-analytics", opts.provider);
|
|
2845
|
+
const providerEnv = await collectProviderEnv(provider);
|
|
2846
|
+
const blank = missingEnvKeys(provider, providerEnv);
|
|
2847
|
+
await runPattern(
|
|
2848
|
+
"enable-analytics",
|
|
2849
|
+
cmd.args,
|
|
2850
|
+
{ provider: provider.id, providerEnv },
|
|
2851
|
+
{
|
|
2852
|
+
summary: `Enabled analytics with ${provider.label}.`,
|
|
2853
|
+
nextSteps: [
|
|
2854
|
+
...blank.map(
|
|
2855
|
+
(key) => `Set ${key} in .env; the analytics component renders nothing until it is set.`
|
|
2856
|
+
),
|
|
2857
|
+
`Run \`vela dev\` and look for a page view in ${provider.label}.`,
|
|
2858
|
+
"Set the same PUBLIC_* variables on each deploy target with `vela env set`.",
|
|
2859
|
+
"The component lives in src/lib/components/analytics/analytics.svelte; edit it freely."
|
|
2860
|
+
],
|
|
2861
|
+
task: {
|
|
2862
|
+
title: "Enabling analytics",
|
|
2863
|
+
success: `Enabled analytics with ${provider.label}`,
|
|
2864
|
+
error: "Failed to enable analytics"
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
);
|
|
2868
|
+
}, "Failed to enable analytics.")
|
|
2869
|
+
);
|
|
2870
|
+
|
|
2871
|
+
// src/commands/enable/auth.ts
|
|
2872
|
+
import { Command as Command11 } from "commander";
|
|
2873
|
+
var auth = new Command11("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2695
2874
|
(_opts, cmd) => runCommand(
|
|
2696
2875
|
() => runPattern(
|
|
2697
2876
|
"enable-auth",
|
|
@@ -2716,8 +2895,8 @@ var auth = new Command10("auth").description("enable authentication (email/passw
|
|
|
2716
2895
|
);
|
|
2717
2896
|
|
|
2718
2897
|
// src/commands/enable/api.ts
|
|
2719
|
-
import { Command as
|
|
2720
|
-
var api = new
|
|
2898
|
+
import { Command as Command12 } from "commander";
|
|
2899
|
+
var api = new Command12("api").description("enable the PocketBase REST API").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2721
2900
|
(_opts, cmd) => runCommand(
|
|
2722
2901
|
() => runPattern(
|
|
2723
2902
|
"enable-api",
|
|
@@ -2742,8 +2921,8 @@ var api = new Command11("api").description("enable the PocketBase REST API").all
|
|
|
2742
2921
|
);
|
|
2743
2922
|
|
|
2744
2923
|
// src/commands/enable/api-keys.ts
|
|
2745
|
-
import { Command as
|
|
2746
|
-
var apiKeys = new
|
|
2924
|
+
import { Command as Command13 } from "commander";
|
|
2925
|
+
var apiKeys = new Command13("api-keys").description("enable API key management").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2747
2926
|
(_opts, cmd) => runCommand(
|
|
2748
2927
|
() => runPattern(
|
|
2749
2928
|
"enable-api-keys",
|
|
@@ -2768,8 +2947,8 @@ var apiKeys = new Command12("api-keys").description("enable API key management")
|
|
|
2768
2947
|
);
|
|
2769
2948
|
|
|
2770
2949
|
// src/commands/enable/backend.ts
|
|
2771
|
-
import { Command as
|
|
2772
|
-
var backend = new
|
|
2950
|
+
import { Command as Command14 } from "commander";
|
|
2951
|
+
var backend = new Command14("backend").description("enable the PocketBase backend").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2773
2952
|
(_opts, cmd) => runCommand(
|
|
2774
2953
|
() => runPattern(
|
|
2775
2954
|
"enable-backend",
|
|
@@ -2794,8 +2973,8 @@ var backend = new Command13("backend").description("enable the PocketBase backen
|
|
|
2794
2973
|
);
|
|
2795
2974
|
|
|
2796
2975
|
// src/commands/enable/i18n.ts
|
|
2797
|
-
import { Command as
|
|
2798
|
-
var i18n = new
|
|
2976
|
+
import { Command as Command15 } from "commander";
|
|
2977
|
+
var i18n = new Command15("i18n").description("enable internationalization").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2799
2978
|
(_opts, cmd) => runCommand(
|
|
2800
2979
|
() => runPattern(
|
|
2801
2980
|
"enable-i18n",
|
|
@@ -2820,8 +2999,8 @@ var i18n = new Command14("i18n").description("enable internationalization").allo
|
|
|
2820
2999
|
);
|
|
2821
3000
|
|
|
2822
3001
|
// src/commands/enable/teams.ts
|
|
2823
|
-
import { Command as
|
|
2824
|
-
var teams = new
|
|
3002
|
+
import { Command as Command16 } from "commander";
|
|
3003
|
+
var teams = new Command16("teams").description("enable team / multi-tenant support").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2825
3004
|
(_opts, cmd) => runCommand(
|
|
2826
3005
|
() => runPattern(
|
|
2827
3006
|
"enable-teams",
|
|
@@ -2846,13 +3025,13 @@ var teams = new Command15("teams").description("enable team / multi-tenant suppo
|
|
|
2846
3025
|
);
|
|
2847
3026
|
|
|
2848
3027
|
// src/commands/enable/payments.ts
|
|
2849
|
-
import
|
|
2850
|
-
import { Command as
|
|
2851
|
-
import * as
|
|
3028
|
+
import process10 from "node:process";
|
|
3029
|
+
import { Command as Command17 } from "commander";
|
|
3030
|
+
import * as p15 from "@clack/prompts";
|
|
2852
3031
|
var PROVIDERS = [{ value: "stripe", label: "Stripe" }];
|
|
2853
|
-
var payments = new
|
|
3032
|
+
var payments = new Command17("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2854
3033
|
(opts, cmd) => runCommand(async () => {
|
|
2855
|
-
const provider = await
|
|
3034
|
+
const provider = await resolveProvider2(opts.provider, cmd.getOptionValueSource("provider"));
|
|
2856
3035
|
const input = {
|
|
2857
3036
|
provider,
|
|
2858
3037
|
stripeSecretKey: await ensureKey("STRIPE_SECRET_KEY", "Stripe secret key (sk_...)"),
|
|
@@ -2878,28 +3057,28 @@ var payments = new Command16("payments").description("enable payments").option("
|
|
|
2878
3057
|
});
|
|
2879
3058
|
}, "Failed to enable payments.")
|
|
2880
3059
|
);
|
|
2881
|
-
async function
|
|
3060
|
+
async function resolveProvider2(value, source) {
|
|
2882
3061
|
if (source && source !== "default") {
|
|
2883
3062
|
if (!PROVIDERS.some((o) => o.value === value)) {
|
|
2884
3063
|
throw new Error(`Unknown payment provider: ${value}`);
|
|
2885
3064
|
}
|
|
2886
3065
|
return value;
|
|
2887
3066
|
}
|
|
2888
|
-
const selected = await
|
|
3067
|
+
const selected = await p15.select({
|
|
2889
3068
|
message: "Which payment provider?",
|
|
2890
3069
|
options: PROVIDERS,
|
|
2891
3070
|
initialValue: "stripe"
|
|
2892
3071
|
});
|
|
2893
|
-
if (
|
|
2894
|
-
|
|
2895
|
-
|
|
3072
|
+
if (p15.isCancel(selected)) {
|
|
3073
|
+
p15.cancel("Operation cancelled.");
|
|
3074
|
+
process10.exit(0);
|
|
2896
3075
|
}
|
|
2897
3076
|
return selected;
|
|
2898
3077
|
}
|
|
2899
3078
|
async function ensureWebhookSecret() {
|
|
2900
|
-
const existing =
|
|
3079
|
+
const existing = process10.env.STRIPE_WEBHOOK_SECRET;
|
|
2901
3080
|
if (existing) return existing;
|
|
2902
|
-
|
|
3081
|
+
p15.note(
|
|
2903
3082
|
[
|
|
2904
3083
|
"Download the Stripe CLI (https://stripe.com/docs/stripe-cli), then run:",
|
|
2905
3084
|
" stripe listen --forward-to localhost:5173/webhooks/stripe",
|
|
@@ -2911,7 +3090,7 @@ async function ensureWebhookSecret() {
|
|
|
2911
3090
|
return promptPassword("Stripe webhook signing secret (whsec_...)");
|
|
2912
3091
|
}
|
|
2913
3092
|
async function ensurePriceId() {
|
|
2914
|
-
|
|
3093
|
+
p15.note(
|
|
2915
3094
|
[
|
|
2916
3095
|
"Stripe checkout requires a product and price_id.",
|
|
2917
3096
|
"If you have a demo product price_id, enter it below, or leave blank to create a demo one for you."
|
|
@@ -2919,36 +3098,36 @@ async function ensurePriceId() {
|
|
|
2919
3098
|
"Stripe demo product",
|
|
2920
3099
|
{ format: (line) => line }
|
|
2921
3100
|
);
|
|
2922
|
-
const value = await
|
|
3101
|
+
const value = await p15.text({
|
|
2923
3102
|
message: "Stripe price_id (price_...)",
|
|
2924
3103
|
placeholder: "leave blank to create a demo product"
|
|
2925
3104
|
});
|
|
2926
|
-
if (
|
|
2927
|
-
|
|
2928
|
-
|
|
3105
|
+
if (p15.isCancel(value)) {
|
|
3106
|
+
p15.cancel("Operation cancelled.");
|
|
3107
|
+
process10.exit(0);
|
|
2929
3108
|
}
|
|
2930
3109
|
return (value ?? "").trim();
|
|
2931
3110
|
}
|
|
2932
3111
|
async function ensureKey(envVar, message) {
|
|
2933
|
-
const existing =
|
|
3112
|
+
const existing = process10.env[envVar];
|
|
2934
3113
|
if (existing) return existing;
|
|
2935
3114
|
return promptPassword(message);
|
|
2936
3115
|
}
|
|
2937
3116
|
async function promptPassword(message) {
|
|
2938
|
-
const value = await
|
|
3117
|
+
const value = await p15.password({
|
|
2939
3118
|
message,
|
|
2940
3119
|
validate: (v10) => v10 && v10.length ? void 0 : "Required"
|
|
2941
3120
|
});
|
|
2942
|
-
if (
|
|
2943
|
-
|
|
2944
|
-
|
|
3121
|
+
if (p15.isCancel(value)) {
|
|
3122
|
+
p15.cancel("Operation cancelled.");
|
|
3123
|
+
process10.exit(0);
|
|
2945
3124
|
}
|
|
2946
3125
|
return value;
|
|
2947
3126
|
}
|
|
2948
3127
|
|
|
2949
3128
|
// src/commands/enable/subscriptions.ts
|
|
2950
|
-
import { Command as
|
|
2951
|
-
var subscriptions = new
|
|
3129
|
+
import { Command as Command18 } from "commander";
|
|
3130
|
+
var subscriptions = new Command18("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2952
3131
|
(_opts, cmd) => runCommand(
|
|
2953
3132
|
() => runPattern(
|
|
2954
3133
|
"enable-subscriptions",
|
|
@@ -2973,8 +3152,8 @@ var subscriptions = new Command17("subscriptions").description("enable Stripe su
|
|
|
2973
3152
|
);
|
|
2974
3153
|
|
|
2975
3154
|
// src/commands/enable/notifications.ts
|
|
2976
|
-
import { Command as
|
|
2977
|
-
var notifications = new
|
|
3155
|
+
import { Command as Command19 } from "commander";
|
|
3156
|
+
var notifications = new Command19("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2978
3157
|
(_opts, cmd) => runCommand(
|
|
2979
3158
|
() => runPattern(
|
|
2980
3159
|
"enable-notifications",
|
|
@@ -2999,15 +3178,15 @@ var notifications = new Command18("notifications").description("enable in-app no
|
|
|
2999
3178
|
);
|
|
3000
3179
|
|
|
3001
3180
|
// src/commands/enable/s3.ts
|
|
3002
|
-
import
|
|
3003
|
-
import { Command as
|
|
3004
|
-
import * as
|
|
3181
|
+
import process14 from "node:process";
|
|
3182
|
+
import { Command as Command20 } from "commander";
|
|
3183
|
+
import * as p18 from "@clack/prompts";
|
|
3005
3184
|
import pc8 from "picocolors";
|
|
3006
3185
|
|
|
3007
3186
|
// src/lib/server-command.ts
|
|
3008
|
-
import
|
|
3187
|
+
import process13 from "node:process";
|
|
3009
3188
|
import * as v6 from "valibot";
|
|
3010
|
-
import * as
|
|
3189
|
+
import * as p16 from "@clack/prompts";
|
|
3011
3190
|
import pc5 from "picocolors";
|
|
3012
3191
|
|
|
3013
3192
|
// src/lib/deploy-config.ts
|
|
@@ -3184,7 +3363,7 @@ import fs20 from "node:fs";
|
|
|
3184
3363
|
import os3 from "node:os";
|
|
3185
3364
|
import path19 from "node:path";
|
|
3186
3365
|
import crypto3 from "node:crypto";
|
|
3187
|
-
import
|
|
3366
|
+
import process11 from "node:process";
|
|
3188
3367
|
import { spawn as spawn2 } from "node:child_process";
|
|
3189
3368
|
var RemoteCommandError = class extends Error {
|
|
3190
3369
|
exitCode;
|
|
@@ -3462,17 +3641,17 @@ function spawnCapture(command, args, opts = {}) {
|
|
|
3462
3641
|
const child = spawn2(command, args, {
|
|
3463
3642
|
stdio,
|
|
3464
3643
|
cwd: opts.cwd,
|
|
3465
|
-
env: opts.env ? { ...
|
|
3644
|
+
env: opts.env ? { ...process11.env, ...opts.env } : void 0
|
|
3466
3645
|
});
|
|
3467
3646
|
let stdout = "";
|
|
3468
3647
|
let stderr = "";
|
|
3469
3648
|
child.stdout?.on("data", (chunk) => {
|
|
3470
3649
|
stdout += chunk;
|
|
3471
|
-
if (opts.streamStdout)
|
|
3650
|
+
if (opts.streamStdout) process11.stdout.write(chunk);
|
|
3472
3651
|
});
|
|
3473
3652
|
child.stderr?.on("data", (chunk) => {
|
|
3474
3653
|
stderr += chunk;
|
|
3475
|
-
if (opts.stream)
|
|
3654
|
+
if (opts.stream) process11.stderr.write(chunk);
|
|
3476
3655
|
});
|
|
3477
3656
|
child.on("error", reject);
|
|
3478
3657
|
child.on("close", (code) => resolve2({ stdout, stderr, exitCode: code ?? 1 }));
|
|
@@ -3523,10 +3702,11 @@ function collectArtifact(cwd, config = {}) {
|
|
|
3523
3702
|
const buildPath = path20.join(cwd, outputDir);
|
|
3524
3703
|
if (!fs21.existsSync(path20.join(buildPath, "index.js"))) {
|
|
3525
3704
|
throw new BuildError(
|
|
3526
|
-
`No ${outputDir}/index.js
|
|
3705
|
+
`No ${outputDir}/index.js to deploy.
|
|
3527
3706
|
|
|
3528
|
-
Deploying to a server needs @sveltejs/adapter-node.
|
|
3529
|
-
|
|
3707
|
+
Deploying to a server needs the output of @sveltejs/adapter-node. Check that the
|
|
3708
|
+
build ran with it as the adapter (and that \`outputDir\` in velastack.config
|
|
3709
|
+
matches where it writes), then deploy again.`
|
|
3530
3710
|
);
|
|
3531
3711
|
}
|
|
3532
3712
|
entries.push({ localPath: buildPath, remoteDir: "" });
|
|
@@ -3578,13 +3758,17 @@ function sshOptionsFrom(options) {
|
|
|
3578
3758
|
import crypto4 from "node:crypto";
|
|
3579
3759
|
import fs22 from "node:fs";
|
|
3580
3760
|
import path21 from "node:path";
|
|
3581
|
-
import
|
|
3761
|
+
import process12 from "node:process";
|
|
3582
3762
|
var VELA_ROOT = "/var/lib/vela";
|
|
3583
3763
|
var VELA_ETC = "/etc/vela";
|
|
3584
3764
|
var VELA_USER = "vela";
|
|
3585
3765
|
var SCRIPT_VERSIONS_DIR = `${VELA_ROOT}/script-versions`;
|
|
3586
3766
|
var PROVISIONED_MARKER = `${VELA_ETC}/provisioned`;
|
|
3587
3767
|
var ORIGIN_FILE = `${VELA_ETC}/origin.json`;
|
|
3768
|
+
function instanceHasBackend(state) {
|
|
3769
|
+
if (!state) return false;
|
|
3770
|
+
return state.backend ?? Boolean(state.pbPort);
|
|
3771
|
+
}
|
|
3588
3772
|
function serverTemplatesDir() {
|
|
3589
3773
|
return path21.join(templatesDir(), "server");
|
|
3590
3774
|
}
|
|
@@ -3611,7 +3795,7 @@ async function syncServerScripts(session) {
|
|
|
3611
3795
|
const dir = `${SCRIPT_VERSIONS_DIR}/${digest}`;
|
|
3612
3796
|
const present = await session.script(`[ -d "$1" ] && echo yes || echo no`, { args: [dir] });
|
|
3613
3797
|
if (present.stdout.trim() !== "yes") {
|
|
3614
|
-
const incoming = `${SCRIPT_VERSIONS_DIR}/.incoming.${digest}.${
|
|
3798
|
+
const incoming = `${SCRIPT_VERSIONS_DIR}/.incoming.${digest}.${process12.pid}.${Date.now()}`;
|
|
3615
3799
|
await session.script(`mkdir -p "$1" && chmod 0755 "$(dirname "$1")" "$1"`, {
|
|
3616
3800
|
args: [incoming]
|
|
3617
3801
|
});
|
|
@@ -3870,8 +4054,8 @@ function describeTarget(target) {
|
|
|
3870
4054
|
return target.name;
|
|
3871
4055
|
}
|
|
3872
4056
|
}
|
|
3873
|
-
function bold(
|
|
3874
|
-
return `\`${
|
|
4057
|
+
function bold(text19) {
|
|
4058
|
+
return `\`${text19}\``;
|
|
3875
4059
|
}
|
|
3876
4060
|
|
|
3877
4061
|
// src/lib/server-command.ts
|
|
@@ -3975,7 +4159,7 @@ async function ensureBinding(workspaceRootDir, target, request = {}) {
|
|
|
3975
4159
|
writeBinding(workspaceRootDir, key, binding);
|
|
3976
4160
|
}
|
|
3977
4161
|
if (moving) {
|
|
3978
|
-
|
|
4162
|
+
p16.log.warn(
|
|
3979
4163
|
`${pc5.cyan(bindingName(target))} now points at ${pc5.cyan(server)}.
|
|
3980
4164
|
|
|
3981
4165
|
Whatever is running on ${existing.server} is left there, and this project can no
|
|
@@ -3986,7 +4170,7 @@ longer reach it. Remove it there first if that was not intended.`
|
|
|
3986
4170
|
}
|
|
3987
4171
|
async function confirmMove(target, from, to) {
|
|
3988
4172
|
const name = bindingName(target);
|
|
3989
|
-
if (!
|
|
4173
|
+
if (!process13.stdout.isTTY || process13.env.CI) {
|
|
3990
4174
|
throw new Error(
|
|
3991
4175
|
`${pc5.cyan(`--server ${to}`)} does not match the server recorded for ${pc5.cyan(name)}, ${pc5.cyan(from)}.
|
|
3992
4176
|
|
|
@@ -3994,13 +4178,13 @@ Drop ${pc5.cyan("--server")} to use the recorded one, or move the binding on pur
|
|
|
3994
4178
|
this command once from a terminal (or editing .vela/project.json).`
|
|
3995
4179
|
);
|
|
3996
4180
|
}
|
|
3997
|
-
const ok = await
|
|
4181
|
+
const ok = await p16.confirm({
|
|
3998
4182
|
message: `${name} ${target.kind === "preview" ? "run" : "runs"} on ${from}. Point ${name} at ${to} instead?`,
|
|
3999
4183
|
initialValue: false
|
|
4000
4184
|
});
|
|
4001
|
-
if (
|
|
4002
|
-
|
|
4003
|
-
|
|
4185
|
+
if (p16.isCancel(ok) || !ok) {
|
|
4186
|
+
p16.cancel("Operation cancelled.");
|
|
4187
|
+
process13.exit(0);
|
|
4004
4188
|
}
|
|
4005
4189
|
}
|
|
4006
4190
|
function bindingName(target) {
|
|
@@ -4008,7 +4192,7 @@ function bindingName(target) {
|
|
|
4008
4192
|
}
|
|
4009
4193
|
async function promptServer(target) {
|
|
4010
4194
|
const name = bindingName(target);
|
|
4011
|
-
if (!
|
|
4195
|
+
if (!process13.stdout.isTTY || process13.env.CI) {
|
|
4012
4196
|
throw new Error(
|
|
4013
4197
|
`${name} ${target.kind === "preview" ? "are" : "is"} not bound to a server yet, and there is no terminal to ask on.
|
|
4014
4198
|
|
|
@@ -4016,29 +4200,29 @@ Pass ${pc5.cyan("--server user@host")}, or run the command once from your own ma
|
|
|
4016
4200
|
and commit ${pc5.cyan(".vela/project.json")}.`
|
|
4017
4201
|
);
|
|
4018
4202
|
}
|
|
4019
|
-
|
|
4203
|
+
p16.log.info(
|
|
4020
4204
|
`${pc5.cyan(name)} ${target.kind === "preview" ? "are" : "is"} not bound to a server yet.`
|
|
4021
4205
|
);
|
|
4022
|
-
const value = await
|
|
4206
|
+
const value = await p16.text({
|
|
4023
4207
|
message: `Which server should ${name} run on?`,
|
|
4024
4208
|
placeholder: "root@203.0.113.10",
|
|
4025
4209
|
validate: (input) => input?.trim() ? void 0 : "An ssh_config alias, or user@host"
|
|
4026
4210
|
});
|
|
4027
|
-
if (
|
|
4028
|
-
|
|
4029
|
-
|
|
4211
|
+
if (p16.isCancel(value)) {
|
|
4212
|
+
p16.cancel("Operation cancelled.");
|
|
4213
|
+
process13.exit(0);
|
|
4030
4214
|
}
|
|
4031
4215
|
return value.trim();
|
|
4032
4216
|
}
|
|
4033
4217
|
async function promptDomain(target) {
|
|
4034
|
-
if (!
|
|
4035
|
-
const value = await
|
|
4218
|
+
if (!process13.stdout.isTTY || process13.env.CI) return void 0;
|
|
4219
|
+
const value = await p16.text({
|
|
4036
4220
|
message: `Which hostname should ${target.name} be served on?`,
|
|
4037
4221
|
placeholder: "example.com \u2014 leave blank to decide later"
|
|
4038
4222
|
});
|
|
4039
|
-
if (
|
|
4040
|
-
|
|
4041
|
-
|
|
4223
|
+
if (p16.isCancel(value)) {
|
|
4224
|
+
p16.cancel("Operation cancelled.");
|
|
4225
|
+
process13.exit(0);
|
|
4042
4226
|
}
|
|
4043
4227
|
return value.trim() || void 0;
|
|
4044
4228
|
}
|
|
@@ -4046,10 +4230,10 @@ async function applyRestart(ctx) {
|
|
|
4046
4230
|
const outcome = await restartInstance(ctx.session, ctx.instance);
|
|
4047
4231
|
if (!outcome.deployed) return;
|
|
4048
4232
|
if (outcome.restarted) {
|
|
4049
|
-
|
|
4233
|
+
p16.log.success("App restarted");
|
|
4050
4234
|
return;
|
|
4051
4235
|
}
|
|
4052
|
-
|
|
4236
|
+
p16.log.error(
|
|
4053
4237
|
`App restart failed.
|
|
4054
4238
|
|
|
4055
4239
|
The new value is stored and will be used the next time the app starts.
|
|
@@ -4058,7 +4242,7 @@ ${pc5.dim(outcome.error ?? "")}`
|
|
|
4058
4242
|
}
|
|
4059
4243
|
async function applyEnvRestart(ctx, changed) {
|
|
4060
4244
|
if (touchesSuperuser(changed)) {
|
|
4061
|
-
|
|
4245
|
+
p16.log.warn(
|
|
4062
4246
|
`PocketBase superuser credentials changed.
|
|
4063
4247
|
|
|
4064
4248
|
The database still holds the old ones, so the app has not been restarted.
|
|
@@ -4095,7 +4279,7 @@ import pc7 from "picocolors";
|
|
|
4095
4279
|
|
|
4096
4280
|
// src/lib/local-env.ts
|
|
4097
4281
|
import fs24 from "node:fs";
|
|
4098
|
-
import * as
|
|
4282
|
+
import * as p17 from "@clack/prompts";
|
|
4099
4283
|
import pc6 from "picocolors";
|
|
4100
4284
|
function readLocalEnv(envFile) {
|
|
4101
4285
|
if (!fs24.existsSync(envFile)) return {};
|
|
@@ -4121,16 +4305,16 @@ async function applyLocalEnvChange(ctx, changed) {
|
|
|
4121
4305
|
process.env.POCKETBASE_SUPERUSER_EMAIL = email3;
|
|
4122
4306
|
process.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
|
|
4123
4307
|
await ensureSuperuser(ctx.workspaceRootDir);
|
|
4124
|
-
|
|
4308
|
+
p17.log.success("Local superuser updated to match");
|
|
4125
4309
|
} else {
|
|
4126
|
-
|
|
4310
|
+
p17.log.warn(
|
|
4127
4311
|
`The local database still has the old superuser.
|
|
4128
4312
|
Set both ${pc6.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc6.cyan("POCKETBASE_SUPERUSER_PASSWORD")} to reconcile it.`
|
|
4129
4313
|
);
|
|
4130
4314
|
}
|
|
4131
4315
|
}
|
|
4132
4316
|
if (getPocketbaseMetadata(ctx.workspaceRootDir)) {
|
|
4133
|
-
|
|
4317
|
+
p17.log.info(`Restart ${pc6.cyan("vela dev")} to pick this up.`);
|
|
4134
4318
|
}
|
|
4135
4319
|
}
|
|
4136
4320
|
|
|
@@ -4138,12 +4322,13 @@ Set both ${pc6.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc6.cyan("POCKETBASE_SU
|
|
|
4138
4322
|
import PocketBase2 from "pocketbase";
|
|
4139
4323
|
async function openRemoteDatabase(session, instance) {
|
|
4140
4324
|
const [state] = await readInstanceStates(session, instance);
|
|
4141
|
-
const pbPort = state?.pbPort;
|
|
4325
|
+
const pbPort = instanceHasBackend(state) ? state?.pbPort : void 0;
|
|
4142
4326
|
if (!pbPort) {
|
|
4143
4327
|
throw new Error(
|
|
4144
4328
|
`${instance} has no deployed database yet.
|
|
4145
4329
|
|
|
4146
|
-
Run \`vela deploy\` first \u2014 the database is created by the first deploy
|
|
4330
|
+
Run \`vela deploy\` first \u2014 the database is created by the first deploy of a
|
|
4331
|
+
project with a backend (\`vela bless\` adds one).`
|
|
4147
4332
|
);
|
|
4148
4333
|
}
|
|
4149
4334
|
const env2 = await readRemoteEnv(session, instance);
|
|
@@ -4293,7 +4478,7 @@ function hasFile(dir) {
|
|
|
4293
4478
|
|
|
4294
4479
|
// src/commands/enable/s3.ts
|
|
4295
4480
|
var s3 = addTargetOptions(
|
|
4296
|
-
new
|
|
4481
|
+
new Command20("s3").description("enable S3 file storage").option("--backups", "configure where backups are kept, not where uploads go").option("--endpoint <url>", "S3 endpoint URL").option("--bucket <name>", "S3 bucket name").option("--region <region>", "S3 region").option("--access-key <key>", "S3 access key").option("--secret <secret>", "S3 secret key \u2014 prefer VELA_S3_SECRET").option("--force-path-style", "address the bucket in the path (MinIO, Ceph)").option("--no-force-path-style", "address the bucket as a subdomain (AWS, R2)").option("--force", "enable it even though uploads already exist on disk").configureHelp(helpConfig),
|
|
4297
4482
|
"local"
|
|
4298
4483
|
).action(
|
|
4299
4484
|
(raw) => runCommand(() => {
|
|
@@ -4311,7 +4496,7 @@ var s3 = addTargetOptions(
|
|
|
4311
4496
|
failure = error instanceof Error ? error.message : String(error);
|
|
4312
4497
|
}
|
|
4313
4498
|
if (failure) {
|
|
4314
|
-
|
|
4499
|
+
p18.log.warn(
|
|
4315
4500
|
`The connection test failed \u2014 the settings are saved but may be wrong.
|
|
4316
4501
|
|
|
4317
4502
|
${pc8.dim(failure)}
|
|
@@ -4355,64 +4540,64 @@ Do that first, then re-run with ${pc8.cyan("--force")}.`
|
|
|
4355
4540
|
);
|
|
4356
4541
|
}
|
|
4357
4542
|
async function promptConfig(options, existing) {
|
|
4358
|
-
const endpoint = options.endpoint ?? await
|
|
4359
|
-
const bucket = options.bucket ?? await
|
|
4360
|
-
const region = options.region ?? await
|
|
4361
|
-
const accessKey = options.accessKey ?? await
|
|
4362
|
-
const secret = options.secret ??
|
|
4543
|
+
const endpoint = options.endpoint ?? await text8("S3 endpoint URL", existing.endpoint || "https://s3.amazonaws.com");
|
|
4544
|
+
const bucket = options.bucket ?? await text8("S3 bucket name", existing.bucket);
|
|
4545
|
+
const region = options.region ?? await text8("S3 region", existing.region || "us-east-1");
|
|
4546
|
+
const accessKey = options.accessKey ?? await text8("S3 access key", existing.accessKey);
|
|
4547
|
+
const secret = options.secret ?? process14.env.VELA_S3_SECRET ?? await password5("S3 secret key");
|
|
4363
4548
|
const forcePathStyle = options.forcePathStyle ?? await confirm4(
|
|
4364
4549
|
"Address the bucket in the path? (MinIO, Ceph and most self-hosted gateways need this)",
|
|
4365
4550
|
defaultForcePathStyle(endpoint)
|
|
4366
4551
|
);
|
|
4367
4552
|
return { endpoint, bucket, region, accessKey, secret, forcePathStyle };
|
|
4368
4553
|
}
|
|
4369
|
-
async function
|
|
4370
|
-
const value = await
|
|
4554
|
+
async function text8(message, initialValue = "") {
|
|
4555
|
+
const value = await p18.text({
|
|
4371
4556
|
message,
|
|
4372
4557
|
initialValue,
|
|
4373
4558
|
validate: (input) => input?.trim() ? void 0 : `${message} is required`
|
|
4374
4559
|
});
|
|
4375
|
-
if (
|
|
4376
|
-
|
|
4377
|
-
|
|
4560
|
+
if (p18.isCancel(value)) {
|
|
4561
|
+
p18.cancel("Operation cancelled.");
|
|
4562
|
+
process14.exit(0);
|
|
4378
4563
|
}
|
|
4379
4564
|
return value.trim();
|
|
4380
4565
|
}
|
|
4381
4566
|
async function password5(message) {
|
|
4382
|
-
const value = await
|
|
4567
|
+
const value = await p18.password({
|
|
4383
4568
|
message,
|
|
4384
4569
|
validate: (input) => input ? void 0 : `${message} is required`
|
|
4385
4570
|
});
|
|
4386
|
-
if (
|
|
4387
|
-
|
|
4388
|
-
|
|
4571
|
+
if (p18.isCancel(value)) {
|
|
4572
|
+
p18.cancel("Operation cancelled.");
|
|
4573
|
+
process14.exit(0);
|
|
4389
4574
|
}
|
|
4390
4575
|
return value;
|
|
4391
4576
|
}
|
|
4392
4577
|
async function confirm4(message, initialValue) {
|
|
4393
|
-
const value = await
|
|
4394
|
-
if (
|
|
4395
|
-
|
|
4396
|
-
|
|
4578
|
+
const value = await p18.confirm({ message, initialValue });
|
|
4579
|
+
if (p18.isCancel(value)) {
|
|
4580
|
+
p18.cancel("Operation cancelled.");
|
|
4581
|
+
process14.exit(0);
|
|
4397
4582
|
}
|
|
4398
4583
|
return value;
|
|
4399
4584
|
}
|
|
4400
4585
|
|
|
4401
4586
|
// src/commands/enable/smtp.ts
|
|
4402
|
-
import
|
|
4403
|
-
import { Command as
|
|
4404
|
-
import * as
|
|
4405
|
-
var smtp = new
|
|
4587
|
+
import process15 from "node:process";
|
|
4588
|
+
import { Command as Command21 } from "commander";
|
|
4589
|
+
import * as p19 from "@clack/prompts";
|
|
4590
|
+
var smtp = new Command21("smtp").description("configure SMTP for transactional email").configureHelp(helpConfig).action(
|
|
4406
4591
|
() => runCommand(async () => {
|
|
4407
4592
|
const { workspaceRootDir } = await getWorkspace();
|
|
4408
|
-
const config = await
|
|
4593
|
+
const config = await p19.group(
|
|
4409
4594
|
{
|
|
4410
|
-
host: () =>
|
|
4595
|
+
host: () => p19.text({
|
|
4411
4596
|
message: "SMTP host",
|
|
4412
4597
|
placeholder: "smtp.example.com",
|
|
4413
4598
|
validate: (v10) => v10 ? void 0 : "Host is required"
|
|
4414
4599
|
}),
|
|
4415
|
-
port: () =>
|
|
4600
|
+
port: () => p19.text({
|
|
4416
4601
|
message: "SMTP port",
|
|
4417
4602
|
initialValue: "587",
|
|
4418
4603
|
validate: (v10) => {
|
|
@@ -4422,13 +4607,13 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
|
|
|
4422
4607
|
return void 0;
|
|
4423
4608
|
}
|
|
4424
4609
|
}),
|
|
4425
|
-
username: () =>
|
|
4426
|
-
password: () =>
|
|
4610
|
+
username: () => p19.text({ message: "SMTP username" }),
|
|
4611
|
+
password: () => p19.password({ message: "SMTP password" })
|
|
4427
4612
|
},
|
|
4428
4613
|
{
|
|
4429
4614
|
onCancel: () => {
|
|
4430
|
-
|
|
4431
|
-
|
|
4615
|
+
p19.cancel("Operation cancelled.");
|
|
4616
|
+
process15.exit(0);
|
|
4432
4617
|
}
|
|
4433
4618
|
}
|
|
4434
4619
|
);
|
|
@@ -4455,24 +4640,24 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
|
|
|
4455
4640
|
);
|
|
4456
4641
|
|
|
4457
4642
|
// src/commands/enable/cms.ts
|
|
4458
|
-
import
|
|
4459
|
-
import { Command as
|
|
4460
|
-
import * as
|
|
4643
|
+
import process16 from "node:process";
|
|
4644
|
+
import { Command as Command22 } from "commander";
|
|
4645
|
+
import * as p20 from "@clack/prompts";
|
|
4461
4646
|
import pc9 from "picocolors";
|
|
4462
|
-
var cms = new
|
|
4647
|
+
var cms = new Command22("cms").description("enable an inline-editing CMS with an admin bar").option(
|
|
4463
4648
|
"--endpoint <url>",
|
|
4464
4649
|
"read from a hosted CMS at this URL instead of installing the backend in this app"
|
|
4465
4650
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4466
4651
|
(opts, cmd) => runCommand(async () => {
|
|
4467
4652
|
if (!opts.endpoint && !hasBackend()) {
|
|
4468
|
-
|
|
4653
|
+
p20.log.error(
|
|
4469
4654
|
`${pc9.cyan("vela enable cms")} needs a server to host the CMS backend, and this project is static.
|
|
4470
4655
|
|
|
4471
4656
|
Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${pc9.cyan("vela enable cms --endpoint <url>")}.`
|
|
4472
4657
|
);
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4658
|
+
p20.log.message();
|
|
4659
|
+
p20.cancel("Operation failed.");
|
|
4660
|
+
process16.exitCode = 1;
|
|
4476
4661
|
return;
|
|
4477
4662
|
}
|
|
4478
4663
|
await runPattern("enable-cms", cmd.args, opts.endpoint ? { endpoint: opts.endpoint } : {}, {
|
|
@@ -4492,8 +4677,8 @@ Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${
|
|
|
4492
4677
|
);
|
|
4493
4678
|
|
|
4494
4679
|
// src/commands/enable/blog.ts
|
|
4495
|
-
import { Command as
|
|
4496
|
-
var blog = new
|
|
4680
|
+
import { Command as Command23 } from "commander";
|
|
4681
|
+
var blog = new Command23("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4497
4682
|
(_opts, cmd) => runCommand(
|
|
4498
4683
|
() => runPattern(
|
|
4499
4684
|
"enable-blog",
|
|
@@ -4518,8 +4703,8 @@ var blog = new Command22("blog").description("enable an mdsvex blog with posts,
|
|
|
4518
4703
|
);
|
|
4519
4704
|
|
|
4520
4705
|
// src/commands/enable/content-negotiation.ts
|
|
4521
|
-
import { Command as
|
|
4522
|
-
var contentNegotiation = new
|
|
4706
|
+
import { Command as Command24 } from "commander";
|
|
4707
|
+
var contentNegotiation = new Command24("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4523
4708
|
(_opts, cmd) => runCommand(
|
|
4524
4709
|
() => runPattern(
|
|
4525
4710
|
"enable-content-negotiation",
|
|
@@ -4543,33 +4728,33 @@ var contentNegotiation = new Command23("content-negotiation").description("enabl
|
|
|
4543
4728
|
);
|
|
4544
4729
|
|
|
4545
4730
|
// src/commands/enable.ts
|
|
4546
|
-
var enable = new
|
|
4731
|
+
var enable = new Command25("enable").description("enable features").configureHelp(helpConfig).addCommand(analytics).addCommand(auth).addCommand(api).addCommand(apiKeys).addCommand(backend).addCommand(contentNegotiation).addCommand(i18n).addCommand(teams).addCommand(payments).addCommand(subscriptions).addCommand(notifications).addCommand(s3).addCommand(smtp).addCommand(cms).addCommand(blog);
|
|
4547
4732
|
|
|
4548
4733
|
// src/commands/disable.ts
|
|
4549
|
-
import { Command as
|
|
4734
|
+
import { Command as Command36 } from "commander";
|
|
4550
4735
|
|
|
4551
4736
|
// src/commands/disable/auth.ts
|
|
4552
|
-
import { Command as
|
|
4737
|
+
import { Command as Command26 } from "commander";
|
|
4553
4738
|
|
|
4554
4739
|
// src/commands/disable/_shared.ts
|
|
4555
|
-
import
|
|
4556
|
-
import * as
|
|
4740
|
+
import process17 from "node:process";
|
|
4741
|
+
import * as p21 from "@clack/prompts";
|
|
4557
4742
|
async function runDisable(opts, flags, cmdArgs) {
|
|
4558
4743
|
if (!flags.yes) {
|
|
4559
|
-
const ok = await
|
|
4744
|
+
const ok = await p21.confirm({
|
|
4560
4745
|
message: opts.confirmMessage,
|
|
4561
4746
|
initialValue: false
|
|
4562
4747
|
});
|
|
4563
|
-
if (
|
|
4564
|
-
|
|
4565
|
-
|
|
4748
|
+
if (p21.isCancel(ok) || !ok) {
|
|
4749
|
+
p21.cancel("Operation cancelled.");
|
|
4750
|
+
process17.exit(0);
|
|
4566
4751
|
}
|
|
4567
4752
|
}
|
|
4568
4753
|
await runPattern(opts.slug, cmdArgs, { destructive: true }, opts.report);
|
|
4569
4754
|
}
|
|
4570
4755
|
|
|
4571
4756
|
// src/commands/disable/auth.ts
|
|
4572
|
-
var auth2 = new
|
|
4757
|
+
var auth2 = new Command26("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4573
4758
|
(opts, cmd) => runCommand(
|
|
4574
4759
|
() => runDisable(
|
|
4575
4760
|
{
|
|
@@ -4595,8 +4780,8 @@ var auth2 = new Command25("auth").description("disable authentication").option("
|
|
|
4595
4780
|
);
|
|
4596
4781
|
|
|
4597
4782
|
// src/commands/disable/api.ts
|
|
4598
|
-
import { Command as
|
|
4599
|
-
var api2 = new
|
|
4783
|
+
import { Command as Command27 } from "commander";
|
|
4784
|
+
var api2 = new Command27("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4600
4785
|
(opts, cmd) => runCommand(
|
|
4601
4786
|
() => runDisable(
|
|
4602
4787
|
{
|
|
@@ -4619,8 +4804,8 @@ var api2 = new Command26("api").description("disable the REST API").option("-y,
|
|
|
4619
4804
|
);
|
|
4620
4805
|
|
|
4621
4806
|
// src/commands/disable/api-keys.ts
|
|
4622
|
-
import { Command as
|
|
4623
|
-
var apiKeys2 = new
|
|
4807
|
+
import { Command as Command28 } from "commander";
|
|
4808
|
+
var apiKeys2 = new Command28("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4624
4809
|
(opts, cmd) => runCommand(
|
|
4625
4810
|
() => runDisable(
|
|
4626
4811
|
{
|
|
@@ -4643,8 +4828,8 @@ var apiKeys2 = new Command27("api-keys").description("disable API key management
|
|
|
4643
4828
|
);
|
|
4644
4829
|
|
|
4645
4830
|
// src/commands/disable/backend.ts
|
|
4646
|
-
import { Command as
|
|
4647
|
-
var backend2 = new
|
|
4831
|
+
import { Command as Command29 } from "commander";
|
|
4832
|
+
var backend2 = new Command29("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4648
4833
|
(opts, cmd) => runCommand(
|
|
4649
4834
|
() => runDisable(
|
|
4650
4835
|
{
|
|
@@ -4667,8 +4852,8 @@ var backend2 = new Command28("backend").description("disable the PocketBase back
|
|
|
4667
4852
|
);
|
|
4668
4853
|
|
|
4669
4854
|
// src/commands/disable/content-negotiation.ts
|
|
4670
|
-
import { Command as
|
|
4671
|
-
var contentNegotiation2 = new
|
|
4855
|
+
import { Command as Command30 } from "commander";
|
|
4856
|
+
var contentNegotiation2 = new Command30("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4672
4857
|
(opts, cmd) => runCommand(
|
|
4673
4858
|
() => runDisable(
|
|
4674
4859
|
{
|
|
@@ -4691,8 +4876,8 @@ var contentNegotiation2 = new Command29("content-negotiation").description("disa
|
|
|
4691
4876
|
);
|
|
4692
4877
|
|
|
4693
4878
|
// src/commands/disable/i18n.ts
|
|
4694
|
-
import { Command as
|
|
4695
|
-
var i18n2 = new
|
|
4879
|
+
import { Command as Command31 } from "commander";
|
|
4880
|
+
var i18n2 = new Command31("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4696
4881
|
(opts, cmd) => runCommand(
|
|
4697
4882
|
() => runDisable(
|
|
4698
4883
|
{
|
|
@@ -4718,8 +4903,8 @@ var i18n2 = new Command30("i18n").description("disable internationalization").op
|
|
|
4718
4903
|
);
|
|
4719
4904
|
|
|
4720
4905
|
// src/commands/disable/teams.ts
|
|
4721
|
-
import { Command as
|
|
4722
|
-
var teams2 = new
|
|
4906
|
+
import { Command as Command32 } from "commander";
|
|
4907
|
+
var teams2 = new Command32("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4723
4908
|
(opts, cmd) => runCommand(
|
|
4724
4909
|
() => runDisable(
|
|
4725
4910
|
{
|
|
@@ -4745,8 +4930,8 @@ var teams2 = new Command31("teams").description("disable teams").option("-y, --y
|
|
|
4745
4930
|
);
|
|
4746
4931
|
|
|
4747
4932
|
// src/commands/disable/payments.ts
|
|
4748
|
-
import { Command as
|
|
4749
|
-
var payments2 = new
|
|
4933
|
+
import { Command as Command33 } from "commander";
|
|
4934
|
+
var payments2 = new Command33("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4750
4935
|
(opts, cmd) => runCommand(
|
|
4751
4936
|
() => runDisable(
|
|
4752
4937
|
{
|
|
@@ -4773,11 +4958,11 @@ var payments2 = new Command32("payments").description("disable payments").option
|
|
|
4773
4958
|
);
|
|
4774
4959
|
|
|
4775
4960
|
// src/commands/disable/s3.ts
|
|
4776
|
-
import { Command as
|
|
4777
|
-
import * as
|
|
4961
|
+
import { Command as Command34 } from "commander";
|
|
4962
|
+
import * as p22 from "@clack/prompts";
|
|
4778
4963
|
import pc10 from "picocolors";
|
|
4779
4964
|
var s32 = addTargetOptions(
|
|
4780
|
-
new
|
|
4965
|
+
new Command34("s3").description("disable S3 file storage").option("--backups", "keep backups on the server again, rather than uploads").configureHelp(helpConfig),
|
|
4781
4966
|
"local"
|
|
4782
4967
|
).action(
|
|
4783
4968
|
(raw) => runCommand(() => {
|
|
@@ -4786,7 +4971,7 @@ var s32 = addTargetOptions(
|
|
|
4786
4971
|
return withBackupTarget(raw, "disable s3", async (ctx) => {
|
|
4787
4972
|
const existing = await readS3(ctx.pb, filesystem);
|
|
4788
4973
|
if (!existing.enabled) {
|
|
4789
|
-
|
|
4974
|
+
p22.log.info(`S3 ${label2(filesystem)} is already off for ${ctx.targetName}.`);
|
|
4790
4975
|
return;
|
|
4791
4976
|
}
|
|
4792
4977
|
await disableS3(ctx.pb, filesystem);
|
|
@@ -4806,8 +4991,8 @@ function label2(filesystem) {
|
|
|
4806
4991
|
}
|
|
4807
4992
|
|
|
4808
4993
|
// src/commands/disable/smtp.ts
|
|
4809
|
-
import { Command as
|
|
4810
|
-
var smtp2 = new
|
|
4994
|
+
import { Command as Command35 } from "commander";
|
|
4995
|
+
var smtp2 = new Command35("smtp").description("disable SMTP configuration").configureHelp(helpConfig).action(
|
|
4811
4996
|
() => runCommand(async () => {
|
|
4812
4997
|
const { workspaceRootDir } = await getWorkspace();
|
|
4813
4998
|
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
@@ -4824,30 +5009,30 @@ var smtp2 = new Command34("smtp").description("disable SMTP configuration").conf
|
|
|
4824
5009
|
);
|
|
4825
5010
|
|
|
4826
5011
|
// src/commands/disable.ts
|
|
4827
|
-
var disable = new
|
|
5012
|
+
var disable = new Command36("disable").description("disable features").configureHelp(helpConfig).addCommand(auth2).addCommand(api2).addCommand(apiKeys2).addCommand(backend2).addCommand(contentNegotiation2).addCommand(i18n2).addCommand(teams2).addCommand(payments2).addCommand(s32).addCommand(smtp2);
|
|
4828
5013
|
|
|
4829
5014
|
// src/commands/destroy.ts
|
|
4830
|
-
import { Command as
|
|
5015
|
+
import { Command as Command42 } from "commander";
|
|
4831
5016
|
|
|
4832
5017
|
// src/commands/destroy/form.ts
|
|
4833
|
-
import { Command as
|
|
5018
|
+
import { Command as Command37 } from "commander";
|
|
4834
5019
|
|
|
4835
5020
|
// src/commands/destroy/_shared.ts
|
|
4836
|
-
import
|
|
4837
|
-
import * as
|
|
5021
|
+
import process18 from "node:process";
|
|
5022
|
+
import * as p23 from "@clack/prompts";
|
|
4838
5023
|
async function runDestroy(slug2, model, confirmMessage, report4, flags) {
|
|
4839
5024
|
if (!flags.yes) {
|
|
4840
|
-
const ok = await
|
|
4841
|
-
if (
|
|
4842
|
-
|
|
4843
|
-
|
|
5025
|
+
const ok = await p23.confirm({ message: confirmMessage, initialValue: false });
|
|
5026
|
+
if (p23.isCancel(ok) || !ok) {
|
|
5027
|
+
p23.cancel("Operation cancelled.");
|
|
5028
|
+
process18.exit(0);
|
|
4844
5029
|
}
|
|
4845
5030
|
}
|
|
4846
5031
|
await runPattern(slug2, [model], { destructive: true, route: flags.route }, report4);
|
|
4847
5032
|
}
|
|
4848
5033
|
|
|
4849
5034
|
// src/commands/destroy/form.ts
|
|
4850
|
-
var form2 = new
|
|
5035
|
+
var form2 = new Command37("form").description("destroy a form generated by `vela generate form`").argument("<model>", "model name used when the form was generated (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").option(
|
|
4851
5036
|
"--route <route>",
|
|
4852
5037
|
"custom route the form was generated at (must match the --route used at generation)"
|
|
4853
5038
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
@@ -4871,8 +5056,8 @@ var form2 = new Command36("form").description("destroy a form generated by `vela
|
|
|
4871
5056
|
);
|
|
4872
5057
|
|
|
4873
5058
|
// src/commands/destroy/schema.ts
|
|
4874
|
-
import { Command as
|
|
4875
|
-
var schema2 = new
|
|
5059
|
+
import { Command as Command38 } from "commander";
|
|
5060
|
+
var schema2 = new Command38("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4876
5061
|
(model, opts) => runCommand(
|
|
4877
5062
|
() => runDestroy(
|
|
4878
5063
|
"destroy-schema",
|
|
@@ -4893,8 +5078,8 @@ var schema2 = new Command37("schema").description("destroy a zod schema generate
|
|
|
4893
5078
|
);
|
|
4894
5079
|
|
|
4895
5080
|
// src/commands/destroy/resource.ts
|
|
4896
|
-
import { Command as
|
|
4897
|
-
var resource2 = new
|
|
5081
|
+
import { Command as Command39 } from "commander";
|
|
5082
|
+
var resource2 = new Command39("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4898
5083
|
(model, opts) => runCommand(
|
|
4899
5084
|
() => runDestroy(
|
|
4900
5085
|
"destroy-resource",
|
|
@@ -4915,8 +5100,8 @@ var resource2 = new Command38("resource").description("destroy a resource genera
|
|
|
4915
5100
|
);
|
|
4916
5101
|
|
|
4917
5102
|
// src/commands/destroy/scaffold.ts
|
|
4918
|
-
import { Command as
|
|
4919
|
-
var scaffold2 = new
|
|
5103
|
+
import { Command as Command40 } from "commander";
|
|
5104
|
+
var scaffold2 = new Command40("scaffold").description("destroy a scaffold generated by `vela generate scaffold`").argument("<model>", "model name used when the scaffold was generated (e.g., contact, todo)").option("-y, --yes", "skip confirmation prompt").option(
|
|
4920
5105
|
"--route <route>",
|
|
4921
5106
|
"custom route the scaffold was generated at (must match the --route used at generation)"
|
|
4922
5107
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
@@ -4943,9 +5128,9 @@ var scaffold2 = new Command39("scaffold").description("destroy a scaffold genera
|
|
|
4943
5128
|
);
|
|
4944
5129
|
|
|
4945
5130
|
// src/commands/destroy/deployment.ts
|
|
4946
|
-
import
|
|
4947
|
-
import { Command as
|
|
4948
|
-
import * as
|
|
5131
|
+
import process19 from "node:process";
|
|
5132
|
+
import { Command as Command41 } from "commander";
|
|
5133
|
+
import * as p26 from "@clack/prompts";
|
|
4949
5134
|
import pc13 from "picocolors";
|
|
4950
5135
|
|
|
4951
5136
|
// src/lib/destroy-guard.ts
|
|
@@ -4993,11 +5178,11 @@ function describe({ appName, envTag, purge }) {
|
|
|
4993
5178
|
}
|
|
4994
5179
|
|
|
4995
5180
|
// src/lib/deploy-report.ts
|
|
4996
|
-
import * as
|
|
5181
|
+
import * as p25 from "@clack/prompts";
|
|
4997
5182
|
import pc12 from "picocolors";
|
|
4998
5183
|
|
|
4999
5184
|
// src/lib/server-identity.ts
|
|
5000
|
-
import * as
|
|
5185
|
+
import * as p24 from "@clack/prompts";
|
|
5001
5186
|
import pc11 from "picocolors";
|
|
5002
5187
|
|
|
5003
5188
|
// src/lib/velastack-api.ts
|
|
@@ -5087,7 +5272,7 @@ async function ensureServerIdentity(session, apiKey) {
|
|
|
5087
5272
|
if (!existing || existing.serverId !== registered.serverId || existing.originHost !== registered.originHost || existing.token !== registered.token) {
|
|
5088
5273
|
await writeServerIdentity(session, registered);
|
|
5089
5274
|
if (existing) {
|
|
5090
|
-
|
|
5275
|
+
p24.log.info(`${pc11.cyan(session.target)} was re-registered with velastack.dev.`);
|
|
5091
5276
|
}
|
|
5092
5277
|
}
|
|
5093
5278
|
await runServerScript(session, "origin.sh");
|
|
@@ -5127,7 +5312,7 @@ function createDeployReporter(workspaceRootDir) {
|
|
|
5127
5312
|
const link2 = readProjectConfig(workspaceRootDir);
|
|
5128
5313
|
const apiKey = link2 ? readApiKey() : null;
|
|
5129
5314
|
if (link2 && !apiKey) {
|
|
5130
|
-
|
|
5315
|
+
p25.log.warn(
|
|
5131
5316
|
`This project is linked to ${pc12.cyan(link2.projectName)} on velastack.dev, but there is no
|
|
5132
5317
|
API key here, so this deploy will not be recorded. Run ${pc12.cyan("vela login")}, or set
|
|
5133
5318
|
${pc12.cyan("VELA_API_KEY")}.`
|
|
@@ -5177,7 +5362,7 @@ async function reportEnvironmentDestroyed(workspaceRootDir, envTag) {
|
|
|
5177
5362
|
}
|
|
5178
5363
|
}
|
|
5179
5364
|
function warn(what, err) {
|
|
5180
|
-
|
|
5365
|
+
p25.log.warn(
|
|
5181
5366
|
`velastack.dev could not ${what}.
|
|
5182
5367
|
${pc12.dim(err instanceof Error ? err.message : String(err))}`
|
|
5183
5368
|
);
|
|
@@ -5186,7 +5371,7 @@ ${pc12.dim(err instanceof Error ? err.message : String(err))}`
|
|
|
5186
5371
|
// src/commands/destroy/deployment.ts
|
|
5187
5372
|
var deployment = addLockWaitOption(
|
|
5188
5373
|
addTargetOptions(
|
|
5189
|
-
new
|
|
5374
|
+
new Command41("deployment").description("remove a deployed environment from its server").configureHelp(helpConfig),
|
|
5190
5375
|
"production"
|
|
5191
5376
|
)
|
|
5192
5377
|
).option("--purge", "also delete the database and uploaded files").option("-y, --yes", "skip the confirmation prompt").option(
|
|
@@ -5205,7 +5390,7 @@ var deployment = addLockWaitOption(
|
|
|
5205
5390
|
purge: options.purge === true,
|
|
5206
5391
|
yes: options.yes === true,
|
|
5207
5392
|
confirm: options.confirm,
|
|
5208
|
-
interactive: Boolean(
|
|
5393
|
+
interactive: Boolean(process19.stdin.isTTY && process19.stdout.isTTY)
|
|
5209
5394
|
});
|
|
5210
5395
|
if (decision.kind === "refuse") throw new Error(decision.message);
|
|
5211
5396
|
if (decision.kind === "prompt") {
|
|
@@ -5220,13 +5405,13 @@ var deployment = addLockWaitOption(
|
|
|
5220
5405
|
stream: true
|
|
5221
5406
|
});
|
|
5222
5407
|
if (result?.existed === false) {
|
|
5223
|
-
|
|
5408
|
+
p26.log.info(
|
|
5224
5409
|
`Nothing named ${pc13.cyan(`${ctx.appName} (${ctx.targetName})`)} on ${ctx.server}; nothing to remove.`
|
|
5225
5410
|
);
|
|
5226
5411
|
return;
|
|
5227
5412
|
}
|
|
5228
5413
|
await reportEnvironmentDestroyed(ctx.workspaceRootDir, ctx.envTag);
|
|
5229
|
-
|
|
5414
|
+
p26.log.success(
|
|
5230
5415
|
`Removed ${pc13.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${ctx.server}.` + (result?.purged ? result.trash ? `
|
|
5231
5416
|
|
|
5232
5417
|
A snapshot of its data is at ${pc13.cyan(result.trash)} on the server for two weeks.` : "" : `
|
|
@@ -5244,35 +5429,35 @@ The database and uploads are still in the instance's shared directory. Pass ${pc
|
|
|
5244
5429
|
);
|
|
5245
5430
|
async function confirm8(appName, targetName, byName) {
|
|
5246
5431
|
if (byName) {
|
|
5247
|
-
const answer = await
|
|
5432
|
+
const answer = await p26.text({
|
|
5248
5433
|
message: `This removes ${pc13.cyan(`${appName} (${targetName})`)}. Type the app name to confirm`,
|
|
5249
5434
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
5250
5435
|
});
|
|
5251
|
-
if (
|
|
5252
|
-
|
|
5253
|
-
|
|
5436
|
+
if (p26.isCancel(answer)) {
|
|
5437
|
+
p26.cancel("Operation cancelled.");
|
|
5438
|
+
process19.exit(0);
|
|
5254
5439
|
}
|
|
5255
5440
|
return;
|
|
5256
5441
|
}
|
|
5257
|
-
const ok = await
|
|
5442
|
+
const ok = await p26.confirm({
|
|
5258
5443
|
message: `Remove ${appName} (${targetName})?`,
|
|
5259
5444
|
initialValue: false
|
|
5260
5445
|
});
|
|
5261
|
-
if (
|
|
5262
|
-
|
|
5263
|
-
|
|
5446
|
+
if (p26.isCancel(ok) || !ok) {
|
|
5447
|
+
p26.cancel("Operation cancelled.");
|
|
5448
|
+
process19.exit(0);
|
|
5264
5449
|
}
|
|
5265
5450
|
}
|
|
5266
5451
|
|
|
5267
5452
|
// src/commands/destroy.ts
|
|
5268
|
-
var destroy = new
|
|
5453
|
+
var destroy = new Command42("destroy").description("destroy scaffolding, or a deployment").configureHelp(helpConfig).addCommand(form2).addCommand(schema2).addCommand(resource2).addCommand(scaffold2).addCommand(deployment);
|
|
5269
5454
|
|
|
5270
5455
|
// src/commands/ui.ts
|
|
5271
|
-
import { Command as
|
|
5456
|
+
import { Command as Command48 } from "commander";
|
|
5272
5457
|
|
|
5273
5458
|
// src/commands/ui/add.ts
|
|
5274
|
-
import { Command as
|
|
5275
|
-
import * as
|
|
5459
|
+
import { Command as Command43 } from "commander";
|
|
5460
|
+
import * as p27 from "@clack/prompts";
|
|
5276
5461
|
import { installComponents } from "@velastack/patterns";
|
|
5277
5462
|
|
|
5278
5463
|
// src/lib/ui-add.ts
|
|
@@ -5321,10 +5506,10 @@ function uiAddReport(requested, outcome) {
|
|
|
5321
5506
|
}
|
|
5322
5507
|
|
|
5323
5508
|
// src/commands/ui/add.ts
|
|
5324
|
-
var add = new
|
|
5509
|
+
var add = new Command43("add").description("add ui components (shadcn-svelte items and vela components such as data-table)").argument("<components...>", "the components to add").option("--overwrite", "replace components that already exist", false).configureHelp(helpConfig).action(
|
|
5325
5510
|
(components, options) => runCommand(async () => {
|
|
5326
5511
|
const { workspaceRootDir } = await getWorkspace();
|
|
5327
|
-
const log45 =
|
|
5512
|
+
const log45 = p27.taskLog({ title: "Adding UI components..." });
|
|
5328
5513
|
let outcome;
|
|
5329
5514
|
try {
|
|
5330
5515
|
outcome = await installComponents({
|
|
@@ -5343,13 +5528,13 @@ var add = new Command42("add").description("add ui components (shadcn-svelte ite
|
|
|
5343
5528
|
);
|
|
5344
5529
|
|
|
5345
5530
|
// src/commands/ui/base.ts
|
|
5346
|
-
import { Command as
|
|
5347
|
-
import * as
|
|
5531
|
+
import { Command as Command44 } from "commander";
|
|
5532
|
+
import * as p28 from "@clack/prompts";
|
|
5348
5533
|
import { applyBaseColor } from "@velastack/patterns";
|
|
5349
|
-
var base = new
|
|
5534
|
+
var base = new Command44("base").description("change the base (gray) palette").argument("<color>", `base color to use (${BASE_COLORS.join(", ")})`).configureHelp(helpConfig).action(
|
|
5350
5535
|
(color) => runCommand(async () => {
|
|
5351
5536
|
const { workspaceRootDir } = await getWorkspace();
|
|
5352
|
-
const log45 =
|
|
5537
|
+
const log45 = p28.taskLog({ title: `Applying the ${color} palette...` });
|
|
5353
5538
|
let outcome;
|
|
5354
5539
|
try {
|
|
5355
5540
|
outcome = await applyBaseColor({ root: workspaceRootDir, color });
|
|
@@ -5371,8 +5556,8 @@ var base = new Command43("base").description("change the base (gray) palette").a
|
|
|
5371
5556
|
);
|
|
5372
5557
|
|
|
5373
5558
|
// src/commands/ui/list.ts
|
|
5374
|
-
import { Command as
|
|
5375
|
-
import * as
|
|
5559
|
+
import { Command as Command45 } from "commander";
|
|
5560
|
+
import * as p29 from "@clack/prompts";
|
|
5376
5561
|
import { listComponents } from "@velastack/patterns";
|
|
5377
5562
|
|
|
5378
5563
|
// src/lib/ui-list.ts
|
|
@@ -5403,7 +5588,7 @@ function uiListReport(result) {
|
|
|
5403
5588
|
}
|
|
5404
5589
|
|
|
5405
5590
|
// src/commands/ui/list.ts
|
|
5406
|
-
var list = new
|
|
5591
|
+
var list = new Command45("list").description("list installed ui components, vela components and the style registry").option("--json", "print the result as JSON", false).configureHelp(helpConfig).action(
|
|
5407
5592
|
(options) => runCommand(async () => {
|
|
5408
5593
|
const { workspaceRootDir } = await getWorkspace();
|
|
5409
5594
|
if (options.json) {
|
|
@@ -5411,7 +5596,7 @@ var list = new Command44("list").description("list installed ui components, vela
|
|
|
5411
5596
|
console.log(JSON.stringify(result2, null, 2));
|
|
5412
5597
|
return;
|
|
5413
5598
|
}
|
|
5414
|
-
const spinner7 =
|
|
5599
|
+
const spinner7 = p29.spinner();
|
|
5415
5600
|
spinner7.start("Reading the registry...");
|
|
5416
5601
|
let result;
|
|
5417
5602
|
try {
|
|
@@ -5423,15 +5608,15 @@ var list = new Command44("list").description("list installed ui components, vela
|
|
|
5423
5608
|
spinner7.stop(`Read the ${result.style} registry`);
|
|
5424
5609
|
reportResult(uiListReport(result));
|
|
5425
5610
|
if (result.registryUnavailable) {
|
|
5426
|
-
|
|
5611
|
+
p29.log.warn(`${result.registryUnavailable}
|
|
5427
5612
|
Registry components are not listed.`);
|
|
5428
5613
|
}
|
|
5429
5614
|
}, "Failed to list UI components.")
|
|
5430
5615
|
);
|
|
5431
5616
|
|
|
5432
5617
|
// src/commands/ui/style.ts
|
|
5433
|
-
import { Command as
|
|
5434
|
-
import * as
|
|
5618
|
+
import { Command as Command46 } from "commander";
|
|
5619
|
+
import * as p30 from "@clack/prompts";
|
|
5435
5620
|
import { switchStyle } from "@velastack/patterns";
|
|
5436
5621
|
|
|
5437
5622
|
// src/lib/ui-style.ts
|
|
@@ -5457,10 +5642,10 @@ function uiStyleReport(result) {
|
|
|
5457
5642
|
}
|
|
5458
5643
|
|
|
5459
5644
|
// src/commands/ui/style.ts
|
|
5460
|
-
var style = new
|
|
5645
|
+
var style = new Command46("style").description("switch the shadcn-svelte style, re-adding its components").argument("<style>", `style to switch to (${STYLES.join(", ")})`).option("-y, --yes", "skip the confirmation prompt").option("--no-font", "keep the current font instead of applying the style's").configureHelp(helpConfig).action(
|
|
5461
5646
|
(name, options) => runCommand(async () => {
|
|
5462
5647
|
const { workspaceRootDir } = await getWorkspace();
|
|
5463
|
-
const spinner7 =
|
|
5648
|
+
const spinner7 = p30.spinner();
|
|
5464
5649
|
spinner7.start(`Reading the ${name} registry...`);
|
|
5465
5650
|
let log45;
|
|
5466
5651
|
let outcome;
|
|
@@ -5473,20 +5658,20 @@ var style = new Command45("style").description("switch the shadcn-svelte style,
|
|
|
5473
5658
|
confirm: async (components) => {
|
|
5474
5659
|
spinner7.stop(`Read the ${name} registry`);
|
|
5475
5660
|
if (components.length > 0) {
|
|
5476
|
-
|
|
5661
|
+
p30.log.info(
|
|
5477
5662
|
`Re-adds ${components.length} component(s) from the ${name} registry; local edits to their files are lost:
|
|
5478
5663
|
${components.map((c) => `- ${c}`).join("\n")}`
|
|
5479
5664
|
);
|
|
5480
5665
|
} else {
|
|
5481
|
-
|
|
5666
|
+
p30.log.info(
|
|
5482
5667
|
`No installed component comes from the registry; only the config changes.`
|
|
5483
5668
|
);
|
|
5484
5669
|
}
|
|
5485
5670
|
if (!options.yes) {
|
|
5486
|
-
const ok = await
|
|
5487
|
-
if (
|
|
5671
|
+
const ok = await p30.confirm({ message: `Switch to ${name}?`, initialValue: false });
|
|
5672
|
+
if (p30.isCancel(ok) || !ok) return false;
|
|
5488
5673
|
}
|
|
5489
|
-
log45 =
|
|
5674
|
+
log45 = p30.taskLog({ title: `Switching to the ${name} style...` });
|
|
5490
5675
|
return true;
|
|
5491
5676
|
}
|
|
5492
5677
|
});
|
|
@@ -5497,11 +5682,11 @@ ${components.map((c) => `- ${c}`).join("\n")}`
|
|
|
5497
5682
|
}
|
|
5498
5683
|
spinner7.stop(`Read the ${name} registry`);
|
|
5499
5684
|
if (outcome.status === "unchanged") {
|
|
5500
|
-
|
|
5685
|
+
p30.log.info(`Already using the ${name} style.`);
|
|
5501
5686
|
return;
|
|
5502
5687
|
}
|
|
5503
5688
|
if (outcome.status === "cancelled") {
|
|
5504
|
-
|
|
5689
|
+
p30.cancel("Operation cancelled.");
|
|
5505
5690
|
return;
|
|
5506
5691
|
}
|
|
5507
5692
|
log45?.success("Style switched");
|
|
@@ -5510,13 +5695,13 @@ ${components.map((c) => `- ${c}`).join("\n")}`
|
|
|
5510
5695
|
);
|
|
5511
5696
|
|
|
5512
5697
|
// src/commands/ui/theme.ts
|
|
5513
|
-
import { Command as
|
|
5514
|
-
import * as
|
|
5698
|
+
import { Command as Command47 } from "commander";
|
|
5699
|
+
import * as p31 from "@clack/prompts";
|
|
5515
5700
|
import { applyTheme } from "@velastack/patterns";
|
|
5516
|
-
var theme = new
|
|
5701
|
+
var theme = new Command47("theme").description("change the accent color, keeping the base palette").argument("<accent>", `accent to use (${THEMES.join(", ")})`).configureHelp(helpConfig).action(
|
|
5517
5702
|
(accent) => runCommand(async () => {
|
|
5518
5703
|
const { workspaceRootDir } = await getWorkspace();
|
|
5519
|
-
const log45 =
|
|
5704
|
+
const log45 = p31.taskLog({ title: `Applying the ${accent} accent...` });
|
|
5520
5705
|
let outcome;
|
|
5521
5706
|
try {
|
|
5522
5707
|
outcome = await applyTheme({ root: workspaceRootDir, theme: accent });
|
|
@@ -5538,22 +5723,22 @@ var theme = new Command46("theme").description("change the accent color, keeping
|
|
|
5538
5723
|
);
|
|
5539
5724
|
|
|
5540
5725
|
// src/commands/ui.ts
|
|
5541
|
-
var ui = new
|
|
5726
|
+
var ui = new Command48("ui").description("generate ui components").configureHelp(helpConfig).addCommand(add).addCommand(list).addCommand(style).addCommand(base).addCommand(theme);
|
|
5542
5727
|
|
|
5543
5728
|
// src/commands/legal.ts
|
|
5544
|
-
import { Command as
|
|
5729
|
+
import { Command as Command51 } from "commander";
|
|
5545
5730
|
|
|
5546
5731
|
// src/commands/legal/terms.ts
|
|
5547
5732
|
import fs26 from "node:fs";
|
|
5548
5733
|
import path23 from "node:path";
|
|
5549
|
-
import { Command as
|
|
5550
|
-
import * as
|
|
5734
|
+
import { Command as Command49 } from "commander";
|
|
5735
|
+
import * as p33 from "@clack/prompts";
|
|
5551
5736
|
|
|
5552
5737
|
// src/commands/legal/shared.ts
|
|
5553
|
-
import
|
|
5554
|
-
import * as
|
|
5738
|
+
import process20 from "node:process";
|
|
5739
|
+
import * as p32 from "@clack/prompts";
|
|
5555
5740
|
var sharedFields = {
|
|
5556
|
-
websiteUrl: () =>
|
|
5741
|
+
websiteUrl: () => p32.text({
|
|
5557
5742
|
message: "What is your website URL?",
|
|
5558
5743
|
placeholder: "http://www.mysite.com",
|
|
5559
5744
|
validate: (value) => {
|
|
@@ -5562,7 +5747,7 @@ var sharedFields = {
|
|
|
5562
5747
|
}
|
|
5563
5748
|
}
|
|
5564
5749
|
}),
|
|
5565
|
-
websiteName: () =>
|
|
5750
|
+
websiteName: () => p32.text({
|
|
5566
5751
|
message: "What is your website name?",
|
|
5567
5752
|
placeholder: "My Site",
|
|
5568
5753
|
validate: (value) => {
|
|
@@ -5571,7 +5756,7 @@ var sharedFields = {
|
|
|
5571
5756
|
}
|
|
5572
5757
|
}
|
|
5573
5758
|
}),
|
|
5574
|
-
entityType: () =>
|
|
5759
|
+
entityType: () => p32.select({
|
|
5575
5760
|
message: "Entity type",
|
|
5576
5761
|
options: [
|
|
5577
5762
|
{
|
|
@@ -5582,7 +5767,7 @@ var sharedFields = {
|
|
|
5582
5767
|
{ value: "individual", label: "I'm an Individual" }
|
|
5583
5768
|
]
|
|
5584
5769
|
}),
|
|
5585
|
-
businessName: ({ results }) => results?.entityType === "business" ?
|
|
5770
|
+
businessName: ({ results }) => results?.entityType === "business" ? p32.text({
|
|
5586
5771
|
message: "What is the name of the business?",
|
|
5587
5772
|
placeholder: "My Company LLC",
|
|
5588
5773
|
validate: (value) => {
|
|
@@ -5591,7 +5776,7 @@ var sharedFields = {
|
|
|
5591
5776
|
}
|
|
5592
5777
|
}
|
|
5593
5778
|
}) : void 0,
|
|
5594
|
-
businessAddress: ({ results }) => results?.entityType === "business" ?
|
|
5779
|
+
businessAddress: ({ results }) => results?.entityType === "business" ? p32.text({
|
|
5595
5780
|
message: "What is the address of the business?",
|
|
5596
5781
|
placeholder: "1 Cupertino, CA 95014",
|
|
5597
5782
|
validate: (value) => {
|
|
@@ -5600,7 +5785,7 @@ var sharedFields = {
|
|
|
5600
5785
|
}
|
|
5601
5786
|
}
|
|
5602
5787
|
}) : void 0,
|
|
5603
|
-
country: () =>
|
|
5788
|
+
country: () => p32.text({
|
|
5604
5789
|
message: "Enter the country",
|
|
5605
5790
|
validate: (value) => {
|
|
5606
5791
|
if (!value) {
|
|
@@ -5608,7 +5793,7 @@ var sharedFields = {
|
|
|
5608
5793
|
}
|
|
5609
5794
|
}
|
|
5610
5795
|
}),
|
|
5611
|
-
state: () =>
|
|
5796
|
+
state: () => p32.text({
|
|
5612
5797
|
message: "Enter the state",
|
|
5613
5798
|
validate: (value) => {
|
|
5614
5799
|
if (!value) {
|
|
@@ -5618,11 +5803,11 @@ var sharedFields = {
|
|
|
5618
5803
|
})
|
|
5619
5804
|
};
|
|
5620
5805
|
var onCancel = () => {
|
|
5621
|
-
|
|
5622
|
-
|
|
5806
|
+
p32.cancel("Operation cancelled.");
|
|
5807
|
+
process20.exit(0);
|
|
5623
5808
|
};
|
|
5624
5809
|
async function contactMethods(type) {
|
|
5625
|
-
const selection = await
|
|
5810
|
+
const selection = await p32.multiselect({
|
|
5626
5811
|
message: `How can users contact you for any questions regarding your ${type === "privacy" ? "Privacy Policy" : "Terms & Conditions"}? Check all that apply`,
|
|
5627
5812
|
options: [
|
|
5628
5813
|
{ value: "email", label: "By email" },
|
|
@@ -5631,11 +5816,11 @@ async function contactMethods(type) {
|
|
|
5631
5816
|
{ value: "mail", label: "By sending post mail" }
|
|
5632
5817
|
]
|
|
5633
5818
|
});
|
|
5634
|
-
if (
|
|
5819
|
+
if (p32.isCancel(selection)) onCancel();
|
|
5635
5820
|
const contact = selection;
|
|
5636
5821
|
const details = {};
|
|
5637
5822
|
if (contact.includes("email")) {
|
|
5638
|
-
const email3 = await
|
|
5823
|
+
const email3 = await p32.text({
|
|
5639
5824
|
message: "What's the email?",
|
|
5640
5825
|
placeholder: "office@mycompany.com",
|
|
5641
5826
|
validate: (value) => {
|
|
@@ -5644,11 +5829,11 @@ async function contactMethods(type) {
|
|
|
5644
5829
|
}
|
|
5645
5830
|
}
|
|
5646
5831
|
});
|
|
5647
|
-
if (
|
|
5832
|
+
if (p32.isCancel(email3)) onCancel();
|
|
5648
5833
|
details.email = email3;
|
|
5649
5834
|
}
|
|
5650
5835
|
if (contact.includes("page")) {
|
|
5651
|
-
const page = await
|
|
5836
|
+
const page = await p32.text({
|
|
5652
5837
|
message: "What's the link?",
|
|
5653
5838
|
placeholder: "http://www.mycompany.com/contact",
|
|
5654
5839
|
validate: (value) => {
|
|
@@ -5657,11 +5842,11 @@ async function contactMethods(type) {
|
|
|
5657
5842
|
}
|
|
5658
5843
|
}
|
|
5659
5844
|
});
|
|
5660
|
-
if (
|
|
5845
|
+
if (p32.isCancel(page)) onCancel();
|
|
5661
5846
|
details.page = page;
|
|
5662
5847
|
}
|
|
5663
5848
|
if (contact.includes("phone")) {
|
|
5664
|
-
const phone = await
|
|
5849
|
+
const phone = await p32.text({
|
|
5665
5850
|
message: "What's the phone number?",
|
|
5666
5851
|
placeholder: "408.996.1010",
|
|
5667
5852
|
validate: (value) => {
|
|
@@ -5670,11 +5855,11 @@ async function contactMethods(type) {
|
|
|
5670
5855
|
}
|
|
5671
5856
|
}
|
|
5672
5857
|
});
|
|
5673
|
-
if (
|
|
5858
|
+
if (p32.isCancel(phone)) onCancel();
|
|
5674
5859
|
details.phone = phone;
|
|
5675
5860
|
}
|
|
5676
5861
|
if (contact.includes("mail")) {
|
|
5677
|
-
const address = await
|
|
5862
|
+
const address = await p32.text({
|
|
5678
5863
|
message: "What's the address?",
|
|
5679
5864
|
placeholder: "767 Fifth Avenue New York, NY 10153, United States",
|
|
5680
5865
|
validate: (value) => {
|
|
@@ -5683,7 +5868,7 @@ async function contactMethods(type) {
|
|
|
5683
5868
|
}
|
|
5684
5869
|
}
|
|
5685
5870
|
});
|
|
5686
|
-
if (
|
|
5871
|
+
if (p32.isCancel(address)) onCancel();
|
|
5687
5872
|
details.address = address;
|
|
5688
5873
|
}
|
|
5689
5874
|
return { methods: contact, details };
|
|
@@ -6079,7 +6264,7 @@ var generateTermsHtml = (answers) => {
|
|
|
6079
6264
|
};
|
|
6080
6265
|
async function termsAction() {
|
|
6081
6266
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
6082
|
-
const core = await
|
|
6267
|
+
const core = await p33.group(
|
|
6083
6268
|
{
|
|
6084
6269
|
websiteUrl: sharedFields.websiteUrl,
|
|
6085
6270
|
websiteName: sharedFields.websiteName,
|
|
@@ -6091,25 +6276,25 @@ async function termsAction() {
|
|
|
6091
6276
|
},
|
|
6092
6277
|
{ onCancel }
|
|
6093
6278
|
);
|
|
6094
|
-
const accounts = await
|
|
6279
|
+
const accounts = await p33.select({
|
|
6095
6280
|
message: "Can users create accounts?",
|
|
6096
6281
|
options: [
|
|
6097
6282
|
{ value: "yes", label: "Yes, users can create accounts" },
|
|
6098
6283
|
{ value: "no", label: "No" }
|
|
6099
6284
|
]
|
|
6100
6285
|
});
|
|
6101
|
-
if (
|
|
6102
|
-
const userContent = await
|
|
6286
|
+
if (p33.isCancel(accounts)) onCancel();
|
|
6287
|
+
const userContent = await p33.select({
|
|
6103
6288
|
message: "Can users create and/or upload content (ie. text, images)?",
|
|
6104
6289
|
options: [
|
|
6105
6290
|
{ value: "yes", label: "Yes, users can create and/or upload content" },
|
|
6106
6291
|
{ value: "no", label: "No" }
|
|
6107
6292
|
]
|
|
6108
6293
|
});
|
|
6109
|
-
if (
|
|
6294
|
+
if (p33.isCancel(userContent)) onCancel();
|
|
6110
6295
|
let infringementEmail;
|
|
6111
6296
|
if (userContent === "yes") {
|
|
6112
|
-
const email3 = await
|
|
6297
|
+
const email3 = await p33.text({
|
|
6113
6298
|
message: "What's the email address where you will receive infringements notices?",
|
|
6114
6299
|
placeholder: "dmca@website.com",
|
|
6115
6300
|
validate: (value) => {
|
|
@@ -6118,10 +6303,10 @@ async function termsAction() {
|
|
|
6118
6303
|
}
|
|
6119
6304
|
}
|
|
6120
6305
|
});
|
|
6121
|
-
if (
|
|
6306
|
+
if (p33.isCancel(email3)) onCancel();
|
|
6122
6307
|
infringementEmail = email3;
|
|
6123
6308
|
}
|
|
6124
|
-
const canBuyGoods = await
|
|
6309
|
+
const canBuyGoods = await p33.select({
|
|
6125
6310
|
message: "Can users buy goods (products, items)?",
|
|
6126
6311
|
options: [
|
|
6127
6312
|
{
|
|
@@ -6131,28 +6316,28 @@ async function termsAction() {
|
|
|
6131
6316
|
{ value: "no", label: "No" }
|
|
6132
6317
|
]
|
|
6133
6318
|
});
|
|
6134
|
-
if (
|
|
6135
|
-
const subscriptions2 = await
|
|
6319
|
+
if (p33.isCancel(canBuyGoods)) onCancel();
|
|
6320
|
+
const subscriptions2 = await p33.select({
|
|
6136
6321
|
message: "Do you offer subscription plans?",
|
|
6137
6322
|
options: [
|
|
6138
6323
|
{ value: "yes", label: "Yes, we offer subscription plans" },
|
|
6139
6324
|
{ value: "no", label: "No" }
|
|
6140
6325
|
]
|
|
6141
6326
|
});
|
|
6142
|
-
if (
|
|
6327
|
+
if (p33.isCancel(subscriptions2)) onCancel();
|
|
6143
6328
|
let freeTrial;
|
|
6144
6329
|
if (subscriptions2 === "yes") {
|
|
6145
|
-
const ft = await
|
|
6330
|
+
const ft = await p33.select({
|
|
6146
6331
|
message: "Do you offer a free trial?",
|
|
6147
6332
|
options: [
|
|
6148
6333
|
{ value: "yes", label: "Yes" },
|
|
6149
6334
|
{ value: "no", label: "No" }
|
|
6150
6335
|
]
|
|
6151
6336
|
});
|
|
6152
|
-
if (
|
|
6337
|
+
if (p33.isCancel(ft)) onCancel();
|
|
6153
6338
|
freeTrial = ft;
|
|
6154
6339
|
}
|
|
6155
|
-
const exclusiveContent = await
|
|
6340
|
+
const exclusiveContent = await p33.select({
|
|
6156
6341
|
message: "Do you want to make it clear that your own content & trademarks are your exclusive property?",
|
|
6157
6342
|
options: [
|
|
6158
6343
|
{
|
|
@@ -6162,24 +6347,24 @@ async function termsAction() {
|
|
|
6162
6347
|
{ value: "no", label: "No" }
|
|
6163
6348
|
]
|
|
6164
6349
|
});
|
|
6165
|
-
if (
|
|
6166
|
-
const feedbackReuse = await
|
|
6350
|
+
if (p33.isCancel(exclusiveContent)) onCancel();
|
|
6351
|
+
const feedbackReuse = await p33.select({
|
|
6167
6352
|
message: "If users provide you feedback & suggestions, do you want to use this feedback without compensation or credits given?",
|
|
6168
6353
|
options: [
|
|
6169
6354
|
{ value: "yes", label: "Yes, we may implement any feedback or suggestions we receive" },
|
|
6170
6355
|
{ value: "no", label: "No" }
|
|
6171
6356
|
]
|
|
6172
6357
|
});
|
|
6173
|
-
if (
|
|
6174
|
-
const promotions = await
|
|
6358
|
+
if (p33.isCancel(feedbackReuse)) onCancel();
|
|
6359
|
+
const promotions = await p33.select({
|
|
6175
6360
|
message: "Do you plan to offer promotions, contests, sweepstakes?",
|
|
6176
6361
|
options: [
|
|
6177
6362
|
{ value: "yes", label: "Yes, we may offer promotions, contests, sweepstakes" },
|
|
6178
6363
|
{ value: "no", label: "No" }
|
|
6179
6364
|
]
|
|
6180
6365
|
});
|
|
6181
|
-
if (
|
|
6182
|
-
const mobileAppRaw = await
|
|
6366
|
+
if (p33.isCancel(promotions)) onCancel();
|
|
6367
|
+
const mobileAppRaw = await p33.multiselect({
|
|
6183
6368
|
message: "Is the Service distributed through any mobile app stores? Check all that apply",
|
|
6184
6369
|
options: [
|
|
6185
6370
|
{ value: "apple", label: "Apple App Store" },
|
|
@@ -6187,7 +6372,7 @@ async function termsAction() {
|
|
|
6187
6372
|
],
|
|
6188
6373
|
required: false
|
|
6189
6374
|
});
|
|
6190
|
-
if (
|
|
6375
|
+
if (p33.isCancel(mobileAppRaw)) onCancel();
|
|
6191
6376
|
const mobileApp = mobileAppRaw ?? [];
|
|
6192
6377
|
const contact = await contactMethods("terms");
|
|
6193
6378
|
const html = generateTermsHtml({
|
|
@@ -6230,13 +6415,13 @@ async function termsAction() {
|
|
|
6230
6415
|
]
|
|
6231
6416
|
});
|
|
6232
6417
|
}
|
|
6233
|
-
var terms = new
|
|
6418
|
+
var terms = new Command49("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
|
|
6234
6419
|
|
|
6235
6420
|
// src/commands/legal/privacy.ts
|
|
6236
6421
|
import fs27 from "node:fs";
|
|
6237
6422
|
import path24 from "node:path";
|
|
6238
|
-
import { Command as
|
|
6239
|
-
import * as
|
|
6423
|
+
import { Command as Command50 } from "commander";
|
|
6424
|
+
import * as p34 from "@clack/prompts";
|
|
6240
6425
|
var mapLabels = {
|
|
6241
6426
|
personalInfo: {
|
|
6242
6427
|
email: "Email address",
|
|
@@ -6654,12 +6839,12 @@ var generatePrivacyHtml = (answers) => {
|
|
|
6654
6839
|
return `<section data-role="content">${sections.join("")}</section>`;
|
|
6655
6840
|
};
|
|
6656
6841
|
async function promptWithCustom(message, options, customMessage) {
|
|
6657
|
-
const selection = await
|
|
6658
|
-
if (
|
|
6842
|
+
const selection = await p34.multiselect({ message, options });
|
|
6843
|
+
if (p34.isCancel(selection)) onCancel();
|
|
6659
6844
|
const values = selection;
|
|
6660
6845
|
if (values.includes("custom")) {
|
|
6661
|
-
const custom = await
|
|
6662
|
-
if (
|
|
6846
|
+
const custom = await p34.text({ message: customMessage });
|
|
6847
|
+
if (p34.isCancel(custom)) onCancel();
|
|
6663
6848
|
const idx = values.indexOf("custom");
|
|
6664
6849
|
if (idx !== -1) values.splice(idx, 1);
|
|
6665
6850
|
if (custom) values.push(String(custom));
|
|
@@ -6668,7 +6853,7 @@ async function promptWithCustom(message, options, customMessage) {
|
|
|
6668
6853
|
}
|
|
6669
6854
|
async function privacyAction() {
|
|
6670
6855
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
6671
|
-
const core = await
|
|
6856
|
+
const core = await p34.group(
|
|
6672
6857
|
{
|
|
6673
6858
|
websiteUrl: sharedFields.websiteUrl,
|
|
6674
6859
|
websiteName: sharedFields.websiteName,
|
|
@@ -6680,7 +6865,7 @@ async function privacyAction() {
|
|
|
6680
6865
|
},
|
|
6681
6866
|
{ onCancel }
|
|
6682
6867
|
);
|
|
6683
|
-
const personalInfo = await
|
|
6868
|
+
const personalInfo = await p34.multiselect({
|
|
6684
6869
|
message: "What kind of personal information do you collect from users? Check all that apply",
|
|
6685
6870
|
options: [
|
|
6686
6871
|
{ value: "email", label: "Email address" },
|
|
@@ -6695,16 +6880,16 @@ async function privacyAction() {
|
|
|
6695
6880
|
],
|
|
6696
6881
|
required: false
|
|
6697
6882
|
});
|
|
6698
|
-
if (
|
|
6883
|
+
if (p34.isCancel(personalInfo)) onCancel();
|
|
6699
6884
|
const contact = await contactMethods("privacy");
|
|
6700
|
-
const tracking = await
|
|
6885
|
+
const tracking = await p34.select({
|
|
6701
6886
|
message: "Do you use tracking and/or analytics tools, such as Google Analytics?",
|
|
6702
6887
|
options: [
|
|
6703
6888
|
{ value: "yes", label: "Yes, we use Google Analytics or other related tools" },
|
|
6704
6889
|
{ value: "no", label: "No" }
|
|
6705
6890
|
]
|
|
6706
6891
|
});
|
|
6707
|
-
if (
|
|
6892
|
+
if (p34.isCancel(tracking)) onCancel();
|
|
6708
6893
|
let trackingTools;
|
|
6709
6894
|
if (tracking === "yes") {
|
|
6710
6895
|
trackingTools = await promptWithCustom(
|
|
@@ -6723,7 +6908,7 @@ async function privacyAction() {
|
|
|
6723
6908
|
"Enter your custom tracking/analytics tool name"
|
|
6724
6909
|
);
|
|
6725
6910
|
}
|
|
6726
|
-
const sendEmails = await
|
|
6911
|
+
const sendEmails = await p34.select({
|
|
6727
6912
|
message: "Do you send emails to users?",
|
|
6728
6913
|
options: [
|
|
6729
6914
|
{
|
|
@@ -6733,7 +6918,7 @@ async function privacyAction() {
|
|
|
6733
6918
|
{ value: "no", label: "No" }
|
|
6734
6919
|
]
|
|
6735
6920
|
});
|
|
6736
|
-
if (
|
|
6921
|
+
if (p34.isCancel(sendEmails)) onCancel();
|
|
6737
6922
|
let emailPlatforms;
|
|
6738
6923
|
if (sendEmails === "yes") {
|
|
6739
6924
|
emailPlatforms = await promptWithCustom(
|
|
@@ -6748,14 +6933,14 @@ async function privacyAction() {
|
|
|
6748
6933
|
"Enter your custom email platform"
|
|
6749
6934
|
);
|
|
6750
6935
|
}
|
|
6751
|
-
const showAds = await
|
|
6936
|
+
const showAds = await p34.select({
|
|
6752
6937
|
message: "Do you show ads?",
|
|
6753
6938
|
options: [
|
|
6754
6939
|
{ value: "yes", label: "Yes, we show ads" },
|
|
6755
6940
|
{ value: "no", label: "No" }
|
|
6756
6941
|
]
|
|
6757
6942
|
});
|
|
6758
|
-
if (
|
|
6943
|
+
if (p34.isCancel(showAds)) onCancel();
|
|
6759
6944
|
let adsPlatforms;
|
|
6760
6945
|
if (showAds === "yes") {
|
|
6761
6946
|
adsPlatforms = await promptWithCustom(
|
|
@@ -6778,7 +6963,7 @@ async function privacyAction() {
|
|
|
6778
6963
|
"Enter your custom ads platform"
|
|
6779
6964
|
);
|
|
6780
6965
|
}
|
|
6781
|
-
const canPay = await
|
|
6966
|
+
const canPay = await p34.select({
|
|
6782
6967
|
message: "Can users pay for products or services?",
|
|
6783
6968
|
options: [
|
|
6784
6969
|
{ value: "yes", label: "Yes, users can pay for our products/services" },
|
|
@@ -6788,7 +6973,7 @@ async function privacyAction() {
|
|
|
6788
6973
|
}
|
|
6789
6974
|
]
|
|
6790
6975
|
});
|
|
6791
|
-
if (
|
|
6976
|
+
if (p34.isCancel(canPay)) onCancel();
|
|
6792
6977
|
let paymentProcessors;
|
|
6793
6978
|
if (canPay === "yes") {
|
|
6794
6979
|
paymentProcessors = await promptWithCustom(
|
|
@@ -6819,14 +7004,14 @@ async function privacyAction() {
|
|
|
6819
7004
|
"Enter your custom payment processor/method"
|
|
6820
7005
|
);
|
|
6821
7006
|
}
|
|
6822
|
-
const remarketing = await
|
|
7007
|
+
const remarketing = await p34.select({
|
|
6823
7008
|
message: "Do you use remarketing services for marketing & advertising purposes?",
|
|
6824
7009
|
options: [
|
|
6825
7010
|
{ value: "yes", label: "Yes, we use remarketing services to advertise our business" },
|
|
6826
7011
|
{ value: "no", label: "No" }
|
|
6827
7012
|
]
|
|
6828
7013
|
});
|
|
6829
|
-
if (
|
|
7014
|
+
if (p34.isCancel(remarketing)) onCancel();
|
|
6830
7015
|
let remarketingPlatforms;
|
|
6831
7016
|
if (remarketing === "yes") {
|
|
6832
7017
|
remarketingPlatforms = await promptWithCustom(
|
|
@@ -6845,7 +7030,7 @@ async function privacyAction() {
|
|
|
6845
7030
|
"Enter your custom remarketing platform"
|
|
6846
7031
|
);
|
|
6847
7032
|
}
|
|
6848
|
-
const providersRaw = await
|
|
7033
|
+
const providersRaw = await p34.multiselect({
|
|
6849
7034
|
message: "Select if you use any of the following providers",
|
|
6850
7035
|
options: [
|
|
6851
7036
|
{ value: "recaptcha", label: "Invisible reCAPTCHA" },
|
|
@@ -6856,16 +7041,16 @@ async function privacyAction() {
|
|
|
6856
7041
|
],
|
|
6857
7042
|
required: false
|
|
6858
7043
|
});
|
|
6859
|
-
if (
|
|
7044
|
+
if (p34.isCancel(providersRaw)) onCancel();
|
|
6860
7045
|
const providers = providersRaw;
|
|
6861
7046
|
if (providers.includes("custom")) {
|
|
6862
|
-
const custom = await
|
|
6863
|
-
if (
|
|
7047
|
+
const custom = await p34.text({ message: "Enter your custom provider" });
|
|
7048
|
+
if (p34.isCancel(custom)) onCancel();
|
|
6864
7049
|
const idx = providers.indexOf("custom");
|
|
6865
7050
|
if (idx !== -1) providers.splice(idx, 1);
|
|
6866
7051
|
if (custom) providers.push(String(custom));
|
|
6867
7052
|
}
|
|
6868
|
-
const usStates = await
|
|
7053
|
+
const usStates = await p34.select({
|
|
6869
7054
|
message: "Include U.S. state privacy rights (CCPA/CPRA, VCDPA, CPA, CTDPA, UCPA, TX, OR, etc.)?",
|
|
6870
7055
|
options: [
|
|
6871
7056
|
{
|
|
@@ -6876,55 +7061,55 @@ async function privacyAction() {
|
|
|
6876
7061
|
],
|
|
6877
7062
|
initialValue: "yes"
|
|
6878
7063
|
});
|
|
6879
|
-
if (
|
|
6880
|
-
const gdpr = await
|
|
7064
|
+
if (p34.isCancel(usStates)) onCancel();
|
|
7065
|
+
const gdpr = await p34.select({
|
|
6881
7066
|
message: "Do you want your Privacy Policy to include GDPR / UK GDPR wording?",
|
|
6882
7067
|
options: [
|
|
6883
7068
|
{ value: "yes", label: "Yes. Include GDPR rights for EEA, UK, and Swiss residents" },
|
|
6884
7069
|
{ value: "no", label: "No" }
|
|
6885
7070
|
]
|
|
6886
7071
|
});
|
|
6887
|
-
if (
|
|
7072
|
+
if (p34.isCancel(gdpr)) onCancel();
|
|
6888
7073
|
let facebookFanPage = "no";
|
|
6889
7074
|
const facebookDetails = { name: "", url: "" };
|
|
6890
7075
|
if (gdpr === "yes") {
|
|
6891
|
-
const fan = await
|
|
7076
|
+
const fan = await p34.select({
|
|
6892
7077
|
message: "Do you have a Facebook Fan Page?",
|
|
6893
7078
|
options: [
|
|
6894
7079
|
{ value: "yes", label: "Yes, we have a Facebook Fan Page" },
|
|
6895
7080
|
{ value: "no", label: "No" }
|
|
6896
7081
|
]
|
|
6897
7082
|
});
|
|
6898
|
-
if (
|
|
7083
|
+
if (p34.isCancel(fan)) onCancel();
|
|
6899
7084
|
facebookFanPage = fan;
|
|
6900
7085
|
if (facebookFanPage === "yes") {
|
|
6901
|
-
const name = await
|
|
7086
|
+
const name = await p34.text({
|
|
6902
7087
|
message: "What is the name of the Facebook Fan Page?",
|
|
6903
7088
|
placeholder: "My Facebook Page"
|
|
6904
7089
|
});
|
|
6905
|
-
if (
|
|
7090
|
+
if (p34.isCancel(name)) onCancel();
|
|
6906
7091
|
facebookDetails.name = name;
|
|
6907
|
-
const url = await
|
|
7092
|
+
const url = await p34.text({
|
|
6908
7093
|
message: "What is the URL of the Facebook Fan Page?",
|
|
6909
7094
|
placeholder: "https://facebook.com/my-facebook-page"
|
|
6910
7095
|
});
|
|
6911
|
-
if (
|
|
7096
|
+
if (p34.isCancel(url)) onCancel();
|
|
6912
7097
|
facebookDetails.url = url;
|
|
6913
7098
|
}
|
|
6914
7099
|
}
|
|
6915
|
-
const kids = await
|
|
7100
|
+
const kids = await p34.select({
|
|
6916
7101
|
message: "Do you collect information from kids under the age of 13?",
|
|
6917
7102
|
options: [
|
|
6918
7103
|
{ value: "yes", label: "Yes. We collect information from children under the age of 13" },
|
|
6919
7104
|
{ value: "no", label: "No" }
|
|
6920
7105
|
]
|
|
6921
7106
|
});
|
|
6922
|
-
if (
|
|
6923
|
-
const retention = await
|
|
7107
|
+
if (p34.isCancel(kids)) onCancel();
|
|
7108
|
+
const retention = await p34.text({
|
|
6924
7109
|
message: "How long do you retain personal information? (leave blank for default wording)",
|
|
6925
7110
|
placeholder: "e.g. 12 months after account closure"
|
|
6926
7111
|
});
|
|
6927
|
-
if (
|
|
7112
|
+
if (p34.isCancel(retention)) onCancel();
|
|
6928
7113
|
const html = generatePrivacyHtml({
|
|
6929
7114
|
core,
|
|
6930
7115
|
personalInfo: personalInfo ?? [],
|
|
@@ -6979,16 +7164,16 @@ async function privacyAction() {
|
|
|
6979
7164
|
]
|
|
6980
7165
|
});
|
|
6981
7166
|
}
|
|
6982
|
-
var privacy = new
|
|
7167
|
+
var privacy = new Command50("privacy").description("generate placeholder privacy policy").configureHelp(helpConfig).action(() => runCommand(privacyAction, "Failed to generate privacy policy."));
|
|
6983
7168
|
|
|
6984
7169
|
// src/commands/legal.ts
|
|
6985
|
-
var legal = new
|
|
7170
|
+
var legal = new Command51("legal").description("generate placeholder legal documents").configureHelp(helpConfig).addCommand(terms).addCommand(privacy);
|
|
6986
7171
|
|
|
6987
7172
|
// src/commands/fixtures.ts
|
|
6988
|
-
import { Command as
|
|
7173
|
+
import { Command as Command57 } from "commander";
|
|
6989
7174
|
|
|
6990
7175
|
// src/commands/fixtures/load.ts
|
|
6991
|
-
import { Command as
|
|
7176
|
+
import { Command as Command52 } from "commander";
|
|
6992
7177
|
|
|
6993
7178
|
// src/lib/data.ts
|
|
6994
7179
|
import fs28 from "node:fs";
|
|
@@ -7178,7 +7363,7 @@ async function hasLoadedFixtures(pb) {
|
|
|
7178
7363
|
}
|
|
7179
7364
|
|
|
7180
7365
|
// src/commands/fixtures/load.ts
|
|
7181
|
-
var load = new
|
|
7366
|
+
var load = new Command52("load").description("load fixtures into the database").configureHelp(helpConfig).action(
|
|
7182
7367
|
() => runCommand(async () => {
|
|
7183
7368
|
const { workspaceRootDir } = await getWorkspace();
|
|
7184
7369
|
let loaded = [];
|
|
@@ -7204,8 +7389,8 @@ var load = new Command51("load").description("load fixtures into the database").
|
|
|
7204
7389
|
);
|
|
7205
7390
|
|
|
7206
7391
|
// src/commands/fixtures/clear.ts
|
|
7207
|
-
import { Command as
|
|
7208
|
-
var clear = new
|
|
7392
|
+
import { Command as Command53 } from "commander";
|
|
7393
|
+
var clear = new Command53("clear").description("clear loaded fixtures").configureHelp(helpConfig).action(
|
|
7209
7394
|
() => runCommand(async () => {
|
|
7210
7395
|
const { workspaceRootDir } = await getWorkspace();
|
|
7211
7396
|
let cleared = [];
|
|
@@ -7234,8 +7419,8 @@ var clear = new Command52("clear").description("clear loaded fixtures").configur
|
|
|
7234
7419
|
);
|
|
7235
7420
|
|
|
7236
7421
|
// src/commands/fixtures/reset.ts
|
|
7237
|
-
import { Command as
|
|
7238
|
-
var reset = new
|
|
7422
|
+
import { Command as Command54 } from "commander";
|
|
7423
|
+
var reset = new Command54("reset").description("clear and reload fixtures").configureHelp(helpConfig).action(
|
|
7239
7424
|
() => runCommand(async () => {
|
|
7240
7425
|
const { workspaceRootDir } = await getWorkspace();
|
|
7241
7426
|
let cleared = [];
|
|
@@ -7267,8 +7452,8 @@ var reset = new Command53("reset").description("clear and reload fixtures").conf
|
|
|
7267
7452
|
// src/commands/fixtures/generate.ts
|
|
7268
7453
|
import fs29 from "node:fs";
|
|
7269
7454
|
import path26 from "node:path";
|
|
7270
|
-
import { Command as
|
|
7271
|
-
import * as
|
|
7455
|
+
import { Command as Command55, InvalidArgumentError } from "commander";
|
|
7456
|
+
import * as p35 from "@clack/prompts";
|
|
7272
7457
|
import { annotate } from "annotate-json-schema";
|
|
7273
7458
|
import { createGenerator } from "json-schema-faker";
|
|
7274
7459
|
import { faker } from "@faker-js/faker";
|
|
@@ -7378,7 +7563,7 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
|
7378
7563
|
}
|
|
7379
7564
|
return { writtenFiles, warnings };
|
|
7380
7565
|
}
|
|
7381
|
-
var generate2 = new
|
|
7566
|
+
var generate2 = new Command55("generate").description("generate fixture data").option("-c, --count <count>", "number of records per collection", parseCount, 10).option("-s, --seed <seed>", "seed for deterministic output", parseSeed).option("-f, --force", "overwrite existing fixture files and clear loaded fixtures").configureHelp(helpConfig).action(
|
|
7382
7567
|
(opts) => runCommand(async () => {
|
|
7383
7568
|
const { workspaceRootDir } = await getWorkspace();
|
|
7384
7569
|
const existing = getFixtureFiles(workspaceRootDir);
|
|
@@ -7407,7 +7592,7 @@ var generate2 = new Command54("generate").description("generate fixture data").o
|
|
|
7407
7592
|
seed: opts.seed
|
|
7408
7593
|
});
|
|
7409
7594
|
});
|
|
7410
|
-
for (const warning of result.warnings)
|
|
7595
|
+
for (const warning of result.warnings) p35.log.warn(warning);
|
|
7411
7596
|
if (result.writtenFiles.length === 0) {
|
|
7412
7597
|
reportResult({
|
|
7413
7598
|
summary: "No eligible collections found to generate fixtures for.",
|
|
@@ -7431,8 +7616,8 @@ var generate2 = new Command54("generate").description("generate fixture data").o
|
|
|
7431
7616
|
);
|
|
7432
7617
|
|
|
7433
7618
|
// src/commands/fixtures/regen.ts
|
|
7434
|
-
import { Command as
|
|
7435
|
-
import * as
|
|
7619
|
+
import { Command as Command56, InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
7620
|
+
import * as p36 from "@clack/prompts";
|
|
7436
7621
|
function parseCount2(value) {
|
|
7437
7622
|
const n = parseInt(value, 10);
|
|
7438
7623
|
if (!Number.isFinite(n) || n <= 0 || n > 999) {
|
|
@@ -7447,7 +7632,7 @@ function parseSeed2(value) {
|
|
|
7447
7632
|
}
|
|
7448
7633
|
return n;
|
|
7449
7634
|
}
|
|
7450
|
-
var regen = new
|
|
7635
|
+
var regen = new Command56("regen").description("clear the database, regenerate fixture files, and reload them").option("-c, --count <count>", "number of records per collection", parseCount2, 10).option("-s, --seed <seed>", "seed for deterministic output", parseSeed2).configureHelp(helpConfig).action(
|
|
7451
7636
|
(opts) => runCommand(async () => {
|
|
7452
7637
|
const { workspaceRootDir } = await getWorkspace();
|
|
7453
7638
|
let cleared = [];
|
|
@@ -7461,7 +7646,7 @@ var regen = new Command55("regen").description("clear the database, regenerate f
|
|
|
7461
7646
|
});
|
|
7462
7647
|
loaded = await loadFixtures(pb, workspaceRootDir);
|
|
7463
7648
|
});
|
|
7464
|
-
for (const warning of result.warnings)
|
|
7649
|
+
for (const warning of result.warnings) p36.log.warn(warning);
|
|
7465
7650
|
reportResult({
|
|
7466
7651
|
summary: `Regenerated fixtures (${loaded.length} collection(s) reloaded).`,
|
|
7467
7652
|
filesCreated: result.writtenFiles,
|
|
@@ -7476,14 +7661,14 @@ var regen = new Command55("regen").description("clear the database, regenerate f
|
|
|
7476
7661
|
);
|
|
7477
7662
|
|
|
7478
7663
|
// src/commands/fixtures.ts
|
|
7479
|
-
var fixtures = new
|
|
7664
|
+
var fixtures = new Command57("fixtures").description("manage fixture data").configureHelp(helpConfig).addCommand(generate2).addCommand(load).addCommand(clear).addCommand(reset).addCommand(regen);
|
|
7480
7665
|
|
|
7481
7666
|
// src/commands/seeds.ts
|
|
7482
|
-
import { Command as
|
|
7667
|
+
import { Command as Command61 } from "commander";
|
|
7483
7668
|
|
|
7484
7669
|
// src/commands/seeds/load.ts
|
|
7485
|
-
import { Command as
|
|
7486
|
-
var load2 = new
|
|
7670
|
+
import { Command as Command58 } from "commander";
|
|
7671
|
+
var load2 = new Command58("load").description("load seeds into the database").option("-f, --force", "load even if target collections already have records").configureHelp(helpConfig).action(
|
|
7487
7672
|
(opts) => runCommand(async () => {
|
|
7488
7673
|
const { workspaceRootDir } = await getWorkspace();
|
|
7489
7674
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -7522,7 +7707,7 @@ var load2 = new Command57("load").description("load seeds into the database").op
|
|
|
7522
7707
|
// src/commands/seeds/save.ts
|
|
7523
7708
|
import fs30 from "node:fs";
|
|
7524
7709
|
import path27 from "node:path";
|
|
7525
|
-
import { Command as
|
|
7710
|
+
import { Command as Command59 } from "commander";
|
|
7526
7711
|
var padZeros2 = (num, length) => num.toString().padStart(length, "0");
|
|
7527
7712
|
function filterSystemFields(record, systemFieldNames) {
|
|
7528
7713
|
const out = {};
|
|
@@ -7533,7 +7718,7 @@ function filterSystemFields(record, systemFieldNames) {
|
|
|
7533
7718
|
}
|
|
7534
7719
|
return out;
|
|
7535
7720
|
}
|
|
7536
|
-
var save = new
|
|
7721
|
+
var save = new Command59("save").description("save the current data as seeds").option("-f, --force", "overwrite existing seed files").configureHelp(helpConfig).action(
|
|
7537
7722
|
(opts) => runCommand(async () => {
|
|
7538
7723
|
const { workspaceRootDir } = await getWorkspace();
|
|
7539
7724
|
const seedsPath = dataDir(workspaceRootDir, "seeds");
|
|
@@ -7605,8 +7790,8 @@ var save = new Command58("save").description("save the current data as seeds").o
|
|
|
7605
7790
|
);
|
|
7606
7791
|
|
|
7607
7792
|
// src/commands/seeds/clear.ts
|
|
7608
|
-
import { Command as
|
|
7609
|
-
var clear2 = new
|
|
7793
|
+
import { Command as Command60 } from "commander";
|
|
7794
|
+
var clear2 = new Command60("clear").description("clear seeded records").configureHelp(helpConfig).action(
|
|
7610
7795
|
() => runCommand(async () => {
|
|
7611
7796
|
const { workspaceRootDir } = await getWorkspace();
|
|
7612
7797
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -7637,23 +7822,23 @@ var clear2 = new Command59("clear").description("clear seeded records").configur
|
|
|
7637
7822
|
);
|
|
7638
7823
|
|
|
7639
7824
|
// src/commands/seeds.ts
|
|
7640
|
-
var seeds = new
|
|
7825
|
+
var seeds = new Command61("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
|
|
7641
7826
|
|
|
7642
7827
|
// src/commands/signup.ts
|
|
7643
|
-
import { Command as
|
|
7644
|
-
import * as
|
|
7828
|
+
import { Command as Command63 } from "commander";
|
|
7829
|
+
import * as p38 from "@clack/prompts";
|
|
7645
7830
|
import makeFetchCookie2 from "fetch-cookie";
|
|
7646
7831
|
|
|
7647
7832
|
// src/commands/login.ts
|
|
7648
7833
|
import os4 from "node:os";
|
|
7649
|
-
import { Command as
|
|
7650
|
-
import * as
|
|
7834
|
+
import { Command as Command62 } from "commander";
|
|
7835
|
+
import * as p37 from "@clack/prompts";
|
|
7651
7836
|
import makeFetchCookie from "fetch-cookie";
|
|
7652
|
-
var login = new
|
|
7837
|
+
var login = new Command62("login").description("login to velastack.dev").configureHelp(helpConfig).action(
|
|
7653
7838
|
() => runCommand(async () => {
|
|
7654
|
-
const { email: email3, password: password11 } = await
|
|
7655
|
-
email: () =>
|
|
7656
|
-
password: () =>
|
|
7839
|
+
const { email: email3, password: password11 } = await p37.group({
|
|
7840
|
+
email: () => p37.text({ message: "Email" }),
|
|
7841
|
+
password: () => p37.password({ message: "Password" })
|
|
7657
7842
|
});
|
|
7658
7843
|
const fetchCookie = makeFetchCookie(fetch);
|
|
7659
7844
|
const loginRes = await fetchCookie(`${API_URL}/login`, {
|
|
@@ -7675,7 +7860,7 @@ var login = new Command61("login").description("login to velastack.dev").configu
|
|
|
7675
7860
|
}
|
|
7676
7861
|
const apiKey = await issueApiKey(fetchCookie);
|
|
7677
7862
|
writeConfig({ apiKey });
|
|
7678
|
-
|
|
7863
|
+
p37.log.success("Logged in to velastack.dev");
|
|
7679
7864
|
}, "Failed to login.")
|
|
7680
7865
|
);
|
|
7681
7866
|
async function issueApiKey(fetchCookie) {
|
|
@@ -7716,12 +7901,12 @@ function extractApiKey(cookie) {
|
|
|
7716
7901
|
}
|
|
7717
7902
|
|
|
7718
7903
|
// src/commands/signup.ts
|
|
7719
|
-
var signup = new
|
|
7904
|
+
var signup = new Command63("signup").description("signup to velastack.dev").configureHelp(helpConfig).action(
|
|
7720
7905
|
() => runCommand(async () => {
|
|
7721
|
-
const { email: email3, password: password11, passwordConfirm } = await
|
|
7722
|
-
email: () =>
|
|
7723
|
-
password: () =>
|
|
7724
|
-
passwordConfirm: () =>
|
|
7906
|
+
const { email: email3, password: password11, passwordConfirm } = await p38.group({
|
|
7907
|
+
email: () => p38.text({ message: "Email" }),
|
|
7908
|
+
password: () => p38.password({ message: "Password" }),
|
|
7909
|
+
passwordConfirm: () => p38.password({ message: "Confirm password" })
|
|
7725
7910
|
});
|
|
7726
7911
|
if (password11 !== passwordConfirm) {
|
|
7727
7912
|
throw new Error("Passwords do not match.");
|
|
@@ -7745,33 +7930,33 @@ var signup = new Command62("signup").description("signup to velastack.dev").conf
|
|
|
7745
7930
|
}
|
|
7746
7931
|
const apiKey = await issueApiKey(fetchCookie);
|
|
7747
7932
|
writeConfig({ apiKey });
|
|
7748
|
-
|
|
7749
|
-
|
|
7933
|
+
p38.log.success("Signed up to velastack.dev");
|
|
7934
|
+
p38.log.info("Check your email for a confirmation link.");
|
|
7750
7935
|
}, "Failed to signup.")
|
|
7751
7936
|
);
|
|
7752
7937
|
|
|
7753
7938
|
// src/commands/logout.ts
|
|
7754
|
-
import { Command as
|
|
7755
|
-
import * as
|
|
7756
|
-
var logout = new
|
|
7939
|
+
import { Command as Command64 } from "commander";
|
|
7940
|
+
import * as p39 from "@clack/prompts";
|
|
7941
|
+
var logout = new Command64("logout").alias("signout").description("logout from velastack.dev").configureHelp(helpConfig).action(
|
|
7757
7942
|
() => runCommand(() => {
|
|
7758
7943
|
if (!readConfig()) {
|
|
7759
|
-
|
|
7944
|
+
p39.log.info("Not logged in");
|
|
7760
7945
|
return;
|
|
7761
7946
|
}
|
|
7762
7947
|
clearConfig();
|
|
7763
|
-
|
|
7948
|
+
p39.log.success("Logged out of velastack.dev");
|
|
7764
7949
|
})
|
|
7765
7950
|
);
|
|
7766
7951
|
|
|
7767
7952
|
// src/commands/whoami.ts
|
|
7768
|
-
import { Command as
|
|
7769
|
-
import * as
|
|
7770
|
-
var whoami = new
|
|
7953
|
+
import { Command as Command65 } from "commander";
|
|
7954
|
+
import * as p40 from "@clack/prompts";
|
|
7955
|
+
var whoami = new Command65("whoami").description("show the current user").configureHelp(helpConfig).action(
|
|
7771
7956
|
() => runCommand(async () => {
|
|
7772
7957
|
const apiKey = readConfig()?.apiKey;
|
|
7773
7958
|
if (!apiKey) {
|
|
7774
|
-
|
|
7959
|
+
p40.log.info("Not logged in. Run `vela login` to login.");
|
|
7775
7960
|
return;
|
|
7776
7961
|
}
|
|
7777
7962
|
const res = await fetch(`${API_URL}/api/collections/users/records`, {
|
|
@@ -7779,22 +7964,22 @@ var whoami = new Command64("whoami").description("show the current user").config
|
|
|
7779
7964
|
});
|
|
7780
7965
|
const data = await res.json();
|
|
7781
7966
|
if (!data.items.length) throw new Error("No user found. Run `vela login` to login.");
|
|
7782
|
-
|
|
7967
|
+
p40.log.success(`Logged in as ${data.items[0].email}`);
|
|
7783
7968
|
})
|
|
7784
7969
|
);
|
|
7785
7970
|
|
|
7786
7971
|
// src/commands/migrate.ts
|
|
7787
|
-
import { Command as
|
|
7972
|
+
import { Command as Command71 } from "commander";
|
|
7788
7973
|
|
|
7789
7974
|
// src/commands/migrate/up.ts
|
|
7790
|
-
import { Command as
|
|
7975
|
+
import { Command as Command66 } from "commander";
|
|
7791
7976
|
|
|
7792
7977
|
// src/lib/migrate.ts
|
|
7793
7978
|
import path28 from "node:path";
|
|
7794
|
-
import
|
|
7979
|
+
import process21 from "node:process";
|
|
7795
7980
|
import { x as x2 } from "tinyexec";
|
|
7796
7981
|
async function runPocketbaseMigrate(args) {
|
|
7797
|
-
const cwd =
|
|
7982
|
+
const cwd = process21.cwd();
|
|
7798
7983
|
const { getBinaryPath } = await import("pocketbase-server");
|
|
7799
7984
|
const binaryPath = getBinaryPath();
|
|
7800
7985
|
await x2(
|
|
@@ -7826,10 +8011,10 @@ async function runMigrateUp() {
|
|
|
7826
8011
|
]
|
|
7827
8012
|
});
|
|
7828
8013
|
}
|
|
7829
|
-
var up = new
|
|
8014
|
+
var up = new Command66("up").description("apply all pending migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations."));
|
|
7830
8015
|
|
|
7831
8016
|
// src/commands/migrate/down.ts
|
|
7832
|
-
import { Command as
|
|
8017
|
+
import { Command as Command67, InvalidArgumentError as InvalidArgumentError3 } from "commander";
|
|
7833
8018
|
function parseSteps(value) {
|
|
7834
8019
|
const n = parseInt(value, 10);
|
|
7835
8020
|
if (!Number.isFinite(n) || n <= 0) {
|
|
@@ -7837,7 +8022,7 @@ function parseSteps(value) {
|
|
|
7837
8022
|
}
|
|
7838
8023
|
return n;
|
|
7839
8024
|
}
|
|
7840
|
-
var down = new
|
|
8025
|
+
var down = new Command67("down").alias("rollback").description("revert the last N applied migrations").argument("[number]", "how many migrations to revert", parseSteps, 1).configureHelp(helpConfig).action(
|
|
7841
8026
|
(n) => runCommand(async () => {
|
|
7842
8027
|
await runPocketbaseMigrate(["down", String(n)]);
|
|
7843
8028
|
reportResult({
|
|
@@ -7853,11 +8038,11 @@ var down = new Command66("down").alias("rollback").description("revert the last
|
|
|
7853
8038
|
// src/commands/migrate/create.ts
|
|
7854
8039
|
import fs31 from "node:fs";
|
|
7855
8040
|
import path29 from "node:path";
|
|
7856
|
-
import
|
|
7857
|
-
import { Command as
|
|
7858
|
-
var create2 = new
|
|
8041
|
+
import process22 from "node:process";
|
|
8042
|
+
import { Command as Command68 } from "commander";
|
|
8043
|
+
var create2 = new Command68("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
|
|
7859
8044
|
(name) => runCommand(async () => {
|
|
7860
|
-
const cwd =
|
|
8045
|
+
const cwd = process22.cwd();
|
|
7861
8046
|
const before = listMigrationFiles(cwd);
|
|
7862
8047
|
await runPocketbaseMigrate(["create", name]);
|
|
7863
8048
|
const after = listMigrationFiles(cwd);
|
|
@@ -7881,11 +8066,11 @@ function listMigrationFiles(cwd) {
|
|
|
7881
8066
|
// src/commands/migrate/collections.ts
|
|
7882
8067
|
import fs32 from "node:fs";
|
|
7883
8068
|
import path30 from "node:path";
|
|
7884
|
-
import
|
|
7885
|
-
import { Command as
|
|
7886
|
-
var collections = new
|
|
8069
|
+
import process23 from "node:process";
|
|
8070
|
+
import { Command as Command69 } from "commander";
|
|
8071
|
+
var collections = new Command69("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
|
|
7887
8072
|
() => runCommand(async () => {
|
|
7888
|
-
const cwd =
|
|
8073
|
+
const cwd = process23.cwd();
|
|
7889
8074
|
const before = listMigrationFiles2(cwd);
|
|
7890
8075
|
await runPocketbaseMigrate(["collections"]);
|
|
7891
8076
|
const after = listMigrationFiles2(cwd);
|
|
@@ -7914,8 +8099,8 @@ function listMigrationFiles2(cwd) {
|
|
|
7914
8099
|
}
|
|
7915
8100
|
|
|
7916
8101
|
// src/commands/migrate/history-sync.ts
|
|
7917
|
-
import { Command as
|
|
7918
|
-
var historySync = new
|
|
8102
|
+
import { Command as Command70 } from "commander";
|
|
8103
|
+
var historySync = new Command70("history-sync").description("drop _migrations rows whose files no longer exist").configureHelp(helpConfig).action(
|
|
7919
8104
|
() => runCommand(async () => {
|
|
7920
8105
|
await runPocketbaseMigrate(["history-sync"]);
|
|
7921
8106
|
reportResult({
|
|
@@ -7926,20 +8111,20 @@ var historySync = new Command69("history-sync").description("drop _migrations ro
|
|
|
7926
8111
|
);
|
|
7927
8112
|
|
|
7928
8113
|
// src/commands/migrate.ts
|
|
7929
|
-
var migrate = new
|
|
8114
|
+
var migrate = new Command71("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
|
|
7930
8115
|
|
|
7931
8116
|
// src/commands/dev.ts
|
|
7932
8117
|
import fs33 from "node:fs";
|
|
7933
8118
|
import path32 from "node:path";
|
|
7934
|
-
import
|
|
8119
|
+
import process25 from "node:process";
|
|
7935
8120
|
import { performance } from "node:perf_hooks";
|
|
7936
|
-
import { Command as
|
|
8121
|
+
import { Command as Command72, InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
7937
8122
|
import pc15 from "picocolors";
|
|
7938
8123
|
import PocketBase4 from "pocketbase";
|
|
7939
8124
|
|
|
7940
8125
|
// src/lib/vite.ts
|
|
7941
8126
|
import path31 from "node:path";
|
|
7942
|
-
import
|
|
8127
|
+
import process24 from "node:process";
|
|
7943
8128
|
import { createRequire as createRequire2 } from "node:module";
|
|
7944
8129
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
7945
8130
|
import pc14 from "picocolors";
|
|
@@ -7963,13 +8148,13 @@ function resolveProjectVite(cwd) {
|
|
|
7963
8148
|
return null;
|
|
7964
8149
|
}
|
|
7965
8150
|
}
|
|
7966
|
-
async function loadVite(cwd =
|
|
8151
|
+
async function loadVite(cwd = process24.cwd()) {
|
|
7967
8152
|
const entry = resolveProjectVite(cwd);
|
|
7968
8153
|
const vite = entry ? await import(pathToFileURL2(entry).href) : await import("vite");
|
|
7969
8154
|
const error = viteVersionError(vite.version);
|
|
7970
8155
|
if (error) {
|
|
7971
8156
|
console.error(`${pc14.redBright("\u2717")} ${error}`);
|
|
7972
|
-
|
|
8157
|
+
process24.exit(1);
|
|
7973
8158
|
}
|
|
7974
8159
|
return vite;
|
|
7975
8160
|
}
|
|
@@ -7982,16 +8167,16 @@ function parsePort(value) {
|
|
|
7982
8167
|
}
|
|
7983
8168
|
return port;
|
|
7984
8169
|
}
|
|
7985
|
-
var dev = new
|
|
7986
|
-
const cwd =
|
|
7987
|
-
|
|
8170
|
+
var dev = new Command72("dev").description("start the development server").option("--open [path]", "open the app in a browser once the server is ready").option("--host [host]", "expose the server on the network").option("--port <port>", "port to listen on", parsePort).option("--strictPort", "exit if the port is already in use instead of taking the next one").option("--cors", "enable CORS").option("--force", "re-bundle dependencies, ignoring the optimizer cache").configureHelp(helpConfig).action(async (options) => {
|
|
8171
|
+
const cwd = process25.cwd();
|
|
8172
|
+
process25.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
7988
8173
|
const startTime = performance.now();
|
|
7989
8174
|
const { createServer, version } = await loadVite(cwd);
|
|
7990
8175
|
const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
|
|
7991
8176
|
const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
|
|
7992
8177
|
let pbProc;
|
|
7993
8178
|
const backend3 = hasBackend(cwd);
|
|
7994
|
-
const needsStart = backend3 && !
|
|
8179
|
+
const needsStart = backend3 && !process25.env.POCKETBASE_URL;
|
|
7995
8180
|
const cleanup = () => {
|
|
7996
8181
|
if (pbProc?.pid) pbProc.kill();
|
|
7997
8182
|
if (fs33.existsSync(viteMetadataFile)) fs33.rmSync(viteMetadataFile);
|
|
@@ -8006,15 +8191,15 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
8006
8191
|
stdio: "pipe"
|
|
8007
8192
|
});
|
|
8008
8193
|
pbProc = started.proc;
|
|
8009
|
-
|
|
8010
|
-
pbProc.stdout?.pipe(
|
|
8011
|
-
pbProc.stderr?.pipe(
|
|
8194
|
+
process25.env.POCKETBASE_URL = started.url;
|
|
8195
|
+
pbProc.stdout?.pipe(process25.stdout);
|
|
8196
|
+
pbProc.stderr?.pipe(process25.stderr);
|
|
8012
8197
|
pbProc.on("error", (err) => console.error("PocketBase error:", err));
|
|
8013
8198
|
pbProc.on("exit", (code) => console.log(`PocketBase exited with code ${code}`));
|
|
8014
|
-
|
|
8015
|
-
|
|
8199
|
+
process25.on("exit", cleanup);
|
|
8200
|
+
process25.on("SIGINT", () => {
|
|
8016
8201
|
cleanup();
|
|
8017
|
-
|
|
8202
|
+
process25.exit(0);
|
|
8018
8203
|
});
|
|
8019
8204
|
}
|
|
8020
8205
|
const serverOptions = {};
|
|
@@ -8036,21 +8221,21 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
8036
8221
|
await fs33.promises.writeFile(
|
|
8037
8222
|
viteMetadataFile,
|
|
8038
8223
|
JSON.stringify({
|
|
8039
|
-
pocketbaseUrl:
|
|
8224
|
+
pocketbaseUrl: process25.env.POCKETBASE_URL,
|
|
8040
8225
|
vitePort,
|
|
8041
8226
|
viteHost
|
|
8042
8227
|
})
|
|
8043
8228
|
);
|
|
8044
|
-
const pb = new PocketBase4(
|
|
8229
|
+
const pb = new PocketBase4(process25.env.POCKETBASE_URL);
|
|
8045
8230
|
await pb.collection("_superusers").authWithPassword(
|
|
8046
|
-
|
|
8047
|
-
|
|
8231
|
+
process25.env.POCKETBASE_SUPERUSER_EMAIL,
|
|
8232
|
+
process25.env.POCKETBASE_SUPERUSER_PASSWORD
|
|
8048
8233
|
);
|
|
8049
8234
|
await pb.settings.update({ meta: { appURL: `http://${viteHost}:${vitePort}` } });
|
|
8050
8235
|
await startWatchingTypes(cwd, pb);
|
|
8051
8236
|
});
|
|
8052
8237
|
await server.listen();
|
|
8053
|
-
const hasExistingLogs =
|
|
8238
|
+
const hasExistingLogs = process25.stdout.bytesWritten > 0 || process25.stderr.bytesWritten > 0;
|
|
8054
8239
|
const startupDurationString = pc15.dim(
|
|
8055
8240
|
`ready in ${pc15.reset(pc15.bold(Math.ceil(performance.now() - startTime)))} ms`
|
|
8056
8241
|
);
|
|
@@ -8090,9 +8275,9 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
8090
8275
|
// src/commands/build.ts
|
|
8091
8276
|
import fs34 from "node:fs";
|
|
8092
8277
|
import path33 from "node:path";
|
|
8093
|
-
import
|
|
8094
|
-
import { Command as
|
|
8095
|
-
import * as
|
|
8278
|
+
import process27 from "node:process";
|
|
8279
|
+
import { Command as Command73 } from "commander";
|
|
8280
|
+
import * as p41 from "@clack/prompts";
|
|
8096
8281
|
import pc16 from "picocolors";
|
|
8097
8282
|
import { x as x3 } from "tinyexec";
|
|
8098
8283
|
import { detect as detect5 } from "package-manager-detector";
|
|
@@ -8105,10 +8290,10 @@ function applyBuildEnv(cwd, env2 = process.env) {
|
|
|
8105
8290
|
}
|
|
8106
8291
|
|
|
8107
8292
|
// src/lib/origin.ts
|
|
8108
|
-
import
|
|
8293
|
+
import process26 from "node:process";
|
|
8109
8294
|
function resolveOrigin(workspaceRootDir, envTag, config = {}) {
|
|
8110
8295
|
return normalizeOrigin(
|
|
8111
|
-
|
|
8296
|
+
process26.env.VELA_ORIGIN ?? readBinding(workspaceRootDir, envTag)?.domain ?? config.deploy?.domain
|
|
8112
8297
|
);
|
|
8113
8298
|
}
|
|
8114
8299
|
function normalizeOrigin(value) {
|
|
@@ -8128,13 +8313,13 @@ function splitHosts(value) {
|
|
|
8128
8313
|
|
|
8129
8314
|
// src/commands/build.ts
|
|
8130
8315
|
var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
|
|
8131
|
-
var build = new
|
|
8132
|
-
const cwd =
|
|
8316
|
+
var build = new Command73("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
|
|
8317
|
+
const cwd = process27.cwd();
|
|
8133
8318
|
applyBuildEnv(cwd);
|
|
8134
8319
|
const origin = await originForBuild(cwd, options.target);
|
|
8135
|
-
if (origin)
|
|
8320
|
+
if (origin) process27.env.VELA_ORIGIN = origin;
|
|
8136
8321
|
let pbProc;
|
|
8137
|
-
const needsStart = hasBackend(cwd) && !
|
|
8322
|
+
const needsStart = hasBackend(cwd) && !process27.env.POCKETBASE_URL;
|
|
8138
8323
|
const cleanup = () => {
|
|
8139
8324
|
if (pbProc?.pid) pbProc.kill();
|
|
8140
8325
|
};
|
|
@@ -8148,11 +8333,11 @@ var build = new Command72("build").description("build the app").configureHelp(he
|
|
|
8148
8333
|
dev: true
|
|
8149
8334
|
});
|
|
8150
8335
|
pbProc = started.proc;
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8336
|
+
process27.env.POCKETBASE_URL = started.url;
|
|
8337
|
+
process27.on("exit", cleanup);
|
|
8338
|
+
process27.on("SIGINT", () => {
|
|
8154
8339
|
cleanup();
|
|
8155
|
-
|
|
8340
|
+
process27.exit(0);
|
|
8156
8341
|
});
|
|
8157
8342
|
}
|
|
8158
8343
|
try {
|
|
@@ -8185,7 +8370,7 @@ async function originForBuild(cwd, target) {
|
|
|
8185
8370
|
function warnIfPrerendered(cwd) {
|
|
8186
8371
|
const dir = path33.join(cwd, PRERENDERED_DIR);
|
|
8187
8372
|
if (!fs34.existsSync(dir) || fs34.readdirSync(dir).length === 0) return;
|
|
8188
|
-
|
|
8373
|
+
p41.log.warn(
|
|
8189
8374
|
`Prerendered pages were built with no domain configured, so their canonical
|
|
8190
8375
|
links point at SvelteKit's placeholder host rather than at this site.
|
|
8191
8376
|
|
|
@@ -8195,16 +8380,16 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
|
|
|
8195
8380
|
|
|
8196
8381
|
// src/commands/preview.ts
|
|
8197
8382
|
import path34 from "node:path";
|
|
8198
|
-
import
|
|
8199
|
-
import { Command as
|
|
8383
|
+
import process28 from "node:process";
|
|
8384
|
+
import { Command as Command74 } from "commander";
|
|
8200
8385
|
import { x as x4 } from "tinyexec";
|
|
8201
8386
|
import { detect as detect6 } from "package-manager-detector";
|
|
8202
8387
|
import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
|
|
8203
|
-
var preview = new
|
|
8204
|
-
const cwd =
|
|
8205
|
-
|
|
8388
|
+
var preview = new Command74("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
|
|
8389
|
+
const cwd = process28.cwd();
|
|
8390
|
+
process28.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
8206
8391
|
let pbProc;
|
|
8207
|
-
const needsStart = hasBackend(cwd) && !
|
|
8392
|
+
const needsStart = hasBackend(cwd) && !process28.env.POCKETBASE_URL;
|
|
8208
8393
|
const cleanup = () => {
|
|
8209
8394
|
if (pbProc?.pid) pbProc.kill();
|
|
8210
8395
|
};
|
|
@@ -8217,11 +8402,11 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
8217
8402
|
dev: true
|
|
8218
8403
|
});
|
|
8219
8404
|
pbProc = started.proc;
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8405
|
+
process28.env.POCKETBASE_URL = started.url;
|
|
8406
|
+
process28.on("exit", cleanup);
|
|
8407
|
+
process28.on("SIGINT", () => {
|
|
8223
8408
|
cleanup();
|
|
8224
|
-
|
|
8409
|
+
process28.exit(0);
|
|
8225
8410
|
});
|
|
8226
8411
|
}
|
|
8227
8412
|
try {
|
|
@@ -8240,8 +8425,8 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
8240
8425
|
|
|
8241
8426
|
// src/commands/sync.ts
|
|
8242
8427
|
import path35 from "node:path";
|
|
8243
|
-
import { Command as
|
|
8244
|
-
var sync = new
|
|
8428
|
+
import { Command as Command75 } from "commander";
|
|
8429
|
+
var sync = new Command75("sync").description("sync types from the database").configureHelp(helpConfig).action(
|
|
8245
8430
|
() => runCommand(async () => {
|
|
8246
8431
|
const { workspaceRootDir } = await getWorkspace();
|
|
8247
8432
|
const typesDir = path35.join(workspaceRootDir, ".svelte-kit", "types");
|
|
@@ -8254,8 +8439,8 @@ var sync = new Command74("sync").description("sync types from the database").con
|
|
|
8254
8439
|
);
|
|
8255
8440
|
|
|
8256
8441
|
// src/commands/provision.ts
|
|
8257
|
-
import { Command as
|
|
8258
|
-
import * as
|
|
8442
|
+
import { Command as Command76 } from "commander";
|
|
8443
|
+
import * as p42 from "@clack/prompts";
|
|
8259
8444
|
import pc17 from "picocolors";
|
|
8260
8445
|
import * as v7 from "valibot";
|
|
8261
8446
|
var OptionsSchema2 = v7.object({
|
|
@@ -8264,24 +8449,24 @@ var OptionsSchema2 = v7.object({
|
|
|
8264
8449
|
nodeMajor: v7.optional(v7.string())
|
|
8265
8450
|
});
|
|
8266
8451
|
var provision = addSshOptions(
|
|
8267
|
-
new
|
|
8452
|
+
new Command76("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
|
|
8268
8453
|
).option("--pb-version <version>", "PocketBase version to install").option("--node-major <version>", "Node.js major version to install", "22").action(
|
|
8269
8454
|
(target, raw) => runCommand(async () => {
|
|
8270
8455
|
const options = parseOptions(OptionsSchema2, raw);
|
|
8271
8456
|
const pbVersion = options.pbVersion ?? pocketbaseVersion();
|
|
8272
|
-
|
|
8273
|
-
|
|
8457
|
+
p42.intro(pc17.bgCyan(pc17.black(" vela provision ")));
|
|
8458
|
+
p42.log.info(`Target ${pc17.cyan(target)}`);
|
|
8274
8459
|
await withSsh(target, sshOptionsFrom(options), async (session) => {
|
|
8275
8460
|
await session.detectElevation();
|
|
8276
8461
|
const existing = await readServerInfo(session);
|
|
8277
8462
|
if (existing) {
|
|
8278
|
-
|
|
8463
|
+
p42.log.info(
|
|
8279
8464
|
`Already provisioned by vela ${existing.cliVersion} on ${existing.provisionedAt}. Bringing it up to date.`
|
|
8280
8465
|
);
|
|
8281
8466
|
}
|
|
8282
|
-
|
|
8467
|
+
p42.log.step("Uploading server scripts");
|
|
8283
8468
|
await syncServerScripts(session);
|
|
8284
|
-
|
|
8469
|
+
p42.log.step("Running provision");
|
|
8285
8470
|
const result = await runServerScript(session, "provision.sh", {
|
|
8286
8471
|
args: [
|
|
8287
8472
|
"--pb-version",
|
|
@@ -8293,7 +8478,7 @@ var provision = addSshOptions(
|
|
|
8293
8478
|
],
|
|
8294
8479
|
stream: true
|
|
8295
8480
|
});
|
|
8296
|
-
|
|
8481
|
+
p42.log.success(
|
|
8297
8482
|
`${target} is ready.
|
|
8298
8483
|
|
|
8299
8484
|
Node ${result?.node ?? "installed"}
|
|
@@ -8301,29 +8486,29 @@ var provision = addSshOptions(
|
|
|
8301
8486
|
PocketBase ${result?.pocketbase ?? pbVersion}`
|
|
8302
8487
|
);
|
|
8303
8488
|
});
|
|
8304
|
-
|
|
8489
|
+
p42.outro(`Deploy with ${pc17.cyan(`vela deploy --server ${target}`)}`);
|
|
8305
8490
|
}, "Failed to provision.")
|
|
8306
8491
|
);
|
|
8307
8492
|
|
|
8308
8493
|
// src/commands/deploy.ts
|
|
8309
|
-
import
|
|
8310
|
-
import
|
|
8311
|
-
import { Command as
|
|
8312
|
-
import * as
|
|
8494
|
+
import path38 from "node:path";
|
|
8495
|
+
import fs37 from "node:fs";
|
|
8496
|
+
import { Command as Command77, Option as Option2 } from "commander";
|
|
8497
|
+
import * as p43 from "@clack/prompts";
|
|
8313
8498
|
import pc18 from "picocolors";
|
|
8314
8499
|
import * as v8 from "valibot";
|
|
8315
8500
|
|
|
8316
8501
|
// src/lib/pocketbase-settings.ts
|
|
8317
8502
|
import fs35 from "node:fs";
|
|
8318
8503
|
import path36 from "node:path";
|
|
8319
|
-
import
|
|
8504
|
+
import process29 from "node:process";
|
|
8320
8505
|
import PocketBase5 from "pocketbase";
|
|
8321
8506
|
var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
|
|
8322
8507
|
async function readLocalMeta(cwd) {
|
|
8323
8508
|
const dataDir2 = path36.join(cwd, DATA_DIR);
|
|
8324
8509
|
if (!fs35.existsSync(dataDir2)) return null;
|
|
8325
|
-
const email3 =
|
|
8326
|
-
const password11 =
|
|
8510
|
+
const email3 = process29.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
8511
|
+
const password11 = process29.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
8327
8512
|
if (!email3 || !password11) return null;
|
|
8328
8513
|
let proc;
|
|
8329
8514
|
try {
|
|
@@ -8371,6 +8556,272 @@ async function seedRemoteMeta(session, instance, local, appURL) {
|
|
|
8371
8556
|
return Object.keys(patch);
|
|
8372
8557
|
}
|
|
8373
8558
|
|
|
8559
|
+
// src/lib/adapter.ts
|
|
8560
|
+
import fs36 from "node:fs";
|
|
8561
|
+
import path37 from "node:path";
|
|
8562
|
+
import {
|
|
8563
|
+
Project as Project2,
|
|
8564
|
+
QuoteKind as QuoteKind2,
|
|
8565
|
+
SyntaxKind as SyntaxKind2
|
|
8566
|
+
} from "ts-morph";
|
|
8567
|
+
import { detect as detect7 } from "package-manager-detector";
|
|
8568
|
+
var ADAPTER_NODE = "@sveltejs/adapter-node";
|
|
8569
|
+
var ADAPTER_AUTO = "@sveltejs/adapter-auto";
|
|
8570
|
+
var ADAPTER_STATIC = "@sveltejs/adapter-static";
|
|
8571
|
+
var ADAPTER_NODE_RANGE = "^5.5.7";
|
|
8572
|
+
var ADAPTER_SNIPPET = `import adapter from '${ADAPTER_NODE}';
|
|
8573
|
+
|
|
8574
|
+
// ...
|
|
8575
|
+
adapter: adapter()`;
|
|
8576
|
+
var AdapterError = class extends Error {
|
|
8577
|
+
constructor(message, snippet = ADAPTER_SNIPPET) {
|
|
8578
|
+
super(message);
|
|
8579
|
+
this.snippet = snippet;
|
|
8580
|
+
this.name = "AdapterError";
|
|
8581
|
+
}
|
|
8582
|
+
snippet;
|
|
8583
|
+
};
|
|
8584
|
+
function newProject() {
|
|
8585
|
+
return new Project2({
|
|
8586
|
+
compilerOptions: { allowJs: true },
|
|
8587
|
+
manipulationSettings: { quoteKind: QuoteKind2.Single }
|
|
8588
|
+
});
|
|
8589
|
+
}
|
|
8590
|
+
function getDefaultExportObject(sourceFile) {
|
|
8591
|
+
const exported = sourceFile.getExportAssignment((ea) => !ea.isExportEquals())?.getExpression();
|
|
8592
|
+
if (exported?.getKind() === SyntaxKind2.ObjectLiteralExpression) {
|
|
8593
|
+
return exported;
|
|
8594
|
+
}
|
|
8595
|
+
if (exported?.getKind() === SyntaxKind2.Identifier) {
|
|
8596
|
+
const init = sourceFile.getVariableDeclaration(exported.getText())?.getInitializer();
|
|
8597
|
+
if (init?.getKind() === SyntaxKind2.ObjectLiteralExpression) {
|
|
8598
|
+
return init;
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8601
|
+
return null;
|
|
8602
|
+
}
|
|
8603
|
+
function resolveKitTarget(root) {
|
|
8604
|
+
const vite = inspectViteSveltekit(root);
|
|
8605
|
+
if (vite?.inlineArg) {
|
|
8606
|
+
return {
|
|
8607
|
+
sourceFile: vite.sourceFile,
|
|
8608
|
+
filePath: vite.filePath,
|
|
8609
|
+
container: "vite-inline",
|
|
8610
|
+
kit: vite.inlineArg,
|
|
8611
|
+
created: false,
|
|
8612
|
+
originalText: vite.sourceFile.getFullText()
|
|
8613
|
+
};
|
|
8614
|
+
}
|
|
8615
|
+
const sveltePath = probeFirstExisting(root, SVELTE_CONFIG_CANDIDATES);
|
|
8616
|
+
if (sveltePath) {
|
|
8617
|
+
const name = path37.basename(sveltePath);
|
|
8618
|
+
if (sveltePath.endsWith(".cjs")) {
|
|
8619
|
+
throw new AdapterError(`${name} is CommonJS, which vela does not edit.`);
|
|
8620
|
+
}
|
|
8621
|
+
const sourceFile = newProject().addSourceFileAtPath(sveltePath);
|
|
8622
|
+
const config = getDefaultExportObject(sourceFile);
|
|
8623
|
+
const kit = config && getOrCreateObjectLiteralProperty(config, "kit", "{}");
|
|
8624
|
+
if (!kit) {
|
|
8625
|
+
throw new AdapterError(`${name} has a shape vela does not understand.`);
|
|
8626
|
+
}
|
|
8627
|
+
return {
|
|
8628
|
+
sourceFile,
|
|
8629
|
+
filePath: sveltePath,
|
|
8630
|
+
container: "svelte-config",
|
|
8631
|
+
kit,
|
|
8632
|
+
created: false,
|
|
8633
|
+
originalText: sourceFile.getFullText()
|
|
8634
|
+
};
|
|
8635
|
+
}
|
|
8636
|
+
if (vite?.sveltekitCall) {
|
|
8637
|
+
const name = path37.basename(vite.filePath);
|
|
8638
|
+
if (vite.nonObjectArg) {
|
|
8639
|
+
throw new AdapterError(`${name} passes sveltekit() something other than an object literal.`);
|
|
8640
|
+
}
|
|
8641
|
+
const originalText = vite.sourceFile.getFullText();
|
|
8642
|
+
const kit = createSveltekitArg(vite);
|
|
8643
|
+
if (!kit)
|
|
8644
|
+
throw new AdapterError(`${name} has a sveltekit() call vela cannot add an argument to.`);
|
|
8645
|
+
return {
|
|
8646
|
+
sourceFile: vite.sourceFile,
|
|
8647
|
+
filePath: vite.filePath,
|
|
8648
|
+
container: "vite-inline",
|
|
8649
|
+
kit,
|
|
8650
|
+
created: true,
|
|
8651
|
+
originalText
|
|
8652
|
+
};
|
|
8653
|
+
}
|
|
8654
|
+
throw new AdapterError(
|
|
8655
|
+
`No svelte.config or vite.config with a sveltekit() plugin found in ${root}.`
|
|
8656
|
+
);
|
|
8657
|
+
}
|
|
8658
|
+
function classify(specifier) {
|
|
8659
|
+
if (specifier === ADAPTER_NODE) return "node";
|
|
8660
|
+
if (specifier === ADAPTER_AUTO) return "auto";
|
|
8661
|
+
if (specifier === ADAPTER_STATIC) return "static";
|
|
8662
|
+
return "other";
|
|
8663
|
+
}
|
|
8664
|
+
function importOf(sourceFile, identifier) {
|
|
8665
|
+
return sourceFile.getImportDeclarations().find((decl) => decl.getDefaultImport()?.getText() === identifier);
|
|
8666
|
+
}
|
|
8667
|
+
function inspectAdapter(target) {
|
|
8668
|
+
const base2 = { file: target.filePath, container: target.container };
|
|
8669
|
+
const prop = target.kit.getProperty("adapter");
|
|
8670
|
+
if (!prop) return { info: { ...base2, kind: "none" } };
|
|
8671
|
+
if (prop.getKind() !== SyntaxKind2.PropertyAssignment) {
|
|
8672
|
+
return { info: { ...base2, kind: "other" } };
|
|
8673
|
+
}
|
|
8674
|
+
const init = prop.asKindOrThrow(SyntaxKind2.PropertyAssignment).getInitializer();
|
|
8675
|
+
if (!init || init.getKind() !== SyntaxKind2.CallExpression) {
|
|
8676
|
+
return { info: { ...base2, kind: "other" } };
|
|
8677
|
+
}
|
|
8678
|
+
const callee = init.asKindOrThrow(SyntaxKind2.CallExpression).getExpression();
|
|
8679
|
+
if (callee.getKind() !== SyntaxKind2.Identifier) {
|
|
8680
|
+
return { info: { ...base2, kind: "other" } };
|
|
8681
|
+
}
|
|
8682
|
+
const importDecl = importOf(target.sourceFile, callee.getText());
|
|
8683
|
+
if (!importDecl) return { info: { ...base2, kind: "other" } };
|
|
8684
|
+
const specifier = importDecl.getModuleSpecifierValue();
|
|
8685
|
+
return { info: { ...base2, kind: classify(specifier), specifier }, importDecl };
|
|
8686
|
+
}
|
|
8687
|
+
async function ensureNodeAdapter(root, { install = true } = {}) {
|
|
8688
|
+
const target = resolveKitTarget(root);
|
|
8689
|
+
const { info, importDecl } = inspectAdapter(target);
|
|
8690
|
+
const name = path37.basename(target.filePath);
|
|
8691
|
+
const outcome = {
|
|
8692
|
+
previous: info.kind,
|
|
8693
|
+
removedDeps: [],
|
|
8694
|
+
packageJsonChanged: false
|
|
8695
|
+
};
|
|
8696
|
+
switch (info.kind) {
|
|
8697
|
+
case "node":
|
|
8698
|
+
break;
|
|
8699
|
+
case "static":
|
|
8700
|
+
throw new AdapterError(
|
|
8701
|
+
`This project builds a static site with ${ADAPTER_STATIC} (${name}).
|
|
8702
|
+
|
|
8703
|
+
vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}. Switch
|
|
8704
|
+
the adapter to deploy it here, or host the static output elsewhere.`
|
|
8705
|
+
);
|
|
8706
|
+
case "other":
|
|
8707
|
+
throw new AdapterError(
|
|
8708
|
+
`This project's adapter${info.specifier ? ` (${info.specifier})` : ""} in ${name} is not one
|
|
8709
|
+
vela will change for you.
|
|
8710
|
+
|
|
8711
|
+
vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}:`
|
|
8712
|
+
);
|
|
8713
|
+
case "auto":
|
|
8714
|
+
switchImport(target, importDecl);
|
|
8715
|
+
outcome.configFile = name;
|
|
8716
|
+
break;
|
|
8717
|
+
case "none":
|
|
8718
|
+
addAdapter(target);
|
|
8719
|
+
outcome.configFile = name;
|
|
8720
|
+
break;
|
|
8721
|
+
}
|
|
8722
|
+
if (outcome.configFile) saveTarget(target);
|
|
8723
|
+
const pkgPath = path37.join(root, "package.json");
|
|
8724
|
+
if (fs36.existsSync(pkgPath)) {
|
|
8725
|
+
const pkg = readPackageJson(pkgPath);
|
|
8726
|
+
const { changed, removed } = adoptNodeAdapter(pkg);
|
|
8727
|
+
if (changed) {
|
|
8728
|
+
writePackageJson(pkgPath, pkg);
|
|
8729
|
+
outcome.packageJsonChanged = true;
|
|
8730
|
+
outcome.removedDeps = removed;
|
|
8731
|
+
}
|
|
8732
|
+
}
|
|
8733
|
+
if (outcome.packageJsonChanged && install) {
|
|
8734
|
+
outcome.installedWith = await installAdapterDependencies(root);
|
|
8735
|
+
}
|
|
8736
|
+
return outcome;
|
|
8737
|
+
}
|
|
8738
|
+
async function installAdapterDependencies(root) {
|
|
8739
|
+
const agent = await packageManager(root);
|
|
8740
|
+
const ok = await installDependencies(agent, root, { exitOnFailure: false });
|
|
8741
|
+
if (!ok) {
|
|
8742
|
+
throw new AdapterError(
|
|
8743
|
+
`Installing ${ADAPTER_NODE} with ${agent} failed.
|
|
8744
|
+
|
|
8745
|
+
The config and package.json are already updated: run \`${agent} install\`, then deploy again.`,
|
|
8746
|
+
""
|
|
8747
|
+
);
|
|
8748
|
+
}
|
|
8749
|
+
return agent;
|
|
8750
|
+
}
|
|
8751
|
+
function switchImport(target, importDecl) {
|
|
8752
|
+
importDecl.setModuleSpecifier(ADAPTER_NODE);
|
|
8753
|
+
const prop = target.kit.getPropertyOrThrow("adapter").asKindOrThrow(SyntaxKind2.PropertyAssignment);
|
|
8754
|
+
const call = prop.getInitializerIfKindOrThrow(SyntaxKind2.CallExpression);
|
|
8755
|
+
for (let i = call.getArguments().length - 1; i >= 0; i--) call.removeArgument(i);
|
|
8756
|
+
dropAdapterAutoComments(target);
|
|
8757
|
+
}
|
|
8758
|
+
var ADAPTER_AUTO_COMMENT = /adapter-auto|svelte\.dev\/docs\/kit\/adapters|switch out the adapter/;
|
|
8759
|
+
function dropAdapterAutoComments(target) {
|
|
8760
|
+
const prop = target.kit.getPropertyOrThrow("adapter");
|
|
8761
|
+
const ranges = prop.getLeadingCommentRanges();
|
|
8762
|
+
if (ranges.length === 0 || !ranges.every((r) => ADAPTER_AUTO_COMMENT.test(r.getText()))) return;
|
|
8763
|
+
const fullStart = prop.getFullStart();
|
|
8764
|
+
const start = prop.getStart();
|
|
8765
|
+
const trivia = target.sourceFile.getFullText().slice(fullStart, start);
|
|
8766
|
+
const lastNewline = trivia.lastIndexOf("\n");
|
|
8767
|
+
if (lastNewline === -1) return;
|
|
8768
|
+
const indent = trivia.slice(lastNewline + 1);
|
|
8769
|
+
target.sourceFile.replaceText([fullStart, start], `
|
|
8770
|
+
${indent}`);
|
|
8771
|
+
}
|
|
8772
|
+
function addAdapter(target) {
|
|
8773
|
+
const taken = importOf(target.sourceFile, "adapter") ?? target.sourceFile.getVariableDeclaration("adapter");
|
|
8774
|
+
if (taken) {
|
|
8775
|
+
throw new AdapterError(
|
|
8776
|
+
`${path37.basename(target.filePath)} already binds the name \`adapter\` to something that is not the SvelteKit adapter.`
|
|
8777
|
+
);
|
|
8778
|
+
}
|
|
8779
|
+
target.sourceFile.addImportDeclaration({
|
|
8780
|
+
defaultImport: "adapter",
|
|
8781
|
+
moduleSpecifier: ADAPTER_NODE
|
|
8782
|
+
});
|
|
8783
|
+
target.kit.addPropertyAssignment({ name: "adapter", initializer: "adapter()" });
|
|
8784
|
+
}
|
|
8785
|
+
function saveTarget(target) {
|
|
8786
|
+
if (target.created) target.sourceFile.formatText();
|
|
8787
|
+
if (target.sourceFile.getFullText() === target.originalText) return;
|
|
8788
|
+
target.sourceFile.saveSync();
|
|
8789
|
+
}
|
|
8790
|
+
function adoptNodeAdapter(pkg) {
|
|
8791
|
+
const removed = [];
|
|
8792
|
+
let changed = false;
|
|
8793
|
+
for (const kind of ["dependencies", "devDependencies"]) {
|
|
8794
|
+
const deps = pkg[kind];
|
|
8795
|
+
if (deps && ADAPTER_AUTO in deps) {
|
|
8796
|
+
delete deps[ADAPTER_AUTO];
|
|
8797
|
+
removed.push(ADAPTER_AUTO);
|
|
8798
|
+
changed = true;
|
|
8799
|
+
}
|
|
8800
|
+
}
|
|
8801
|
+
if (!pkg.dependencies?.[ADAPTER_NODE] && !pkg.devDependencies?.[ADAPTER_NODE]) {
|
|
8802
|
+
pkg.devDependencies = sortKeys({ ...pkg.devDependencies, [ADAPTER_NODE]: ADAPTER_NODE_RANGE });
|
|
8803
|
+
changed = true;
|
|
8804
|
+
}
|
|
8805
|
+
return { changed, removed: [...new Set(removed)] };
|
|
8806
|
+
}
|
|
8807
|
+
function lockfileFor(agent) {
|
|
8808
|
+
switch (agent) {
|
|
8809
|
+
case "pnpm":
|
|
8810
|
+
return "pnpm-lock.yaml";
|
|
8811
|
+
case "yarn":
|
|
8812
|
+
return "yarn.lock";
|
|
8813
|
+
case "bun":
|
|
8814
|
+
return "bun.lock";
|
|
8815
|
+
case "deno":
|
|
8816
|
+
return "deno.lock";
|
|
8817
|
+
default:
|
|
8818
|
+
return "package-lock.json";
|
|
8819
|
+
}
|
|
8820
|
+
}
|
|
8821
|
+
async function packageManager(root) {
|
|
8822
|
+
return (await detect7({ cwd: root }))?.name ?? getUserAgent() ?? "npm";
|
|
8823
|
+
}
|
|
8824
|
+
|
|
8374
8825
|
// src/commands/deploy.ts
|
|
8375
8826
|
var OptionsSchema3 = v8.object({
|
|
8376
8827
|
...SSH_OPTION_SCHEMA,
|
|
@@ -8386,7 +8837,7 @@ var OptionsSchema3 = v8.object({
|
|
|
8386
8837
|
});
|
|
8387
8838
|
var deploy = addLockWaitOption(
|
|
8388
8839
|
addTargetOptions(
|
|
8389
|
-
new
|
|
8840
|
+
new Command77("deploy").description("deploy the app").configureHelp(helpConfig),
|
|
8390
8841
|
"production"
|
|
8391
8842
|
)
|
|
8392
8843
|
).option("--project <name>", "override the project name").option("--domain <hosts>", "hostname(s) to serve on, comma separated").option("--health-path <path>", "path the health check requests").option("--keep <count>", "how many old releases to keep on the server").option("--pb-version <version>", "PocketBase version to run").option("--no-build", "deploy the existing build output without rebuilding").addOption(
|
|
@@ -8402,13 +8853,17 @@ var deploy = addLockWaitOption(
|
|
|
8402
8853
|
(raw) => runCommand(async () => {
|
|
8403
8854
|
const options = parseOptions(OptionsSchema3, raw);
|
|
8404
8855
|
const backend3 = hasBackend();
|
|
8405
|
-
|
|
8856
|
+
p43.intro(pc18.bgCyan(pc18.black(" vela deploy ")));
|
|
8857
|
+
if (options.build !== false) {
|
|
8858
|
+
const { workspaceRootDir } = await getWorkspace();
|
|
8859
|
+
await prepareAdapter(workspaceRootDir);
|
|
8860
|
+
}
|
|
8406
8861
|
await withTarget(
|
|
8407
8862
|
raw,
|
|
8408
8863
|
{
|
|
8409
8864
|
remote: async (ctx) => {
|
|
8410
8865
|
const { session, instance, workspaceRootDir, config } = ctx;
|
|
8411
|
-
|
|
8866
|
+
p43.log.info(
|
|
8412
8867
|
`${pc18.cyan(ctx.appName)} ${pc18.dim("\u2192")} ${pc18.cyan(ctx.targetName)} ${pc18.dim(`(${ctx.server})`)}`
|
|
8413
8868
|
);
|
|
8414
8869
|
const [existing] = await readInstanceStates(session, instance);
|
|
@@ -8416,7 +8871,12 @@ var deploy = addLockWaitOption(
|
|
|
8416
8871
|
const isPreview2 = ctx.target.kind === "preview";
|
|
8417
8872
|
const configured = options.domain ?? (isPreview2 ? existing?.domain : ctx.binding.domain ?? config.deploy?.domain ?? existing?.domain) ?? "";
|
|
8418
8873
|
const askedForRemoteDb = options.remoteDb ?? config.deploy?.buildAgainstRemote;
|
|
8419
|
-
const remoteDb = askedForRemoteDb ??
|
|
8874
|
+
const remoteDb = askedForRemoteDb ?? instanceHasBackend(existing);
|
|
8875
|
+
if (existing && instanceHasBackend(existing) !== backend3) {
|
|
8876
|
+
p43.log.info(
|
|
8877
|
+
backend3 ? `${pc18.cyan(ctx.targetName)} was deployed without a backend before. This deploy adds PocketBase.` : `${pc18.cyan(ctx.targetName)} was deployed with a backend before. This deploy removes PocketBase; its database stays on the server.`
|
|
8878
|
+
);
|
|
8879
|
+
}
|
|
8420
8880
|
const sha = await gitSha(workspaceRootDir);
|
|
8421
8881
|
const reporter = createDeployReporter(workspaceRootDir);
|
|
8422
8882
|
const server = await reporter.identifyServer(session);
|
|
@@ -8456,7 +8916,7 @@ with DNS of your own pointing at ${ctx.server}.`
|
|
|
8456
8916
|
tunnel = await openDatabaseTunnel(session, instance, existing);
|
|
8457
8917
|
} catch (err) {
|
|
8458
8918
|
if (askedForRemoteDb) throw err;
|
|
8459
|
-
|
|
8919
|
+
p43.log.warn(
|
|
8460
8920
|
`Could not build against the ${pc18.cyan(ctx.targetName)} database, using a local one instead.
|
|
8461
8921
|
${pc18.dim(String(err))}`
|
|
8462
8922
|
);
|
|
@@ -8464,13 +8924,13 @@ ${pc18.dim(String(err))}`
|
|
|
8464
8924
|
}
|
|
8465
8925
|
if (tunnel) {
|
|
8466
8926
|
buildEnv = { ...buildEnv, ...tunnel.env };
|
|
8467
|
-
|
|
8927
|
+
p43.log.info(
|
|
8468
8928
|
`Building against the ${pc18.cyan(ctx.targetName)} database on ${ctx.server} ${pc18.dim(`(port ${tunnel.pbPort})`)}`
|
|
8469
8929
|
);
|
|
8470
8930
|
} else if (backend3) {
|
|
8471
8931
|
await ensureSuperuser(workspaceRootDir);
|
|
8472
8932
|
}
|
|
8473
|
-
|
|
8933
|
+
p43.log.step("Building");
|
|
8474
8934
|
try {
|
|
8475
8935
|
await runBuild(workspaceRootDir, config.deploy?.buildCommand, buildEnv);
|
|
8476
8936
|
} finally {
|
|
@@ -8478,9 +8938,9 @@ ${pc18.dim(String(err))}`
|
|
|
8478
8938
|
}
|
|
8479
8939
|
}
|
|
8480
8940
|
const entries = collectArtifact(workspaceRootDir, config.deploy ?? {});
|
|
8481
|
-
|
|
8941
|
+
p43.log.step(`Uploading release ${pc18.dim(release)}`);
|
|
8482
8942
|
await uploadRelease(session, instance, release, entries);
|
|
8483
|
-
|
|
8943
|
+
p43.log.step("Activating");
|
|
8484
8944
|
result = await runServerScript(session, "apply.sh", {
|
|
8485
8945
|
args: [
|
|
8486
8946
|
instance,
|
|
@@ -8531,7 +8991,7 @@ ${pc18.dim(String(err))}`
|
|
|
8531
8991
|
url: primaryHost ? url : void 0
|
|
8532
8992
|
});
|
|
8533
8993
|
const redirects = started?.environment.redirects ?? [];
|
|
8534
|
-
|
|
8994
|
+
p43.log.success(
|
|
8535
8995
|
`Deployed ${pc18.cyan(ctx.appName)} ${pc18.dim(release)}
|
|
8536
8996
|
|
|
8537
8997
|
URL ${url}
|
|
@@ -8539,7 +8999,7 @@ ${pc18.dim(String(err))}`
|
|
|
8539
8999
|
` : "") + ` Port ${result?.webPort ?? "?"}${backend3 ? ` (PocketBase ${result?.pbPort ?? "?"})` : ""}`
|
|
8540
9000
|
);
|
|
8541
9001
|
if (managed && managed !== existing?.managed) {
|
|
8542
|
-
|
|
9002
|
+
p43.log.info(`${pc18.cyan(managed)} goes live within a minute.`);
|
|
8543
9003
|
}
|
|
8544
9004
|
if (result?.superuserCreated) {
|
|
8545
9005
|
await copyLocalBranding(
|
|
@@ -8548,7 +9008,7 @@ ${pc18.dim(String(err))}`
|
|
|
8548
9008
|
workspaceRootDir,
|
|
8549
9009
|
primaryHost ? result?.url ?? "" : ""
|
|
8550
9010
|
);
|
|
8551
|
-
|
|
9011
|
+
p43.log.info(
|
|
8552
9012
|
`Created the PocketBase superuser this app authenticates as.
|
|
8553
9013
|
|
|
8554
9014
|
Its credentials are stored in the environment on the server. To use
|
|
@@ -8559,7 +9019,7 @@ and deploy again.`
|
|
|
8559
9019
|
await reportAppURLDrift(session, instance, primaryHost);
|
|
8560
9020
|
}
|
|
8561
9021
|
if (!primaryHost) {
|
|
8562
|
-
|
|
9022
|
+
p43.log.warn(
|
|
8563
9023
|
`No domain configured, so nothing is proxied to this app yet.
|
|
8564
9024
|
Redeploy with ${pc18.cyan("--domain example.com")} once DNS points at ${ctx.server}` + (reporter.enabled ? "" : `,
|
|
8565
9025
|
or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
@@ -8569,15 +9029,47 @@ or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
|
8569
9029
|
},
|
|
8570
9030
|
{ project: options.project, askDomain: true, label: "deploy" }
|
|
8571
9031
|
);
|
|
8572
|
-
|
|
9032
|
+
p43.outro(`${pc18.cyan("vela status")} to see what is running`);
|
|
8573
9033
|
}, "Failed to deploy.")
|
|
8574
9034
|
);
|
|
9035
|
+
async function prepareAdapter(workspaceRootDir) {
|
|
9036
|
+
const rethrow = (err) => {
|
|
9037
|
+
if (err instanceof AdapterError) {
|
|
9038
|
+
throw new Error(err.snippet ? `${err.message}
|
|
9039
|
+
|
|
9040
|
+
${pc18.cyan(err.snippet)}` : err.message);
|
|
9041
|
+
}
|
|
9042
|
+
throw err;
|
|
9043
|
+
};
|
|
9044
|
+
const outcome = await ensureNodeAdapter(workspaceRootDir, { install: false }).catch(rethrow);
|
|
9045
|
+
if (!outcome.configFile && !outcome.packageJsonChanged) return;
|
|
9046
|
+
const changed = [
|
|
9047
|
+
outcome.configFile,
|
|
9048
|
+
outcome.packageJsonChanged ? "package.json" : void 0
|
|
9049
|
+
].filter((f) => Boolean(f));
|
|
9050
|
+
const why = outcome.previous === "auto" ? `${ADAPTER_AUTO} builds nothing for a server of your own` : outcome.previous === "none" ? "No adapter was configured" : `${ADAPTER_NODE} was configured but not in package.json`;
|
|
9051
|
+
p43.log.step(`Switching the adapter to ${pc18.cyan(ADAPTER_NODE)}`);
|
|
9052
|
+
p43.log.info(
|
|
9053
|
+
`${why}, and vela deploy runs the app as a Node server.
|
|
9054
|
+
|
|
9055
|
+
Changed ${changed.join(", ")}` + (outcome.removedDeps.length ? `
|
|
9056
|
+
Removed ${outcome.removedDeps.join(", ")}` : "")
|
|
9057
|
+
);
|
|
9058
|
+
if (outcome.packageJsonChanged) {
|
|
9059
|
+
try {
|
|
9060
|
+
changed.push(lockfileFor(await installAdapterDependencies(workspaceRootDir)));
|
|
9061
|
+
} catch (err) {
|
|
9062
|
+
rethrow(err);
|
|
9063
|
+
}
|
|
9064
|
+
}
|
|
9065
|
+
p43.log.warn(`Commit ${changed.join(", ")} so every deploy builds the same way.`);
|
|
9066
|
+
}
|
|
8575
9067
|
async function reportAppURLDrift(session, instance, domain) {
|
|
8576
9068
|
const expected = normalizeOrigin(domain);
|
|
8577
9069
|
if (!expected) return;
|
|
8578
9070
|
const current = await readRemoteAppURL(session, instance);
|
|
8579
9071
|
if (!current || normalizeOrigin(current) === expected) return;
|
|
8580
|
-
|
|
9072
|
+
p43.log.warn(
|
|
8581
9073
|
`This app's PocketBase ${pc18.cyan("appURL")} is ${pc18.dim(current)}, but it is served on ${pc18.dim(expected)}.
|
|
8582
9074
|
|
|
8583
9075
|
Emails and anything else PocketBase links to will use the former. Update it in
|
|
@@ -8592,25 +9084,25 @@ async function copyLocalBranding(session, instance, workspaceRootDir, appURL) {
|
|
|
8592
9084
|
if (copied.length === 0) return;
|
|
8593
9085
|
const outcome = await restartInstance(session, instance);
|
|
8594
9086
|
if (outcome.deployed && !outcome.restarted) {
|
|
8595
|
-
|
|
9087
|
+
p43.log.warn(
|
|
8596
9088
|
`Copied ${copied.join(", ")}, but the app did not restart to pick them up.
|
|
8597
9089
|
${pc18.dim(outcome.error ?? "")}`
|
|
8598
9090
|
);
|
|
8599
9091
|
return;
|
|
8600
9092
|
}
|
|
8601
|
-
|
|
9093
|
+
p43.log.success(`Copied ${copied.join(", ")} from this project's database`);
|
|
8602
9094
|
} catch (err) {
|
|
8603
|
-
|
|
9095
|
+
p43.log.warn(
|
|
8604
9096
|
`Could not copy this project's PocketBase settings across.
|
|
8605
9097
|
Set them in the admin panel instead. ${pc18.dim(String(err))}`
|
|
8606
9098
|
);
|
|
8607
9099
|
}
|
|
8608
9100
|
}
|
|
8609
9101
|
async function openDatabaseTunnel(session, instance, state) {
|
|
8610
|
-
const pbPort = state?.pbPort;
|
|
9102
|
+
const pbPort = instanceHasBackend(state) ? state?.pbPort : void 0;
|
|
8611
9103
|
if (!pbPort) {
|
|
8612
9104
|
throw new Error(
|
|
8613
|
-
`--remote-db needs
|
|
9105
|
+
`--remote-db needs a deployed database to build against, and ${instance} ${state ? "has no backend" : "has not been deployed yet"}.
|
|
8614
9106
|
|
|
8615
9107
|
Deploy once without it, then turn it on.`
|
|
8616
9108
|
);
|
|
@@ -8684,7 +9176,7 @@ async function uploadRelease(session, instance, release, entries) {
|
|
|
8684
9176
|
}
|
|
8685
9177
|
function isDirectory(target) {
|
|
8686
9178
|
try {
|
|
8687
|
-
return
|
|
9179
|
+
return fs37.statSync(target).isDirectory();
|
|
8688
9180
|
} catch {
|
|
8689
9181
|
return false;
|
|
8690
9182
|
}
|
|
@@ -8692,8 +9184,8 @@ function isDirectory(target) {
|
|
|
8692
9184
|
async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
8693
9185
|
const remote = await readRemoteEnv(session, instance);
|
|
8694
9186
|
if (Object.keys(remote).length > 0) return;
|
|
8695
|
-
if (!
|
|
8696
|
-
|
|
9187
|
+
if (!fs37.existsSync(path38.join(workspaceRootDir, ".env"))) return;
|
|
9188
|
+
p43.log.warn(
|
|
8697
9189
|
`This app has no production environment variables yet.
|
|
8698
9190
|
|
|
8699
9191
|
Local ${pc18.cyan(".env")} values are not uploaded by a deploy. Set them with
|
|
@@ -8704,23 +9196,23 @@ async function serverTimeOrLocal(session) {
|
|
|
8704
9196
|
try {
|
|
8705
9197
|
return await serverTime(session);
|
|
8706
9198
|
} catch {
|
|
8707
|
-
|
|
9199
|
+
p43.log.warn("Could not read the clock on the server; stamping this release from this machine.");
|
|
8708
9200
|
return /* @__PURE__ */ new Date();
|
|
8709
9201
|
}
|
|
8710
9202
|
}
|
|
8711
9203
|
|
|
8712
9204
|
// src/commands/link.ts
|
|
8713
|
-
import
|
|
8714
|
-
import
|
|
8715
|
-
import { Command as
|
|
8716
|
-
import * as
|
|
9205
|
+
import path39 from "node:path";
|
|
9206
|
+
import process30 from "node:process";
|
|
9207
|
+
import { Command as Command78 } from "commander";
|
|
9208
|
+
import * as p44 from "@clack/prompts";
|
|
8717
9209
|
var CREATE_NEW = "__new__";
|
|
8718
|
-
var link = new
|
|
9210
|
+
var link = new Command78("link").description("link this project to a velastack.dev project").configureHelp(helpConfig).action(() => runCommand(linkProject, "Failed to link the project."));
|
|
8719
9211
|
async function linkProject() {
|
|
8720
9212
|
const { workspaceRootDir } = await getWorkspace();
|
|
8721
9213
|
const existing = readProjectConfig(workspaceRootDir);
|
|
8722
9214
|
if (existing) {
|
|
8723
|
-
|
|
9215
|
+
p44.log.success(`Linked to ${existing.projectName}.`);
|
|
8724
9216
|
return;
|
|
8725
9217
|
}
|
|
8726
9218
|
const apiKey = requireApiKey();
|
|
@@ -8747,10 +9239,10 @@ async function linkProject() {
|
|
|
8747
9239
|
projectName = created.name;
|
|
8748
9240
|
}
|
|
8749
9241
|
writeProjectConfig(workspaceRootDir, { projectId, teamId, projectName });
|
|
8750
|
-
|
|
9242
|
+
p44.log.success(`Linked to ${projectName}.`);
|
|
8751
9243
|
}
|
|
8752
9244
|
async function pickExistingProject(projects) {
|
|
8753
|
-
const choice = await
|
|
9245
|
+
const choice = await p44.select({
|
|
8754
9246
|
message: "Select a project",
|
|
8755
9247
|
options: [
|
|
8756
9248
|
...projects.map((pr) => ({
|
|
@@ -8760,61 +9252,61 @@ async function pickExistingProject(projects) {
|
|
|
8760
9252
|
{ value: CREATE_NEW, label: "Create a new project" }
|
|
8761
9253
|
]
|
|
8762
9254
|
});
|
|
8763
|
-
if (
|
|
8764
|
-
|
|
8765
|
-
|
|
9255
|
+
if (p44.isCancel(choice)) {
|
|
9256
|
+
p44.cancel("Operation cancelled.");
|
|
9257
|
+
process30.exit(0);
|
|
8766
9258
|
}
|
|
8767
9259
|
return choice;
|
|
8768
9260
|
}
|
|
8769
9261
|
async function pickTeam(teams3) {
|
|
8770
9262
|
if (teams3.length === 1) return teams3[0];
|
|
8771
|
-
const choice = await
|
|
9263
|
+
const choice = await p44.select({
|
|
8772
9264
|
message: "Select a team",
|
|
8773
9265
|
options: teams3.map((team) => ({
|
|
8774
9266
|
value: team.id,
|
|
8775
9267
|
label: team.is_personal ? `${team.name} (personal)` : team.name
|
|
8776
9268
|
}))
|
|
8777
9269
|
});
|
|
8778
|
-
if (
|
|
8779
|
-
|
|
8780
|
-
|
|
9270
|
+
if (p44.isCancel(choice)) {
|
|
9271
|
+
p44.cancel("Operation cancelled.");
|
|
9272
|
+
process30.exit(0);
|
|
8781
9273
|
}
|
|
8782
9274
|
return teams3.find((team) => team.id === choice);
|
|
8783
9275
|
}
|
|
8784
9276
|
async function promptProjectName(workspaceRootDir) {
|
|
8785
9277
|
const defaultValue = defaultProjectName2(workspaceRootDir);
|
|
8786
|
-
const value = await
|
|
9278
|
+
const value = await p44.text({
|
|
8787
9279
|
message: "Project name",
|
|
8788
9280
|
defaultValue,
|
|
8789
9281
|
initialValue: defaultValue,
|
|
8790
9282
|
placeholder: defaultValue,
|
|
8791
9283
|
validate: (v10) => !v10?.trim() ? "Required" : void 0
|
|
8792
9284
|
});
|
|
8793
|
-
if (
|
|
8794
|
-
|
|
8795
|
-
|
|
9285
|
+
if (p44.isCancel(value)) {
|
|
9286
|
+
p44.cancel("Operation cancelled.");
|
|
9287
|
+
process30.exit(0);
|
|
8796
9288
|
}
|
|
8797
9289
|
return value.trim();
|
|
8798
9290
|
}
|
|
8799
9291
|
function defaultProjectName2(workspaceRootDir) {
|
|
8800
9292
|
try {
|
|
8801
|
-
const pkg = readPackageJson(
|
|
9293
|
+
const pkg = readPackageJson(path39.join(workspaceRootDir, "package.json"));
|
|
8802
9294
|
const name = pkg.name;
|
|
8803
9295
|
if (typeof name === "string" && name.trim()) return name.trim();
|
|
8804
9296
|
} catch {
|
|
8805
9297
|
}
|
|
8806
|
-
return
|
|
9298
|
+
return path39.basename(workspaceRootDir);
|
|
8807
9299
|
}
|
|
8808
9300
|
|
|
8809
9301
|
// src/commands/env.ts
|
|
8810
|
-
import { Command as
|
|
9302
|
+
import { Command as Command83 } from "commander";
|
|
8811
9303
|
|
|
8812
9304
|
// src/commands/env/list.ts
|
|
8813
|
-
import { Command as
|
|
8814
|
-
import * as
|
|
9305
|
+
import { Command as Command79 } from "commander";
|
|
9306
|
+
import * as p45 from "@clack/prompts";
|
|
8815
9307
|
import pc19 from "picocolors";
|
|
8816
9308
|
var envList = addTargetOptions(
|
|
8817
|
-
new
|
|
9309
|
+
new Command79("list").description("list environment variable names").configureHelp(helpConfig),
|
|
8818
9310
|
"local"
|
|
8819
9311
|
).action(
|
|
8820
9312
|
(raw) => runCommand(
|
|
@@ -8836,10 +9328,10 @@ var envList = addTargetOptions(
|
|
|
8836
9328
|
);
|
|
8837
9329
|
function report(keys, where) {
|
|
8838
9330
|
if (keys.length === 0) {
|
|
8839
|
-
|
|
9331
|
+
p45.log.info(`No environment variables configured ${pc19.dim(`(${where})`)}.`);
|
|
8840
9332
|
return;
|
|
8841
9333
|
}
|
|
8842
|
-
|
|
9334
|
+
p45.log.info(
|
|
8843
9335
|
`Environment ${pc19.dim(`(${where})`)}
|
|
8844
9336
|
|
|
8845
9337
|
` + keys.sort().map((key) => ` ${key}`).join("\n")
|
|
@@ -8847,12 +9339,12 @@ function report(keys, where) {
|
|
|
8847
9339
|
}
|
|
8848
9340
|
|
|
8849
9341
|
// src/commands/env/set.ts
|
|
8850
|
-
import
|
|
8851
|
-
import { Command as
|
|
8852
|
-
import * as
|
|
9342
|
+
import process31 from "node:process";
|
|
9343
|
+
import { Command as Command80 } from "commander";
|
|
9344
|
+
import * as p46 from "@clack/prompts";
|
|
8853
9345
|
import pc20 from "picocolors";
|
|
8854
9346
|
var envSet = addTargetOptions(
|
|
8855
|
-
new
|
|
9347
|
+
new Command80("set").description("set an environment variable").argument("<key>", "variable name").argument("[value]", "value \u2014 prompted for, without echo, when omitted").configureHelp(helpConfig),
|
|
8856
9348
|
"local"
|
|
8857
9349
|
).action(
|
|
8858
9350
|
(key, value, raw) => runCommand(
|
|
@@ -8862,14 +9354,14 @@ var envSet = addTargetOptions(
|
|
|
8862
9354
|
local: async (ctx) => {
|
|
8863
9355
|
const resolved = await resolveValue(key, value);
|
|
8864
9356
|
setLocalEnv(ctx.envFile, key, resolved);
|
|
8865
|
-
|
|
9357
|
+
p46.log.success(`${key} updated ${pc20.dim("(local)")}`);
|
|
8866
9358
|
await applyLocalEnvChange(ctx, [key]);
|
|
8867
9359
|
},
|
|
8868
9360
|
remote: async (ctx) => {
|
|
8869
9361
|
const resolved = await resolveValue(key, value);
|
|
8870
9362
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
8871
9363
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...env2, [key]: resolved });
|
|
8872
|
-
|
|
9364
|
+
p46.log.success(`${key} updated ${pc20.dim(`(${ctx.targetName})`)}`);
|
|
8873
9365
|
await applyEnvRestart(ctx, [key]);
|
|
8874
9366
|
}
|
|
8875
9367
|
},
|
|
@@ -8883,23 +9375,23 @@ async function resolveValue(key, value) {
|
|
|
8883
9375
|
return value ?? await promptValue(key);
|
|
8884
9376
|
}
|
|
8885
9377
|
async function promptValue(key) {
|
|
8886
|
-
const value = await
|
|
9378
|
+
const value = await p46.password({
|
|
8887
9379
|
message: `Value for ${pc20.cyan(key)}`,
|
|
8888
9380
|
validate: (input) => !input?.length ? "Required" : void 0
|
|
8889
9381
|
});
|
|
8890
|
-
if (
|
|
8891
|
-
|
|
8892
|
-
|
|
9382
|
+
if (p46.isCancel(value)) {
|
|
9383
|
+
p46.cancel("Operation cancelled.");
|
|
9384
|
+
process31.exit(0);
|
|
8893
9385
|
}
|
|
8894
9386
|
return value;
|
|
8895
9387
|
}
|
|
8896
9388
|
|
|
8897
9389
|
// src/commands/env/unset.ts
|
|
8898
|
-
import { Command as
|
|
8899
|
-
import * as
|
|
9390
|
+
import { Command as Command81 } from "commander";
|
|
9391
|
+
import * as p47 from "@clack/prompts";
|
|
8900
9392
|
import pc21 from "picocolors";
|
|
8901
9393
|
var envUnset = addTargetOptions(
|
|
8902
|
-
new
|
|
9394
|
+
new Command81("unset").description("remove an environment variable").argument("<key>", "variable name").configureHelp(helpConfig),
|
|
8903
9395
|
"local"
|
|
8904
9396
|
).action(
|
|
8905
9397
|
(key, raw) => runCommand(
|
|
@@ -8908,22 +9400,22 @@ var envUnset = addTargetOptions(
|
|
|
8908
9400
|
{
|
|
8909
9401
|
local: async (ctx) => {
|
|
8910
9402
|
if (!(key in readLocalEnv(ctx.envFile))) {
|
|
8911
|
-
|
|
9403
|
+
p47.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
8912
9404
|
return;
|
|
8913
9405
|
}
|
|
8914
9406
|
unsetLocalEnv(ctx.envFile, key);
|
|
8915
|
-
|
|
9407
|
+
p47.log.success(`${key} removed ${pc21.dim("(local)")}`);
|
|
8916
9408
|
await applyLocalEnvChange(ctx, [key]);
|
|
8917
9409
|
},
|
|
8918
9410
|
remote: async (ctx) => {
|
|
8919
9411
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
8920
9412
|
if (!(key in env2)) {
|
|
8921
|
-
|
|
9413
|
+
p47.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
8922
9414
|
return;
|
|
8923
9415
|
}
|
|
8924
9416
|
delete env2[key];
|
|
8925
9417
|
await writeRemoteEnv(ctx.session, ctx.instance, env2);
|
|
8926
|
-
|
|
9418
|
+
p47.log.success(`${key} removed ${pc21.dim(`(${ctx.targetName})`)}`);
|
|
8927
9419
|
await applyEnvRestart(ctx, [key]);
|
|
8928
9420
|
}
|
|
8929
9421
|
},
|
|
@@ -8934,14 +9426,14 @@ var envUnset = addTargetOptions(
|
|
|
8934
9426
|
);
|
|
8935
9427
|
|
|
8936
9428
|
// src/commands/env/import.ts
|
|
8937
|
-
import
|
|
8938
|
-
import
|
|
8939
|
-
import
|
|
8940
|
-
import { Command as
|
|
8941
|
-
import * as
|
|
9429
|
+
import fs38 from "node:fs";
|
|
9430
|
+
import path40 from "node:path";
|
|
9431
|
+
import process32 from "node:process";
|
|
9432
|
+
import { Command as Command82 } from "commander";
|
|
9433
|
+
import * as p48 from "@clack/prompts";
|
|
8942
9434
|
import pc22 from "picocolors";
|
|
8943
9435
|
var envImport = addTargetOptions(
|
|
8944
|
-
new
|
|
9436
|
+
new Command82("import").description("merge a dotenv file into the environment").argument("<file>", "dotenv file to read").configureHelp(helpConfig),
|
|
8945
9437
|
"local"
|
|
8946
9438
|
).action(
|
|
8947
9439
|
(file, raw) => runCommand(
|
|
@@ -8956,22 +9448,22 @@ var envImport = addTargetOptions(
|
|
|
8956
9448
|
const incoming = read(source, file);
|
|
8957
9449
|
const keys = Object.keys(incoming);
|
|
8958
9450
|
if (keys.length === 0) return;
|
|
8959
|
-
|
|
9451
|
+
p48.log.step(`Importing ${keys.length} variable(s) from ${pc22.cyan(file)}`);
|
|
8960
9452
|
editLocalEnv(
|
|
8961
9453
|
ctx.envFile,
|
|
8962
9454
|
(content) => keys.reduce((acc, key) => upsertEnvVar(acc, key, incoming[key]), content)
|
|
8963
9455
|
);
|
|
8964
|
-
|
|
9456
|
+
p48.log.success(`${keys.length} variable(s) updated ${pc22.dim("(local)")}`);
|
|
8965
9457
|
await applyLocalEnvChange(ctx, keys);
|
|
8966
9458
|
},
|
|
8967
9459
|
remote: async (ctx) => {
|
|
8968
9460
|
const incoming = read(resolve(file), file);
|
|
8969
9461
|
const keys = Object.keys(incoming);
|
|
8970
9462
|
if (keys.length === 0) return;
|
|
8971
|
-
|
|
9463
|
+
p48.log.step(`Importing ${keys.length} variable(s) from ${pc22.cyan(file)}`);
|
|
8972
9464
|
const existing = await readRemoteEnv(ctx.session, ctx.instance);
|
|
8973
9465
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...existing, ...incoming });
|
|
8974
|
-
|
|
9466
|
+
p48.log.success(`${keys.length} variable(s) updated ${pc22.dim(`(${ctx.targetName})`)}`);
|
|
8975
9467
|
await applyEnvRestart(ctx, keys);
|
|
8976
9468
|
}
|
|
8977
9469
|
},
|
|
@@ -8981,24 +9473,24 @@ var envImport = addTargetOptions(
|
|
|
8981
9473
|
)
|
|
8982
9474
|
);
|
|
8983
9475
|
function resolve(file) {
|
|
8984
|
-
return
|
|
9476
|
+
return path40.resolve(process32.cwd(), file);
|
|
8985
9477
|
}
|
|
8986
9478
|
function read(resolved, shown) {
|
|
8987
|
-
if (!
|
|
9479
|
+
if (!fs38.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
8988
9480
|
const incoming = readLocalEnvFile(resolved);
|
|
8989
|
-
if (Object.keys(incoming).length === 0)
|
|
9481
|
+
if (Object.keys(incoming).length === 0) p48.log.info(`${shown} has no variables to import.`);
|
|
8990
9482
|
return incoming;
|
|
8991
9483
|
}
|
|
8992
9484
|
|
|
8993
9485
|
// src/commands/env.ts
|
|
8994
|
-
var env = new
|
|
9486
|
+
var env = new Command83("env").description("manage environment variables, locally or on a target").configureHelp(helpConfig).addCommand(envList).addCommand(envSet).addCommand(envUnset).addCommand(envImport);
|
|
8995
9487
|
|
|
8996
9488
|
// src/commands/status.ts
|
|
8997
|
-
import { Command as
|
|
8998
|
-
import * as
|
|
9489
|
+
import { Command as Command84 } from "commander";
|
|
9490
|
+
import * as p49 from "@clack/prompts";
|
|
8999
9491
|
import pc23 from "picocolors";
|
|
9000
9492
|
var status = addTargetOptions(
|
|
9001
|
-
new
|
|
9493
|
+
new Command84("status").description("show what is deployed").configureHelp(helpConfig),
|
|
9002
9494
|
"production"
|
|
9003
9495
|
).option("--all", "show every app on the server, not just this project").option("--json", "print raw JSON").action(
|
|
9004
9496
|
(raw) => runCommand(async () => {
|
|
@@ -9029,11 +9521,11 @@ function report2(states, json) {
|
|
|
9029
9521
|
return;
|
|
9030
9522
|
}
|
|
9031
9523
|
if (states.length === 0) {
|
|
9032
|
-
|
|
9524
|
+
p49.log.info("Nothing is deployed here yet.");
|
|
9033
9525
|
return;
|
|
9034
9526
|
}
|
|
9035
9527
|
for (const state of states) {
|
|
9036
|
-
|
|
9528
|
+
p49.log.info(describe2(state));
|
|
9037
9529
|
}
|
|
9038
9530
|
}
|
|
9039
9531
|
function describe2(state) {
|
|
@@ -9057,12 +9549,12 @@ function describe2(state) {
|
|
|
9057
9549
|
}
|
|
9058
9550
|
|
|
9059
9551
|
// src/commands/rollback.ts
|
|
9060
|
-
import { Command as
|
|
9061
|
-
import * as
|
|
9552
|
+
import { Command as Command85 } from "commander";
|
|
9553
|
+
import * as p50 from "@clack/prompts";
|
|
9062
9554
|
import pc24 from "picocolors";
|
|
9063
9555
|
var rollback = addLockWaitOption(
|
|
9064
9556
|
addTargetOptions(
|
|
9065
|
-
new
|
|
9557
|
+
new Command85("rollback").description("put the previous release back").configureHelp(helpConfig),
|
|
9066
9558
|
"production"
|
|
9067
9559
|
)
|
|
9068
9560
|
).option("--to <release>", "roll back to a specific release instead of the previous one").action(
|
|
@@ -9072,7 +9564,7 @@ var rollback = addLockWaitOption(
|
|
|
9072
9564
|
raw,
|
|
9073
9565
|
{
|
|
9074
9566
|
remote: async (ctx) => {
|
|
9075
|
-
|
|
9567
|
+
p50.log.step(
|
|
9076
9568
|
`Rolling back ${pc24.cyan(ctx.appName)} ${pc24.dim(`(${ctx.targetName})`)} on ${ctx.server}`
|
|
9077
9569
|
);
|
|
9078
9570
|
const result = await runServerScript(
|
|
@@ -9087,7 +9579,7 @@ var rollback = addLockWaitOption(
|
|
|
9087
9579
|
stream: true
|
|
9088
9580
|
}
|
|
9089
9581
|
);
|
|
9090
|
-
|
|
9582
|
+
p50.log.success(
|
|
9091
9583
|
`Rolled back to ${pc24.cyan(result?.release ?? "the previous release")}` + (result?.from ? ` ${pc24.dim(`(was ${result.from})`)}` : "")
|
|
9092
9584
|
);
|
|
9093
9585
|
}
|
|
@@ -9101,9 +9593,9 @@ var rollback = addLockWaitOption(
|
|
|
9101
9593
|
);
|
|
9102
9594
|
|
|
9103
9595
|
// src/commands/logs.ts
|
|
9104
|
-
import { Command as
|
|
9596
|
+
import { Command as Command86 } from "commander";
|
|
9105
9597
|
var logs = addTargetOptions(
|
|
9106
|
-
new
|
|
9598
|
+
new Command86("logs").description("tail the logs of a deployed app").configureHelp(helpConfig),
|
|
9107
9599
|
"production"
|
|
9108
9600
|
).option("-f, --follow", "keep streaming new output").option("-n, --lines <count>", "how many lines of history to show", "100").option("--pocketbase", "show the PocketBase service instead of the app").action(
|
|
9109
9601
|
(raw) => runCommand(async () => {
|
|
@@ -9137,16 +9629,16 @@ var logs = addTargetOptions(
|
|
|
9137
9629
|
);
|
|
9138
9630
|
|
|
9139
9631
|
// src/commands/admin.ts
|
|
9140
|
-
import { Command as
|
|
9632
|
+
import { Command as Command88 } from "commander";
|
|
9141
9633
|
|
|
9142
9634
|
// src/commands/admin/create.ts
|
|
9143
|
-
import
|
|
9144
|
-
import { Command as
|
|
9145
|
-
import * as
|
|
9635
|
+
import process33 from "node:process";
|
|
9636
|
+
import { Command as Command87 } from "commander";
|
|
9637
|
+
import * as p51 from "@clack/prompts";
|
|
9146
9638
|
import pc25 from "picocolors";
|
|
9147
9639
|
var MIN_PASSWORD = 10;
|
|
9148
9640
|
var adminCreate = addTargetOptions(
|
|
9149
|
-
new
|
|
9641
|
+
new Command87("create").description("create a login for the admin panel").argument("[email]", "email to sign in with \u2014 prompted for when omitted").configureHelp(helpConfig),
|
|
9150
9642
|
"local"
|
|
9151
9643
|
).action(
|
|
9152
9644
|
(email3, raw) => runCommand(
|
|
@@ -9174,7 +9666,7 @@ var adminCreate = addTargetOptions(
|
|
|
9174
9666
|
const metadata = getPocketbaseMetadata(ctx.workspaceRootDir);
|
|
9175
9667
|
if (metadata) signIn = `http://${metadata.viteHost}:${metadata.vitePort}`;
|
|
9176
9668
|
}
|
|
9177
|
-
|
|
9669
|
+
p51.log.info(
|
|
9178
9670
|
signIn ? `Sign in at ${pc25.cyan(`${signIn}/admin`)}` : `Sign in at ${pc25.cyan("/admin")} once ${pc25.cyan("vela dev")} is running.`
|
|
9179
9671
|
);
|
|
9180
9672
|
},
|
|
@@ -9188,7 +9680,7 @@ var adminCreate = addTargetOptions(
|
|
|
9188
9680
|
(pb) => upsertSuperuser(pb, address, password11)
|
|
9189
9681
|
);
|
|
9190
9682
|
const base2 = state?.domain ? `https://${state.domain.split(",")[0].trim()}` : "";
|
|
9191
|
-
|
|
9683
|
+
p51.log.info(
|
|
9192
9684
|
base2 ? `Sign in at ${pc25.cyan(`${base2}/admin`)}` : `Sign in at ${pc25.cyan("/admin")} once a domain is configured for this target.`
|
|
9193
9685
|
);
|
|
9194
9686
|
}
|
|
@@ -9201,20 +9693,20 @@ var adminCreate = addTargetOptions(
|
|
|
9201
9693
|
async function upsertSuperuser(pb, email3, password11) {
|
|
9202
9694
|
const existing = await findSuperuser(pb, email3);
|
|
9203
9695
|
if (existing) {
|
|
9204
|
-
const confirmed = await
|
|
9696
|
+
const confirmed = await p51.confirm({
|
|
9205
9697
|
message: `${email3} already has an account, update its password?`,
|
|
9206
9698
|
initialValue: false
|
|
9207
9699
|
});
|
|
9208
|
-
if (
|
|
9209
|
-
|
|
9210
|
-
|
|
9700
|
+
if (p51.isCancel(confirmed) || !confirmed) {
|
|
9701
|
+
p51.cancel("Operation cancelled.");
|
|
9702
|
+
process33.exit(0);
|
|
9211
9703
|
}
|
|
9212
9704
|
await pb.collection("_superusers").update(existing, { password: password11, passwordConfirm: password11 });
|
|
9213
|
-
|
|
9705
|
+
p51.log.success(`Password updated for ${pc25.cyan(email3)}, you can sign in now`);
|
|
9214
9706
|
return;
|
|
9215
9707
|
}
|
|
9216
9708
|
await pb.collection("_superusers").create({ email: email3, password: password11, passwordConfirm: password11 });
|
|
9217
|
-
|
|
9709
|
+
p51.log.success(`${pc25.cyan(email3)} can now sign in`);
|
|
9218
9710
|
}
|
|
9219
9711
|
async function findSuperuser(pb, email3) {
|
|
9220
9712
|
try {
|
|
@@ -9225,47 +9717,47 @@ async function findSuperuser(pb, email3) {
|
|
|
9225
9717
|
}
|
|
9226
9718
|
}
|
|
9227
9719
|
async function promptEmail() {
|
|
9228
|
-
const value = await
|
|
9720
|
+
const value = await p51.text({
|
|
9229
9721
|
message: "Email to sign in with",
|
|
9230
9722
|
validate: (input) => input?.includes("@") ? void 0 : "An email address is required"
|
|
9231
9723
|
});
|
|
9232
|
-
if (
|
|
9233
|
-
|
|
9234
|
-
|
|
9724
|
+
if (p51.isCancel(value)) {
|
|
9725
|
+
p51.cancel("Operation cancelled.");
|
|
9726
|
+
process33.exit(0);
|
|
9235
9727
|
}
|
|
9236
9728
|
return value.trim();
|
|
9237
9729
|
}
|
|
9238
9730
|
async function promptPassword2() {
|
|
9239
|
-
const value = await
|
|
9731
|
+
const value = await p51.password({
|
|
9240
9732
|
message: "Password",
|
|
9241
9733
|
validate: (input) => (input?.length ?? 0) >= MIN_PASSWORD ? void 0 : `At least ${MIN_PASSWORD} characters is required`
|
|
9242
9734
|
});
|
|
9243
|
-
if (
|
|
9244
|
-
|
|
9245
|
-
|
|
9735
|
+
if (p51.isCancel(value)) {
|
|
9736
|
+
p51.cancel("Operation cancelled.");
|
|
9737
|
+
process33.exit(0);
|
|
9246
9738
|
}
|
|
9247
|
-
const again = await
|
|
9739
|
+
const again = await p51.password({
|
|
9248
9740
|
message: "Password again",
|
|
9249
9741
|
validate: (input) => input === value ? void 0 : "The two do not match"
|
|
9250
9742
|
});
|
|
9251
|
-
if (
|
|
9252
|
-
|
|
9253
|
-
|
|
9743
|
+
if (p51.isCancel(again)) {
|
|
9744
|
+
p51.cancel("Operation cancelled.");
|
|
9745
|
+
process33.exit(0);
|
|
9254
9746
|
}
|
|
9255
9747
|
return value;
|
|
9256
9748
|
}
|
|
9257
9749
|
|
|
9258
9750
|
// src/commands/admin.ts
|
|
9259
|
-
var admin = new
|
|
9751
|
+
var admin = new Command88("admin").description("manage admin panel logins").configureHelp(helpConfig).addCommand(adminCreate);
|
|
9260
9752
|
|
|
9261
9753
|
// src/commands/backup.ts
|
|
9262
|
-
import { Command as
|
|
9754
|
+
import { Command as Command94 } from "commander";
|
|
9263
9755
|
|
|
9264
9756
|
// src/commands/backup/create.ts
|
|
9265
|
-
import
|
|
9266
|
-
import
|
|
9267
|
-
import { Command as
|
|
9268
|
-
import * as
|
|
9757
|
+
import fs39 from "node:fs";
|
|
9758
|
+
import path41 from "node:path";
|
|
9759
|
+
import { Command as Command89 } from "commander";
|
|
9760
|
+
import * as p52 from "@clack/prompts";
|
|
9269
9761
|
import pc26 from "picocolors";
|
|
9270
9762
|
|
|
9271
9763
|
// src/lib/backups.ts
|
|
@@ -9353,7 +9845,7 @@ async function writeSchedule(pb, cron, maxKeep) {
|
|
|
9353
9845
|
// src/commands/backup/create.ts
|
|
9354
9846
|
var DEFAULT_BACKUP_DIR = "backups";
|
|
9355
9847
|
var backupCreate = addTargetOptions(
|
|
9356
|
-
new
|
|
9848
|
+
new Command89("create").description("take a backup of the database and uploads").argument("[name]", "name for the archive \u2014 generated when omitted").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).option("--no-download", "leave the archive on the server").configureHelp(helpConfig),
|
|
9357
9849
|
"production"
|
|
9358
9850
|
).action(
|
|
9359
9851
|
(name, raw) => runCommand(() => {
|
|
@@ -9369,7 +9861,7 @@ Backup names are lowercase letters, digits, ${pc26.cyan("-")} and ${pc26.cyan("_
|
|
|
9369
9861
|
}
|
|
9370
9862
|
const storage = await readStorageSettings(ctx.pb);
|
|
9371
9863
|
if (storage.s3Enabled) {
|
|
9372
|
-
|
|
9864
|
+
p52.log.warn(
|
|
9373
9865
|
`Uploads are stored in S3, so this archive holds the database only.
|
|
9374
9866
|
|
|
9375
9867
|
PocketBase leaves ${pc26.cyan("storage/")} out of a backup whenever S3 is on.
|
|
@@ -9377,7 +9869,7 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
9377
9869
|
);
|
|
9378
9870
|
}
|
|
9379
9871
|
if (ctx.session) await checkpointAppDatabases(ctx.session, ctx.instance);
|
|
9380
|
-
const spinner7 =
|
|
9872
|
+
const spinner7 = p52.spinner();
|
|
9381
9873
|
spinner7.start(`Backing up ${ctx.targetName}`);
|
|
9382
9874
|
try {
|
|
9383
9875
|
await createBackup(ctx.pb, key);
|
|
@@ -9417,14 +9909,14 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
9417
9909
|
}, "Failed to create the backup.")
|
|
9418
9910
|
);
|
|
9419
9911
|
async function download(ctx, key, outputDir) {
|
|
9420
|
-
const dir =
|
|
9421
|
-
|
|
9422
|
-
const destination =
|
|
9912
|
+
const dir = path41.resolve(ctx.workspaceRootDir, outputDir);
|
|
9913
|
+
fs39.mkdirSync(dir, { recursive: true });
|
|
9914
|
+
const destination = path41.join(dir, key);
|
|
9423
9915
|
if (!ctx.session) {
|
|
9424
|
-
|
|
9425
|
-
return
|
|
9916
|
+
fs39.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9917
|
+
return path41.relative(ctx.workspaceRootDir, destination);
|
|
9426
9918
|
}
|
|
9427
|
-
const spinner7 =
|
|
9919
|
+
const spinner7 = p52.spinner();
|
|
9428
9920
|
spinner7.start(`Downloading ${key}`);
|
|
9429
9921
|
try {
|
|
9430
9922
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
@@ -9433,22 +9925,22 @@ async function download(ctx, key, outputDir) {
|
|
|
9433
9925
|
throw error;
|
|
9434
9926
|
}
|
|
9435
9927
|
spinner7.stop(`Downloaded ${key}`);
|
|
9436
|
-
return
|
|
9928
|
+
return path41.relative(ctx.workspaceRootDir, destination);
|
|
9437
9929
|
}
|
|
9438
9930
|
|
|
9439
9931
|
// src/commands/backup/list.ts
|
|
9440
|
-
import { Command as
|
|
9441
|
-
import * as
|
|
9932
|
+
import { Command as Command90 } from "commander";
|
|
9933
|
+
import * as p53 from "@clack/prompts";
|
|
9442
9934
|
import pc27 from "picocolors";
|
|
9443
9935
|
var backupList = addTargetOptions(
|
|
9444
|
-
new
|
|
9936
|
+
new Command90("list").description("list the backups on a target").configureHelp(helpConfig),
|
|
9445
9937
|
"production"
|
|
9446
9938
|
).action(
|
|
9447
9939
|
(raw) => runCommand(
|
|
9448
9940
|
() => withBackupTarget(raw, "backup list", async (ctx) => {
|
|
9449
9941
|
const backups = await listBackups(ctx.pb);
|
|
9450
9942
|
if (backups.length === 0) {
|
|
9451
|
-
|
|
9943
|
+
p53.log.info(
|
|
9452
9944
|
`${pc27.cyan(ctx.targetName)} has no backups yet.
|
|
9453
9945
|
|
|
9454
9946
|
Take one with ${pc27.cyan("vela backup create")}.`
|
|
@@ -9456,7 +9948,7 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9456
9948
|
return;
|
|
9457
9949
|
}
|
|
9458
9950
|
const width = Math.max(...backups.map((b) => b.key.length));
|
|
9459
|
-
|
|
9951
|
+
p53.log.message(
|
|
9460
9952
|
backups.map(
|
|
9461
9953
|
(b) => `${b.key.padEnd(width)} ${pc27.dim(formatBytes(b.size).padStart(8))} ${pc27.dim(b.modified)}`
|
|
9462
9954
|
).join("\n")
|
|
@@ -9467,13 +9959,13 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9467
9959
|
);
|
|
9468
9960
|
|
|
9469
9961
|
// src/commands/backup/download.ts
|
|
9470
|
-
import
|
|
9471
|
-
import
|
|
9472
|
-
import { Command as
|
|
9473
|
-
import * as
|
|
9962
|
+
import fs40 from "node:fs";
|
|
9963
|
+
import path42 from "node:path";
|
|
9964
|
+
import { Command as Command91 } from "commander";
|
|
9965
|
+
import * as p54 from "@clack/prompts";
|
|
9474
9966
|
import pc28 from "picocolors";
|
|
9475
9967
|
var backupDownload = addTargetOptions(
|
|
9476
|
-
new
|
|
9968
|
+
new Command91("download").description("save a backup off the server").argument("<key>", "archive to download, as shown by `vela backup list`").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).configureHelp(helpConfig),
|
|
9477
9969
|
"production"
|
|
9478
9970
|
).action(
|
|
9479
9971
|
(key, raw) => runCommand(() => {
|
|
@@ -9495,13 +9987,13 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
|
|
|
9495
9987
|
Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
9496
9988
|
);
|
|
9497
9989
|
}
|
|
9498
|
-
const dir =
|
|
9499
|
-
|
|
9500
|
-
const destination =
|
|
9990
|
+
const dir = path42.resolve(ctx.workspaceRootDir, options.output);
|
|
9991
|
+
fs40.mkdirSync(dir, { recursive: true });
|
|
9992
|
+
const destination = path42.join(dir, key);
|
|
9501
9993
|
if (!ctx.session) {
|
|
9502
|
-
|
|
9994
|
+
fs40.copyFileSync(path42.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9503
9995
|
} else {
|
|
9504
|
-
const spinner7 =
|
|
9996
|
+
const spinner7 = p54.spinner();
|
|
9505
9997
|
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
9506
9998
|
try {
|
|
9507
9999
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
@@ -9513,19 +10005,19 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9513
10005
|
}
|
|
9514
10006
|
reportResult({
|
|
9515
10007
|
summary: `Saved ${key} from ${ctx.targetName}.`,
|
|
9516
|
-
filesCreated: [
|
|
10008
|
+
filesCreated: [path42.relative(ctx.workspaceRootDir, destination)]
|
|
9517
10009
|
});
|
|
9518
10010
|
});
|
|
9519
10011
|
}, "Failed to download the backup.")
|
|
9520
10012
|
);
|
|
9521
10013
|
|
|
9522
10014
|
// src/commands/backup/delete.ts
|
|
9523
|
-
import
|
|
9524
|
-
import { Command as
|
|
9525
|
-
import * as
|
|
10015
|
+
import process34 from "node:process";
|
|
10016
|
+
import { Command as Command92 } from "commander";
|
|
10017
|
+
import * as p55 from "@clack/prompts";
|
|
9526
10018
|
import pc29 from "picocolors";
|
|
9527
10019
|
var backupDelete = addTargetOptions(
|
|
9528
|
-
new
|
|
10020
|
+
new Command92("delete").description("remove a backup from a target").argument("<key>", "archive to delete, as shown by `vela backup list`").option("-y, --yes", "skip the confirmation").configureHelp(helpConfig),
|
|
9529
10021
|
"production"
|
|
9530
10022
|
).action(
|
|
9531
10023
|
(key, raw) => runCommand(() => {
|
|
@@ -9540,13 +10032,13 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
9540
10032
|
);
|
|
9541
10033
|
}
|
|
9542
10034
|
if (!options.yes) {
|
|
9543
|
-
const confirmed = await
|
|
10035
|
+
const confirmed = await p55.confirm({
|
|
9544
10036
|
message: `Delete ${key} (${formatBytes(found.size)}) from ${ctx.targetName}?`,
|
|
9545
10037
|
initialValue: false
|
|
9546
10038
|
});
|
|
9547
|
-
if (
|
|
9548
|
-
|
|
9549
|
-
|
|
10039
|
+
if (p55.isCancel(confirmed) || !confirmed) {
|
|
10040
|
+
p55.cancel("Operation cancelled.");
|
|
10041
|
+
process34.exit(0);
|
|
9550
10042
|
}
|
|
9551
10043
|
}
|
|
9552
10044
|
await ctx.pb.backups.delete(key);
|
|
@@ -9556,12 +10048,12 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
9556
10048
|
);
|
|
9557
10049
|
|
|
9558
10050
|
// src/commands/backup/schedule.ts
|
|
9559
|
-
import { Command as
|
|
9560
|
-
import * as
|
|
10051
|
+
import { Command as Command93 } from "commander";
|
|
10052
|
+
import * as p56 from "@clack/prompts";
|
|
9561
10053
|
import pc30 from "picocolors";
|
|
9562
10054
|
var DEFAULT_KEEP = 7;
|
|
9563
10055
|
var backupSchedule = addTargetOptions(
|
|
9564
|
-
new
|
|
10056
|
+
new Command93("schedule").description("back up automatically on a schedule").argument("[cron]", "when to run, as a cron expression \u2014 shows the current one when omitted").option("--keep <n>", "how many scheduled archives to keep", String(DEFAULT_KEEP)).option("--off", "stop backing up automatically").configureHelp(helpConfig),
|
|
9565
10057
|
"production"
|
|
9566
10058
|
).action(
|
|
9567
10059
|
(cron, raw) => runCommand(() => {
|
|
@@ -9574,7 +10066,7 @@ var backupSchedule = addTargetOptions(
|
|
|
9574
10066
|
}
|
|
9575
10067
|
if (!cron) {
|
|
9576
10068
|
const current = await readSchedule(ctx.pb);
|
|
9577
|
-
|
|
10069
|
+
p56.log.info(
|
|
9578
10070
|
current.cron ? `${ctx.targetName} backs up on ${pc30.cyan(current.cron)}, keeping ${current.maxKeep}.` : `${ctx.targetName} has no backup schedule.
|
|
9579
10071
|
|
|
9580
10072
|
Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
@@ -9605,18 +10097,18 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
|
9605
10097
|
);
|
|
9606
10098
|
|
|
9607
10099
|
// src/commands/backup.ts
|
|
9608
|
-
var backup = new
|
|
10100
|
+
var backup = new Command94("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
|
|
9609
10101
|
|
|
9610
10102
|
// src/commands/restore.ts
|
|
9611
|
-
import
|
|
9612
|
-
import
|
|
9613
|
-
import
|
|
9614
|
-
import { Command as
|
|
9615
|
-
import * as
|
|
10103
|
+
import fs41 from "node:fs";
|
|
10104
|
+
import path43 from "node:path";
|
|
10105
|
+
import process35 from "node:process";
|
|
10106
|
+
import { Command as Command95 } from "commander";
|
|
10107
|
+
import * as p57 from "@clack/prompts";
|
|
9616
10108
|
import pc31 from "picocolors";
|
|
9617
10109
|
var restore = addLockWaitOption(
|
|
9618
10110
|
addTargetOptions(
|
|
9619
|
-
new
|
|
10111
|
+
new Command95("restore").description("replace a deployment\u2019s database and uploads from a backup").argument("[source]", "a backup key on the target, or a path to a local archive").configureHelp(helpConfig),
|
|
9620
10112
|
"production"
|
|
9621
10113
|
)
|
|
9622
10114
|
).option("-y, --yes", "skip the confirmation prompt").option("--no-migrate", "do not run migrations against the restored database").option("--keep-previous <n>", "how many replaced databases to keep", "1").action(
|
|
@@ -9632,7 +10124,7 @@ var restore = addLockWaitOption(
|
|
|
9632
10124
|
`${ctx.targetName} was deployed without a database, so there is nothing to restore.`
|
|
9633
10125
|
);
|
|
9634
10126
|
}
|
|
9635
|
-
const local = source &&
|
|
10127
|
+
const local = source && fs41.existsSync(source) ? source : void 0;
|
|
9636
10128
|
const key = local ? void 0 : await resolveKey(ctx, source);
|
|
9637
10129
|
if (!options.yes) {
|
|
9638
10130
|
await confirm13(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
|
|
@@ -9653,18 +10145,18 @@ var restore = addLockWaitOption(
|
|
|
9653
10145
|
],
|
|
9654
10146
|
stream: true
|
|
9655
10147
|
});
|
|
9656
|
-
|
|
10148
|
+
p57.log.success(
|
|
9657
10149
|
`Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
|
|
9658
|
-
local ?
|
|
10150
|
+
local ? path43.basename(local) : key
|
|
9659
10151
|
)}.`
|
|
9660
10152
|
);
|
|
9661
10153
|
if (result?.storageCarriedOver) {
|
|
9662
|
-
|
|
10154
|
+
p57.log.info(
|
|
9663
10155
|
"The archive held no uploads, so the files already on the server were kept."
|
|
9664
10156
|
);
|
|
9665
10157
|
}
|
|
9666
10158
|
if (result?.previousDataDir) {
|
|
9667
|
-
|
|
10159
|
+
p57.log.info(
|
|
9668
10160
|
`The database this replaced is at ${pc31.cyan(result.previousDataDir)}.
|
|
9669
10161
|
|
|
9670
10162
|
It is the only way back. Remove it once you are satisfied with the restore.`
|
|
@@ -9705,7 +10197,7 @@ Run ${pc31.cyan("vela backup list")} to see what it does have.`
|
|
|
9705
10197
|
Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive on this machine.`
|
|
9706
10198
|
);
|
|
9707
10199
|
}
|
|
9708
|
-
const chosen = await
|
|
10200
|
+
const chosen = await p57.select({
|
|
9709
10201
|
message: `Which backup should ${ctx.targetName} be restored from?`,
|
|
9710
10202
|
options: backups.map((b) => ({
|
|
9711
10203
|
value: b.key,
|
|
@@ -9713,53 +10205,53 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
|
|
|
9713
10205
|
hint: `${formatBytes(b.size)}, ${b.modified}`
|
|
9714
10206
|
}))
|
|
9715
10207
|
});
|
|
9716
|
-
if (
|
|
9717
|
-
|
|
9718
|
-
|
|
10208
|
+
if (p57.isCancel(chosen)) {
|
|
10209
|
+
p57.cancel("Operation cancelled.");
|
|
10210
|
+
process35.exit(0);
|
|
9719
10211
|
}
|
|
9720
10212
|
return chosen;
|
|
9721
10213
|
}
|
|
9722
10214
|
async function stage(ctx, file) {
|
|
9723
10215
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
9724
|
-
const remote = `${dir}/${
|
|
9725
|
-
const spinner7 =
|
|
9726
|
-
spinner7.start(`Uploading ${
|
|
10216
|
+
const remote = `${dir}/${path43.basename(file)}`;
|
|
10217
|
+
const spinner7 = p57.spinner();
|
|
10218
|
+
spinner7.start(`Uploading ${path43.basename(file)}`);
|
|
9727
10219
|
try {
|
|
9728
10220
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
9729
10221
|
await ctx.session.upload([file], dir);
|
|
9730
10222
|
} catch (error) {
|
|
9731
|
-
spinner7.stop(`Could not upload ${
|
|
10223
|
+
spinner7.stop(`Could not upload ${path43.basename(file)}.`);
|
|
9732
10224
|
throw error;
|
|
9733
10225
|
}
|
|
9734
|
-
spinner7.stop(`Uploaded ${
|
|
10226
|
+
spinner7.stop(`Uploaded ${path43.basename(file)}`);
|
|
9735
10227
|
return remote;
|
|
9736
10228
|
}
|
|
9737
10229
|
async function confirm13(appName, targetName, envTag, from) {
|
|
9738
|
-
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(
|
|
10230
|
+
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path43.basename(from))}`;
|
|
9739
10231
|
if (isProd(envTag)) {
|
|
9740
|
-
const answer = await
|
|
10232
|
+
const answer = await p57.text({
|
|
9741
10233
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
9742
10234
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
9743
10235
|
});
|
|
9744
|
-
if (
|
|
9745
|
-
|
|
9746
|
-
|
|
10236
|
+
if (p57.isCancel(answer)) {
|
|
10237
|
+
p57.cancel("Operation cancelled.");
|
|
10238
|
+
process35.exit(0);
|
|
9747
10239
|
}
|
|
9748
10240
|
return;
|
|
9749
10241
|
}
|
|
9750
|
-
const ok = await
|
|
10242
|
+
const ok = await p57.confirm({
|
|
9751
10243
|
message: `Replace the database and uploads of ${what}?`,
|
|
9752
10244
|
initialValue: false
|
|
9753
10245
|
});
|
|
9754
|
-
if (
|
|
9755
|
-
|
|
9756
|
-
|
|
10246
|
+
if (p57.isCancel(ok) || !ok) {
|
|
10247
|
+
p57.cancel("Operation cancelled.");
|
|
10248
|
+
process35.exit(0);
|
|
9757
10249
|
}
|
|
9758
10250
|
}
|
|
9759
10251
|
|
|
9760
10252
|
// src/commands/targets.ts
|
|
9761
|
-
import { Command as
|
|
9762
|
-
import * as
|
|
10253
|
+
import { Command as Command96 } from "commander";
|
|
10254
|
+
import * as p58 from "@clack/prompts";
|
|
9763
10255
|
import pc32 from "picocolors";
|
|
9764
10256
|
import * as v9 from "valibot";
|
|
9765
10257
|
var OptionsSchema4 = v9.object({
|
|
@@ -9768,7 +10260,7 @@ var OptionsSchema4 = v9.object({
|
|
|
9768
10260
|
offline: v9.optional(v9.boolean())
|
|
9769
10261
|
});
|
|
9770
10262
|
var targets = addSshOptions(
|
|
9771
|
-
new
|
|
10263
|
+
new Command96("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
|
|
9772
10264
|
).option("--json", "print raw JSON").option("--offline", "skip connecting to servers").action(
|
|
9773
10265
|
(raw) => runCommand(async () => {
|
|
9774
10266
|
const options = parseOptions(OptionsSchema4, raw);
|
|
@@ -9834,11 +10326,11 @@ function report3(rows, offline) {
|
|
|
9834
10326
|
const lines = rows.map(
|
|
9835
10327
|
(row) => `${row.kind === "local" ? pc32.dim(row.target.padEnd(target)) : pc32.cyan(row.target.padEnd(target))} ${row.server.padEnd(server)} ${row.domain.padEnd(domain)} ${row.release}`
|
|
9836
10328
|
);
|
|
9837
|
-
|
|
10329
|
+
p58.log.info(`${pc32.dim(header)}
|
|
9838
10330
|
${lines.join("\n")}`);
|
|
9839
10331
|
const unreachable = rows.filter((row) => row.kind === "remote" && !row.reachable);
|
|
9840
10332
|
if (!offline && unreachable.length > 0) {
|
|
9841
|
-
|
|
10333
|
+
p58.log.warn(
|
|
9842
10334
|
`Could not reach ${unreachable.map((row) => row.server).join(", ")}.
|
|
9843
10335
|
Release and domain are shown from what this project recorded.`
|
|
9844
10336
|
);
|
|
@@ -9846,36 +10338,36 @@ Release and domain are shown from what this project recorded.`
|
|
|
9846
10338
|
}
|
|
9847
10339
|
|
|
9848
10340
|
// src/commands/test.ts
|
|
9849
|
-
import
|
|
9850
|
-
import
|
|
9851
|
-
import { Command as
|
|
10341
|
+
import path44 from "node:path";
|
|
10342
|
+
import process36 from "node:process";
|
|
10343
|
+
import { Command as Command97 } from "commander";
|
|
9852
10344
|
import PocketBase6 from "pocketbase";
|
|
9853
10345
|
import pc33 from "picocolors";
|
|
9854
10346
|
import { x as x5 } from "tinyexec";
|
|
9855
|
-
import { detect as
|
|
10347
|
+
import { detect as detect8 } from "package-manager-detector";
|
|
9856
10348
|
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
9857
|
-
import
|
|
9858
|
-
var testServer = new
|
|
9859
|
-
const cwd =
|
|
10349
|
+
import fs42 from "node:fs";
|
|
10350
|
+
var testServer = new Command97("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
10351
|
+
const cwd = process36.cwd();
|
|
9860
10352
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
9861
10353
|
const password11 = "password";
|
|
9862
|
-
const testDataDir =
|
|
9863
|
-
|
|
10354
|
+
const testDataDir = path44.join(cwd, "test-data");
|
|
10355
|
+
fs42.rmSync(testDataDir, { recursive: true, force: true });
|
|
9864
10356
|
const { stop, url } = await launchPocketbase(cwd, {
|
|
9865
10357
|
dir: testDataDir,
|
|
9866
|
-
migrationsDir:
|
|
10358
|
+
migrationsDir: path44.join(cwd, MIGRATIONS_DIR),
|
|
9867
10359
|
// The app's PocketBase hooks (slug generation, personal teams, …) are part
|
|
9868
10360
|
// of its behaviour; the suite runs against the same server dev and build
|
|
9869
10361
|
// start, so it loads them from the same place.
|
|
9870
|
-
hooksDir:
|
|
10362
|
+
hooksDir: path44.join(cwd, DATA_DIR, "hooks"),
|
|
9871
10363
|
email: email3,
|
|
9872
10364
|
password: password11
|
|
9873
10365
|
});
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
10366
|
+
process36.env.POCKETBASE_URL = url;
|
|
10367
|
+
process36.env.POCKETBASE_SUPERUSER_EMAIL = email3;
|
|
10368
|
+
process36.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
|
|
10369
|
+
process36.env.VELA_DATA_DIR = testDataDir;
|
|
10370
|
+
process36.env.TEST = "true";
|
|
9879
10371
|
console.log(`${pc33.greenBright("\u2713")} Created test database`);
|
|
9880
10372
|
let vite;
|
|
9881
10373
|
let cleanedUp = false;
|
|
@@ -9883,7 +10375,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9883
10375
|
if (cleanedUp) return;
|
|
9884
10376
|
cleanedUp = true;
|
|
9885
10377
|
stop();
|
|
9886
|
-
|
|
10378
|
+
fs42.rmSync(testDataDir, { recursive: true, force: true });
|
|
9887
10379
|
};
|
|
9888
10380
|
const cleanup = async () => {
|
|
9889
10381
|
if (cleanedUp) return;
|
|
@@ -9894,12 +10386,12 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9894
10386
|
const fail = async (message) => {
|
|
9895
10387
|
console.error(`${pc33.redBright("\u2717")} ${message}`);
|
|
9896
10388
|
await cleanup();
|
|
9897
|
-
|
|
10389
|
+
process36.exit(1);
|
|
9898
10390
|
};
|
|
9899
|
-
|
|
9900
|
-
|
|
10391
|
+
process36.on("exit", cleanupSync);
|
|
10392
|
+
process36.on("SIGINT", () => {
|
|
9901
10393
|
cleanupSync();
|
|
9902
|
-
|
|
10394
|
+
process36.exit(130);
|
|
9903
10395
|
});
|
|
9904
10396
|
const pb = new PocketBase6(url);
|
|
9905
10397
|
try {
|
|
@@ -9927,7 +10419,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9927
10419
|
});
|
|
9928
10420
|
const vitePort = await findFreePort();
|
|
9929
10421
|
await vite.listen(vitePort);
|
|
9930
|
-
|
|
10422
|
+
process36.env.VITE_TEST_URL = `http://localhost:${vitePort}`;
|
|
9931
10423
|
console.log(`${pc33.greenBright("\u2713")} Started Vite: http://localhost:${vitePort}`);
|
|
9932
10424
|
console.log(`${pc33.greenBright("\u2713")} Started PocketBase: ${url}`);
|
|
9933
10425
|
const extraArgs = (cmd.parent?.args ?? []).slice(1);
|
|
@@ -9935,7 +10427,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9935
10427
|
const passthrough = filter ? extraArgs.filter((a) => a !== filter) : extraArgs;
|
|
9936
10428
|
if (!filter) filter = "server";
|
|
9937
10429
|
try {
|
|
9938
|
-
const pm = (await
|
|
10430
|
+
const pm = (await detect8({ cwd }))?.name ?? "npm";
|
|
9939
10431
|
const resolved = resolveCommand7(pm, "execute", [
|
|
9940
10432
|
"vitest",
|
|
9941
10433
|
"run",
|
|
@@ -9946,12 +10438,12 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9946
10438
|
const resolvedArgs = resolved.args.slice();
|
|
9947
10439
|
if (pm === "npm") resolvedArgs.unshift("--yes");
|
|
9948
10440
|
const result = await x5(resolved.command, resolvedArgs, {
|
|
9949
|
-
nodeOptions: { cwd, stdio: "inherit", env: { ...
|
|
10441
|
+
nodeOptions: { cwd, stdio: "inherit", env: { ...process36.env, CI: "1" } }
|
|
9950
10442
|
});
|
|
9951
|
-
|
|
10443
|
+
process36.exitCode = result.exitCode ?? 1;
|
|
9952
10444
|
} catch (e) {
|
|
9953
10445
|
console.error(`${pc33.redBright("\u2717")} ${e.message}`);
|
|
9954
|
-
|
|
10446
|
+
process36.exitCode = 1;
|
|
9955
10447
|
} finally {
|
|
9956
10448
|
await cleanup();
|
|
9957
10449
|
}
|
|
@@ -9982,9 +10474,9 @@ function stubPagesPlugin() {
|
|
|
9982
10474
|
}
|
|
9983
10475
|
|
|
9984
10476
|
// src/commands/routes.ts
|
|
9985
|
-
import
|
|
9986
|
-
import
|
|
9987
|
-
import { Command as
|
|
10477
|
+
import fs43 from "node:fs";
|
|
10478
|
+
import path45 from "node:path";
|
|
10479
|
+
import { Command as Command98 } from "commander";
|
|
9988
10480
|
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
9989
10481
|
"GET",
|
|
9990
10482
|
"POST",
|
|
@@ -9995,32 +10487,32 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
9995
10487
|
"HEAD",
|
|
9996
10488
|
"fallback"
|
|
9997
10489
|
]);
|
|
9998
|
-
var routes = new
|
|
10490
|
+
var routes = new Command98("routes").description("list routes").configureHelp(helpConfig).action(async () => {
|
|
9999
10491
|
const { workspaceRootDir, routesDir } = await getWorkspace();
|
|
10000
|
-
const routesRoot =
|
|
10492
|
+
const routesRoot = path45.join(workspaceRootDir, routesDir);
|
|
10001
10493
|
const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
|
|
10002
10494
|
found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
|
|
10003
10495
|
printTable(found);
|
|
10004
10496
|
});
|
|
10005
10497
|
function walk(root, dir) {
|
|
10006
|
-
const entries =
|
|
10498
|
+
const entries = fs43.readdirSync(dir, { withFileTypes: true });
|
|
10007
10499
|
const routes2 = [];
|
|
10008
10500
|
const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
|
|
10009
10501
|
if (hasLeaf) {
|
|
10010
|
-
const id = "/" +
|
|
10502
|
+
const id = "/" + path45.relative(root, dir).split(path45.sep).filter(Boolean).join("/");
|
|
10011
10503
|
const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
|
|
10012
10504
|
const methods = /* @__PURE__ */ new Set();
|
|
10013
10505
|
for (const entry of entries) {
|
|
10014
10506
|
if (!entry.isFile()) continue;
|
|
10015
10507
|
if (entry.name.endsWith("+page.svelte")) methods.add("GET");
|
|
10016
10508
|
if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
|
|
10017
|
-
extractMethods(
|
|
10509
|
+
extractMethods(path45.join(dir, entry.name)).forEach((m) => methods.add(m));
|
|
10018
10510
|
}
|
|
10019
10511
|
}
|
|
10020
10512
|
routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
|
|
10021
10513
|
}
|
|
10022
10514
|
for (const entry of entries) {
|
|
10023
|
-
if (entry.isDirectory()) routes2.push(...walk(root,
|
|
10515
|
+
if (entry.isDirectory()) routes2.push(...walk(root, path45.join(dir, entry.name)));
|
|
10024
10516
|
}
|
|
10025
10517
|
return routes2;
|
|
10026
10518
|
}
|
|
@@ -10029,7 +10521,7 @@ function isRouteFile(name) {
|
|
|
10029
10521
|
}
|
|
10030
10522
|
function extractMethods(file) {
|
|
10031
10523
|
try {
|
|
10032
|
-
const content =
|
|
10524
|
+
const content = fs43.readFileSync(file, "utf8");
|
|
10033
10525
|
const methods = [];
|
|
10034
10526
|
const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
|
|
10035
10527
|
let match;
|
|
@@ -10070,14 +10562,14 @@ function printTable(routes2) {
|
|
|
10070
10562
|
}
|
|
10071
10563
|
|
|
10072
10564
|
// src/commands/i18n.ts
|
|
10073
|
-
import
|
|
10074
|
-
import { Command as
|
|
10565
|
+
import process37 from "node:process";
|
|
10566
|
+
import { Command as Command99 } from "commander";
|
|
10075
10567
|
import { x as x6 } from "tinyexec";
|
|
10076
|
-
import { detect as
|
|
10568
|
+
import { detect as detect9 } from "package-manager-detector";
|
|
10077
10569
|
import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
|
|
10078
10570
|
async function runWuchale(extraArgs) {
|
|
10079
|
-
const cwd =
|
|
10080
|
-
const pm = (await
|
|
10571
|
+
const cwd = process37.cwd();
|
|
10572
|
+
const pm = (await detect9({ cwd }))?.name ?? "npm";
|
|
10081
10573
|
const resolved = resolveCommand8(pm, "execute", ["wuchale", ...extraArgs]);
|
|
10082
10574
|
const args = resolved.args.slice();
|
|
10083
10575
|
if (pm === "npm") args.unshift("--yes");
|
|
@@ -10086,11 +10578,11 @@ async function runWuchale(extraArgs) {
|
|
|
10086
10578
|
throwOnError: true
|
|
10087
10579
|
});
|
|
10088
10580
|
}
|
|
10089
|
-
var extract2 = new
|
|
10090
|
-
var watch = new
|
|
10091
|
-
var status2 = new
|
|
10092
|
-
var clean = new
|
|
10093
|
-
var i18n3 = new
|
|
10581
|
+
var extract2 = new Command99("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
|
|
10582
|
+
var watch = new Command99("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
|
|
10583
|
+
var status2 = new Command99("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
|
|
10584
|
+
var clean = new Command99("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--clean"]));
|
|
10585
|
+
var i18n3 = new Command99("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
|
|
10094
10586
|
|
|
10095
10587
|
// src/commands/oauth.ts
|
|
10096
10588
|
var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
@@ -10099,28 +10591,28 @@ var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
|
10099
10591
|
var schemas = stubCommand("schemas", "manage database schemas");
|
|
10100
10592
|
|
|
10101
10593
|
// src/commands/cms.ts
|
|
10102
|
-
import { Command as
|
|
10594
|
+
import { Command as Command104 } from "commander";
|
|
10103
10595
|
|
|
10104
10596
|
// src/commands/cms/editor.ts
|
|
10105
|
-
import { Command as
|
|
10597
|
+
import { Command as Command103 } from "commander";
|
|
10106
10598
|
|
|
10107
10599
|
// src/commands/cms/editor/add.ts
|
|
10108
10600
|
import { randomBytes } from "node:crypto";
|
|
10109
|
-
import { Command as
|
|
10110
|
-
import * as
|
|
10601
|
+
import { Command as Command100 } from "commander";
|
|
10602
|
+
import * as p59 from "@clack/prompts";
|
|
10111
10603
|
import pc35 from "picocolors";
|
|
10112
10604
|
|
|
10113
10605
|
// src/lib/cms-backend.ts
|
|
10114
10606
|
import { createRequire as createRequire3 } from "node:module";
|
|
10115
|
-
import
|
|
10116
|
-
import
|
|
10607
|
+
import path46 from "node:path";
|
|
10608
|
+
import process38 from "node:process";
|
|
10117
10609
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
10118
10610
|
import pc34 from "picocolors";
|
|
10119
10611
|
var DEFAULT_PROJECT = "default";
|
|
10120
10612
|
async function loadBackendModule(root) {
|
|
10121
10613
|
let entry;
|
|
10122
10614
|
try {
|
|
10123
|
-
entry = createRequire3(
|
|
10615
|
+
entry = createRequire3(path46.join(root, "package.json")).resolve("@velastack/cms/backend");
|
|
10124
10616
|
} catch {
|
|
10125
10617
|
throw new Error(
|
|
10126
10618
|
`@velastack/cms is not installed in this project.
|
|
@@ -10130,7 +10622,7 @@ Run ${pc34.cyan("vela enable cms")} first.`
|
|
|
10130
10622
|
}
|
|
10131
10623
|
return await import(pathToFileURL3(entry).href);
|
|
10132
10624
|
}
|
|
10133
|
-
async function withCmsBackend(fn, cwd =
|
|
10625
|
+
async function withCmsBackend(fn, cwd = process38.cwd()) {
|
|
10134
10626
|
const root = findWorkspaceRoot(cwd);
|
|
10135
10627
|
if (!root) {
|
|
10136
10628
|
throw new Error("Could not find workspace root (no package.json found)");
|
|
@@ -10138,8 +10630,8 @@ async function withCmsBackend(fn, cwd = process37.cwd()) {
|
|
|
10138
10630
|
const { createCmsBackend } = await loadBackendModule(root);
|
|
10139
10631
|
const dataDir2 = localDataDir(root);
|
|
10140
10632
|
const backend3 = createCmsBackend({
|
|
10141
|
-
dbPath:
|
|
10142
|
-
uploadDir:
|
|
10633
|
+
dbPath: path46.join(dataDir2, "cms.sqlite"),
|
|
10634
|
+
uploadDir: path46.join(dataDir2, "uploads")
|
|
10143
10635
|
});
|
|
10144
10636
|
try {
|
|
10145
10637
|
return await fn(backend3);
|
|
@@ -10149,7 +10641,7 @@ async function withCmsBackend(fn, cwd = process37.cwd()) {
|
|
|
10149
10641
|
}
|
|
10150
10642
|
|
|
10151
10643
|
// src/commands/cms/editor/add.ts
|
|
10152
|
-
var editorAdd = new
|
|
10644
|
+
var editorAdd = new Command100("add").description("create an editor who can sign in to the admin bar").argument("<email>", "email the editor signs in with").option("--password <password>", "password to set \u2014 generated and shown once when omitted").option("--project <id>", "project the editor may edit", DEFAULT_PROJECT).configureHelp(helpConfig).action(
|
|
10153
10645
|
(email3, options) => runCommand(async () => {
|
|
10154
10646
|
const generated = options.password === void 0;
|
|
10155
10647
|
const password11 = options.password ?? randomBytes(12).toString("base64url");
|
|
@@ -10160,31 +10652,31 @@ var editorAdd = new Command99("add").description("create an editor who can sign
|
|
|
10160
10652
|
if (generated) {
|
|
10161
10653
|
lines.push("", `Password: ${pc35.bold(password11)}`, "", "It is shown once; copy it now.");
|
|
10162
10654
|
}
|
|
10163
|
-
|
|
10164
|
-
|
|
10655
|
+
p59.log.success(lines.join("\n"));
|
|
10656
|
+
p59.log.info(
|
|
10165
10657
|
`Run ${pc35.cyan("vela dev")}, open any page with ${pc35.cyan("?edit")} on the URL (or press ${pc35.cyan("Ctrl+E")}), and sign in.`
|
|
10166
10658
|
);
|
|
10167
10659
|
}, "Failed to add the editor.")
|
|
10168
10660
|
);
|
|
10169
10661
|
|
|
10170
10662
|
// src/commands/cms/editor/password.ts
|
|
10171
|
-
import { Command as
|
|
10172
|
-
import * as
|
|
10663
|
+
import { Command as Command101 } from "commander";
|
|
10664
|
+
import * as p60 from "@clack/prompts";
|
|
10173
10665
|
import pc36 from "picocolors";
|
|
10174
|
-
var editorPassword = new
|
|
10666
|
+
var editorPassword = new Command101("password").description("set an editor's password").argument("<email>", "email of the editor").argument("<password>", "new password").configureHelp(helpConfig).action(
|
|
10175
10667
|
(email3, password11) => runCommand(async () => {
|
|
10176
10668
|
await withCmsBackend((cms3) => cms3.editors.setPassword(email3, password11));
|
|
10177
|
-
|
|
10669
|
+
p60.log.success(
|
|
10178
10670
|
`Updated the password for ${pc36.cyan(email3)}. Existing sessions were signed out.`
|
|
10179
10671
|
);
|
|
10180
10672
|
}, "Failed to set the password.")
|
|
10181
10673
|
);
|
|
10182
10674
|
|
|
10183
10675
|
// src/commands/cms/editor/list.ts
|
|
10184
|
-
import { Command as
|
|
10185
|
-
import * as
|
|
10676
|
+
import { Command as Command102 } from "commander";
|
|
10677
|
+
import * as p61 from "@clack/prompts";
|
|
10186
10678
|
import pc37 from "picocolors";
|
|
10187
|
-
var editorList = new
|
|
10679
|
+
var editorList = new Command102("list").description("list editors and the projects they may edit").configureHelp(helpConfig).action(
|
|
10188
10680
|
() => runCommand(async () => {
|
|
10189
10681
|
const rows = await withCmsBackend(
|
|
10190
10682
|
async (cms3) => cms3.editors.list().map((editor2) => ({
|
|
@@ -10193,11 +10685,11 @@ var editorList = new Command101("list").description("list editors and the projec
|
|
|
10193
10685
|
}))
|
|
10194
10686
|
);
|
|
10195
10687
|
if (rows.length === 0) {
|
|
10196
|
-
|
|
10688
|
+
p61.log.info(`No editors yet. Add one with ${pc37.cyan("vela cms editor add <email>")}.`);
|
|
10197
10689
|
return;
|
|
10198
10690
|
}
|
|
10199
10691
|
const width = Math.max(...rows.map((row) => row.email.length));
|
|
10200
|
-
|
|
10692
|
+
p61.log.info(
|
|
10201
10693
|
`Editors
|
|
10202
10694
|
|
|
10203
10695
|
` + rows.map(
|
|
@@ -10208,10 +10700,10 @@ var editorList = new Command101("list").description("list editors and the projec
|
|
|
10208
10700
|
);
|
|
10209
10701
|
|
|
10210
10702
|
// src/commands/cms/editor.ts
|
|
10211
|
-
var editor = new
|
|
10703
|
+
var editor = new Command103("editor").description("manage who can sign in to the admin bar").configureHelp(helpConfig).addCommand(editorAdd).addCommand(editorPassword).addCommand(editorList);
|
|
10212
10704
|
|
|
10213
10705
|
// src/commands/cms.ts
|
|
10214
|
-
var cms2 = new
|
|
10706
|
+
var cms2 = new Command104("cms").description("manage the CMS").configureHelp(helpConfig).addCommand(editor);
|
|
10215
10707
|
|
|
10216
10708
|
// src/program.ts
|
|
10217
10709
|
var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -10229,6 +10721,8 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
|
10229
10721
|
"generate form",
|
|
10230
10722
|
// The CMS keeps its own SQLite database and editors; PocketBase is never involved.
|
|
10231
10723
|
"enable cms",
|
|
10724
|
+
// Analytics only touches the root layout and .env; it must work on static sites.
|
|
10725
|
+
"enable analytics",
|
|
10232
10726
|
"cms",
|
|
10233
10727
|
// Server commands talk to a VPS over SSH, never to the local database.
|
|
10234
10728
|
"provision",
|
|
@@ -10242,35 +10736,38 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
|
10242
10736
|
// Acts on whichever target `-t` names; the local path reads the project's
|
|
10243
10737
|
// own credentials rather than requiring them in this process.
|
|
10244
10738
|
"backup",
|
|
10245
|
-
"restore"
|
|
10739
|
+
"restore",
|
|
10740
|
+
// Removes a copy from its server; the other `destroy` subcommands edit the
|
|
10741
|
+
// local schema and stay gated.
|
|
10742
|
+
"destroy deployment"
|
|
10246
10743
|
]);
|
|
10247
10744
|
var BACKEND_OPTIONAL_COMMANDS = /* @__PURE__ */ new Set(["dev", "build", "preview", "deploy"]);
|
|
10248
10745
|
var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
|
|
10249
|
-
var program = new
|
|
10746
|
+
var program = new Command105().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
|
|
10250
10747
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
10251
10748
|
if (isStub(actionCommand)) return;
|
|
10252
|
-
const envRoot = findWorkspaceRoot() ??
|
|
10749
|
+
const envRoot = findWorkspaceRoot() ?? process39.cwd();
|
|
10253
10750
|
dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
|
|
10254
|
-
const
|
|
10255
|
-
if (NO_BACKEND_COMMMANDS.has(
|
|
10256
|
-
const top =
|
|
10751
|
+
const path47 = getCommandPath(actionCommand);
|
|
10752
|
+
if (NO_BACKEND_COMMMANDS.has(path47)) return;
|
|
10753
|
+
const top = path47.split(" ", 1)[0];
|
|
10257
10754
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
10258
10755
|
if (!hasBackend()) {
|
|
10259
10756
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
10260
|
-
|
|
10261
|
-
`${pc38.cyan(`vela ${
|
|
10757
|
+
p62.log.error(
|
|
10758
|
+
`${pc38.cyan(`vela ${path47}`)} needs a backend, and this project does not have one.
|
|
10262
10759
|
|
|
10263
10760
|
Static projects have no database to talk to.
|
|
10264
10761
|
|
|
10265
10762
|
To add a backend to this project, run ${pc38.cyan("vela bless")}.`
|
|
10266
10763
|
);
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10764
|
+
p62.log.message();
|
|
10765
|
+
p62.cancel("Operation failed.");
|
|
10766
|
+
process39.exit(1);
|
|
10270
10767
|
}
|
|
10271
|
-
if (SELF_CREDENTIALED_COMMANDS.has(
|
|
10272
|
-
if (!
|
|
10273
|
-
|
|
10768
|
+
if (SELF_CREDENTIALED_COMMANDS.has(path47)) return;
|
|
10769
|
+
if (!process39.env.POCKETBASE_SUPERUSER_EMAIL || !process39.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
10770
|
+
p62.log.error(
|
|
10274
10771
|
`PocketBase superuser credentials are required.
|
|
10275
10772
|
|
|
10276
10773
|
Set ${pc38.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc38.cyan("POCKETBASE_SUPERUSER_PASSWORD")} in your .env file.
|
|
@@ -10278,9 +10775,9 @@ Set ${pc38.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc38.cyan("POCKETBASE_SUPER
|
|
|
10278
10775
|
To set up a new project, run ${pc38.cyan("vela create")}.
|
|
10279
10776
|
To set up an existing project, run ${pc38.cyan("vela bless")}.`
|
|
10280
10777
|
);
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10778
|
+
p62.log.message();
|
|
10779
|
+
p62.cancel("Operation failed.");
|
|
10780
|
+
process39.exit(1);
|
|
10284
10781
|
}
|
|
10285
10782
|
});
|
|
10286
10783
|
function getCommandPath(cmd) {
|
|
@@ -10334,5 +10831,5 @@ for (const command of [
|
|
|
10334
10831
|
}
|
|
10335
10832
|
|
|
10336
10833
|
// src/bin.ts
|
|
10337
|
-
program.parse(normalizeArgv(
|
|
10834
|
+
program.parse(normalizeArgv(process40.argv.slice(2)), { from: "user" });
|
|
10338
10835
|
//# sourceMappingURL=bin.js.map
|