vela 0.11.6 → 0.12.1
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 +10 -0
- package/dist/bin.js +1312 -1072
- package/dist/bin.js.map +4 -4
- package/package.json +1 -1
- package/templates/static/src/lib/site.template.ts +1 -1
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 process42 from "node:process";
|
|
5
5
|
|
|
6
6
|
// src/lib/argv.ts
|
|
7
7
|
function normalizeArgv(argv) {
|
|
@@ -11,8 +11,8 @@ function normalizeArgv(argv) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// src/program.ts
|
|
14
|
-
import
|
|
15
|
-
import * as
|
|
14
|
+
import process41 from "node:process";
|
|
15
|
+
import * as p63 from "@clack/prompts";
|
|
16
16
|
import { Command as Command105 } from "commander";
|
|
17
17
|
import nodePath from "node:path";
|
|
18
18
|
import dotenv2 from "dotenv";
|
|
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.
|
|
24
|
+
version: "0.12.1",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -321,10 +321,15 @@ function readPackageJson(path47) {
|
|
|
321
321
|
var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
|
|
322
322
|
var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
|
|
323
323
|
var CLI_VERSION_PLACEHOLDER = /~VELA_VERSION~/g;
|
|
324
|
+
var SITE_URL_PLACEHOLDER = /~SITE_URL~/g;
|
|
325
|
+
var CMS_ENDPOINT_PLACEHOLDER = /~CMS_ENDPOINT~/g;
|
|
326
|
+
var LOCAL_SITE_URL = "http://localhost:5173";
|
|
324
327
|
function fillTemplatePlaceholders(raw, values) {
|
|
325
328
|
const packageName = toValidPackageName(values.appName);
|
|
326
329
|
const appName = escapeSingleQuoted(values.appName);
|
|
327
|
-
|
|
330
|
+
const siteUrl = escapeSingleQuoted(values.siteUrl ?? LOCAL_SITE_URL);
|
|
331
|
+
const cmsEndpoint = escapeSingleQuoted(values.cmsEndpoint ?? "");
|
|
332
|
+
return raw.replace(PACKAGE_NAME_PLACEHOLDER, () => packageName).replace(APP_NAME_PLACEHOLDER, () => appName).replace(CLI_VERSION_PLACEHOLDER, () => values.cliVersion).replace(SITE_URL_PLACEHOLDER, () => siteUrl).replace(CMS_ENDPOINT_PLACEHOLDER, () => cmsEndpoint);
|
|
328
333
|
}
|
|
329
334
|
function escapeSingleQuoted(value) {
|
|
330
335
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -358,6 +363,11 @@ function hasBackend(from = process3.cwd()) {
|
|
|
358
363
|
const root = findWorkspaceRoot(from);
|
|
359
364
|
return root !== null && fs2.existsSync(path.join(root, DATA_DIR));
|
|
360
365
|
}
|
|
366
|
+
function hasApiRoutes(root) {
|
|
367
|
+
const dir = path.join(root, "src", "routes", "api");
|
|
368
|
+
if (!fs2.existsSync(dir)) return false;
|
|
369
|
+
return fs2.readdirSync(dir).some((entry) => entry !== "README.md");
|
|
370
|
+
}
|
|
361
371
|
function localDataDir(from = process3.cwd()) {
|
|
362
372
|
return path.join(findWorkspaceRoot(from) ?? from, DATA_DIR);
|
|
363
373
|
}
|
|
@@ -399,7 +409,7 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
|
|
|
399
409
|
const hasDep = (name) => Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
|
|
400
410
|
return {
|
|
401
411
|
auth: isAppMode,
|
|
402
|
-
api:
|
|
412
|
+
api: hasApiRoutes(root),
|
|
403
413
|
apiKeys: has("src/routes/api/api-keys") || has("src/routes/(app)/api-keys"),
|
|
404
414
|
backend: has(DATA_DIR),
|
|
405
415
|
i18n: has("wuchale.config.js") || hasDep("wuchale"),
|
|
@@ -562,6 +572,10 @@ var entrySchema = v2.object({
|
|
|
562
572
|
price: v2.optional(v2.number()),
|
|
563
573
|
previewUrl: v2.optional(v2.string()),
|
|
564
574
|
nextSteps: v2.optional(v2.array(v2.string())),
|
|
575
|
+
/** Reads its copy from a hosted CMS through `site.cmsEndpoint`. */
|
|
576
|
+
cms: v2.optional(v2.boolean()),
|
|
577
|
+
/** A prebuilt static build is published for velastack.dev's instant deploys. */
|
|
578
|
+
instantDeploy: v2.optional(v2.boolean()),
|
|
565
579
|
/** Tarball location, relative to the index URL. */
|
|
566
580
|
file: v2.string(),
|
|
567
581
|
sha256: v2.pipe(v2.string(), v2.regex(/^[0-9a-f]{64}$/)),
|
|
@@ -753,6 +767,7 @@ async function listAllTemplates(options = {}) {
|
|
|
753
767
|
tags: entry.tags,
|
|
754
768
|
price: entry.price,
|
|
755
769
|
nextSteps: entry.nextSteps,
|
|
770
|
+
cms: entry.cms,
|
|
756
771
|
entry,
|
|
757
772
|
indexUrl
|
|
758
773
|
});
|
|
@@ -833,6 +848,7 @@ function readManifest(root, name) {
|
|
|
833
848
|
tags: optionalStringArray(manifest.tags),
|
|
834
849
|
price: typeof manifest.price === "number" ? manifest.price : void 0,
|
|
835
850
|
nextSteps: optionalStringArray(manifest.nextSteps),
|
|
851
|
+
cms: typeof manifest.cms === "boolean" ? manifest.cms : void 0,
|
|
836
852
|
dir: path5.join(root, name)
|
|
837
853
|
};
|
|
838
854
|
}
|
|
@@ -968,7 +984,7 @@ function waitForReadyOrExit(proc, url, maxAttempts = 40) {
|
|
|
968
984
|
};
|
|
969
985
|
proc.once("exit", onExit);
|
|
970
986
|
let attempts = 0;
|
|
971
|
-
const
|
|
987
|
+
const check2 = async () => {
|
|
972
988
|
if (settled) return;
|
|
973
989
|
attempts++;
|
|
974
990
|
try {
|
|
@@ -989,9 +1005,9 @@ function waitForReadyOrExit(proc, url, maxAttempts = 40) {
|
|
|
989
1005
|
reject(new Error(`Timed out waiting for health at ${url}`));
|
|
990
1006
|
return;
|
|
991
1007
|
}
|
|
992
|
-
setTimeout(
|
|
1008
|
+
setTimeout(check2, 250);
|
|
993
1009
|
};
|
|
994
|
-
|
|
1010
|
+
check2();
|
|
995
1011
|
});
|
|
996
1012
|
}
|
|
997
1013
|
async function startPocketbaseServe(opts) {
|
|
@@ -1912,205 +1928,17 @@ function printNextSteps(projectPath, packageManager2) {
|
|
|
1912
1928
|
}
|
|
1913
1929
|
|
|
1914
1930
|
// src/commands/create.ts
|
|
1915
|
-
import
|
|
1916
|
-
import
|
|
1917
|
-
import
|
|
1931
|
+
import fs17 from "node:fs";
|
|
1932
|
+
import path15 from "node:path";
|
|
1933
|
+
import process11 from "node:process";
|
|
1918
1934
|
import * as v4 from "valibot";
|
|
1919
|
-
import { Command as Command3 } from "commander";
|
|
1920
|
-
import * as p5 from "@clack/prompts";
|
|
1921
|
-
import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
1922
|
-
function optionsSchema2(listing) {
|
|
1923
|
-
const names = listing.templates.map((template) => template.name);
|
|
1924
|
-
let choices2 = `must be one of: ${templateChoicesMessage(listing.templates)}`;
|
|
1925
|
-
if (listing.registryError) {
|
|
1926
|
-
choices2 += ` (could not reach the template registry: ${listing.registryError})`;
|
|
1927
|
-
}
|
|
1928
|
-
return v4.strictObject({
|
|
1929
|
-
install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
1930
|
-
template: v4.optional(v4.picklist(names, choices2)),
|
|
1931
|
-
name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
|
|
1932
|
-
email: v4.optional(v4.pipe(v4.string(), v4.email("must be a valid email address"))),
|
|
1933
|
-
password: v4.optional(v4.pipe(v4.string(), v4.minLength(8, "must be at least 8 characters long")))
|
|
1934
|
-
});
|
|
1935
|
-
}
|
|
1936
|
-
var create = new Command3("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold (built-in or from the registry)", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
|
|
1937
|
-
return runCommand(async () => {
|
|
1938
|
-
const listing = await listAllTemplates();
|
|
1939
|
-
const options = parseOptions(optionsSchema2(listing), rawOpts);
|
|
1940
|
-
const { directory, packageManager: packageManager2, name, template } = await createProject(
|
|
1941
|
-
projectPath,
|
|
1942
|
-
options,
|
|
1943
|
-
listing
|
|
1944
|
-
);
|
|
1945
|
-
const relative = path14.relative(process8.cwd(), directory);
|
|
1946
|
-
const pm = packageManager2 ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
1947
|
-
const nextSteps = [];
|
|
1948
|
-
if (relative !== "") {
|
|
1949
|
-
const hasSpaces = relative.includes(" ");
|
|
1950
|
-
nextSteps.push(`\`cd ${hasSpaces ? `"${relative}"` : relative}\``);
|
|
1951
|
-
}
|
|
1952
|
-
if (!packageManager2) {
|
|
1953
|
-
const resolved = resolveCommand3(pm, "install", []);
|
|
1954
|
-
if (resolved) {
|
|
1955
|
-
nextSteps.push(
|
|
1956
|
-
`\`${resolved.command} ${resolved.args.join(" ")}\` to install dependencies`
|
|
1957
|
-
);
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
const runDev = resolveCommand3(pm, "run", ["dev", "--open"]);
|
|
1961
|
-
if (runDev) {
|
|
1962
|
-
nextSteps.push(
|
|
1963
|
-
`\`${runDev.command} ${runDev.args.join(" ")}\` to start the dev server (Ctrl-C to stop)`
|
|
1964
|
-
);
|
|
1965
|
-
}
|
|
1966
|
-
if (template.nextSteps) {
|
|
1967
|
-
nextSteps.push(...template.nextSteps);
|
|
1968
|
-
} else if (template.backend) {
|
|
1969
|
-
nextSteps.push("Run `vela generate scaffold <model>` to generate your first CRUD pages.");
|
|
1970
|
-
} else {
|
|
1971
|
-
nextSteps.push(
|
|
1972
|
-
"Set your deployed URL in `src/lib/site.ts` before building for production."
|
|
1973
|
-
);
|
|
1974
|
-
nextSteps.push("Run `vela ui add <component>` to add UI components.");
|
|
1975
|
-
}
|
|
1976
|
-
nextSteps.push("Stuck? Visit https://docs.velastack.dev");
|
|
1977
|
-
reportResult({
|
|
1978
|
-
summary: `Created ${name} at ${directory}.`,
|
|
1979
|
-
nextSteps
|
|
1980
|
-
});
|
|
1981
|
-
}, "Failed to create project.");
|
|
1982
|
-
});
|
|
1983
|
-
async function createProject(cwdArg, options, listing) {
|
|
1984
|
-
const onCancel2 = () => {
|
|
1985
|
-
p5.cancel("Operation cancelled.");
|
|
1986
|
-
process8.exit(0);
|
|
1987
|
-
};
|
|
1988
|
-
const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
|
|
1989
|
-
if (!template.backend && (options.email || options.password)) {
|
|
1990
|
-
throw new Error(
|
|
1991
|
-
`--email and --password don't apply to the ${template.name} template \u2014 it has no backend.`
|
|
1992
|
-
);
|
|
1993
|
-
}
|
|
1994
|
-
let directory;
|
|
1995
|
-
if (cwdArg) {
|
|
1996
|
-
directory = path14.resolve(cwdArg);
|
|
1997
|
-
} else {
|
|
1998
|
-
const answer = await p5.text({
|
|
1999
|
-
message: "Where would you like your project to be created?",
|
|
2000
|
-
placeholder: " (hit Enter to use current directory)",
|
|
2001
|
-
defaultValue: "./"
|
|
2002
|
-
});
|
|
2003
|
-
if (p5.isCancel(answer)) onCancel2();
|
|
2004
|
-
directory = path14.resolve(answer);
|
|
2005
|
-
}
|
|
2006
|
-
if (fs16.existsSync(directory) && fs16.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
|
|
2007
|
-
const force = await p5.confirm({
|
|
2008
|
-
message: "Directory not empty. Continue?",
|
|
2009
|
-
initialValue: false
|
|
2010
|
-
});
|
|
2011
|
-
if (p5.isCancel(force) || !force) onCancel2();
|
|
2012
|
-
}
|
|
2013
|
-
const dirName = path14.basename(directory);
|
|
2014
|
-
const { name } = await p5.group(
|
|
2015
|
-
{
|
|
2016
|
-
name: () => {
|
|
2017
|
-
if (options.name) return Promise.resolve(options.name);
|
|
2018
|
-
return p5.text({
|
|
2019
|
-
message: "App name (used for emails, etc)",
|
|
2020
|
-
initialValue: dirName || "SvelteKit",
|
|
2021
|
-
validate: (value) => value?.trim() ? void 0 : "App name is required"
|
|
2022
|
-
});
|
|
2023
|
-
}
|
|
2024
|
-
},
|
|
2025
|
-
{ onCancel: onCancel2 }
|
|
2026
|
-
);
|
|
2027
|
-
const credentials = template.backend ? await promptCredentials(options, onCancel2) : void 0;
|
|
2028
|
-
const projectPath = directory;
|
|
2029
|
-
if (template.source === "remote") p5.log.step(`Downloading template ${template.name}...`);
|
|
2030
|
-
const resolved = await resolveTemplate(template);
|
|
2031
|
-
try {
|
|
2032
|
-
copyTemplate(resolved, projectPath);
|
|
2033
|
-
applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
|
|
2034
|
-
} finally {
|
|
2035
|
-
resolved.cleanup();
|
|
2036
|
-
}
|
|
2037
|
-
if (!fs16.existsSync(path14.join(projectPath, "package.json"))) {
|
|
2038
|
-
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
2039
|
-
}
|
|
2040
|
-
p5.log.success("Project created");
|
|
2041
|
-
let packageManager2;
|
|
2042
|
-
if (options.install !== false) {
|
|
2043
|
-
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
2044
|
-
if (pm) {
|
|
2045
|
-
const builds = template.backend ? ["esbuild", "pocketbase-server"] : ["esbuild"];
|
|
2046
|
-
addPnpmBuildDependencies(projectPath, pm, builds);
|
|
2047
|
-
await installDependencies(pm, projectPath);
|
|
2048
|
-
packageManager2 = pm;
|
|
2049
|
-
}
|
|
2050
|
-
}
|
|
2051
|
-
if (credentials) {
|
|
2052
|
-
const { email: email3, password: password11 } = credentials;
|
|
2053
|
-
p5.log.step("Initializing PocketBase...");
|
|
2054
|
-
await createSuperuser(projectPath, email3, password11);
|
|
2055
|
-
await withPocketbase(
|
|
2056
|
-
projectPath,
|
|
2057
|
-
async (pb) => {
|
|
2058
|
-
await pb.settings.update({
|
|
2059
|
-
meta: { appName: name, appURL: "http://localhost:5173" }
|
|
2060
|
-
});
|
|
2061
|
-
},
|
|
2062
|
-
{ email: email3, password: password11 }
|
|
2063
|
-
);
|
|
2064
|
-
writeEnvFile(
|
|
2065
|
-
projectPath,
|
|
2066
|
-
{
|
|
2067
|
-
POCKETBASE_SUPERUSER_EMAIL: email3,
|
|
2068
|
-
POCKETBASE_SUPERUSER_PASSWORD: password11
|
|
2069
|
-
},
|
|
2070
|
-
["PocketBase superuser credentials \u2014 used by `vela` commands"]
|
|
2071
|
-
);
|
|
2072
|
-
p5.log.success("PocketBase initialized");
|
|
2073
|
-
}
|
|
2074
|
-
return { directory: projectPath, packageManager: packageManager2, name, template };
|
|
2075
|
-
}
|
|
2076
|
-
function promptCredentials(options, onCancel2) {
|
|
2077
|
-
return p5.group(
|
|
2078
|
-
{
|
|
2079
|
-
email: () => {
|
|
2080
|
-
if (options.email) return Promise.resolve(options.email);
|
|
2081
|
-
return p5.text({
|
|
2082
|
-
message: "Enter an email for the admin user",
|
|
2083
|
-
initialValue: "admin@example.com",
|
|
2084
|
-
validate: (value) => !value ? "Email is required" : !value.includes("@") ? "Invalid email" : void 0
|
|
2085
|
-
});
|
|
2086
|
-
},
|
|
2087
|
-
password: () => {
|
|
2088
|
-
if (options.password) return Promise.resolve(options.password);
|
|
2089
|
-
return p5.password({
|
|
2090
|
-
message: "Enter a password for the admin user (at least 8 characters)",
|
|
2091
|
-
validate: (value) => !value ? "Password is required" : value.length < 8 ? "Password must be at least 8 characters long" : void 0
|
|
2092
|
-
});
|
|
2093
|
-
}
|
|
2094
|
-
},
|
|
2095
|
-
{ onCancel: onCancel2 }
|
|
2096
|
-
);
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
|
-
// src/commands/generate.ts
|
|
2100
|
-
import { Command as Command9 } from "commander";
|
|
2101
|
-
|
|
2102
|
-
// src/commands/generate/form.ts
|
|
2103
1935
|
import { Command as Command4 } from "commander";
|
|
2104
|
-
import * as
|
|
2105
|
-
|
|
2106
|
-
// src/lib/pattern-runner.ts
|
|
2107
|
-
import path15 from "node:path";
|
|
2108
|
-
import * as p7 from "@clack/prompts";
|
|
2109
|
-
import { bySlug as bySlug2 } from "@velastack/patterns";
|
|
1936
|
+
import * as p8 from "@clack/prompts";
|
|
1937
|
+
import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
2110
1938
|
|
|
2111
1939
|
// src/lib/providers.ts
|
|
2112
|
-
import
|
|
2113
|
-
import * as
|
|
1940
|
+
import process8 from "node:process";
|
|
1941
|
+
import * as p5 from "@clack/prompts";
|
|
2114
1942
|
import { bySlug } from "@velastack/patterns";
|
|
2115
1943
|
function capabilityName(slug2) {
|
|
2116
1944
|
return slug2.replace(/^enable-/, "");
|
|
@@ -2145,7 +1973,7 @@ function article(word) {
|
|
|
2145
1973
|
return /^[aeiou]/i.test(word) ? "an" : "a";
|
|
2146
1974
|
}
|
|
2147
1975
|
function isInteractive() {
|
|
2148
|
-
return Boolean(
|
|
1976
|
+
return Boolean(process8.stdout.isTTY) && !process8.env.CI;
|
|
2149
1977
|
}
|
|
2150
1978
|
function providerFlagInArgv(argv) {
|
|
2151
1979
|
return argv.some((arg) => arg === "--provider" || arg.startsWith("--provider="));
|
|
@@ -2177,13 +2005,13 @@ async function resolveProvider(slug2, flagValue) {
|
|
|
2177
2005
|
});
|
|
2178
2006
|
if (decision.kind === "error") throw new Error(decision.message);
|
|
2179
2007
|
if (decision.kind === "use") return decision.provider;
|
|
2180
|
-
const selected = await
|
|
2008
|
+
const selected = await p5.select({
|
|
2181
2009
|
message: `Select ${patternName} provider`,
|
|
2182
2010
|
options: providers.map((provider) => ({ value: provider.id, label: provider.label }))
|
|
2183
2011
|
});
|
|
2184
|
-
if (
|
|
2185
|
-
|
|
2186
|
-
|
|
2012
|
+
if (p5.isCancel(selected)) {
|
|
2013
|
+
p5.cancel("Operation cancelled.");
|
|
2014
|
+
process8.exit(0);
|
|
2187
2015
|
}
|
|
2188
2016
|
return providers.find((provider) => provider.id === selected);
|
|
2189
2017
|
}
|
|
@@ -2191,7 +2019,7 @@ async function collectProviderEnv(provider) {
|
|
|
2191
2019
|
const values = {};
|
|
2192
2020
|
const interactive = isInteractive();
|
|
2193
2021
|
for (const variable of provider.env ?? []) {
|
|
2194
|
-
const existing =
|
|
2022
|
+
const existing = process8.env[variable.key];
|
|
2195
2023
|
if (existing) {
|
|
2196
2024
|
values[variable.key] = existing;
|
|
2197
2025
|
continue;
|
|
@@ -2200,14 +2028,14 @@ async function collectProviderEnv(provider) {
|
|
|
2200
2028
|
values[variable.key] = variable.default ?? "";
|
|
2201
2029
|
continue;
|
|
2202
2030
|
}
|
|
2203
|
-
const value = await
|
|
2031
|
+
const value = await p5.text({
|
|
2204
2032
|
message: variable.label,
|
|
2205
2033
|
placeholder: variable.placeholder,
|
|
2206
2034
|
initialValue: variable.default
|
|
2207
2035
|
});
|
|
2208
|
-
if (
|
|
2209
|
-
|
|
2210
|
-
|
|
2036
|
+
if (p5.isCancel(value)) {
|
|
2037
|
+
p5.cancel("Operation cancelled.");
|
|
2038
|
+
process8.exit(0);
|
|
2211
2039
|
}
|
|
2212
2040
|
values[variable.key] = (value ?? "").trim();
|
|
2213
2041
|
}
|
|
@@ -2217,92 +2045,212 @@ function missingEnvKeys(provider, values) {
|
|
|
2217
2045
|
return (provider.env ?? []).filter((variable) => !(values[variable.key] ?? "").trim() && !variable.default).map((variable) => variable.key);
|
|
2218
2046
|
}
|
|
2219
2047
|
|
|
2220
|
-
// src/lib/
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
var
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2048
|
+
// src/lib/link-on-create.ts
|
|
2049
|
+
var FREE_CMS_HINT = "Get a free CMS at https://velastack.dev";
|
|
2050
|
+
var PROJECT_ID_RE = /^[a-z0-9]{15}$/;
|
|
2051
|
+
var CMS_URL_RE = /^https?:\/\/\S+$/;
|
|
2052
|
+
var NOT_LOGGED_IN = "Not logged in. Run `vela login` to login, or set VELA_API_KEY.";
|
|
2053
|
+
var NO_CMS_WARNING = `No CMS configured: \`cmsEndpoint\` in src/lib/site.ts is empty, so the site shows its fallback copy. Pass \`--link new\`, \`--link <project-id>\` or \`--cms <url>\` to set it, or fill it in later. ${FREE_CMS_HINT}.`;
|
|
2054
|
+
function decideLink(request) {
|
|
2055
|
+
const { link: link2, needsCms, loggedIn, interactive } = request;
|
|
2056
|
+
if (link2 === "none") return { kind: "none" };
|
|
2057
|
+
if (link2 === "new") {
|
|
2058
|
+
return loggedIn ? { kind: "create" } : { kind: "error", message: NOT_LOGGED_IN };
|
|
2059
|
+
}
|
|
2060
|
+
if (link2 !== void 0) {
|
|
2061
|
+
return loggedIn ? { kind: "existing", projectId: link2 } : { kind: "error", message: NOT_LOGGED_IN };
|
|
2062
|
+
}
|
|
2063
|
+
if (!interactive) return { kind: "none", warn: needsCms ? NO_CMS_WARNING : void 0 };
|
|
2064
|
+
if (loggedIn) return { kind: "create" };
|
|
2065
|
+
return needsCms ? { kind: "prompt-cms" } : { kind: "none" };
|
|
2066
|
+
}
|
|
2067
|
+
function cmsEndpointFor(projectId) {
|
|
2068
|
+
return `${API_URL}/v1/projects/${projectId}/cms`;
|
|
2069
|
+
}
|
|
2070
|
+
function normalizeCmsUrl(url) {
|
|
2071
|
+
return url.trim().replace(/\/+$/, "");
|
|
2072
|
+
}
|
|
2073
|
+
function linkNextSteps(outcome) {
|
|
2074
|
+
const steps = [];
|
|
2075
|
+
const { linked, cmsEndpoint, cmsSource, templateCms, loggedIn, interactive } = outcome;
|
|
2076
|
+
if (templateCms && linked && cmsSource === "linked") {
|
|
2077
|
+
steps.push(
|
|
2078
|
+
`Add an editor at ${linked.dashboardUrl}/cms/editors, then open any page with \`?edit\` and sign in from the admin bar.`
|
|
2079
|
+
);
|
|
2080
|
+
} else if (cmsEndpoint) {
|
|
2081
|
+
steps.push("Open any page with `?edit` and sign in from the admin bar.");
|
|
2082
|
+
} else if (templateCms) {
|
|
2083
|
+
steps.push(
|
|
2084
|
+
`When you have a CMS, set \`cmsEndpoint\` in \`src/lib/site.ts\`. ${FREE_CMS_HINT}.`
|
|
2085
|
+
);
|
|
2258
2086
|
}
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
}));
|
|
2266
|
-
const created = result.creates.filter(isSuccess);
|
|
2267
|
-
const modified = result.modifies.filter(isSuccess);
|
|
2268
|
-
const deleted = result.deletes.filter(isSuccess);
|
|
2269
|
-
const totalChanges = created.length + modified.length + deleted.length + result.components.length + result.packages.length + result.collections.length;
|
|
2270
|
-
if (totalChanges === 0 && failures.length === 0) {
|
|
2271
|
-
p7.log.info(`${pattern.title ?? slug2} produced no changes.`);
|
|
2272
|
-
return;
|
|
2087
|
+
if (linked && !(templateCms && cmsSource === "linked")) {
|
|
2088
|
+
steps.push(
|
|
2089
|
+
`Run \`vela deploy\` when you're ready; the project is linked to ${linked.dashboardUrl}.`
|
|
2090
|
+
);
|
|
2091
|
+
} else if (!linked && interactive && !loggedIn && !templateCms) {
|
|
2092
|
+
steps.push("Run `vela login` then `vela link` to get a free velastack.app hostname on deploy.");
|
|
2273
2093
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2094
|
+
return steps;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// src/lib/link-project.ts
|
|
2098
|
+
import process9 from "node:process";
|
|
2099
|
+
import * as p6 from "@clack/prompts";
|
|
2100
|
+
|
|
2101
|
+
// src/lib/velastack-api.ts
|
|
2102
|
+
async function apiFetch(apiKey, pathAndQuery, init) {
|
|
2103
|
+
const headers = new Headers(init?.headers);
|
|
2104
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
2105
|
+
if (init?.body && !headers.has("Content-Type")) {
|
|
2106
|
+
headers.set("Content-Type", "application/json");
|
|
2107
|
+
}
|
|
2108
|
+
const res = await fetch(`${API_URL}${pathAndQuery}`, { ...init, headers });
|
|
2109
|
+
if (res.status === 401) {
|
|
2110
|
+
throw new Error("API key invalid \u2014 run `vela login`");
|
|
2111
|
+
}
|
|
2112
|
+
if (res.status === 403) {
|
|
2113
|
+
const body = await res.text().catch(() => "");
|
|
2114
|
+
throw new Error(`velastack.dev refused this key (${body || "forbidden"}) \u2014 run \`vela login\``);
|
|
2115
|
+
}
|
|
2116
|
+
if (!res.ok) {
|
|
2117
|
+
const body = await res.text().catch(() => "");
|
|
2118
|
+
throw new Error(`Velastack API error (${res.status}): ${body || res.statusText}`);
|
|
2119
|
+
}
|
|
2120
|
+
return await res.json();
|
|
2121
|
+
}
|
|
2122
|
+
async function getCurrentUser(apiKey) {
|
|
2123
|
+
const data = await apiFetch(
|
|
2124
|
+
apiKey,
|
|
2125
|
+
"/api/collections/users/records?perPage=1"
|
|
2126
|
+
);
|
|
2127
|
+
const user = data.items[0];
|
|
2128
|
+
if (!user) throw new Error("No user found. Run `vela login` to login.");
|
|
2129
|
+
return user;
|
|
2130
|
+
}
|
|
2131
|
+
async function listTeams(apiKey) {
|
|
2132
|
+
const data = await apiFetch(
|
|
2133
|
+
apiKey,
|
|
2134
|
+
"/api/collections/teams/records?perPage=200"
|
|
2135
|
+
);
|
|
2136
|
+
return data.items;
|
|
2137
|
+
}
|
|
2138
|
+
async function listProjects(apiKey) {
|
|
2139
|
+
const data = await apiFetch(
|
|
2140
|
+
apiKey,
|
|
2141
|
+
"/api/collections/projects/records?perPage=200&expand=team"
|
|
2142
|
+
);
|
|
2143
|
+
return data.items;
|
|
2144
|
+
}
|
|
2145
|
+
async function createProject(apiKey, args) {
|
|
2146
|
+
return apiFetch(apiKey, "/api/collections/projects/records", {
|
|
2147
|
+
method: "POST",
|
|
2148
|
+
body: JSON.stringify({
|
|
2149
|
+
name: args.name,
|
|
2150
|
+
team: args.teamId,
|
|
2151
|
+
user: args.userId,
|
|
2152
|
+
...args.template ? { template: args.template } : {}
|
|
2153
|
+
})
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
async function registerServer(apiKey, input) {
|
|
2157
|
+
return apiFetch(apiKey, "/v1/servers", {
|
|
2158
|
+
method: "POST",
|
|
2159
|
+
body: JSON.stringify(input)
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
async function startDeployment(apiKey, projectId, input) {
|
|
2163
|
+
return apiFetch(apiKey, `/v1/projects/${projectId}/deployments`, {
|
|
2164
|
+
method: "POST",
|
|
2165
|
+
body: JSON.stringify(input)
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
async function finishDeployment(apiKey, projectId, deploymentId, input) {
|
|
2169
|
+
return apiFetch(apiKey, `/v1/projects/${projectId}/deployments/${deploymentId}`, {
|
|
2170
|
+
method: "PATCH",
|
|
2171
|
+
body: JSON.stringify(input)
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2174
|
+
async function destroyEnvironment(apiKey, projectId, envTag) {
|
|
2175
|
+
return apiFetch(apiKey, `/v1/projects/${projectId}/environments/${encodeURIComponent(envTag)}`, {
|
|
2176
|
+
method: "DELETE"
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
// src/lib/link-project.ts
|
|
2181
|
+
function dashboardUrl(teamSlug, projectSlug) {
|
|
2182
|
+
return teamSlug && projectSlug ? `${API_URL}/${teamSlug}/${projectSlug}` : API_URL;
|
|
2183
|
+
}
|
|
2184
|
+
async function pickTeam(teams3) {
|
|
2185
|
+
if (teams3.length === 1) return teams3[0];
|
|
2186
|
+
const choice = await p6.select({
|
|
2187
|
+
message: "Select a team",
|
|
2188
|
+
options: teams3.map((team) => ({
|
|
2189
|
+
value: team.id,
|
|
2190
|
+
label: team.is_personal ? `${team.name} (personal)` : team.name
|
|
2191
|
+
}))
|
|
2192
|
+
});
|
|
2193
|
+
if (p6.isCancel(choice)) {
|
|
2194
|
+
p6.cancel("Operation cancelled.");
|
|
2195
|
+
process9.exit(0);
|
|
2196
|
+
}
|
|
2197
|
+
return teams3.find((team) => team.id === choice);
|
|
2198
|
+
}
|
|
2199
|
+
async function resolveTeam(teams3, options) {
|
|
2200
|
+
if (options.teamId) {
|
|
2201
|
+
const team = teams3.find((candidate) => candidate.id === options.teamId);
|
|
2202
|
+
if (!team) {
|
|
2203
|
+
throw new Error(
|
|
2204
|
+
`You are not a member of team ${options.teamId}. Omit --team to use your personal team.`
|
|
2205
|
+
);
|
|
2206
|
+
}
|
|
2207
|
+
return team;
|
|
2208
|
+
}
|
|
2209
|
+
if (teams3.length === 0) throw new Error("No team found on velastack.dev for this account.");
|
|
2210
|
+
const personal = teams3.find((team) => team.is_personal);
|
|
2211
|
+
if (personal) return personal;
|
|
2212
|
+
if (options.interactive) return pickTeam(teams3);
|
|
2213
|
+
throw new Error("Several teams and no personal one: pass --team <id>.");
|
|
2214
|
+
}
|
|
2215
|
+
async function linkNewProject(apiKey, args) {
|
|
2216
|
+
const [user, teams3] = await Promise.all([getCurrentUser(apiKey), listTeams(apiKey)]);
|
|
2217
|
+
const team = await resolveTeam(teams3, { teamId: args.teamId, interactive: args.interactive });
|
|
2218
|
+
const project = await createProject(apiKey, {
|
|
2219
|
+
name: args.name,
|
|
2220
|
+
teamId: team.id,
|
|
2221
|
+
userId: user.id,
|
|
2222
|
+
template: args.template
|
|
2223
|
+
});
|
|
2224
|
+
return toLinked(project, team);
|
|
2225
|
+
}
|
|
2226
|
+
async function linkExistingProject(apiKey, projectId) {
|
|
2227
|
+
const projects = await listProjects(apiKey);
|
|
2228
|
+
const project = projects.find((candidate) => candidate.id === projectId);
|
|
2229
|
+
if (!project) {
|
|
2230
|
+
throw new Error(`No project ${projectId} on velastack.dev for this account.`);
|
|
2231
|
+
}
|
|
2232
|
+
return toLinked(project, project.expand?.team);
|
|
2233
|
+
}
|
|
2234
|
+
function toLinked(project, team) {
|
|
2235
|
+
return {
|
|
2236
|
+
projectId: project.id,
|
|
2237
|
+
teamId: project.team,
|
|
2238
|
+
projectName: project.name,
|
|
2239
|
+
dashboardUrl: dashboardUrl(team?.slug, project.slug)
|
|
2240
|
+
};
|
|
2287
2241
|
}
|
|
2288
2242
|
|
|
2289
|
-
// src/lib/ai-flow.ts
|
|
2290
|
-
import fs18 from "node:fs";
|
|
2291
|
-
import path17 from "node:path";
|
|
2292
|
-
import * as p11 from "@clack/prompts";
|
|
2293
|
-
import pc4 from "picocolors";
|
|
2294
|
-
|
|
2295
2243
|
// src/lib/project-config.ts
|
|
2296
|
-
import
|
|
2297
|
-
import
|
|
2244
|
+
import fs16 from "node:fs";
|
|
2245
|
+
import path14 from "node:path";
|
|
2298
2246
|
function projectConfigPath(workspaceRootDir) {
|
|
2299
|
-
return
|
|
2247
|
+
return path14.join(workspaceRootDir, ".vela", "project.json");
|
|
2300
2248
|
}
|
|
2301
2249
|
function readProjectConfig(workspaceRootDir) {
|
|
2302
2250
|
const file = projectConfigPath(workspaceRootDir);
|
|
2303
|
-
if (!
|
|
2251
|
+
if (!fs16.existsSync(file)) return null;
|
|
2304
2252
|
try {
|
|
2305
|
-
const parsed = JSON.parse(
|
|
2253
|
+
const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
2306
2254
|
if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
|
|
2307
2255
|
return null;
|
|
2308
2256
|
}
|
|
@@ -2317,17 +2265,483 @@ function readProjectConfig(workspaceRootDir) {
|
|
|
2317
2265
|
}
|
|
2318
2266
|
function writeProjectConfig(workspaceRootDir, config) {
|
|
2319
2267
|
const file = projectConfigPath(workspaceRootDir);
|
|
2320
|
-
|
|
2268
|
+
fs16.mkdirSync(path14.dirname(file), { recursive: true });
|
|
2321
2269
|
let existing = {};
|
|
2322
|
-
if (
|
|
2270
|
+
if (fs16.existsSync(file)) {
|
|
2323
2271
|
try {
|
|
2324
|
-
existing = JSON.parse(
|
|
2272
|
+
existing = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
2325
2273
|
} catch {
|
|
2326
2274
|
}
|
|
2327
2275
|
}
|
|
2328
|
-
|
|
2276
|
+
fs16.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
// src/commands/login.ts
|
|
2280
|
+
import os3 from "node:os";
|
|
2281
|
+
import process10 from "node:process";
|
|
2282
|
+
import { Command as Command3 } from "commander";
|
|
2283
|
+
import * as p7 from "@clack/prompts";
|
|
2284
|
+
import makeFetchCookie from "fetch-cookie";
|
|
2285
|
+
var login = new Command3("login").description("login to velastack.dev").configureHelp(helpConfig).action(
|
|
2286
|
+
() => runCommand(async () => {
|
|
2287
|
+
await loginInteractively();
|
|
2288
|
+
p7.log.success("Logged in to velastack.dev");
|
|
2289
|
+
}, "Failed to login.")
|
|
2290
|
+
);
|
|
2291
|
+
async function loginInteractively() {
|
|
2292
|
+
const { email: email3, password: password11 } = await p7.group(
|
|
2293
|
+
{
|
|
2294
|
+
email: () => p7.text({ message: "Email" }),
|
|
2295
|
+
password: () => p7.password({ message: "Password" })
|
|
2296
|
+
},
|
|
2297
|
+
{
|
|
2298
|
+
onCancel: () => {
|
|
2299
|
+
p7.cancel("Operation cancelled.");
|
|
2300
|
+
process10.exit(0);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
);
|
|
2304
|
+
const fetchCookie = makeFetchCookie(fetch);
|
|
2305
|
+
const loginRes = await fetchCookie(`${API_URL}/login`, {
|
|
2306
|
+
method: "POST",
|
|
2307
|
+
headers: {
|
|
2308
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
2309
|
+
Origin: API_URL
|
|
2310
|
+
},
|
|
2311
|
+
body: new URLSearchParams({ type: "password", email: email3, password: password11 }).toString()
|
|
2312
|
+
});
|
|
2313
|
+
if (!loginRes.headers.get("Set-Cookie")) {
|
|
2314
|
+
throw new Error(
|
|
2315
|
+
"Run `vela signup` to create an account or reset at https://velastack.dev/reset"
|
|
2316
|
+
);
|
|
2317
|
+
}
|
|
2318
|
+
const apiKey = await issueApiKey(fetchCookie);
|
|
2319
|
+
writeConfig({ apiKey });
|
|
2320
|
+
return apiKey;
|
|
2321
|
+
}
|
|
2322
|
+
async function issueApiKey(fetchCookie) {
|
|
2323
|
+
const label4 = `CLI - ${os3.hostname()}`;
|
|
2324
|
+
await fetchCookie(`${API_URL}/api-keys/new`, {
|
|
2325
|
+
method: "POST",
|
|
2326
|
+
headers: {
|
|
2327
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
2328
|
+
Origin: API_URL
|
|
2329
|
+
},
|
|
2330
|
+
body: new URLSearchParams({ label: label4 }).toString()
|
|
2331
|
+
});
|
|
2332
|
+
const cookie = await fetchCookie.cookieJar.getCookieString(API_URL);
|
|
2333
|
+
const apiKey = extractApiKey(cookie);
|
|
2334
|
+
if (!apiKey) {
|
|
2335
|
+
throw new Error("Failed to create API key. Try again or contact support.");
|
|
2336
|
+
}
|
|
2337
|
+
const [id] = apiKey.split(".");
|
|
2338
|
+
const res = await fetchCookie(`${API_URL}/api/collections/api_keys/records`, {
|
|
2339
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2340
|
+
});
|
|
2341
|
+
const data = await res.json();
|
|
2342
|
+
for (const item of data.items) {
|
|
2343
|
+
if (item.label === label4 && item.id !== id) {
|
|
2344
|
+
await fetchCookie(`${API_URL}/api/collections/api_keys/records/${item.id}`, {
|
|
2345
|
+
method: "DELETE",
|
|
2346
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return apiKey;
|
|
2351
|
+
}
|
|
2352
|
+
function extractApiKey(cookie) {
|
|
2353
|
+
const flashCookie = cookie.split(";").find((c) => c.trim().startsWith("flash="));
|
|
2354
|
+
if (!flashCookie) return null;
|
|
2355
|
+
const decoded = decodeURIComponent(flashCookie.split("=")[1]);
|
|
2356
|
+
return JSON.parse(decoded).apiKey;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// src/commands/create.ts
|
|
2360
|
+
function optionsSchema2(listing) {
|
|
2361
|
+
const names = listing.templates.map((template) => template.name);
|
|
2362
|
+
let choices2 = `must be one of: ${templateChoicesMessage(listing.templates)}`;
|
|
2363
|
+
if (listing.registryError) {
|
|
2364
|
+
choices2 += ` (could not reach the template registry: ${listing.registryError})`;
|
|
2365
|
+
}
|
|
2366
|
+
return v4.strictObject({
|
|
2367
|
+
install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
2368
|
+
template: v4.optional(v4.picklist(names, choices2)),
|
|
2369
|
+
name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
|
|
2370
|
+
email: v4.optional(v4.pipe(v4.string(), v4.email("must be a valid email address"))),
|
|
2371
|
+
password: v4.optional(v4.pipe(v4.string(), v4.minLength(8, "must be at least 8 characters long"))),
|
|
2372
|
+
link: v4.optional(
|
|
2373
|
+
v4.pipe(
|
|
2374
|
+
v4.string(),
|
|
2375
|
+
v4.check(
|
|
2376
|
+
(value) => value === "new" || value === "none" || PROJECT_ID_RE.test(value),
|
|
2377
|
+
"must be `new`, `none` or a velastack.dev project id"
|
|
2378
|
+
)
|
|
2379
|
+
)
|
|
2380
|
+
),
|
|
2381
|
+
team: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
|
|
2382
|
+
cms: v4.optional(
|
|
2383
|
+
v4.pipe(v4.string(), v4.trim(), v4.regex(CMS_URL_RE, "must be an absolute CMS URL"))
|
|
2384
|
+
)
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2387
|
+
function checkFlagsForTemplate(template, options) {
|
|
2388
|
+
if (!template.backend && (options.email || options.password)) {
|
|
2389
|
+
throw new Error(
|
|
2390
|
+
`--email and --password don't apply to the ${template.name} template \u2014 it has no backend.`
|
|
2391
|
+
);
|
|
2392
|
+
}
|
|
2393
|
+
if (options.cms !== void 0 && !template.cms) {
|
|
2394
|
+
throw new Error(
|
|
2395
|
+
`--cms doesn't apply to the ${template.name} template \u2014 it reads no copy from a CMS.`
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
if (options.team !== void 0 && options.link !== "new") {
|
|
2399
|
+
throw new Error("--team only applies together with --link new.");
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
var create = new Command4("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold (built-in or from the registry)", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").option(
|
|
2403
|
+
"--link <new|none|project-id>",
|
|
2404
|
+
"link to a velastack.dev project: create one, skip, or use an existing project id (default: create when logged in at a terminal)"
|
|
2405
|
+
).option("--team <id>", "velastack.dev team for `--link new` (default: your personal team)").option(
|
|
2406
|
+
"--cms <url>",
|
|
2407
|
+
"read from a CMS at this URL instead of the linked project's (CMS-ready templates only)"
|
|
2408
|
+
).addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
|
|
2409
|
+
return runCommand(async () => {
|
|
2410
|
+
const listing = await listAllTemplates();
|
|
2411
|
+
const options = parseOptions(optionsSchema2(listing), rawOpts);
|
|
2412
|
+
const { directory, packageManager: packageManager2, name, template, link: link2 } = await createProject2(
|
|
2413
|
+
projectPath,
|
|
2414
|
+
options,
|
|
2415
|
+
listing
|
|
2416
|
+
);
|
|
2417
|
+
const relative = path15.relative(process11.cwd(), directory);
|
|
2418
|
+
const pm = packageManager2 ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
2419
|
+
const nextSteps = [];
|
|
2420
|
+
if (relative !== "") {
|
|
2421
|
+
const hasSpaces = relative.includes(" ");
|
|
2422
|
+
nextSteps.push(`\`cd ${hasSpaces ? `"${relative}"` : relative}\``);
|
|
2423
|
+
}
|
|
2424
|
+
if (!packageManager2) {
|
|
2425
|
+
const resolved = resolveCommand3(pm, "install", []);
|
|
2426
|
+
if (resolved) {
|
|
2427
|
+
nextSteps.push(
|
|
2428
|
+
`\`${resolved.command} ${resolved.args.join(" ")}\` to install dependencies`
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
const runDev = resolveCommand3(pm, "run", ["dev", "--open"]);
|
|
2433
|
+
if (runDev) {
|
|
2434
|
+
nextSteps.push(
|
|
2435
|
+
`\`${runDev.command} ${runDev.args.join(" ")}\` to start the dev server (Ctrl-C to stop)`
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
if (template.nextSteps) {
|
|
2439
|
+
nextSteps.push(...template.nextSteps);
|
|
2440
|
+
} else if (template.backend) {
|
|
2441
|
+
nextSteps.push("Run `vela generate scaffold <model>` to generate your first CRUD pages.");
|
|
2442
|
+
} else {
|
|
2443
|
+
nextSteps.push(
|
|
2444
|
+
"Set your deployed URL in `src/lib/site.ts` before building for production."
|
|
2445
|
+
);
|
|
2446
|
+
nextSteps.push("Run `vela ui add <component>` to add UI components.");
|
|
2447
|
+
}
|
|
2448
|
+
nextSteps.push(...linkNextSteps(link2));
|
|
2449
|
+
nextSteps.push("Stuck? Visit https://docs.velastack.dev");
|
|
2450
|
+
reportResult({
|
|
2451
|
+
summary: `Created ${name} at ${directory}.`,
|
|
2452
|
+
nextSteps
|
|
2453
|
+
});
|
|
2454
|
+
}, "Failed to create project.");
|
|
2455
|
+
});
|
|
2456
|
+
async function createProject2(cwdArg, options, listing) {
|
|
2457
|
+
const onCancel2 = () => {
|
|
2458
|
+
p8.cancel("Operation cancelled.");
|
|
2459
|
+
process11.exit(0);
|
|
2460
|
+
};
|
|
2461
|
+
const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
|
|
2462
|
+
checkFlagsForTemplate(template, options);
|
|
2463
|
+
let directory;
|
|
2464
|
+
if (cwdArg) {
|
|
2465
|
+
directory = path15.resolve(cwdArg);
|
|
2466
|
+
} else {
|
|
2467
|
+
const answer = await p8.text({
|
|
2468
|
+
message: "Where would you like your project to be created?",
|
|
2469
|
+
placeholder: " (hit Enter to use current directory)",
|
|
2470
|
+
defaultValue: "./"
|
|
2471
|
+
});
|
|
2472
|
+
if (p8.isCancel(answer)) onCancel2();
|
|
2473
|
+
directory = path15.resolve(answer);
|
|
2474
|
+
}
|
|
2475
|
+
if (fs17.existsSync(directory) && fs17.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
|
|
2476
|
+
const force = await p8.confirm({
|
|
2477
|
+
message: "Directory not empty. Continue?",
|
|
2478
|
+
initialValue: false
|
|
2479
|
+
});
|
|
2480
|
+
if (p8.isCancel(force) || !force) onCancel2();
|
|
2481
|
+
}
|
|
2482
|
+
const dirName = path15.basename(directory);
|
|
2483
|
+
const { name } = await p8.group(
|
|
2484
|
+
{
|
|
2485
|
+
name: () => {
|
|
2486
|
+
if (options.name) return Promise.resolve(options.name);
|
|
2487
|
+
return p8.text({
|
|
2488
|
+
message: "App name (used for emails, etc)",
|
|
2489
|
+
initialValue: dirName || "SvelteKit",
|
|
2490
|
+
validate: (value) => value?.trim() ? void 0 : "App name is required"
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
},
|
|
2494
|
+
{ onCancel: onCancel2 }
|
|
2495
|
+
);
|
|
2496
|
+
const credentials = template.backend ? await promptCredentials(options, onCancel2) : void 0;
|
|
2497
|
+
const link2 = await linkOnCreate(name, template, options, onCancel2);
|
|
2498
|
+
const projectPath = directory;
|
|
2499
|
+
if (template.source === "remote") p8.log.step(`Downloading template ${template.name}...`);
|
|
2500
|
+
const resolved = await resolveTemplate(template);
|
|
2501
|
+
try {
|
|
2502
|
+
copyTemplate(resolved, projectPath);
|
|
2503
|
+
applyTemplateFiles(projectPath, {
|
|
2504
|
+
appName: name,
|
|
2505
|
+
cliVersion: package_default.version,
|
|
2506
|
+
cmsEndpoint: link2.cmsEndpoint
|
|
2507
|
+
});
|
|
2508
|
+
} finally {
|
|
2509
|
+
resolved.cleanup();
|
|
2510
|
+
}
|
|
2511
|
+
if (!fs17.existsSync(path15.join(projectPath, "package.json"))) {
|
|
2512
|
+
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
2513
|
+
}
|
|
2514
|
+
if (link2.linked) {
|
|
2515
|
+
const { projectId, teamId, projectName } = link2.linked;
|
|
2516
|
+
writeProjectConfig(projectPath, { projectId, teamId, projectName });
|
|
2517
|
+
}
|
|
2518
|
+
p8.log.success("Project created");
|
|
2519
|
+
let packageManager2;
|
|
2520
|
+
if (options.install !== false) {
|
|
2521
|
+
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
2522
|
+
if (pm) {
|
|
2523
|
+
const builds = template.backend ? ["esbuild", "pocketbase-server"] : ["esbuild"];
|
|
2524
|
+
addPnpmBuildDependencies(projectPath, pm, builds);
|
|
2525
|
+
await installDependencies(pm, projectPath);
|
|
2526
|
+
packageManager2 = pm;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
if (credentials) {
|
|
2530
|
+
const { email: email3, password: password11 } = credentials;
|
|
2531
|
+
p8.log.step("Initializing PocketBase...");
|
|
2532
|
+
await createSuperuser(projectPath, email3, password11);
|
|
2533
|
+
await withPocketbase(
|
|
2534
|
+
projectPath,
|
|
2535
|
+
async (pb) => {
|
|
2536
|
+
await pb.settings.update({
|
|
2537
|
+
meta: { appName: name, appURL: "http://localhost:5173" }
|
|
2538
|
+
});
|
|
2539
|
+
},
|
|
2540
|
+
{ email: email3, password: password11 }
|
|
2541
|
+
);
|
|
2542
|
+
writeEnvFile(
|
|
2543
|
+
projectPath,
|
|
2544
|
+
{
|
|
2545
|
+
POCKETBASE_SUPERUSER_EMAIL: email3,
|
|
2546
|
+
POCKETBASE_SUPERUSER_PASSWORD: password11
|
|
2547
|
+
},
|
|
2548
|
+
["PocketBase superuser credentials \u2014 used by `vela` commands"]
|
|
2549
|
+
);
|
|
2550
|
+
p8.log.success("PocketBase initialized");
|
|
2551
|
+
}
|
|
2552
|
+
return { directory: projectPath, packageManager: packageManager2, name, template, link: link2 };
|
|
2553
|
+
}
|
|
2554
|
+
async function linkOnCreate(name, template, options, onCancel2) {
|
|
2555
|
+
const templateCms = template.cms === true;
|
|
2556
|
+
const interactive = isInteractive();
|
|
2557
|
+
const loggedIn = readApiKey() !== null;
|
|
2558
|
+
const outcome = {
|
|
2559
|
+
cmsEndpoint: options.cms ? normalizeCmsUrl(options.cms) : "",
|
|
2560
|
+
cmsSource: options.cms ? "flag" : "none",
|
|
2561
|
+
templateCms,
|
|
2562
|
+
loggedIn,
|
|
2563
|
+
interactive
|
|
2564
|
+
};
|
|
2565
|
+
let decision = decideLink({
|
|
2566
|
+
link: options.link,
|
|
2567
|
+
needsCms: templateCms && !options.cms,
|
|
2568
|
+
loggedIn,
|
|
2569
|
+
interactive
|
|
2570
|
+
});
|
|
2571
|
+
if (decision.kind === "prompt-cms") {
|
|
2572
|
+
const choice = await promptCms(onCancel2);
|
|
2573
|
+
if (choice.kind === "url") {
|
|
2574
|
+
outcome.cmsEndpoint = choice.url;
|
|
2575
|
+
outcome.cmsSource = "prompt";
|
|
2576
|
+
decision = { kind: "none" };
|
|
2577
|
+
} else {
|
|
2578
|
+
decision = { kind: choice.kind === "login" ? "login-then-create" : "none" };
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
if (decision.kind === "error") throw new Error(decision.message);
|
|
2582
|
+
let apiKey;
|
|
2583
|
+
if (decision.kind === "login-then-create") {
|
|
2584
|
+
apiKey = await loginInteractively();
|
|
2585
|
+
outcome.loggedIn = true;
|
|
2586
|
+
decision = { kind: "create" };
|
|
2587
|
+
}
|
|
2588
|
+
let linked;
|
|
2589
|
+
if (decision.kind === "create") {
|
|
2590
|
+
p8.log.step(
|
|
2591
|
+
options.link === "new" ? "Linking to a new velastack.dev project..." : "Linking to a new velastack.dev project (pass `--link none` to skip)..."
|
|
2592
|
+
);
|
|
2593
|
+
linked = await linkNewProject(apiKey ?? requireApiKey(), {
|
|
2594
|
+
name,
|
|
2595
|
+
template: template.name,
|
|
2596
|
+
teamId: options.team,
|
|
2597
|
+
interactive
|
|
2598
|
+
});
|
|
2599
|
+
} else if (decision.kind === "existing") {
|
|
2600
|
+
p8.log.step("Linking to velastack.dev...");
|
|
2601
|
+
linked = await linkExistingProject(requireApiKey(), decision.projectId);
|
|
2602
|
+
} else if (decision.kind === "none" && decision.warn) {
|
|
2603
|
+
p8.log.warn(decision.warn);
|
|
2604
|
+
}
|
|
2605
|
+
if (linked) {
|
|
2606
|
+
outcome.linked = linked;
|
|
2607
|
+
p8.log.success(`Linked to ${linked.projectName} (${linked.dashboardUrl})`);
|
|
2608
|
+
if (templateCms && !outcome.cmsEndpoint) {
|
|
2609
|
+
outcome.cmsEndpoint = cmsEndpointFor(linked.projectId);
|
|
2610
|
+
outcome.cmsSource = "linked";
|
|
2611
|
+
p8.log.success(`CMS: ${outcome.cmsEndpoint}`);
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
return outcome;
|
|
2615
|
+
}
|
|
2616
|
+
async function promptCms(onCancel2) {
|
|
2617
|
+
p8.note(`This template reads its copy from a hosted CMS.
|
|
2618
|
+
${FREE_CMS_HINT}.`, "CMS");
|
|
2619
|
+
const choice = await p8.select({
|
|
2620
|
+
message: "Where should the site read its content from?",
|
|
2621
|
+
options: [
|
|
2622
|
+
{ value: "login", label: "Log in to velastack.dev and create one", hint: "free" },
|
|
2623
|
+
{ value: "url", label: "Use an existing CMS URL" },
|
|
2624
|
+
{ value: "skip", label: "Skip for now", hint: "the site shows its fallback copy" }
|
|
2625
|
+
]
|
|
2626
|
+
});
|
|
2627
|
+
if (p8.isCancel(choice)) onCancel2();
|
|
2628
|
+
if (choice !== "url") return { kind: choice };
|
|
2629
|
+
const url = await p8.text({
|
|
2630
|
+
message: "CMS URL",
|
|
2631
|
+
placeholder: "https://velastack.dev/v1/projects/<project>/cms",
|
|
2632
|
+
validate: (value) => CMS_URL_RE.test(value?.trim() ?? "") ? void 0 : "Enter an absolute http(s) URL"
|
|
2633
|
+
});
|
|
2634
|
+
if (p8.isCancel(url)) onCancel2();
|
|
2635
|
+
return { kind: "url", url: normalizeCmsUrl(url) };
|
|
2636
|
+
}
|
|
2637
|
+
function promptCredentials(options, onCancel2) {
|
|
2638
|
+
return p8.group(
|
|
2639
|
+
{
|
|
2640
|
+
email: () => {
|
|
2641
|
+
if (options.email) return Promise.resolve(options.email);
|
|
2642
|
+
return p8.text({
|
|
2643
|
+
message: "Enter an email for the admin user",
|
|
2644
|
+
initialValue: "admin@example.com",
|
|
2645
|
+
validate: (value) => !value ? "Email is required" : !value.includes("@") ? "Invalid email" : void 0
|
|
2646
|
+
});
|
|
2647
|
+
},
|
|
2648
|
+
password: () => {
|
|
2649
|
+
if (options.password) return Promise.resolve(options.password);
|
|
2650
|
+
return p8.password({
|
|
2651
|
+
message: "Enter a password for the admin user (at least 8 characters)",
|
|
2652
|
+
validate: (value) => !value ? "Password is required" : value.length < 8 ? "Password must be at least 8 characters long" : void 0
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
},
|
|
2656
|
+
{ onCancel: onCancel2 }
|
|
2657
|
+
);
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
// src/commands/generate.ts
|
|
2661
|
+
import { Command as Command10 } from "commander";
|
|
2662
|
+
|
|
2663
|
+
// src/commands/generate/form.ts
|
|
2664
|
+
import { Command as Command5 } from "commander";
|
|
2665
|
+
import * as p14 from "@clack/prompts";
|
|
2666
|
+
|
|
2667
|
+
// src/lib/pattern-runner.ts
|
|
2668
|
+
import path16 from "node:path";
|
|
2669
|
+
import * as p9 from "@clack/prompts";
|
|
2670
|
+
import { bySlug as bySlug2 } from "@velastack/patterns";
|
|
2671
|
+
function toRelative(root, filePath) {
|
|
2672
|
+
return path16.isAbsolute(filePath) ? path16.relative(root, filePath) : filePath;
|
|
2673
|
+
}
|
|
2674
|
+
var isSuccess = (f) => (f.status ?? "success") === "success";
|
|
2675
|
+
async function runPattern(slug2, argv, input, report4) {
|
|
2676
|
+
const pattern = bySlug2[slug2];
|
|
2677
|
+
if (!pattern) {
|
|
2678
|
+
throw new Error(`Unknown pattern: ${slug2}`);
|
|
2679
|
+
}
|
|
2680
|
+
checkProviderInput(pattern, argv, input);
|
|
2681
|
+
const { workspaceRootDir, features } = await getWorkspace();
|
|
2682
|
+
const log45 = p9.taskLog({ title: report4.task.title });
|
|
2683
|
+
let result;
|
|
2684
|
+
try {
|
|
2685
|
+
result = await pattern.generate({
|
|
2686
|
+
argv,
|
|
2687
|
+
env: "runtime",
|
|
2688
|
+
root: workspaceRootDir,
|
|
2689
|
+
features,
|
|
2690
|
+
input,
|
|
2691
|
+
// Patterns no longer read the schema themselves: @velastack/pocketbase-codegen
|
|
2692
|
+
// takes an injected client, and only the CLI knows how to reach (or spawn)
|
|
2693
|
+
// a PocketBase for this workspace.
|
|
2694
|
+
getCollections: async () => {
|
|
2695
|
+
const { getCollections } = await import("@velastack/pocketbase-codegen");
|
|
2696
|
+
let collections2 = [];
|
|
2697
|
+
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
2698
|
+
collections2 = await getCollections(pb);
|
|
2699
|
+
});
|
|
2700
|
+
return collections2;
|
|
2701
|
+
},
|
|
2702
|
+
logger: { info: (message) => log45.message(message) }
|
|
2703
|
+
});
|
|
2704
|
+
log45.success(report4.task.success);
|
|
2705
|
+
} catch (e) {
|
|
2706
|
+
log45.error(report4.task.error);
|
|
2707
|
+
throw e;
|
|
2708
|
+
}
|
|
2709
|
+
const rel = (f) => toRelative(workspaceRootDir, f);
|
|
2710
|
+
const files = [...result.creates, ...result.modifies, ...result.deletes];
|
|
2711
|
+
const failures = files.filter((f) => !isSuccess(f)).map((f) => ({
|
|
2712
|
+
path: rel(f.path),
|
|
2713
|
+
status: f.status === "not-found" ? "not-found" : "failed",
|
|
2714
|
+
message: f.message
|
|
2715
|
+
}));
|
|
2716
|
+
const created = result.creates.filter(isSuccess);
|
|
2717
|
+
const modified = result.modifies.filter(isSuccess);
|
|
2718
|
+
const deleted = result.deletes.filter(isSuccess);
|
|
2719
|
+
const totalChanges = created.length + modified.length + deleted.length + result.components.length + result.packages.length + result.collections.length;
|
|
2720
|
+
if (totalChanges === 0 && failures.length === 0) {
|
|
2721
|
+
p9.log.info(`${pattern.title ?? slug2} produced no changes.`);
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
reportResult({
|
|
2725
|
+
summary: report4.summary ?? `Applied ${pattern.title ?? slug2}.`,
|
|
2726
|
+
filesCreated: created.map((f) => rel(f.path)),
|
|
2727
|
+
filesModified: modified.map((f) => rel(f.path)),
|
|
2728
|
+
filesDeleted: deleted.map((f) => rel(f.path)),
|
|
2729
|
+
componentsAdded: result.components,
|
|
2730
|
+
packagesInstalled: result.packages,
|
|
2731
|
+
collectionsAdded: result.collections.map((c) => c.name),
|
|
2732
|
+
failures,
|
|
2733
|
+
// Next steps assume the pattern applied; when part of it didn't, the
|
|
2734
|
+
// remediation snippets above are the actual next step.
|
|
2735
|
+
nextSteps: failures.length > 0 ? void 0 : report4.nextSteps
|
|
2736
|
+
});
|
|
2329
2737
|
}
|
|
2330
2738
|
|
|
2739
|
+
// src/lib/ai-flow.ts
|
|
2740
|
+
import fs18 from "node:fs";
|
|
2741
|
+
import path17 from "node:path";
|
|
2742
|
+
import * as p13 from "@clack/prompts";
|
|
2743
|
+
import pc4 from "picocolors";
|
|
2744
|
+
|
|
2331
2745
|
// src/lib/ai-client.ts
|
|
2332
2746
|
async function aiPost(workspaceRootDir, endpoint, body) {
|
|
2333
2747
|
const apiKey = requireApiKey();
|
|
@@ -2362,14 +2776,14 @@ var aiSchema = (workspaceRootDir, body) => aiPost(workspaceRootDir, "schema", bo
|
|
|
2362
2776
|
var aiForm = (workspaceRootDir, body) => aiPost(workspaceRootDir, "form", body);
|
|
2363
2777
|
|
|
2364
2778
|
// src/lib/ai-loop.ts
|
|
2365
|
-
import * as
|
|
2779
|
+
import * as p10 from "@clack/prompts";
|
|
2366
2780
|
async function aiLoop(opts) {
|
|
2367
2781
|
let prompt = opts.initialPrompt;
|
|
2368
2782
|
let history = [];
|
|
2369
2783
|
let attempt = 0;
|
|
2370
2784
|
while (true) {
|
|
2371
2785
|
attempt++;
|
|
2372
|
-
const spinner7 =
|
|
2786
|
+
const spinner7 = p10.spinner();
|
|
2373
2787
|
spinner7.start(`${opts.stageLabel} (${attempt > 1 ? "iteration " + attempt : "first pass"})\u2026`);
|
|
2374
2788
|
let result;
|
|
2375
2789
|
let turn;
|
|
@@ -2383,12 +2797,12 @@ async function aiLoop(opts) {
|
|
|
2383
2797
|
throw e;
|
|
2384
2798
|
}
|
|
2385
2799
|
opts.renderPreview(result);
|
|
2386
|
-
const next = await
|
|
2800
|
+
const next = await p10.text({
|
|
2387
2801
|
message: "Refine the result, or press Enter to apply.",
|
|
2388
2802
|
placeholder: opts.refinePlaceholder,
|
|
2389
2803
|
defaultValue: ""
|
|
2390
2804
|
});
|
|
2391
|
-
if (
|
|
2805
|
+
if (p10.isCancel(next)) return null;
|
|
2392
2806
|
const trimmed = (typeof next === "string" ? next : "").trim();
|
|
2393
2807
|
if (trimmed === "") return result;
|
|
2394
2808
|
history = turn;
|
|
@@ -2397,7 +2811,7 @@ async function aiLoop(opts) {
|
|
|
2397
2811
|
}
|
|
2398
2812
|
|
|
2399
2813
|
// src/lib/ai-existing-models.ts
|
|
2400
|
-
import * as
|
|
2814
|
+
import * as p11 from "@clack/prompts";
|
|
2401
2815
|
async function loadExistingModels(workspaceRootDir) {
|
|
2402
2816
|
let result = [];
|
|
2403
2817
|
try {
|
|
@@ -2422,7 +2836,7 @@ async function loadExistingModels(workspaceRootDir) {
|
|
|
2422
2836
|
});
|
|
2423
2837
|
} catch (e) {
|
|
2424
2838
|
const msg = e instanceof Error ? e.message : String(e);
|
|
2425
|
-
|
|
2839
|
+
p11.log.warn(
|
|
2426
2840
|
`Could not load existing schema from PocketBase (${msg}). The AI agent will design without that context.`
|
|
2427
2841
|
);
|
|
2428
2842
|
return [];
|
|
@@ -2431,7 +2845,7 @@ async function loadExistingModels(workspaceRootDir) {
|
|
|
2431
2845
|
}
|
|
2432
2846
|
|
|
2433
2847
|
// src/lib/ai-to-argv.ts
|
|
2434
|
-
import * as
|
|
2848
|
+
import * as p12 from "@clack/prompts";
|
|
2435
2849
|
var PRIMITIVE_TYPES = /* @__PURE__ */ new Set(["text", "number", "bool", "email", "date", "url", "file"]);
|
|
2436
2850
|
function singularize(name) {
|
|
2437
2851
|
if (name.endsWith("ies") && name.length > 3) return `${name.slice(0, -3)}y`;
|
|
@@ -2454,7 +2868,7 @@ function collectionSpecToArgv(spec) {
|
|
|
2454
2868
|
for (const field of spec.fields) {
|
|
2455
2869
|
const type = typeArg(field);
|
|
2456
2870
|
if (type === null) {
|
|
2457
|
-
|
|
2871
|
+
p12.log.warn(
|
|
2458
2872
|
`Skipping field "${field.name}" (type "${field.type}" cannot be represented as a pattern argument)`
|
|
2459
2873
|
);
|
|
2460
2874
|
continue;
|
|
@@ -2557,10 +2971,10 @@ function renderModel(spec) {
|
|
|
2557
2971
|
const tail = extra.length > 0 ? " " + pc4.dim(extra.join(" ")) : "";
|
|
2558
2972
|
lines.push(` ${f.name.padEnd(nameWidth)} ${f.type.padEnd(typeWidth)} ${required}${tail}`);
|
|
2559
2973
|
}
|
|
2560
|
-
|
|
2974
|
+
p13.log.message(lines.join("\n"));
|
|
2561
2975
|
}
|
|
2562
2976
|
function renderLayout(layout) {
|
|
2563
|
-
|
|
2977
|
+
p13.log.message(renderGrid(layout));
|
|
2564
2978
|
}
|
|
2565
2979
|
async function runSchemaStage(opts) {
|
|
2566
2980
|
const { workspaceRootDir } = await getWorkspace();
|
|
@@ -2607,7 +3021,7 @@ function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
|
|
|
2607
3021
|
}
|
|
2608
3022
|
|
|
2609
3023
|
// src/commands/generate/form.ts
|
|
2610
|
-
var form = new
|
|
3024
|
+
var form = new Command5("form").description("generate a form from a model").argument("[model]", 'model name (e.g. "contact")').argument("[fields...]", 'field definitions (e.g. "name:text", "email:email")').option("--remote", "generate a form backed by a remote PocketBase collection").option(
|
|
2611
3025
|
"--route <route>",
|
|
2612
3026
|
'place the form at a custom route (e.g. "(app)/[team_id]/projects/new"). Defaults to the model name under (app)/(public).'
|
|
2613
3027
|
).option(
|
|
@@ -2624,12 +3038,12 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2624
3038
|
}
|
|
2625
3039
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "form" });
|
|
2626
3040
|
if (!stage2) {
|
|
2627
|
-
|
|
3041
|
+
p14.cancel("Aborted before any files were written.");
|
|
2628
3042
|
return;
|
|
2629
3043
|
}
|
|
2630
3044
|
const layout = await runLayoutStage(stage2.workspaceRootDir, stage2.model);
|
|
2631
3045
|
if (!layout) {
|
|
2632
|
-
|
|
3046
|
+
p14.cancel("Aborted before any files were written.");
|
|
2633
3047
|
return;
|
|
2634
3048
|
}
|
|
2635
3049
|
argv = specToArgv(stage2.model);
|
|
@@ -2670,9 +3084,9 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2670
3084
|
);
|
|
2671
3085
|
|
|
2672
3086
|
// src/commands/generate/schema.ts
|
|
2673
|
-
import { Command as
|
|
2674
|
-
import * as
|
|
2675
|
-
var schema = new
|
|
3087
|
+
import { Command as Command6 } from "commander";
|
|
3088
|
+
import * as p15 from "@clack/prompts";
|
|
3089
|
+
var schema = new Command6("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(
|
|
2676
3090
|
(model, fields, options) => runCommand(async () => {
|
|
2677
3091
|
let argv;
|
|
2678
3092
|
let modelName;
|
|
@@ -2682,7 +3096,7 @@ var schema = new Command5("schema").description("generate a schema from a model"
|
|
|
2682
3096
|
}
|
|
2683
3097
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "schema" });
|
|
2684
3098
|
if (!stage2) {
|
|
2685
|
-
|
|
3099
|
+
p15.cancel("Aborted before any files were written.");
|
|
2686
3100
|
return;
|
|
2687
3101
|
}
|
|
2688
3102
|
argv = specToArgv(stage2.model);
|
|
@@ -2715,8 +3129,8 @@ var schema = new Command5("schema").description("generate a schema from a model"
|
|
|
2715
3129
|
);
|
|
2716
3130
|
|
|
2717
3131
|
// src/commands/generate/resource.ts
|
|
2718
|
-
import { Command as
|
|
2719
|
-
var resource = new
|
|
3132
|
+
import { Command as Command7 } from "commander";
|
|
3133
|
+
var resource = new Command7("resource").description("generate a resource (model + CRUD pages)").argument("<model>", "model name").argument("[fields...]", "field definitions").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2720
3134
|
(model, fields) => runCommand(
|
|
2721
3135
|
() => runPattern(
|
|
2722
3136
|
"generate-resource",
|
|
@@ -2741,9 +3155,9 @@ var resource = new Command6("resource").description("generate a resource (model
|
|
|
2741
3155
|
);
|
|
2742
3156
|
|
|
2743
3157
|
// src/commands/generate/scaffold.ts
|
|
2744
|
-
import { Command as
|
|
2745
|
-
import * as
|
|
2746
|
-
var scaffold = new
|
|
3158
|
+
import { Command as Command8 } from "commander";
|
|
3159
|
+
import * as p16 from "@clack/prompts";
|
|
3160
|
+
var scaffold = new Command8("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(
|
|
2747
3161
|
"--route <route>",
|
|
2748
3162
|
'place the scaffold at a custom route (e.g. "(app)/[team_id]/projects"). Defaults to the pluralized model name under (app)/(public).'
|
|
2749
3163
|
).option(
|
|
@@ -2760,12 +3174,12 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2760
3174
|
}
|
|
2761
3175
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "scaffold" });
|
|
2762
3176
|
if (!stage2) {
|
|
2763
|
-
|
|
3177
|
+
p16.cancel("Aborted before any files were written.");
|
|
2764
3178
|
return;
|
|
2765
3179
|
}
|
|
2766
3180
|
const layout = await runLayoutStage(stage2.workspaceRootDir, stage2.model);
|
|
2767
3181
|
if (!layout) {
|
|
2768
|
-
|
|
3182
|
+
p16.cancel("Aborted before any files were written.");
|
|
2769
3183
|
return;
|
|
2770
3184
|
}
|
|
2771
3185
|
argv = specToArgv(stage2.model);
|
|
@@ -2807,8 +3221,8 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2807
3221
|
);
|
|
2808
3222
|
|
|
2809
3223
|
// src/commands/generate/migration.ts
|
|
2810
|
-
import { Command as
|
|
2811
|
-
var migration = new
|
|
3224
|
+
import { Command as Command9 } from "commander";
|
|
3225
|
+
var migration = new Command9("migration").description("generate a migration for an existing collection").argument("<collection>", "collection name").argument("<op>", "operation (add, remove, rename, references)").argument("[args...]", 'operation arguments (e.g. "birthday:date")').allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2812
3226
|
(collection, op, args) => runCommand(
|
|
2813
3227
|
() => runPattern(
|
|
2814
3228
|
"generate-migration",
|
|
@@ -2832,14 +3246,14 @@ var migration = new Command8("migration").description("generate a migration for
|
|
|
2832
3246
|
);
|
|
2833
3247
|
|
|
2834
3248
|
// src/commands/generate.ts
|
|
2835
|
-
var generate = new
|
|
3249
|
+
var generate = new Command10("generate").description("generate scaffolding for database models and forms").configureHelp(helpConfig).addCommand(form).addCommand(schema).addCommand(resource).addCommand(scaffold).addCommand(migration);
|
|
2836
3250
|
|
|
2837
3251
|
// src/commands/enable.ts
|
|
2838
|
-
import { Command as
|
|
3252
|
+
import { Command as Command26 } from "commander";
|
|
2839
3253
|
|
|
2840
3254
|
// src/commands/enable/analytics.ts
|
|
2841
|
-
import { Command as
|
|
2842
|
-
var analytics = new
|
|
3255
|
+
import { Command as Command11 } from "commander";
|
|
3256
|
+
var analytics = new Command11("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
3257
|
(opts, cmd) => runCommand(async () => {
|
|
2844
3258
|
const provider = await resolveProvider("enable-analytics", opts.provider);
|
|
2845
3259
|
const providerEnv = await collectProviderEnv(provider);
|
|
@@ -2869,8 +3283,8 @@ var analytics = new Command10("analytics").description("enable web analytics (Pl
|
|
|
2869
3283
|
);
|
|
2870
3284
|
|
|
2871
3285
|
// src/commands/enable/auth.ts
|
|
2872
|
-
import { Command as
|
|
2873
|
-
var auth = new
|
|
3286
|
+
import { Command as Command12 } from "commander";
|
|
3287
|
+
var auth = new Command12("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2874
3288
|
(_opts, cmd) => runCommand(
|
|
2875
3289
|
() => runPattern(
|
|
2876
3290
|
"enable-auth",
|
|
@@ -2895,8 +3309,8 @@ var auth = new Command11("auth").description("enable authentication (email/passw
|
|
|
2895
3309
|
);
|
|
2896
3310
|
|
|
2897
3311
|
// src/commands/enable/api.ts
|
|
2898
|
-
import { Command as
|
|
2899
|
-
var api = new
|
|
3312
|
+
import { Command as Command13 } from "commander";
|
|
3313
|
+
var api = new Command13("api").description("enable the PocketBase REST API").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2900
3314
|
(_opts, cmd) => runCommand(
|
|
2901
3315
|
() => runPattern(
|
|
2902
3316
|
"enable-api",
|
|
@@ -2921,8 +3335,8 @@ var api = new Command12("api").description("enable the PocketBase REST API").all
|
|
|
2921
3335
|
);
|
|
2922
3336
|
|
|
2923
3337
|
// src/commands/enable/api-keys.ts
|
|
2924
|
-
import { Command as
|
|
2925
|
-
var apiKeys = new
|
|
3338
|
+
import { Command as Command14 } from "commander";
|
|
3339
|
+
var apiKeys = new Command14("api-keys").description("enable API key management").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2926
3340
|
(_opts, cmd) => runCommand(
|
|
2927
3341
|
() => runPattern(
|
|
2928
3342
|
"enable-api-keys",
|
|
@@ -2947,8 +3361,8 @@ var apiKeys = new Command13("api-keys").description("enable API key management")
|
|
|
2947
3361
|
);
|
|
2948
3362
|
|
|
2949
3363
|
// src/commands/enable/backend.ts
|
|
2950
|
-
import { Command as
|
|
2951
|
-
var backend = new
|
|
3364
|
+
import { Command as Command15 } from "commander";
|
|
3365
|
+
var backend = new Command15("backend").description("enable the PocketBase backend").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2952
3366
|
(_opts, cmd) => runCommand(
|
|
2953
3367
|
() => runPattern(
|
|
2954
3368
|
"enable-backend",
|
|
@@ -2973,8 +3387,8 @@ var backend = new Command14("backend").description("enable the PocketBase backen
|
|
|
2973
3387
|
);
|
|
2974
3388
|
|
|
2975
3389
|
// src/commands/enable/i18n.ts
|
|
2976
|
-
import { Command as
|
|
2977
|
-
var i18n = new
|
|
3390
|
+
import { Command as Command16 } from "commander";
|
|
3391
|
+
var i18n = new Command16("i18n").description("enable internationalization").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
2978
3392
|
(_opts, cmd) => runCommand(
|
|
2979
3393
|
() => runPattern(
|
|
2980
3394
|
"enable-i18n",
|
|
@@ -2999,8 +3413,8 @@ var i18n = new Command15("i18n").description("enable internationalization").allo
|
|
|
2999
3413
|
);
|
|
3000
3414
|
|
|
3001
3415
|
// src/commands/enable/teams.ts
|
|
3002
|
-
import { Command as
|
|
3003
|
-
var teams = new
|
|
3416
|
+
import { Command as Command17 } from "commander";
|
|
3417
|
+
var teams = new Command17("teams").description("enable team / multi-tenant support").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
3004
3418
|
(_opts, cmd) => runCommand(
|
|
3005
3419
|
() => runPattern(
|
|
3006
3420
|
"enable-teams",
|
|
@@ -3025,11 +3439,11 @@ var teams = new Command16("teams").description("enable team / multi-tenant suppo
|
|
|
3025
3439
|
);
|
|
3026
3440
|
|
|
3027
3441
|
// src/commands/enable/payments.ts
|
|
3028
|
-
import
|
|
3029
|
-
import { Command as
|
|
3030
|
-
import * as
|
|
3442
|
+
import process12 from "node:process";
|
|
3443
|
+
import { Command as Command18 } from "commander";
|
|
3444
|
+
import * as p17 from "@clack/prompts";
|
|
3031
3445
|
var PROVIDERS = [{ value: "stripe", label: "Stripe" }];
|
|
3032
|
-
var payments = new
|
|
3446
|
+
var payments = new Command18("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
3033
3447
|
(opts, cmd) => runCommand(async () => {
|
|
3034
3448
|
const provider = await resolveProvider2(opts.provider, cmd.getOptionValueSource("provider"));
|
|
3035
3449
|
const input = {
|
|
@@ -3064,21 +3478,21 @@ async function resolveProvider2(value, source) {
|
|
|
3064
3478
|
}
|
|
3065
3479
|
return value;
|
|
3066
3480
|
}
|
|
3067
|
-
const selected = await
|
|
3481
|
+
const selected = await p17.select({
|
|
3068
3482
|
message: "Which payment provider?",
|
|
3069
3483
|
options: PROVIDERS,
|
|
3070
3484
|
initialValue: "stripe"
|
|
3071
3485
|
});
|
|
3072
|
-
if (
|
|
3073
|
-
|
|
3074
|
-
|
|
3486
|
+
if (p17.isCancel(selected)) {
|
|
3487
|
+
p17.cancel("Operation cancelled.");
|
|
3488
|
+
process12.exit(0);
|
|
3075
3489
|
}
|
|
3076
3490
|
return selected;
|
|
3077
3491
|
}
|
|
3078
3492
|
async function ensureWebhookSecret() {
|
|
3079
|
-
const existing =
|
|
3493
|
+
const existing = process12.env.STRIPE_WEBHOOK_SECRET;
|
|
3080
3494
|
if (existing) return existing;
|
|
3081
|
-
|
|
3495
|
+
p17.note(
|
|
3082
3496
|
[
|
|
3083
3497
|
"Download the Stripe CLI (https://stripe.com/docs/stripe-cli), then run:",
|
|
3084
3498
|
" stripe listen --forward-to localhost:5173/webhooks/stripe",
|
|
@@ -3090,7 +3504,7 @@ async function ensureWebhookSecret() {
|
|
|
3090
3504
|
return promptPassword("Stripe webhook signing secret (whsec_...)");
|
|
3091
3505
|
}
|
|
3092
3506
|
async function ensurePriceId() {
|
|
3093
|
-
|
|
3507
|
+
p17.note(
|
|
3094
3508
|
[
|
|
3095
3509
|
"Stripe checkout requires a product and price_id.",
|
|
3096
3510
|
"If you have a demo product price_id, enter it below, or leave blank to create a demo one for you."
|
|
@@ -3098,36 +3512,36 @@ async function ensurePriceId() {
|
|
|
3098
3512
|
"Stripe demo product",
|
|
3099
3513
|
{ format: (line) => line }
|
|
3100
3514
|
);
|
|
3101
|
-
const value = await
|
|
3515
|
+
const value = await p17.text({
|
|
3102
3516
|
message: "Stripe price_id (price_...)",
|
|
3103
3517
|
placeholder: "leave blank to create a demo product"
|
|
3104
3518
|
});
|
|
3105
|
-
if (
|
|
3106
|
-
|
|
3107
|
-
|
|
3519
|
+
if (p17.isCancel(value)) {
|
|
3520
|
+
p17.cancel("Operation cancelled.");
|
|
3521
|
+
process12.exit(0);
|
|
3108
3522
|
}
|
|
3109
3523
|
return (value ?? "").trim();
|
|
3110
3524
|
}
|
|
3111
3525
|
async function ensureKey(envVar, message) {
|
|
3112
|
-
const existing =
|
|
3526
|
+
const existing = process12.env[envVar];
|
|
3113
3527
|
if (existing) return existing;
|
|
3114
3528
|
return promptPassword(message);
|
|
3115
3529
|
}
|
|
3116
3530
|
async function promptPassword(message) {
|
|
3117
|
-
const value = await
|
|
3531
|
+
const value = await p17.password({
|
|
3118
3532
|
message,
|
|
3119
3533
|
validate: (v10) => v10 && v10.length ? void 0 : "Required"
|
|
3120
3534
|
});
|
|
3121
|
-
if (
|
|
3122
|
-
|
|
3123
|
-
|
|
3535
|
+
if (p17.isCancel(value)) {
|
|
3536
|
+
p17.cancel("Operation cancelled.");
|
|
3537
|
+
process12.exit(0);
|
|
3124
3538
|
}
|
|
3125
3539
|
return value;
|
|
3126
3540
|
}
|
|
3127
3541
|
|
|
3128
3542
|
// src/commands/enable/subscriptions.ts
|
|
3129
|
-
import { Command as
|
|
3130
|
-
var subscriptions = new
|
|
3543
|
+
import { Command as Command19 } from "commander";
|
|
3544
|
+
var subscriptions = new Command19("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
3131
3545
|
(_opts, cmd) => runCommand(
|
|
3132
3546
|
() => runPattern(
|
|
3133
3547
|
"enable-subscriptions",
|
|
@@ -3152,8 +3566,8 @@ var subscriptions = new Command18("subscriptions").description("enable Stripe su
|
|
|
3152
3566
|
);
|
|
3153
3567
|
|
|
3154
3568
|
// src/commands/enable/notifications.ts
|
|
3155
|
-
import { Command as
|
|
3156
|
-
var notifications = new
|
|
3569
|
+
import { Command as Command20 } from "commander";
|
|
3570
|
+
var notifications = new Command20("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
3157
3571
|
(_opts, cmd) => runCommand(
|
|
3158
3572
|
() => runPattern(
|
|
3159
3573
|
"enable-notifications",
|
|
@@ -3178,15 +3592,15 @@ var notifications = new Command19("notifications").description("enable in-app no
|
|
|
3178
3592
|
);
|
|
3179
3593
|
|
|
3180
3594
|
// src/commands/enable/s3.ts
|
|
3181
|
-
import
|
|
3182
|
-
import { Command as
|
|
3183
|
-
import * as
|
|
3595
|
+
import process16 from "node:process";
|
|
3596
|
+
import { Command as Command21 } from "commander";
|
|
3597
|
+
import * as p20 from "@clack/prompts";
|
|
3184
3598
|
import pc8 from "picocolors";
|
|
3185
3599
|
|
|
3186
3600
|
// src/lib/server-command.ts
|
|
3187
|
-
import
|
|
3601
|
+
import process15 from "node:process";
|
|
3188
3602
|
import * as v6 from "valibot";
|
|
3189
|
-
import * as
|
|
3603
|
+
import * as p18 from "@clack/prompts";
|
|
3190
3604
|
import pc5 from "picocolors";
|
|
3191
3605
|
|
|
3192
3606
|
// src/lib/deploy-config.ts
|
|
@@ -3360,10 +3774,10 @@ import { resolveCommand as resolveCommand4 } from "package-manager-detector/comm
|
|
|
3360
3774
|
|
|
3361
3775
|
// src/lib/ssh.ts
|
|
3362
3776
|
import fs20 from "node:fs";
|
|
3363
|
-
import
|
|
3777
|
+
import os4 from "node:os";
|
|
3364
3778
|
import path19 from "node:path";
|
|
3365
3779
|
import crypto3 from "node:crypto";
|
|
3366
|
-
import
|
|
3780
|
+
import process13 from "node:process";
|
|
3367
3781
|
import { spawn as spawn2 } from "node:child_process";
|
|
3368
3782
|
var RemoteCommandError = class extends Error {
|
|
3369
3783
|
exitCode;
|
|
@@ -3404,7 +3818,7 @@ var SshSession = class {
|
|
|
3404
3818
|
}
|
|
3405
3819
|
async open() {
|
|
3406
3820
|
if (this.controlPath) return;
|
|
3407
|
-
const dir = path19.join(
|
|
3821
|
+
const dir = path19.join(os4.tmpdir(), "vela-ssh");
|
|
3408
3822
|
fs20.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3409
3823
|
const socket = path19.join(dir, `${crypto3.randomBytes(6).toString("hex")}.sock`);
|
|
3410
3824
|
this.controlPath = socket;
|
|
@@ -3641,17 +4055,17 @@ function spawnCapture(command, args, opts = {}) {
|
|
|
3641
4055
|
const child = spawn2(command, args, {
|
|
3642
4056
|
stdio,
|
|
3643
4057
|
cwd: opts.cwd,
|
|
3644
|
-
env: opts.env ? { ...
|
|
4058
|
+
env: opts.env ? { ...process13.env, ...opts.env } : void 0
|
|
3645
4059
|
});
|
|
3646
4060
|
let stdout = "";
|
|
3647
4061
|
let stderr = "";
|
|
3648
4062
|
child.stdout?.on("data", (chunk) => {
|
|
3649
4063
|
stdout += chunk;
|
|
3650
|
-
if (opts.streamStdout)
|
|
4064
|
+
if (opts.streamStdout) process13.stdout.write(chunk);
|
|
3651
4065
|
});
|
|
3652
4066
|
child.stderr?.on("data", (chunk) => {
|
|
3653
4067
|
stderr += chunk;
|
|
3654
|
-
if (opts.stream)
|
|
4068
|
+
if (opts.stream) process13.stderr.write(chunk);
|
|
3655
4069
|
});
|
|
3656
4070
|
child.on("error", reject);
|
|
3657
4071
|
child.on("close", (code) => resolve2({ stdout, stderr, exitCode: code ?? 1 }));
|
|
@@ -3758,7 +4172,7 @@ function sshOptionsFrom(options) {
|
|
|
3758
4172
|
import crypto4 from "node:crypto";
|
|
3759
4173
|
import fs22 from "node:fs";
|
|
3760
4174
|
import path21 from "node:path";
|
|
3761
|
-
import
|
|
4175
|
+
import process14 from "node:process";
|
|
3762
4176
|
var VELA_ROOT = "/var/lib/vela";
|
|
3763
4177
|
var VELA_ETC = "/etc/vela";
|
|
3764
4178
|
var VELA_USER = "vela";
|
|
@@ -3795,7 +4209,7 @@ async function syncServerScripts(session) {
|
|
|
3795
4209
|
const dir = `${SCRIPT_VERSIONS_DIR}/${digest}`;
|
|
3796
4210
|
const present = await session.script(`[ -d "$1" ] && echo yes || echo no`, { args: [dir] });
|
|
3797
4211
|
if (present.stdout.trim() !== "yes") {
|
|
3798
|
-
const incoming = `${SCRIPT_VERSIONS_DIR}/.incoming.${digest}.${
|
|
4212
|
+
const incoming = `${SCRIPT_VERSIONS_DIR}/.incoming.${digest}.${process14.pid}.${Date.now()}`;
|
|
3799
4213
|
await session.script(`mkdir -p "$1" && chmod 0755 "$(dirname "$1")" "$1"`, {
|
|
3800
4214
|
args: [incoming]
|
|
3801
4215
|
});
|
|
@@ -4159,7 +4573,7 @@ async function ensureBinding(workspaceRootDir, target, request = {}) {
|
|
|
4159
4573
|
writeBinding(workspaceRootDir, key, binding);
|
|
4160
4574
|
}
|
|
4161
4575
|
if (moving) {
|
|
4162
|
-
|
|
4576
|
+
p18.log.warn(
|
|
4163
4577
|
`${pc5.cyan(bindingName(target))} now points at ${pc5.cyan(server)}.
|
|
4164
4578
|
|
|
4165
4579
|
Whatever is running on ${existing.server} is left there, and this project can no
|
|
@@ -4170,7 +4584,7 @@ longer reach it. Remove it there first if that was not intended.`
|
|
|
4170
4584
|
}
|
|
4171
4585
|
async function confirmMove(target, from, to) {
|
|
4172
4586
|
const name = bindingName(target);
|
|
4173
|
-
if (!
|
|
4587
|
+
if (!process15.stdout.isTTY || process15.env.CI) {
|
|
4174
4588
|
throw new Error(
|
|
4175
4589
|
`${pc5.cyan(`--server ${to}`)} does not match the server recorded for ${pc5.cyan(name)}, ${pc5.cyan(from)}.
|
|
4176
4590
|
|
|
@@ -4178,13 +4592,13 @@ Drop ${pc5.cyan("--server")} to use the recorded one, or move the binding on pur
|
|
|
4178
4592
|
this command once from a terminal (or editing .vela/project.json).`
|
|
4179
4593
|
);
|
|
4180
4594
|
}
|
|
4181
|
-
const ok = await
|
|
4595
|
+
const ok = await p18.confirm({
|
|
4182
4596
|
message: `${name} ${target.kind === "preview" ? "run" : "runs"} on ${from}. Point ${name} at ${to} instead?`,
|
|
4183
4597
|
initialValue: false
|
|
4184
4598
|
});
|
|
4185
|
-
if (
|
|
4186
|
-
|
|
4187
|
-
|
|
4599
|
+
if (p18.isCancel(ok) || !ok) {
|
|
4600
|
+
p18.cancel("Operation cancelled.");
|
|
4601
|
+
process15.exit(0);
|
|
4188
4602
|
}
|
|
4189
4603
|
}
|
|
4190
4604
|
function bindingName(target) {
|
|
@@ -4192,7 +4606,7 @@ function bindingName(target) {
|
|
|
4192
4606
|
}
|
|
4193
4607
|
async function promptServer(target) {
|
|
4194
4608
|
const name = bindingName(target);
|
|
4195
|
-
if (!
|
|
4609
|
+
if (!process15.stdout.isTTY || process15.env.CI) {
|
|
4196
4610
|
throw new Error(
|
|
4197
4611
|
`${name} ${target.kind === "preview" ? "are" : "is"} not bound to a server yet, and there is no terminal to ask on.
|
|
4198
4612
|
|
|
@@ -4200,29 +4614,29 @@ Pass ${pc5.cyan("--server user@host")}, or run the command once from your own ma
|
|
|
4200
4614
|
and commit ${pc5.cyan(".vela/project.json")}.`
|
|
4201
4615
|
);
|
|
4202
4616
|
}
|
|
4203
|
-
|
|
4617
|
+
p18.log.info(
|
|
4204
4618
|
`${pc5.cyan(name)} ${target.kind === "preview" ? "are" : "is"} not bound to a server yet.`
|
|
4205
4619
|
);
|
|
4206
|
-
const value = await
|
|
4620
|
+
const value = await p18.text({
|
|
4207
4621
|
message: `Which server should ${name} run on?`,
|
|
4208
4622
|
placeholder: "root@203.0.113.10",
|
|
4209
4623
|
validate: (input) => input?.trim() ? void 0 : "An ssh_config alias, or user@host"
|
|
4210
4624
|
});
|
|
4211
|
-
if (
|
|
4212
|
-
|
|
4213
|
-
|
|
4625
|
+
if (p18.isCancel(value)) {
|
|
4626
|
+
p18.cancel("Operation cancelled.");
|
|
4627
|
+
process15.exit(0);
|
|
4214
4628
|
}
|
|
4215
4629
|
return value.trim();
|
|
4216
4630
|
}
|
|
4217
4631
|
async function promptDomain(target) {
|
|
4218
|
-
if (!
|
|
4219
|
-
const value = await
|
|
4632
|
+
if (!process15.stdout.isTTY || process15.env.CI) return void 0;
|
|
4633
|
+
const value = await p18.text({
|
|
4220
4634
|
message: `Which hostname should ${target.name} be served on?`,
|
|
4221
4635
|
placeholder: "example.com \u2014 leave blank to decide later"
|
|
4222
4636
|
});
|
|
4223
|
-
if (
|
|
4224
|
-
|
|
4225
|
-
|
|
4637
|
+
if (p18.isCancel(value)) {
|
|
4638
|
+
p18.cancel("Operation cancelled.");
|
|
4639
|
+
process15.exit(0);
|
|
4226
4640
|
}
|
|
4227
4641
|
return value.trim() || void 0;
|
|
4228
4642
|
}
|
|
@@ -4230,10 +4644,10 @@ async function applyRestart(ctx) {
|
|
|
4230
4644
|
const outcome = await restartInstance(ctx.session, ctx.instance);
|
|
4231
4645
|
if (!outcome.deployed) return;
|
|
4232
4646
|
if (outcome.restarted) {
|
|
4233
|
-
|
|
4647
|
+
p18.log.success("App restarted");
|
|
4234
4648
|
return;
|
|
4235
4649
|
}
|
|
4236
|
-
|
|
4650
|
+
p18.log.error(
|
|
4237
4651
|
`App restart failed.
|
|
4238
4652
|
|
|
4239
4653
|
The new value is stored and will be used the next time the app starts.
|
|
@@ -4242,7 +4656,7 @@ ${pc5.dim(outcome.error ?? "")}`
|
|
|
4242
4656
|
}
|
|
4243
4657
|
async function applyEnvRestart(ctx, changed) {
|
|
4244
4658
|
if (touchesSuperuser(changed)) {
|
|
4245
|
-
|
|
4659
|
+
p18.log.warn(
|
|
4246
4660
|
`PocketBase superuser credentials changed.
|
|
4247
4661
|
|
|
4248
4662
|
The database still holds the old ones, so the app has not been restarted.
|
|
@@ -4279,7 +4693,7 @@ import pc7 from "picocolors";
|
|
|
4279
4693
|
|
|
4280
4694
|
// src/lib/local-env.ts
|
|
4281
4695
|
import fs24 from "node:fs";
|
|
4282
|
-
import * as
|
|
4696
|
+
import * as p19 from "@clack/prompts";
|
|
4283
4697
|
import pc6 from "picocolors";
|
|
4284
4698
|
function readLocalEnv(envFile) {
|
|
4285
4699
|
if (!fs24.existsSync(envFile)) return {};
|
|
@@ -4305,16 +4719,16 @@ async function applyLocalEnvChange(ctx, changed) {
|
|
|
4305
4719
|
process.env.POCKETBASE_SUPERUSER_EMAIL = email3;
|
|
4306
4720
|
process.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
|
|
4307
4721
|
await ensureSuperuser(ctx.workspaceRootDir);
|
|
4308
|
-
|
|
4722
|
+
p19.log.success("Local superuser updated to match");
|
|
4309
4723
|
} else {
|
|
4310
|
-
|
|
4724
|
+
p19.log.warn(
|
|
4311
4725
|
`The local database still has the old superuser.
|
|
4312
4726
|
Set both ${pc6.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc6.cyan("POCKETBASE_SUPERUSER_PASSWORD")} to reconcile it.`
|
|
4313
4727
|
);
|
|
4314
4728
|
}
|
|
4315
4729
|
}
|
|
4316
4730
|
if (getPocketbaseMetadata(ctx.workspaceRootDir)) {
|
|
4317
|
-
|
|
4731
|
+
p19.log.info(`Restart ${pc6.cyan("vela dev")} to pick this up.`);
|
|
4318
4732
|
}
|
|
4319
4733
|
}
|
|
4320
4734
|
|
|
@@ -4478,7 +4892,7 @@ function hasFile(dir) {
|
|
|
4478
4892
|
|
|
4479
4893
|
// src/commands/enable/s3.ts
|
|
4480
4894
|
var s3 = addTargetOptions(
|
|
4481
|
-
new
|
|
4895
|
+
new Command21("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),
|
|
4482
4896
|
"local"
|
|
4483
4897
|
).action(
|
|
4484
4898
|
(raw) => runCommand(() => {
|
|
@@ -4496,7 +4910,7 @@ var s3 = addTargetOptions(
|
|
|
4496
4910
|
failure = error instanceof Error ? error.message : String(error);
|
|
4497
4911
|
}
|
|
4498
4912
|
if (failure) {
|
|
4499
|
-
|
|
4913
|
+
p20.log.warn(
|
|
4500
4914
|
`The connection test failed \u2014 the settings are saved but may be wrong.
|
|
4501
4915
|
|
|
4502
4916
|
${pc8.dim(failure)}
|
|
@@ -4540,64 +4954,64 @@ Do that first, then re-run with ${pc8.cyan("--force")}.`
|
|
|
4540
4954
|
);
|
|
4541
4955
|
}
|
|
4542
4956
|
async function promptConfig(options, existing) {
|
|
4543
|
-
const endpoint = options.endpoint ?? await
|
|
4544
|
-
const bucket = options.bucket ?? await
|
|
4545
|
-
const region = options.region ?? await
|
|
4546
|
-
const accessKey = options.accessKey ?? await
|
|
4547
|
-
const secret = options.secret ??
|
|
4957
|
+
const endpoint = options.endpoint ?? await text9("S3 endpoint URL", existing.endpoint || "https://s3.amazonaws.com");
|
|
4958
|
+
const bucket = options.bucket ?? await text9("S3 bucket name", existing.bucket);
|
|
4959
|
+
const region = options.region ?? await text9("S3 region", existing.region || "us-east-1");
|
|
4960
|
+
const accessKey = options.accessKey ?? await text9("S3 access key", existing.accessKey);
|
|
4961
|
+
const secret = options.secret ?? process16.env.VELA_S3_SECRET ?? await password6("S3 secret key");
|
|
4548
4962
|
const forcePathStyle = options.forcePathStyle ?? await confirm4(
|
|
4549
4963
|
"Address the bucket in the path? (MinIO, Ceph and most self-hosted gateways need this)",
|
|
4550
4964
|
defaultForcePathStyle(endpoint)
|
|
4551
4965
|
);
|
|
4552
4966
|
return { endpoint, bucket, region, accessKey, secret, forcePathStyle };
|
|
4553
4967
|
}
|
|
4554
|
-
async function
|
|
4555
|
-
const value = await
|
|
4968
|
+
async function text9(message, initialValue = "") {
|
|
4969
|
+
const value = await p20.text({
|
|
4556
4970
|
message,
|
|
4557
4971
|
initialValue,
|
|
4558
4972
|
validate: (input) => input?.trim() ? void 0 : `${message} is required`
|
|
4559
4973
|
});
|
|
4560
|
-
if (
|
|
4561
|
-
|
|
4562
|
-
|
|
4974
|
+
if (p20.isCancel(value)) {
|
|
4975
|
+
p20.cancel("Operation cancelled.");
|
|
4976
|
+
process16.exit(0);
|
|
4563
4977
|
}
|
|
4564
4978
|
return value.trim();
|
|
4565
4979
|
}
|
|
4566
|
-
async function
|
|
4567
|
-
const value = await
|
|
4980
|
+
async function password6(message) {
|
|
4981
|
+
const value = await p20.password({
|
|
4568
4982
|
message,
|
|
4569
4983
|
validate: (input) => input ? void 0 : `${message} is required`
|
|
4570
4984
|
});
|
|
4571
|
-
if (
|
|
4572
|
-
|
|
4573
|
-
|
|
4985
|
+
if (p20.isCancel(value)) {
|
|
4986
|
+
p20.cancel("Operation cancelled.");
|
|
4987
|
+
process16.exit(0);
|
|
4574
4988
|
}
|
|
4575
4989
|
return value;
|
|
4576
4990
|
}
|
|
4577
4991
|
async function confirm4(message, initialValue) {
|
|
4578
|
-
const value = await
|
|
4579
|
-
if (
|
|
4580
|
-
|
|
4581
|
-
|
|
4992
|
+
const value = await p20.confirm({ message, initialValue });
|
|
4993
|
+
if (p20.isCancel(value)) {
|
|
4994
|
+
p20.cancel("Operation cancelled.");
|
|
4995
|
+
process16.exit(0);
|
|
4582
4996
|
}
|
|
4583
4997
|
return value;
|
|
4584
4998
|
}
|
|
4585
4999
|
|
|
4586
5000
|
// src/commands/enable/smtp.ts
|
|
4587
|
-
import
|
|
4588
|
-
import { Command as
|
|
4589
|
-
import * as
|
|
4590
|
-
var smtp = new
|
|
5001
|
+
import process17 from "node:process";
|
|
5002
|
+
import { Command as Command22 } from "commander";
|
|
5003
|
+
import * as p21 from "@clack/prompts";
|
|
5004
|
+
var smtp = new Command22("smtp").description("configure SMTP for transactional email").configureHelp(helpConfig).action(
|
|
4591
5005
|
() => runCommand(async () => {
|
|
4592
5006
|
const { workspaceRootDir } = await getWorkspace();
|
|
4593
|
-
const config = await
|
|
5007
|
+
const config = await p21.group(
|
|
4594
5008
|
{
|
|
4595
|
-
host: () =>
|
|
5009
|
+
host: () => p21.text({
|
|
4596
5010
|
message: "SMTP host",
|
|
4597
5011
|
placeholder: "smtp.example.com",
|
|
4598
5012
|
validate: (v10) => v10 ? void 0 : "Host is required"
|
|
4599
5013
|
}),
|
|
4600
|
-
port: () =>
|
|
5014
|
+
port: () => p21.text({
|
|
4601
5015
|
message: "SMTP port",
|
|
4602
5016
|
initialValue: "587",
|
|
4603
5017
|
validate: (v10) => {
|
|
@@ -4607,13 +5021,13 @@ var smtp = new Command21("smtp").description("configure SMTP for transactional e
|
|
|
4607
5021
|
return void 0;
|
|
4608
5022
|
}
|
|
4609
5023
|
}),
|
|
4610
|
-
username: () =>
|
|
4611
|
-
password: () =>
|
|
5024
|
+
username: () => p21.text({ message: "SMTP username" }),
|
|
5025
|
+
password: () => p21.password({ message: "SMTP password" })
|
|
4612
5026
|
},
|
|
4613
5027
|
{
|
|
4614
5028
|
onCancel: () => {
|
|
4615
|
-
|
|
4616
|
-
|
|
5029
|
+
p21.cancel("Operation cancelled.");
|
|
5030
|
+
process17.exit(0);
|
|
4617
5031
|
}
|
|
4618
5032
|
}
|
|
4619
5033
|
);
|
|
@@ -4640,24 +5054,24 @@ var smtp = new Command21("smtp").description("configure SMTP for transactional e
|
|
|
4640
5054
|
);
|
|
4641
5055
|
|
|
4642
5056
|
// src/commands/enable/cms.ts
|
|
4643
|
-
import
|
|
4644
|
-
import { Command as
|
|
4645
|
-
import * as
|
|
5057
|
+
import process18 from "node:process";
|
|
5058
|
+
import { Command as Command23 } from "commander";
|
|
5059
|
+
import * as p22 from "@clack/prompts";
|
|
4646
5060
|
import pc9 from "picocolors";
|
|
4647
|
-
var cms = new
|
|
5061
|
+
var cms = new Command23("cms").description("enable an inline-editing CMS with an admin bar").option(
|
|
4648
5062
|
"--endpoint <url>",
|
|
4649
5063
|
"read from a hosted CMS at this URL instead of installing the backend in this app"
|
|
4650
5064
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4651
5065
|
(opts, cmd) => runCommand(async () => {
|
|
4652
5066
|
if (!opts.endpoint && !hasBackend()) {
|
|
4653
|
-
|
|
5067
|
+
p22.log.error(
|
|
4654
5068
|
`${pc9.cyan("vela enable cms")} needs a server to host the CMS backend, and this project is static.
|
|
4655
5069
|
|
|
4656
5070
|
Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${pc9.cyan("vela enable cms --endpoint <url>")}.`
|
|
4657
5071
|
);
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
5072
|
+
p22.log.message();
|
|
5073
|
+
p22.cancel("Operation failed.");
|
|
5074
|
+
process18.exitCode = 1;
|
|
4661
5075
|
return;
|
|
4662
5076
|
}
|
|
4663
5077
|
await runPattern("enable-cms", cmd.args, opts.endpoint ? { endpoint: opts.endpoint } : {}, {
|
|
@@ -4677,8 +5091,8 @@ Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${
|
|
|
4677
5091
|
);
|
|
4678
5092
|
|
|
4679
5093
|
// src/commands/enable/blog.ts
|
|
4680
|
-
import { Command as
|
|
4681
|
-
var blog = new
|
|
5094
|
+
import { Command as Command24 } from "commander";
|
|
5095
|
+
var blog = new Command24("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4682
5096
|
(_opts, cmd) => runCommand(
|
|
4683
5097
|
() => runPattern(
|
|
4684
5098
|
"enable-blog",
|
|
@@ -4703,8 +5117,8 @@ var blog = new Command23("blog").description("enable an mdsvex blog with posts,
|
|
|
4703
5117
|
);
|
|
4704
5118
|
|
|
4705
5119
|
// src/commands/enable/content-negotiation.ts
|
|
4706
|
-
import { Command as
|
|
4707
|
-
var contentNegotiation = new
|
|
5120
|
+
import { Command as Command25 } from "commander";
|
|
5121
|
+
var contentNegotiation = new Command25("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4708
5122
|
(_opts, cmd) => runCommand(
|
|
4709
5123
|
() => runPattern(
|
|
4710
5124
|
"enable-content-negotiation",
|
|
@@ -4728,33 +5142,33 @@ var contentNegotiation = new Command24("content-negotiation").description("enabl
|
|
|
4728
5142
|
);
|
|
4729
5143
|
|
|
4730
5144
|
// src/commands/enable.ts
|
|
4731
|
-
var enable = new
|
|
5145
|
+
var enable = new Command26("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);
|
|
4732
5146
|
|
|
4733
5147
|
// src/commands/disable.ts
|
|
4734
|
-
import { Command as
|
|
5148
|
+
import { Command as Command37 } from "commander";
|
|
4735
5149
|
|
|
4736
5150
|
// src/commands/disable/auth.ts
|
|
4737
|
-
import { Command as
|
|
5151
|
+
import { Command as Command27 } from "commander";
|
|
4738
5152
|
|
|
4739
5153
|
// src/commands/disable/_shared.ts
|
|
4740
|
-
import
|
|
4741
|
-
import * as
|
|
5154
|
+
import process19 from "node:process";
|
|
5155
|
+
import * as p23 from "@clack/prompts";
|
|
4742
5156
|
async function runDisable(opts, flags, cmdArgs) {
|
|
4743
5157
|
if (!flags.yes) {
|
|
4744
|
-
const ok = await
|
|
5158
|
+
const ok = await p23.confirm({
|
|
4745
5159
|
message: opts.confirmMessage,
|
|
4746
5160
|
initialValue: false
|
|
4747
5161
|
});
|
|
4748
|
-
if (
|
|
4749
|
-
|
|
4750
|
-
|
|
5162
|
+
if (p23.isCancel(ok) || !ok) {
|
|
5163
|
+
p23.cancel("Operation cancelled.");
|
|
5164
|
+
process19.exit(0);
|
|
4751
5165
|
}
|
|
4752
5166
|
}
|
|
4753
5167
|
await runPattern(opts.slug, cmdArgs, { destructive: true }, opts.report);
|
|
4754
5168
|
}
|
|
4755
5169
|
|
|
4756
5170
|
// src/commands/disable/auth.ts
|
|
4757
|
-
var auth2 = new
|
|
5171
|
+
var auth2 = new Command27("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4758
5172
|
(opts, cmd) => runCommand(
|
|
4759
5173
|
() => runDisable(
|
|
4760
5174
|
{
|
|
@@ -4780,8 +5194,8 @@ var auth2 = new Command26("auth").description("disable authentication").option("
|
|
|
4780
5194
|
);
|
|
4781
5195
|
|
|
4782
5196
|
// src/commands/disable/api.ts
|
|
4783
|
-
import { Command as
|
|
4784
|
-
var api2 = new
|
|
5197
|
+
import { Command as Command28 } from "commander";
|
|
5198
|
+
var api2 = new Command28("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4785
5199
|
(opts, cmd) => runCommand(
|
|
4786
5200
|
() => runDisable(
|
|
4787
5201
|
{
|
|
@@ -4804,8 +5218,8 @@ var api2 = new Command27("api").description("disable the REST API").option("-y,
|
|
|
4804
5218
|
);
|
|
4805
5219
|
|
|
4806
5220
|
// src/commands/disable/api-keys.ts
|
|
4807
|
-
import { Command as
|
|
4808
|
-
var apiKeys2 = new
|
|
5221
|
+
import { Command as Command29 } from "commander";
|
|
5222
|
+
var apiKeys2 = new Command29("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4809
5223
|
(opts, cmd) => runCommand(
|
|
4810
5224
|
() => runDisable(
|
|
4811
5225
|
{
|
|
@@ -4828,8 +5242,8 @@ var apiKeys2 = new Command28("api-keys").description("disable API key management
|
|
|
4828
5242
|
);
|
|
4829
5243
|
|
|
4830
5244
|
// src/commands/disable/backend.ts
|
|
4831
|
-
import { Command as
|
|
4832
|
-
var backend2 = new
|
|
5245
|
+
import { Command as Command30 } from "commander";
|
|
5246
|
+
var backend2 = new Command30("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4833
5247
|
(opts, cmd) => runCommand(
|
|
4834
5248
|
() => runDisable(
|
|
4835
5249
|
{
|
|
@@ -4852,8 +5266,8 @@ var backend2 = new Command29("backend").description("disable the PocketBase back
|
|
|
4852
5266
|
);
|
|
4853
5267
|
|
|
4854
5268
|
// src/commands/disable/content-negotiation.ts
|
|
4855
|
-
import { Command as
|
|
4856
|
-
var contentNegotiation2 = new
|
|
5269
|
+
import { Command as Command31 } from "commander";
|
|
5270
|
+
var contentNegotiation2 = new Command31("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4857
5271
|
(opts, cmd) => runCommand(
|
|
4858
5272
|
() => runDisable(
|
|
4859
5273
|
{
|
|
@@ -4876,8 +5290,8 @@ var contentNegotiation2 = new Command30("content-negotiation").description("disa
|
|
|
4876
5290
|
);
|
|
4877
5291
|
|
|
4878
5292
|
// src/commands/disable/i18n.ts
|
|
4879
|
-
import { Command as
|
|
4880
|
-
var i18n2 = new
|
|
5293
|
+
import { Command as Command32 } from "commander";
|
|
5294
|
+
var i18n2 = new Command32("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4881
5295
|
(opts, cmd) => runCommand(
|
|
4882
5296
|
() => runDisable(
|
|
4883
5297
|
{
|
|
@@ -4903,8 +5317,8 @@ var i18n2 = new Command31("i18n").description("disable internationalization").op
|
|
|
4903
5317
|
);
|
|
4904
5318
|
|
|
4905
5319
|
// src/commands/disable/teams.ts
|
|
4906
|
-
import { Command as
|
|
4907
|
-
var teams2 = new
|
|
5320
|
+
import { Command as Command33 } from "commander";
|
|
5321
|
+
var teams2 = new Command33("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4908
5322
|
(opts, cmd) => runCommand(
|
|
4909
5323
|
() => runDisable(
|
|
4910
5324
|
{
|
|
@@ -4930,8 +5344,8 @@ var teams2 = new Command32("teams").description("disable teams").option("-y, --y
|
|
|
4930
5344
|
);
|
|
4931
5345
|
|
|
4932
5346
|
// src/commands/disable/payments.ts
|
|
4933
|
-
import { Command as
|
|
4934
|
-
var payments2 = new
|
|
5347
|
+
import { Command as Command34 } from "commander";
|
|
5348
|
+
var payments2 = new Command34("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4935
5349
|
(opts, cmd) => runCommand(
|
|
4936
5350
|
() => runDisable(
|
|
4937
5351
|
{
|
|
@@ -4958,11 +5372,11 @@ var payments2 = new Command33("payments").description("disable payments").option
|
|
|
4958
5372
|
);
|
|
4959
5373
|
|
|
4960
5374
|
// src/commands/disable/s3.ts
|
|
4961
|
-
import { Command as
|
|
4962
|
-
import * as
|
|
5375
|
+
import { Command as Command35 } from "commander";
|
|
5376
|
+
import * as p24 from "@clack/prompts";
|
|
4963
5377
|
import pc10 from "picocolors";
|
|
4964
5378
|
var s32 = addTargetOptions(
|
|
4965
|
-
new
|
|
5379
|
+
new Command35("s3").description("disable S3 file storage").option("--backups", "keep backups on the server again, rather than uploads").configureHelp(helpConfig),
|
|
4966
5380
|
"local"
|
|
4967
5381
|
).action(
|
|
4968
5382
|
(raw) => runCommand(() => {
|
|
@@ -4971,7 +5385,7 @@ var s32 = addTargetOptions(
|
|
|
4971
5385
|
return withBackupTarget(raw, "disable s3", async (ctx) => {
|
|
4972
5386
|
const existing = await readS3(ctx.pb, filesystem);
|
|
4973
5387
|
if (!existing.enabled) {
|
|
4974
|
-
|
|
5388
|
+
p24.log.info(`S3 ${label2(filesystem)} is already off for ${ctx.targetName}.`);
|
|
4975
5389
|
return;
|
|
4976
5390
|
}
|
|
4977
5391
|
await disableS3(ctx.pb, filesystem);
|
|
@@ -4991,8 +5405,8 @@ function label2(filesystem) {
|
|
|
4991
5405
|
}
|
|
4992
5406
|
|
|
4993
5407
|
// src/commands/disable/smtp.ts
|
|
4994
|
-
import { Command as
|
|
4995
|
-
var smtp2 = new
|
|
5408
|
+
import { Command as Command36 } from "commander";
|
|
5409
|
+
var smtp2 = new Command36("smtp").description("disable SMTP configuration").configureHelp(helpConfig).action(
|
|
4996
5410
|
() => runCommand(async () => {
|
|
4997
5411
|
const { workspaceRootDir } = await getWorkspace();
|
|
4998
5412
|
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
@@ -5009,30 +5423,30 @@ var smtp2 = new Command35("smtp").description("disable SMTP configuration").conf
|
|
|
5009
5423
|
);
|
|
5010
5424
|
|
|
5011
5425
|
// src/commands/disable.ts
|
|
5012
|
-
var disable = new
|
|
5426
|
+
var disable = new Command37("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);
|
|
5013
5427
|
|
|
5014
5428
|
// src/commands/destroy.ts
|
|
5015
|
-
import { Command as
|
|
5429
|
+
import { Command as Command43 } from "commander";
|
|
5016
5430
|
|
|
5017
5431
|
// src/commands/destroy/form.ts
|
|
5018
|
-
import { Command as
|
|
5432
|
+
import { Command as Command38 } from "commander";
|
|
5019
5433
|
|
|
5020
5434
|
// src/commands/destroy/_shared.ts
|
|
5021
|
-
import
|
|
5022
|
-
import * as
|
|
5435
|
+
import process20 from "node:process";
|
|
5436
|
+
import * as p25 from "@clack/prompts";
|
|
5023
5437
|
async function runDestroy(slug2, model, confirmMessage, report4, flags) {
|
|
5024
5438
|
if (!flags.yes) {
|
|
5025
|
-
const ok = await
|
|
5026
|
-
if (
|
|
5027
|
-
|
|
5028
|
-
|
|
5439
|
+
const ok = await p25.confirm({ message: confirmMessage, initialValue: false });
|
|
5440
|
+
if (p25.isCancel(ok) || !ok) {
|
|
5441
|
+
p25.cancel("Operation cancelled.");
|
|
5442
|
+
process20.exit(0);
|
|
5029
5443
|
}
|
|
5030
5444
|
}
|
|
5031
5445
|
await runPattern(slug2, [model], { destructive: true, route: flags.route }, report4);
|
|
5032
5446
|
}
|
|
5033
5447
|
|
|
5034
5448
|
// src/commands/destroy/form.ts
|
|
5035
|
-
var form2 = new
|
|
5449
|
+
var form2 = new Command38("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(
|
|
5036
5450
|
"--route <route>",
|
|
5037
5451
|
"custom route the form was generated at (must match the --route used at generation)"
|
|
5038
5452
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
@@ -5056,8 +5470,8 @@ var form2 = new Command37("form").description("destroy a form generated by `vela
|
|
|
5056
5470
|
);
|
|
5057
5471
|
|
|
5058
5472
|
// src/commands/destroy/schema.ts
|
|
5059
|
-
import { Command as
|
|
5060
|
-
var schema2 = new
|
|
5473
|
+
import { Command as Command39 } from "commander";
|
|
5474
|
+
var schema2 = new Command39("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(
|
|
5061
5475
|
(model, opts) => runCommand(
|
|
5062
5476
|
() => runDestroy(
|
|
5063
5477
|
"destroy-schema",
|
|
@@ -5078,8 +5492,8 @@ var schema2 = new Command38("schema").description("destroy a zod schema generate
|
|
|
5078
5492
|
);
|
|
5079
5493
|
|
|
5080
5494
|
// src/commands/destroy/resource.ts
|
|
5081
|
-
import { Command as
|
|
5082
|
-
var resource2 = new
|
|
5495
|
+
import { Command as Command40 } from "commander";
|
|
5496
|
+
var resource2 = new Command40("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(
|
|
5083
5497
|
(model, opts) => runCommand(
|
|
5084
5498
|
() => runDestroy(
|
|
5085
5499
|
"destroy-resource",
|
|
@@ -5100,8 +5514,8 @@ var resource2 = new Command39("resource").description("destroy a resource genera
|
|
|
5100
5514
|
);
|
|
5101
5515
|
|
|
5102
5516
|
// src/commands/destroy/scaffold.ts
|
|
5103
|
-
import { Command as
|
|
5104
|
-
var scaffold2 = new
|
|
5517
|
+
import { Command as Command41 } from "commander";
|
|
5518
|
+
var scaffold2 = new Command41("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(
|
|
5105
5519
|
"--route <route>",
|
|
5106
5520
|
"custom route the scaffold was generated at (must match the --route used at generation)"
|
|
5107
5521
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
@@ -5128,9 +5542,9 @@ var scaffold2 = new Command40("scaffold").description("destroy a scaffold genera
|
|
|
5128
5542
|
);
|
|
5129
5543
|
|
|
5130
5544
|
// src/commands/destroy/deployment.ts
|
|
5131
|
-
import
|
|
5132
|
-
import { Command as
|
|
5133
|
-
import * as
|
|
5545
|
+
import process21 from "node:process";
|
|
5546
|
+
import { Command as Command42 } from "commander";
|
|
5547
|
+
import * as p28 from "@clack/prompts";
|
|
5134
5548
|
import pc13 from "picocolors";
|
|
5135
5549
|
|
|
5136
5550
|
// src/lib/destroy-guard.ts
|
|
@@ -5163,103 +5577,27 @@ Pass \`--confirm ${appName}\` as well \u2014 the app name, the same thing a term
|
|
|
5163
5577
|
message: `Removing ${what} needs a confirmation, and there is no terminal to ask on.
|
|
5164
5578
|
|
|
5165
5579
|
Pass \`--confirm ${appName}\` \u2014 the app name, the same thing a terminal would ask you to type.`
|
|
5166
|
-
};
|
|
5167
|
-
}
|
|
5168
|
-
if (yes) return { kind: "proceed" };
|
|
5169
|
-
if (interactive) return { kind: "prompt", byName: false };
|
|
5170
|
-
return {
|
|
5171
|
-
kind: "refuse",
|
|
5172
|
-
message: `Removing ${what} needs a confirmation, and there is no terminal to ask on. Pass \`--yes\`.`
|
|
5173
|
-
};
|
|
5174
|
-
}
|
|
5175
|
-
function describe({ appName, envTag, purge }) {
|
|
5176
|
-
const target = isProd(envTag) ? "production" : `the ${envTag} environment`;
|
|
5177
|
-
return purge ? `${target} of ${appName} and its database` : `${target} of ${appName}`;
|
|
5178
|
-
}
|
|
5179
|
-
|
|
5180
|
-
// src/lib/deploy-report.ts
|
|
5181
|
-
import * as p25 from "@clack/prompts";
|
|
5182
|
-
import pc12 from "picocolors";
|
|
5183
|
-
|
|
5184
|
-
// src/lib/server-identity.ts
|
|
5185
|
-
import * as p24 from "@clack/prompts";
|
|
5186
|
-
import pc11 from "picocolors";
|
|
5187
|
-
|
|
5188
|
-
// src/lib/velastack-api.ts
|
|
5189
|
-
async function apiFetch(apiKey, pathAndQuery, init) {
|
|
5190
|
-
const headers = new Headers(init?.headers);
|
|
5191
|
-
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
5192
|
-
if (init?.body && !headers.has("Content-Type")) {
|
|
5193
|
-
headers.set("Content-Type", "application/json");
|
|
5194
|
-
}
|
|
5195
|
-
const res = await fetch(`${API_URL}${pathAndQuery}`, { ...init, headers });
|
|
5196
|
-
if (res.status === 401) {
|
|
5197
|
-
throw new Error("API key invalid \u2014 run `vela login`");
|
|
5198
|
-
}
|
|
5199
|
-
if (res.status === 403) {
|
|
5200
|
-
const body = await res.text().catch(() => "");
|
|
5201
|
-
throw new Error(`velastack.dev refused this key (${body || "forbidden"}) \u2014 run \`vela login\``);
|
|
5202
|
-
}
|
|
5203
|
-
if (!res.ok) {
|
|
5204
|
-
const body = await res.text().catch(() => "");
|
|
5205
|
-
throw new Error(`Velastack API error (${res.status}): ${body || res.statusText}`);
|
|
5206
|
-
}
|
|
5207
|
-
return await res.json();
|
|
5208
|
-
}
|
|
5209
|
-
async function getCurrentUser(apiKey) {
|
|
5210
|
-
const data = await apiFetch(
|
|
5211
|
-
apiKey,
|
|
5212
|
-
"/api/collections/users/records?perPage=1"
|
|
5213
|
-
);
|
|
5214
|
-
const user = data.items[0];
|
|
5215
|
-
if (!user) throw new Error("No user found. Run `vela login` to login.");
|
|
5216
|
-
return user;
|
|
5217
|
-
}
|
|
5218
|
-
async function listTeams(apiKey) {
|
|
5219
|
-
const data = await apiFetch(
|
|
5220
|
-
apiKey,
|
|
5221
|
-
"/api/collections/teams/records?perPage=200"
|
|
5222
|
-
);
|
|
5223
|
-
return data.items;
|
|
5224
|
-
}
|
|
5225
|
-
async function listProjects(apiKey) {
|
|
5226
|
-
const data = await apiFetch(
|
|
5227
|
-
apiKey,
|
|
5228
|
-
"/api/collections/projects/records?perPage=200&expand=team"
|
|
5229
|
-
);
|
|
5230
|
-
return data.items;
|
|
5231
|
-
}
|
|
5232
|
-
async function createProject2(apiKey, args) {
|
|
5233
|
-
return apiFetch(apiKey, "/api/collections/projects/records", {
|
|
5234
|
-
method: "POST",
|
|
5235
|
-
body: JSON.stringify({ name: args.name, team: args.teamId, user: args.userId })
|
|
5236
|
-
});
|
|
5237
|
-
}
|
|
5238
|
-
async function registerServer(apiKey, input) {
|
|
5239
|
-
return apiFetch(apiKey, "/v1/servers", {
|
|
5240
|
-
method: "POST",
|
|
5241
|
-
body: JSON.stringify(input)
|
|
5242
|
-
});
|
|
5243
|
-
}
|
|
5244
|
-
async function startDeployment(apiKey, projectId, input) {
|
|
5245
|
-
return apiFetch(apiKey, `/v1/projects/${projectId}/deployments`, {
|
|
5246
|
-
method: "POST",
|
|
5247
|
-
body: JSON.stringify(input)
|
|
5248
|
-
});
|
|
5249
|
-
}
|
|
5250
|
-
async function finishDeployment(apiKey, projectId, deploymentId, input) {
|
|
5251
|
-
return apiFetch(apiKey, `/v1/projects/${projectId}/deployments/${deploymentId}`, {
|
|
5252
|
-
method: "PATCH",
|
|
5253
|
-
body: JSON.stringify(input)
|
|
5254
|
-
});
|
|
5580
|
+
};
|
|
5581
|
+
}
|
|
5582
|
+
if (yes) return { kind: "proceed" };
|
|
5583
|
+
if (interactive) return { kind: "prompt", byName: false };
|
|
5584
|
+
return {
|
|
5585
|
+
kind: "refuse",
|
|
5586
|
+
message: `Removing ${what} needs a confirmation, and there is no terminal to ask on. Pass \`--yes\`.`
|
|
5587
|
+
};
|
|
5255
5588
|
}
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
});
|
|
5589
|
+
function describe({ appName, envTag, purge }) {
|
|
5590
|
+
const target = isProd(envTag) ? "production" : `the ${envTag} environment`;
|
|
5591
|
+
return purge ? `${target} of ${appName} and its database` : `${target} of ${appName}`;
|
|
5260
5592
|
}
|
|
5261
5593
|
|
|
5594
|
+
// src/lib/deploy-report.ts
|
|
5595
|
+
import * as p27 from "@clack/prompts";
|
|
5596
|
+
import pc12 from "picocolors";
|
|
5597
|
+
|
|
5262
5598
|
// src/lib/server-identity.ts
|
|
5599
|
+
import * as p26 from "@clack/prompts";
|
|
5600
|
+
import pc11 from "picocolors";
|
|
5263
5601
|
var IPV4 = /^\d{1,3}(?:\.\d{1,3}){3}$/;
|
|
5264
5602
|
async function ensureServerIdentity(session, apiKey) {
|
|
5265
5603
|
const existing = await readServerIdentity(session);
|
|
@@ -5272,7 +5610,7 @@ async function ensureServerIdentity(session, apiKey) {
|
|
|
5272
5610
|
if (!existing || existing.serverId !== registered.serverId || existing.originHost !== registered.originHost || existing.token !== registered.token) {
|
|
5273
5611
|
await writeServerIdentity(session, registered);
|
|
5274
5612
|
if (existing) {
|
|
5275
|
-
|
|
5613
|
+
p26.log.info(`${pc11.cyan(session.target)} was re-registered with velastack.dev.`);
|
|
5276
5614
|
}
|
|
5277
5615
|
}
|
|
5278
5616
|
await runServerScript(session, "origin.sh");
|
|
@@ -5312,7 +5650,7 @@ function createDeployReporter(workspaceRootDir) {
|
|
|
5312
5650
|
const link2 = readProjectConfig(workspaceRootDir);
|
|
5313
5651
|
const apiKey = link2 ? readApiKey() : null;
|
|
5314
5652
|
if (link2 && !apiKey) {
|
|
5315
|
-
|
|
5653
|
+
p27.log.warn(
|
|
5316
5654
|
`This project is linked to ${pc12.cyan(link2.projectName)} on velastack.dev, but there is no
|
|
5317
5655
|
API key here, so this deploy will not be recorded. Run ${pc12.cyan("vela login")}, or set
|
|
5318
5656
|
${pc12.cyan("VELA_API_KEY")}.`
|
|
@@ -5362,7 +5700,7 @@ async function reportEnvironmentDestroyed(workspaceRootDir, envTag) {
|
|
|
5362
5700
|
}
|
|
5363
5701
|
}
|
|
5364
5702
|
function warn(what, err) {
|
|
5365
|
-
|
|
5703
|
+
p27.log.warn(
|
|
5366
5704
|
`velastack.dev could not ${what}.
|
|
5367
5705
|
${pc12.dim(err instanceof Error ? err.message : String(err))}`
|
|
5368
5706
|
);
|
|
@@ -5371,7 +5709,7 @@ ${pc12.dim(err instanceof Error ? err.message : String(err))}`
|
|
|
5371
5709
|
// src/commands/destroy/deployment.ts
|
|
5372
5710
|
var deployment = addLockWaitOption(
|
|
5373
5711
|
addTargetOptions(
|
|
5374
|
-
new
|
|
5712
|
+
new Command42("deployment").description("remove a deployed environment from its server").configureHelp(helpConfig),
|
|
5375
5713
|
"production"
|
|
5376
5714
|
)
|
|
5377
5715
|
).option("--purge", "also delete the database and uploaded files").option("-y, --yes", "skip the confirmation prompt").option(
|
|
@@ -5390,7 +5728,7 @@ var deployment = addLockWaitOption(
|
|
|
5390
5728
|
purge: options.purge === true,
|
|
5391
5729
|
yes: options.yes === true,
|
|
5392
5730
|
confirm: options.confirm,
|
|
5393
|
-
interactive: Boolean(
|
|
5731
|
+
interactive: Boolean(process21.stdin.isTTY && process21.stdout.isTTY)
|
|
5394
5732
|
});
|
|
5395
5733
|
if (decision.kind === "refuse") throw new Error(decision.message);
|
|
5396
5734
|
if (decision.kind === "prompt") {
|
|
@@ -5405,13 +5743,13 @@ var deployment = addLockWaitOption(
|
|
|
5405
5743
|
stream: true
|
|
5406
5744
|
});
|
|
5407
5745
|
if (result?.existed === false) {
|
|
5408
|
-
|
|
5746
|
+
p28.log.info(
|
|
5409
5747
|
`Nothing named ${pc13.cyan(`${ctx.appName} (${ctx.targetName})`)} on ${ctx.server}; nothing to remove.`
|
|
5410
5748
|
);
|
|
5411
5749
|
return;
|
|
5412
5750
|
}
|
|
5413
5751
|
await reportEnvironmentDestroyed(ctx.workspaceRootDir, ctx.envTag);
|
|
5414
|
-
|
|
5752
|
+
p28.log.success(
|
|
5415
5753
|
`Removed ${pc13.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${ctx.server}.` + (result?.purged ? result.trash ? `
|
|
5416
5754
|
|
|
5417
5755
|
A snapshot of its data is at ${pc13.cyan(result.trash)} on the server for two weeks.` : "" : `
|
|
@@ -5429,35 +5767,35 @@ The database and uploads are still in the instance's shared directory. Pass ${pc
|
|
|
5429
5767
|
);
|
|
5430
5768
|
async function confirm8(appName, targetName, byName) {
|
|
5431
5769
|
if (byName) {
|
|
5432
|
-
const answer = await
|
|
5770
|
+
const answer = await p28.text({
|
|
5433
5771
|
message: `This removes ${pc13.cyan(`${appName} (${targetName})`)}. Type the app name to confirm`,
|
|
5434
5772
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
5435
5773
|
});
|
|
5436
|
-
if (
|
|
5437
|
-
|
|
5438
|
-
|
|
5774
|
+
if (p28.isCancel(answer)) {
|
|
5775
|
+
p28.cancel("Operation cancelled.");
|
|
5776
|
+
process21.exit(0);
|
|
5439
5777
|
}
|
|
5440
5778
|
return;
|
|
5441
5779
|
}
|
|
5442
|
-
const ok = await
|
|
5780
|
+
const ok = await p28.confirm({
|
|
5443
5781
|
message: `Remove ${appName} (${targetName})?`,
|
|
5444
5782
|
initialValue: false
|
|
5445
5783
|
});
|
|
5446
|
-
if (
|
|
5447
|
-
|
|
5448
|
-
|
|
5784
|
+
if (p28.isCancel(ok) || !ok) {
|
|
5785
|
+
p28.cancel("Operation cancelled.");
|
|
5786
|
+
process21.exit(0);
|
|
5449
5787
|
}
|
|
5450
5788
|
}
|
|
5451
5789
|
|
|
5452
5790
|
// src/commands/destroy.ts
|
|
5453
|
-
var destroy = new
|
|
5791
|
+
var destroy = new Command43("destroy").description("destroy scaffolding, or a deployment").configureHelp(helpConfig).addCommand(form2).addCommand(schema2).addCommand(resource2).addCommand(scaffold2).addCommand(deployment);
|
|
5454
5792
|
|
|
5455
5793
|
// src/commands/ui.ts
|
|
5456
|
-
import { Command as
|
|
5794
|
+
import { Command as Command49 } from "commander";
|
|
5457
5795
|
|
|
5458
5796
|
// src/commands/ui/add.ts
|
|
5459
|
-
import { Command as
|
|
5460
|
-
import * as
|
|
5797
|
+
import { Command as Command44 } from "commander";
|
|
5798
|
+
import * as p29 from "@clack/prompts";
|
|
5461
5799
|
import { installComponents } from "@velastack/patterns";
|
|
5462
5800
|
|
|
5463
5801
|
// src/lib/ui-add.ts
|
|
@@ -5506,10 +5844,10 @@ function uiAddReport(requested, outcome) {
|
|
|
5506
5844
|
}
|
|
5507
5845
|
|
|
5508
5846
|
// src/commands/ui/add.ts
|
|
5509
|
-
var add = new
|
|
5847
|
+
var add = new Command44("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(
|
|
5510
5848
|
(components, options) => runCommand(async () => {
|
|
5511
5849
|
const { workspaceRootDir } = await getWorkspace();
|
|
5512
|
-
const log45 =
|
|
5850
|
+
const log45 = p29.taskLog({ title: "Adding UI components..." });
|
|
5513
5851
|
let outcome;
|
|
5514
5852
|
try {
|
|
5515
5853
|
outcome = await installComponents({
|
|
@@ -5528,13 +5866,13 @@ var add = new Command43("add").description("add ui components (shadcn-svelte ite
|
|
|
5528
5866
|
);
|
|
5529
5867
|
|
|
5530
5868
|
// src/commands/ui/base.ts
|
|
5531
|
-
import { Command as
|
|
5532
|
-
import * as
|
|
5869
|
+
import { Command as Command45 } from "commander";
|
|
5870
|
+
import * as p30 from "@clack/prompts";
|
|
5533
5871
|
import { applyBaseColor } from "@velastack/patterns";
|
|
5534
|
-
var base = new
|
|
5872
|
+
var base = new Command45("base").description("change the base (gray) palette").argument("<color>", `base color to use (${BASE_COLORS.join(", ")})`).configureHelp(helpConfig).action(
|
|
5535
5873
|
(color) => runCommand(async () => {
|
|
5536
5874
|
const { workspaceRootDir } = await getWorkspace();
|
|
5537
|
-
const log45 =
|
|
5875
|
+
const log45 = p30.taskLog({ title: `Applying the ${color} palette...` });
|
|
5538
5876
|
let outcome;
|
|
5539
5877
|
try {
|
|
5540
5878
|
outcome = await applyBaseColor({ root: workspaceRootDir, color });
|
|
@@ -5556,8 +5894,8 @@ var base = new Command44("base").description("change the base (gray) palette").a
|
|
|
5556
5894
|
);
|
|
5557
5895
|
|
|
5558
5896
|
// src/commands/ui/list.ts
|
|
5559
|
-
import { Command as
|
|
5560
|
-
import * as
|
|
5897
|
+
import { Command as Command46 } from "commander";
|
|
5898
|
+
import * as p31 from "@clack/prompts";
|
|
5561
5899
|
import { listComponents } from "@velastack/patterns";
|
|
5562
5900
|
|
|
5563
5901
|
// src/lib/ui-list.ts
|
|
@@ -5588,7 +5926,7 @@ function uiListReport(result) {
|
|
|
5588
5926
|
}
|
|
5589
5927
|
|
|
5590
5928
|
// src/commands/ui/list.ts
|
|
5591
|
-
var list = new
|
|
5929
|
+
var list = new Command46("list").description("list installed ui components, vela components and the style registry").option("--json", "print the result as JSON", false).configureHelp(helpConfig).action(
|
|
5592
5930
|
(options) => runCommand(async () => {
|
|
5593
5931
|
const { workspaceRootDir } = await getWorkspace();
|
|
5594
5932
|
if (options.json) {
|
|
@@ -5596,7 +5934,7 @@ var list = new Command45("list").description("list installed ui components, vela
|
|
|
5596
5934
|
console.log(JSON.stringify(result2, null, 2));
|
|
5597
5935
|
return;
|
|
5598
5936
|
}
|
|
5599
|
-
const spinner7 =
|
|
5937
|
+
const spinner7 = p31.spinner();
|
|
5600
5938
|
spinner7.start("Reading the registry...");
|
|
5601
5939
|
let result;
|
|
5602
5940
|
try {
|
|
@@ -5608,15 +5946,15 @@ var list = new Command45("list").description("list installed ui components, vela
|
|
|
5608
5946
|
spinner7.stop(`Read the ${result.style} registry`);
|
|
5609
5947
|
reportResult(uiListReport(result));
|
|
5610
5948
|
if (result.registryUnavailable) {
|
|
5611
|
-
|
|
5949
|
+
p31.log.warn(`${result.registryUnavailable}
|
|
5612
5950
|
Registry components are not listed.`);
|
|
5613
5951
|
}
|
|
5614
5952
|
}, "Failed to list UI components.")
|
|
5615
5953
|
);
|
|
5616
5954
|
|
|
5617
5955
|
// src/commands/ui/style.ts
|
|
5618
|
-
import { Command as
|
|
5619
|
-
import * as
|
|
5956
|
+
import { Command as Command47 } from "commander";
|
|
5957
|
+
import * as p32 from "@clack/prompts";
|
|
5620
5958
|
import { switchStyle } from "@velastack/patterns";
|
|
5621
5959
|
|
|
5622
5960
|
// src/lib/ui-style.ts
|
|
@@ -5642,10 +5980,10 @@ function uiStyleReport(result) {
|
|
|
5642
5980
|
}
|
|
5643
5981
|
|
|
5644
5982
|
// src/commands/ui/style.ts
|
|
5645
|
-
var style = new
|
|
5983
|
+
var style = new Command47("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(
|
|
5646
5984
|
(name, options) => runCommand(async () => {
|
|
5647
5985
|
const { workspaceRootDir } = await getWorkspace();
|
|
5648
|
-
const spinner7 =
|
|
5986
|
+
const spinner7 = p32.spinner();
|
|
5649
5987
|
spinner7.start(`Reading the ${name} registry...`);
|
|
5650
5988
|
let log45;
|
|
5651
5989
|
let outcome;
|
|
@@ -5658,20 +5996,20 @@ var style = new Command46("style").description("switch the shadcn-svelte style,
|
|
|
5658
5996
|
confirm: async (components) => {
|
|
5659
5997
|
spinner7.stop(`Read the ${name} registry`);
|
|
5660
5998
|
if (components.length > 0) {
|
|
5661
|
-
|
|
5999
|
+
p32.log.info(
|
|
5662
6000
|
`Re-adds ${components.length} component(s) from the ${name} registry; local edits to their files are lost:
|
|
5663
6001
|
${components.map((c) => `- ${c}`).join("\n")}`
|
|
5664
6002
|
);
|
|
5665
6003
|
} else {
|
|
5666
|
-
|
|
6004
|
+
p32.log.info(
|
|
5667
6005
|
`No installed component comes from the registry; only the config changes.`
|
|
5668
6006
|
);
|
|
5669
6007
|
}
|
|
5670
6008
|
if (!options.yes) {
|
|
5671
|
-
const ok = await
|
|
5672
|
-
if (
|
|
6009
|
+
const ok = await p32.confirm({ message: `Switch to ${name}?`, initialValue: false });
|
|
6010
|
+
if (p32.isCancel(ok) || !ok) return false;
|
|
5673
6011
|
}
|
|
5674
|
-
log45 =
|
|
6012
|
+
log45 = p32.taskLog({ title: `Switching to the ${name} style...` });
|
|
5675
6013
|
return true;
|
|
5676
6014
|
}
|
|
5677
6015
|
});
|
|
@@ -5682,11 +6020,11 @@ ${components.map((c) => `- ${c}`).join("\n")}`
|
|
|
5682
6020
|
}
|
|
5683
6021
|
spinner7.stop(`Read the ${name} registry`);
|
|
5684
6022
|
if (outcome.status === "unchanged") {
|
|
5685
|
-
|
|
6023
|
+
p32.log.info(`Already using the ${name} style.`);
|
|
5686
6024
|
return;
|
|
5687
6025
|
}
|
|
5688
6026
|
if (outcome.status === "cancelled") {
|
|
5689
|
-
|
|
6027
|
+
p32.cancel("Operation cancelled.");
|
|
5690
6028
|
return;
|
|
5691
6029
|
}
|
|
5692
6030
|
log45?.success("Style switched");
|
|
@@ -5695,13 +6033,13 @@ ${components.map((c) => `- ${c}`).join("\n")}`
|
|
|
5695
6033
|
);
|
|
5696
6034
|
|
|
5697
6035
|
// src/commands/ui/theme.ts
|
|
5698
|
-
import { Command as
|
|
5699
|
-
import * as
|
|
6036
|
+
import { Command as Command48 } from "commander";
|
|
6037
|
+
import * as p33 from "@clack/prompts";
|
|
5700
6038
|
import { applyTheme } from "@velastack/patterns";
|
|
5701
|
-
var theme = new
|
|
6039
|
+
var theme = new Command48("theme").description("change the accent color, keeping the base palette").argument("<accent>", `accent to use (${THEMES.join(", ")})`).configureHelp(helpConfig).action(
|
|
5702
6040
|
(accent) => runCommand(async () => {
|
|
5703
6041
|
const { workspaceRootDir } = await getWorkspace();
|
|
5704
|
-
const log45 =
|
|
6042
|
+
const log45 = p33.taskLog({ title: `Applying the ${accent} accent...` });
|
|
5705
6043
|
let outcome;
|
|
5706
6044
|
try {
|
|
5707
6045
|
outcome = await applyTheme({ root: workspaceRootDir, theme: accent });
|
|
@@ -5723,22 +6061,22 @@ var theme = new Command47("theme").description("change the accent color, keeping
|
|
|
5723
6061
|
);
|
|
5724
6062
|
|
|
5725
6063
|
// src/commands/ui.ts
|
|
5726
|
-
var ui = new
|
|
6064
|
+
var ui = new Command49("ui").description("generate ui components").configureHelp(helpConfig).addCommand(add).addCommand(list).addCommand(style).addCommand(base).addCommand(theme);
|
|
5727
6065
|
|
|
5728
6066
|
// src/commands/legal.ts
|
|
5729
|
-
import { Command as
|
|
6067
|
+
import { Command as Command52 } from "commander";
|
|
5730
6068
|
|
|
5731
6069
|
// src/commands/legal/terms.ts
|
|
5732
6070
|
import fs26 from "node:fs";
|
|
5733
6071
|
import path23 from "node:path";
|
|
5734
|
-
import { Command as
|
|
5735
|
-
import * as
|
|
6072
|
+
import { Command as Command50 } from "commander";
|
|
6073
|
+
import * as p35 from "@clack/prompts";
|
|
5736
6074
|
|
|
5737
6075
|
// src/commands/legal/shared.ts
|
|
5738
|
-
import
|
|
5739
|
-
import * as
|
|
6076
|
+
import process22 from "node:process";
|
|
6077
|
+
import * as p34 from "@clack/prompts";
|
|
5740
6078
|
var sharedFields = {
|
|
5741
|
-
websiteUrl: () =>
|
|
6079
|
+
websiteUrl: () => p34.text({
|
|
5742
6080
|
message: "What is your website URL?",
|
|
5743
6081
|
placeholder: "http://www.mysite.com",
|
|
5744
6082
|
validate: (value) => {
|
|
@@ -5747,7 +6085,7 @@ var sharedFields = {
|
|
|
5747
6085
|
}
|
|
5748
6086
|
}
|
|
5749
6087
|
}),
|
|
5750
|
-
websiteName: () =>
|
|
6088
|
+
websiteName: () => p34.text({
|
|
5751
6089
|
message: "What is your website name?",
|
|
5752
6090
|
placeholder: "My Site",
|
|
5753
6091
|
validate: (value) => {
|
|
@@ -5756,7 +6094,7 @@ var sharedFields = {
|
|
|
5756
6094
|
}
|
|
5757
6095
|
}
|
|
5758
6096
|
}),
|
|
5759
|
-
entityType: () =>
|
|
6097
|
+
entityType: () => p34.select({
|
|
5760
6098
|
message: "Entity type",
|
|
5761
6099
|
options: [
|
|
5762
6100
|
{
|
|
@@ -5767,7 +6105,7 @@ var sharedFields = {
|
|
|
5767
6105
|
{ value: "individual", label: "I'm an Individual" }
|
|
5768
6106
|
]
|
|
5769
6107
|
}),
|
|
5770
|
-
businessName: ({ results }) => results?.entityType === "business" ?
|
|
6108
|
+
businessName: ({ results }) => results?.entityType === "business" ? p34.text({
|
|
5771
6109
|
message: "What is the name of the business?",
|
|
5772
6110
|
placeholder: "My Company LLC",
|
|
5773
6111
|
validate: (value) => {
|
|
@@ -5776,7 +6114,7 @@ var sharedFields = {
|
|
|
5776
6114
|
}
|
|
5777
6115
|
}
|
|
5778
6116
|
}) : void 0,
|
|
5779
|
-
businessAddress: ({ results }) => results?.entityType === "business" ?
|
|
6117
|
+
businessAddress: ({ results }) => results?.entityType === "business" ? p34.text({
|
|
5780
6118
|
message: "What is the address of the business?",
|
|
5781
6119
|
placeholder: "1 Cupertino, CA 95014",
|
|
5782
6120
|
validate: (value) => {
|
|
@@ -5785,7 +6123,7 @@ var sharedFields = {
|
|
|
5785
6123
|
}
|
|
5786
6124
|
}
|
|
5787
6125
|
}) : void 0,
|
|
5788
|
-
country: () =>
|
|
6126
|
+
country: () => p34.text({
|
|
5789
6127
|
message: "Enter the country",
|
|
5790
6128
|
validate: (value) => {
|
|
5791
6129
|
if (!value) {
|
|
@@ -5793,7 +6131,7 @@ var sharedFields = {
|
|
|
5793
6131
|
}
|
|
5794
6132
|
}
|
|
5795
6133
|
}),
|
|
5796
|
-
state: () =>
|
|
6134
|
+
state: () => p34.text({
|
|
5797
6135
|
message: "Enter the state",
|
|
5798
6136
|
validate: (value) => {
|
|
5799
6137
|
if (!value) {
|
|
@@ -5803,11 +6141,11 @@ var sharedFields = {
|
|
|
5803
6141
|
})
|
|
5804
6142
|
};
|
|
5805
6143
|
var onCancel = () => {
|
|
5806
|
-
|
|
5807
|
-
|
|
6144
|
+
p34.cancel("Operation cancelled.");
|
|
6145
|
+
process22.exit(0);
|
|
5808
6146
|
};
|
|
5809
6147
|
async function contactMethods(type) {
|
|
5810
|
-
const selection = await
|
|
6148
|
+
const selection = await p34.multiselect({
|
|
5811
6149
|
message: `How can users contact you for any questions regarding your ${type === "privacy" ? "Privacy Policy" : "Terms & Conditions"}? Check all that apply`,
|
|
5812
6150
|
options: [
|
|
5813
6151
|
{ value: "email", label: "By email" },
|
|
@@ -5816,11 +6154,11 @@ async function contactMethods(type) {
|
|
|
5816
6154
|
{ value: "mail", label: "By sending post mail" }
|
|
5817
6155
|
]
|
|
5818
6156
|
});
|
|
5819
|
-
if (
|
|
6157
|
+
if (p34.isCancel(selection)) onCancel();
|
|
5820
6158
|
const contact = selection;
|
|
5821
6159
|
const details = {};
|
|
5822
6160
|
if (contact.includes("email")) {
|
|
5823
|
-
const email3 = await
|
|
6161
|
+
const email3 = await p34.text({
|
|
5824
6162
|
message: "What's the email?",
|
|
5825
6163
|
placeholder: "office@mycompany.com",
|
|
5826
6164
|
validate: (value) => {
|
|
@@ -5829,11 +6167,11 @@ async function contactMethods(type) {
|
|
|
5829
6167
|
}
|
|
5830
6168
|
}
|
|
5831
6169
|
});
|
|
5832
|
-
if (
|
|
6170
|
+
if (p34.isCancel(email3)) onCancel();
|
|
5833
6171
|
details.email = email3;
|
|
5834
6172
|
}
|
|
5835
6173
|
if (contact.includes("page")) {
|
|
5836
|
-
const page = await
|
|
6174
|
+
const page = await p34.text({
|
|
5837
6175
|
message: "What's the link?",
|
|
5838
6176
|
placeholder: "http://www.mycompany.com/contact",
|
|
5839
6177
|
validate: (value) => {
|
|
@@ -5842,11 +6180,11 @@ async function contactMethods(type) {
|
|
|
5842
6180
|
}
|
|
5843
6181
|
}
|
|
5844
6182
|
});
|
|
5845
|
-
if (
|
|
6183
|
+
if (p34.isCancel(page)) onCancel();
|
|
5846
6184
|
details.page = page;
|
|
5847
6185
|
}
|
|
5848
6186
|
if (contact.includes("phone")) {
|
|
5849
|
-
const phone = await
|
|
6187
|
+
const phone = await p34.text({
|
|
5850
6188
|
message: "What's the phone number?",
|
|
5851
6189
|
placeholder: "408.996.1010",
|
|
5852
6190
|
validate: (value) => {
|
|
@@ -5855,11 +6193,11 @@ async function contactMethods(type) {
|
|
|
5855
6193
|
}
|
|
5856
6194
|
}
|
|
5857
6195
|
});
|
|
5858
|
-
if (
|
|
6196
|
+
if (p34.isCancel(phone)) onCancel();
|
|
5859
6197
|
details.phone = phone;
|
|
5860
6198
|
}
|
|
5861
6199
|
if (contact.includes("mail")) {
|
|
5862
|
-
const address = await
|
|
6200
|
+
const address = await p34.text({
|
|
5863
6201
|
message: "What's the address?",
|
|
5864
6202
|
placeholder: "767 Fifth Avenue New York, NY 10153, United States",
|
|
5865
6203
|
validate: (value) => {
|
|
@@ -5868,7 +6206,7 @@ async function contactMethods(type) {
|
|
|
5868
6206
|
}
|
|
5869
6207
|
}
|
|
5870
6208
|
});
|
|
5871
|
-
if (
|
|
6209
|
+
if (p34.isCancel(address)) onCancel();
|
|
5872
6210
|
details.address = address;
|
|
5873
6211
|
}
|
|
5874
6212
|
return { methods: contact, details };
|
|
@@ -6264,7 +6602,7 @@ var generateTermsHtml = (answers) => {
|
|
|
6264
6602
|
};
|
|
6265
6603
|
async function termsAction() {
|
|
6266
6604
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
6267
|
-
const core = await
|
|
6605
|
+
const core = await p35.group(
|
|
6268
6606
|
{
|
|
6269
6607
|
websiteUrl: sharedFields.websiteUrl,
|
|
6270
6608
|
websiteName: sharedFields.websiteName,
|
|
@@ -6276,25 +6614,25 @@ async function termsAction() {
|
|
|
6276
6614
|
},
|
|
6277
6615
|
{ onCancel }
|
|
6278
6616
|
);
|
|
6279
|
-
const accounts = await
|
|
6617
|
+
const accounts = await p35.select({
|
|
6280
6618
|
message: "Can users create accounts?",
|
|
6281
6619
|
options: [
|
|
6282
6620
|
{ value: "yes", label: "Yes, users can create accounts" },
|
|
6283
6621
|
{ value: "no", label: "No" }
|
|
6284
6622
|
]
|
|
6285
6623
|
});
|
|
6286
|
-
if (
|
|
6287
|
-
const userContent = await
|
|
6624
|
+
if (p35.isCancel(accounts)) onCancel();
|
|
6625
|
+
const userContent = await p35.select({
|
|
6288
6626
|
message: "Can users create and/or upload content (ie. text, images)?",
|
|
6289
6627
|
options: [
|
|
6290
6628
|
{ value: "yes", label: "Yes, users can create and/or upload content" },
|
|
6291
6629
|
{ value: "no", label: "No" }
|
|
6292
6630
|
]
|
|
6293
6631
|
});
|
|
6294
|
-
if (
|
|
6632
|
+
if (p35.isCancel(userContent)) onCancel();
|
|
6295
6633
|
let infringementEmail;
|
|
6296
6634
|
if (userContent === "yes") {
|
|
6297
|
-
const email3 = await
|
|
6635
|
+
const email3 = await p35.text({
|
|
6298
6636
|
message: "What's the email address where you will receive infringements notices?",
|
|
6299
6637
|
placeholder: "dmca@website.com",
|
|
6300
6638
|
validate: (value) => {
|
|
@@ -6303,10 +6641,10 @@ async function termsAction() {
|
|
|
6303
6641
|
}
|
|
6304
6642
|
}
|
|
6305
6643
|
});
|
|
6306
|
-
if (
|
|
6644
|
+
if (p35.isCancel(email3)) onCancel();
|
|
6307
6645
|
infringementEmail = email3;
|
|
6308
6646
|
}
|
|
6309
|
-
const canBuyGoods = await
|
|
6647
|
+
const canBuyGoods = await p35.select({
|
|
6310
6648
|
message: "Can users buy goods (products, items)?",
|
|
6311
6649
|
options: [
|
|
6312
6650
|
{
|
|
@@ -6316,28 +6654,28 @@ async function termsAction() {
|
|
|
6316
6654
|
{ value: "no", label: "No" }
|
|
6317
6655
|
]
|
|
6318
6656
|
});
|
|
6319
|
-
if (
|
|
6320
|
-
const subscriptions2 = await
|
|
6657
|
+
if (p35.isCancel(canBuyGoods)) onCancel();
|
|
6658
|
+
const subscriptions2 = await p35.select({
|
|
6321
6659
|
message: "Do you offer subscription plans?",
|
|
6322
6660
|
options: [
|
|
6323
6661
|
{ value: "yes", label: "Yes, we offer subscription plans" },
|
|
6324
6662
|
{ value: "no", label: "No" }
|
|
6325
6663
|
]
|
|
6326
6664
|
});
|
|
6327
|
-
if (
|
|
6665
|
+
if (p35.isCancel(subscriptions2)) onCancel();
|
|
6328
6666
|
let freeTrial;
|
|
6329
6667
|
if (subscriptions2 === "yes") {
|
|
6330
|
-
const ft = await
|
|
6668
|
+
const ft = await p35.select({
|
|
6331
6669
|
message: "Do you offer a free trial?",
|
|
6332
6670
|
options: [
|
|
6333
6671
|
{ value: "yes", label: "Yes" },
|
|
6334
6672
|
{ value: "no", label: "No" }
|
|
6335
6673
|
]
|
|
6336
6674
|
});
|
|
6337
|
-
if (
|
|
6675
|
+
if (p35.isCancel(ft)) onCancel();
|
|
6338
6676
|
freeTrial = ft;
|
|
6339
6677
|
}
|
|
6340
|
-
const exclusiveContent = await
|
|
6678
|
+
const exclusiveContent = await p35.select({
|
|
6341
6679
|
message: "Do you want to make it clear that your own content & trademarks are your exclusive property?",
|
|
6342
6680
|
options: [
|
|
6343
6681
|
{
|
|
@@ -6347,24 +6685,24 @@ async function termsAction() {
|
|
|
6347
6685
|
{ value: "no", label: "No" }
|
|
6348
6686
|
]
|
|
6349
6687
|
});
|
|
6350
|
-
if (
|
|
6351
|
-
const feedbackReuse = await
|
|
6688
|
+
if (p35.isCancel(exclusiveContent)) onCancel();
|
|
6689
|
+
const feedbackReuse = await p35.select({
|
|
6352
6690
|
message: "If users provide you feedback & suggestions, do you want to use this feedback without compensation or credits given?",
|
|
6353
6691
|
options: [
|
|
6354
6692
|
{ value: "yes", label: "Yes, we may implement any feedback or suggestions we receive" },
|
|
6355
6693
|
{ value: "no", label: "No" }
|
|
6356
6694
|
]
|
|
6357
6695
|
});
|
|
6358
|
-
if (
|
|
6359
|
-
const promotions = await
|
|
6696
|
+
if (p35.isCancel(feedbackReuse)) onCancel();
|
|
6697
|
+
const promotions = await p35.select({
|
|
6360
6698
|
message: "Do you plan to offer promotions, contests, sweepstakes?",
|
|
6361
6699
|
options: [
|
|
6362
6700
|
{ value: "yes", label: "Yes, we may offer promotions, contests, sweepstakes" },
|
|
6363
6701
|
{ value: "no", label: "No" }
|
|
6364
6702
|
]
|
|
6365
6703
|
});
|
|
6366
|
-
if (
|
|
6367
|
-
const mobileAppRaw = await
|
|
6704
|
+
if (p35.isCancel(promotions)) onCancel();
|
|
6705
|
+
const mobileAppRaw = await p35.multiselect({
|
|
6368
6706
|
message: "Is the Service distributed through any mobile app stores? Check all that apply",
|
|
6369
6707
|
options: [
|
|
6370
6708
|
{ value: "apple", label: "Apple App Store" },
|
|
@@ -6372,7 +6710,7 @@ async function termsAction() {
|
|
|
6372
6710
|
],
|
|
6373
6711
|
required: false
|
|
6374
6712
|
});
|
|
6375
|
-
if (
|
|
6713
|
+
if (p35.isCancel(mobileAppRaw)) onCancel();
|
|
6376
6714
|
const mobileApp = mobileAppRaw ?? [];
|
|
6377
6715
|
const contact = await contactMethods("terms");
|
|
6378
6716
|
const html = generateTermsHtml({
|
|
@@ -6415,13 +6753,13 @@ async function termsAction() {
|
|
|
6415
6753
|
]
|
|
6416
6754
|
});
|
|
6417
6755
|
}
|
|
6418
|
-
var terms = new
|
|
6756
|
+
var terms = new Command50("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
|
|
6419
6757
|
|
|
6420
6758
|
// src/commands/legal/privacy.ts
|
|
6421
6759
|
import fs27 from "node:fs";
|
|
6422
6760
|
import path24 from "node:path";
|
|
6423
|
-
import { Command as
|
|
6424
|
-
import * as
|
|
6761
|
+
import { Command as Command51 } from "commander";
|
|
6762
|
+
import * as p36 from "@clack/prompts";
|
|
6425
6763
|
var mapLabels = {
|
|
6426
6764
|
personalInfo: {
|
|
6427
6765
|
email: "Email address",
|
|
@@ -6839,12 +7177,12 @@ var generatePrivacyHtml = (answers) => {
|
|
|
6839
7177
|
return `<section data-role="content">${sections.join("")}</section>`;
|
|
6840
7178
|
};
|
|
6841
7179
|
async function promptWithCustom(message, options, customMessage) {
|
|
6842
|
-
const selection = await
|
|
6843
|
-
if (
|
|
7180
|
+
const selection = await p36.multiselect({ message, options });
|
|
7181
|
+
if (p36.isCancel(selection)) onCancel();
|
|
6844
7182
|
const values = selection;
|
|
6845
7183
|
if (values.includes("custom")) {
|
|
6846
|
-
const custom = await
|
|
6847
|
-
if (
|
|
7184
|
+
const custom = await p36.text({ message: customMessage });
|
|
7185
|
+
if (p36.isCancel(custom)) onCancel();
|
|
6848
7186
|
const idx = values.indexOf("custom");
|
|
6849
7187
|
if (idx !== -1) values.splice(idx, 1);
|
|
6850
7188
|
if (custom) values.push(String(custom));
|
|
@@ -6853,7 +7191,7 @@ async function promptWithCustom(message, options, customMessage) {
|
|
|
6853
7191
|
}
|
|
6854
7192
|
async function privacyAction() {
|
|
6855
7193
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
6856
|
-
const core = await
|
|
7194
|
+
const core = await p36.group(
|
|
6857
7195
|
{
|
|
6858
7196
|
websiteUrl: sharedFields.websiteUrl,
|
|
6859
7197
|
websiteName: sharedFields.websiteName,
|
|
@@ -6865,7 +7203,7 @@ async function privacyAction() {
|
|
|
6865
7203
|
},
|
|
6866
7204
|
{ onCancel }
|
|
6867
7205
|
);
|
|
6868
|
-
const personalInfo = await
|
|
7206
|
+
const personalInfo = await p36.multiselect({
|
|
6869
7207
|
message: "What kind of personal information do you collect from users? Check all that apply",
|
|
6870
7208
|
options: [
|
|
6871
7209
|
{ value: "email", label: "Email address" },
|
|
@@ -6880,16 +7218,16 @@ async function privacyAction() {
|
|
|
6880
7218
|
],
|
|
6881
7219
|
required: false
|
|
6882
7220
|
});
|
|
6883
|
-
if (
|
|
7221
|
+
if (p36.isCancel(personalInfo)) onCancel();
|
|
6884
7222
|
const contact = await contactMethods("privacy");
|
|
6885
|
-
const tracking = await
|
|
7223
|
+
const tracking = await p36.select({
|
|
6886
7224
|
message: "Do you use tracking and/or analytics tools, such as Google Analytics?",
|
|
6887
7225
|
options: [
|
|
6888
7226
|
{ value: "yes", label: "Yes, we use Google Analytics or other related tools" },
|
|
6889
7227
|
{ value: "no", label: "No" }
|
|
6890
7228
|
]
|
|
6891
7229
|
});
|
|
6892
|
-
if (
|
|
7230
|
+
if (p36.isCancel(tracking)) onCancel();
|
|
6893
7231
|
let trackingTools;
|
|
6894
7232
|
if (tracking === "yes") {
|
|
6895
7233
|
trackingTools = await promptWithCustom(
|
|
@@ -6908,7 +7246,7 @@ async function privacyAction() {
|
|
|
6908
7246
|
"Enter your custom tracking/analytics tool name"
|
|
6909
7247
|
);
|
|
6910
7248
|
}
|
|
6911
|
-
const sendEmails = await
|
|
7249
|
+
const sendEmails = await p36.select({
|
|
6912
7250
|
message: "Do you send emails to users?",
|
|
6913
7251
|
options: [
|
|
6914
7252
|
{
|
|
@@ -6918,7 +7256,7 @@ async function privacyAction() {
|
|
|
6918
7256
|
{ value: "no", label: "No" }
|
|
6919
7257
|
]
|
|
6920
7258
|
});
|
|
6921
|
-
if (
|
|
7259
|
+
if (p36.isCancel(sendEmails)) onCancel();
|
|
6922
7260
|
let emailPlatforms;
|
|
6923
7261
|
if (sendEmails === "yes") {
|
|
6924
7262
|
emailPlatforms = await promptWithCustom(
|
|
@@ -6933,14 +7271,14 @@ async function privacyAction() {
|
|
|
6933
7271
|
"Enter your custom email platform"
|
|
6934
7272
|
);
|
|
6935
7273
|
}
|
|
6936
|
-
const showAds = await
|
|
7274
|
+
const showAds = await p36.select({
|
|
6937
7275
|
message: "Do you show ads?",
|
|
6938
7276
|
options: [
|
|
6939
7277
|
{ value: "yes", label: "Yes, we show ads" },
|
|
6940
7278
|
{ value: "no", label: "No" }
|
|
6941
7279
|
]
|
|
6942
7280
|
});
|
|
6943
|
-
if (
|
|
7281
|
+
if (p36.isCancel(showAds)) onCancel();
|
|
6944
7282
|
let adsPlatforms;
|
|
6945
7283
|
if (showAds === "yes") {
|
|
6946
7284
|
adsPlatforms = await promptWithCustom(
|
|
@@ -6963,7 +7301,7 @@ async function privacyAction() {
|
|
|
6963
7301
|
"Enter your custom ads platform"
|
|
6964
7302
|
);
|
|
6965
7303
|
}
|
|
6966
|
-
const canPay = await
|
|
7304
|
+
const canPay = await p36.select({
|
|
6967
7305
|
message: "Can users pay for products or services?",
|
|
6968
7306
|
options: [
|
|
6969
7307
|
{ value: "yes", label: "Yes, users can pay for our products/services" },
|
|
@@ -6973,7 +7311,7 @@ async function privacyAction() {
|
|
|
6973
7311
|
}
|
|
6974
7312
|
]
|
|
6975
7313
|
});
|
|
6976
|
-
if (
|
|
7314
|
+
if (p36.isCancel(canPay)) onCancel();
|
|
6977
7315
|
let paymentProcessors;
|
|
6978
7316
|
if (canPay === "yes") {
|
|
6979
7317
|
paymentProcessors = await promptWithCustom(
|
|
@@ -7004,14 +7342,14 @@ async function privacyAction() {
|
|
|
7004
7342
|
"Enter your custom payment processor/method"
|
|
7005
7343
|
);
|
|
7006
7344
|
}
|
|
7007
|
-
const remarketing = await
|
|
7345
|
+
const remarketing = await p36.select({
|
|
7008
7346
|
message: "Do you use remarketing services for marketing & advertising purposes?",
|
|
7009
7347
|
options: [
|
|
7010
7348
|
{ value: "yes", label: "Yes, we use remarketing services to advertise our business" },
|
|
7011
7349
|
{ value: "no", label: "No" }
|
|
7012
7350
|
]
|
|
7013
7351
|
});
|
|
7014
|
-
if (
|
|
7352
|
+
if (p36.isCancel(remarketing)) onCancel();
|
|
7015
7353
|
let remarketingPlatforms;
|
|
7016
7354
|
if (remarketing === "yes") {
|
|
7017
7355
|
remarketingPlatforms = await promptWithCustom(
|
|
@@ -7030,7 +7368,7 @@ async function privacyAction() {
|
|
|
7030
7368
|
"Enter your custom remarketing platform"
|
|
7031
7369
|
);
|
|
7032
7370
|
}
|
|
7033
|
-
const providersRaw = await
|
|
7371
|
+
const providersRaw = await p36.multiselect({
|
|
7034
7372
|
message: "Select if you use any of the following providers",
|
|
7035
7373
|
options: [
|
|
7036
7374
|
{ value: "recaptcha", label: "Invisible reCAPTCHA" },
|
|
@@ -7041,16 +7379,16 @@ async function privacyAction() {
|
|
|
7041
7379
|
],
|
|
7042
7380
|
required: false
|
|
7043
7381
|
});
|
|
7044
|
-
if (
|
|
7382
|
+
if (p36.isCancel(providersRaw)) onCancel();
|
|
7045
7383
|
const providers = providersRaw;
|
|
7046
7384
|
if (providers.includes("custom")) {
|
|
7047
|
-
const custom = await
|
|
7048
|
-
if (
|
|
7385
|
+
const custom = await p36.text({ message: "Enter your custom provider" });
|
|
7386
|
+
if (p36.isCancel(custom)) onCancel();
|
|
7049
7387
|
const idx = providers.indexOf("custom");
|
|
7050
7388
|
if (idx !== -1) providers.splice(idx, 1);
|
|
7051
7389
|
if (custom) providers.push(String(custom));
|
|
7052
7390
|
}
|
|
7053
|
-
const usStates = await
|
|
7391
|
+
const usStates = await p36.select({
|
|
7054
7392
|
message: "Include U.S. state privacy rights (CCPA/CPRA, VCDPA, CPA, CTDPA, UCPA, TX, OR, etc.)?",
|
|
7055
7393
|
options: [
|
|
7056
7394
|
{
|
|
@@ -7061,55 +7399,55 @@ async function privacyAction() {
|
|
|
7061
7399
|
],
|
|
7062
7400
|
initialValue: "yes"
|
|
7063
7401
|
});
|
|
7064
|
-
if (
|
|
7065
|
-
const gdpr = await
|
|
7402
|
+
if (p36.isCancel(usStates)) onCancel();
|
|
7403
|
+
const gdpr = await p36.select({
|
|
7066
7404
|
message: "Do you want your Privacy Policy to include GDPR / UK GDPR wording?",
|
|
7067
7405
|
options: [
|
|
7068
7406
|
{ value: "yes", label: "Yes. Include GDPR rights for EEA, UK, and Swiss residents" },
|
|
7069
7407
|
{ value: "no", label: "No" }
|
|
7070
7408
|
]
|
|
7071
7409
|
});
|
|
7072
|
-
if (
|
|
7410
|
+
if (p36.isCancel(gdpr)) onCancel();
|
|
7073
7411
|
let facebookFanPage = "no";
|
|
7074
7412
|
const facebookDetails = { name: "", url: "" };
|
|
7075
7413
|
if (gdpr === "yes") {
|
|
7076
|
-
const fan = await
|
|
7414
|
+
const fan = await p36.select({
|
|
7077
7415
|
message: "Do you have a Facebook Fan Page?",
|
|
7078
7416
|
options: [
|
|
7079
7417
|
{ value: "yes", label: "Yes, we have a Facebook Fan Page" },
|
|
7080
7418
|
{ value: "no", label: "No" }
|
|
7081
7419
|
]
|
|
7082
7420
|
});
|
|
7083
|
-
if (
|
|
7421
|
+
if (p36.isCancel(fan)) onCancel();
|
|
7084
7422
|
facebookFanPage = fan;
|
|
7085
7423
|
if (facebookFanPage === "yes") {
|
|
7086
|
-
const name = await
|
|
7424
|
+
const name = await p36.text({
|
|
7087
7425
|
message: "What is the name of the Facebook Fan Page?",
|
|
7088
7426
|
placeholder: "My Facebook Page"
|
|
7089
7427
|
});
|
|
7090
|
-
if (
|
|
7428
|
+
if (p36.isCancel(name)) onCancel();
|
|
7091
7429
|
facebookDetails.name = name;
|
|
7092
|
-
const url = await
|
|
7430
|
+
const url = await p36.text({
|
|
7093
7431
|
message: "What is the URL of the Facebook Fan Page?",
|
|
7094
7432
|
placeholder: "https://facebook.com/my-facebook-page"
|
|
7095
7433
|
});
|
|
7096
|
-
if (
|
|
7434
|
+
if (p36.isCancel(url)) onCancel();
|
|
7097
7435
|
facebookDetails.url = url;
|
|
7098
7436
|
}
|
|
7099
7437
|
}
|
|
7100
|
-
const kids = await
|
|
7438
|
+
const kids = await p36.select({
|
|
7101
7439
|
message: "Do you collect information from kids under the age of 13?",
|
|
7102
7440
|
options: [
|
|
7103
7441
|
{ value: "yes", label: "Yes. We collect information from children under the age of 13" },
|
|
7104
7442
|
{ value: "no", label: "No" }
|
|
7105
7443
|
]
|
|
7106
7444
|
});
|
|
7107
|
-
if (
|
|
7108
|
-
const retention = await
|
|
7445
|
+
if (p36.isCancel(kids)) onCancel();
|
|
7446
|
+
const retention = await p36.text({
|
|
7109
7447
|
message: "How long do you retain personal information? (leave blank for default wording)",
|
|
7110
7448
|
placeholder: "e.g. 12 months after account closure"
|
|
7111
7449
|
});
|
|
7112
|
-
if (
|
|
7450
|
+
if (p36.isCancel(retention)) onCancel();
|
|
7113
7451
|
const html = generatePrivacyHtml({
|
|
7114
7452
|
core,
|
|
7115
7453
|
personalInfo: personalInfo ?? [],
|
|
@@ -7164,16 +7502,16 @@ async function privacyAction() {
|
|
|
7164
7502
|
]
|
|
7165
7503
|
});
|
|
7166
7504
|
}
|
|
7167
|
-
var privacy = new
|
|
7505
|
+
var privacy = new Command51("privacy").description("generate placeholder privacy policy").configureHelp(helpConfig).action(() => runCommand(privacyAction, "Failed to generate privacy policy."));
|
|
7168
7506
|
|
|
7169
7507
|
// src/commands/legal.ts
|
|
7170
|
-
var legal = new
|
|
7508
|
+
var legal = new Command52("legal").description("generate placeholder legal documents").configureHelp(helpConfig).addCommand(terms).addCommand(privacy);
|
|
7171
7509
|
|
|
7172
7510
|
// src/commands/fixtures.ts
|
|
7173
|
-
import { Command as
|
|
7511
|
+
import { Command as Command58 } from "commander";
|
|
7174
7512
|
|
|
7175
7513
|
// src/commands/fixtures/load.ts
|
|
7176
|
-
import { Command as
|
|
7514
|
+
import { Command as Command53 } from "commander";
|
|
7177
7515
|
|
|
7178
7516
|
// src/lib/data.ts
|
|
7179
7517
|
import fs28 from "node:fs";
|
|
@@ -7363,7 +7701,7 @@ async function hasLoadedFixtures(pb) {
|
|
|
7363
7701
|
}
|
|
7364
7702
|
|
|
7365
7703
|
// src/commands/fixtures/load.ts
|
|
7366
|
-
var load = new
|
|
7704
|
+
var load = new Command53("load").description("load fixtures into the database").configureHelp(helpConfig).action(
|
|
7367
7705
|
() => runCommand(async () => {
|
|
7368
7706
|
const { workspaceRootDir } = await getWorkspace();
|
|
7369
7707
|
let loaded = [];
|
|
@@ -7389,8 +7727,8 @@ var load = new Command52("load").description("load fixtures into the database").
|
|
|
7389
7727
|
);
|
|
7390
7728
|
|
|
7391
7729
|
// src/commands/fixtures/clear.ts
|
|
7392
|
-
import { Command as
|
|
7393
|
-
var clear = new
|
|
7730
|
+
import { Command as Command54 } from "commander";
|
|
7731
|
+
var clear = new Command54("clear").description("clear loaded fixtures").configureHelp(helpConfig).action(
|
|
7394
7732
|
() => runCommand(async () => {
|
|
7395
7733
|
const { workspaceRootDir } = await getWorkspace();
|
|
7396
7734
|
let cleared = [];
|
|
@@ -7419,8 +7757,8 @@ var clear = new Command53("clear").description("clear loaded fixtures").configur
|
|
|
7419
7757
|
);
|
|
7420
7758
|
|
|
7421
7759
|
// src/commands/fixtures/reset.ts
|
|
7422
|
-
import { Command as
|
|
7423
|
-
var reset = new
|
|
7760
|
+
import { Command as Command55 } from "commander";
|
|
7761
|
+
var reset = new Command55("reset").description("clear and reload fixtures").configureHelp(helpConfig).action(
|
|
7424
7762
|
() => runCommand(async () => {
|
|
7425
7763
|
const { workspaceRootDir } = await getWorkspace();
|
|
7426
7764
|
let cleared = [];
|
|
@@ -7452,8 +7790,8 @@ var reset = new Command54("reset").description("clear and reload fixtures").conf
|
|
|
7452
7790
|
// src/commands/fixtures/generate.ts
|
|
7453
7791
|
import fs29 from "node:fs";
|
|
7454
7792
|
import path26 from "node:path";
|
|
7455
|
-
import { Command as
|
|
7456
|
-
import * as
|
|
7793
|
+
import { Command as Command56, InvalidArgumentError } from "commander";
|
|
7794
|
+
import * as p37 from "@clack/prompts";
|
|
7457
7795
|
import { annotate } from "annotate-json-schema";
|
|
7458
7796
|
import { createGenerator } from "json-schema-faker";
|
|
7459
7797
|
import { faker } from "@faker-js/faker";
|
|
@@ -7563,7 +7901,7 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
|
7563
7901
|
}
|
|
7564
7902
|
return { writtenFiles, warnings };
|
|
7565
7903
|
}
|
|
7566
|
-
var generate2 = new
|
|
7904
|
+
var generate2 = new Command56("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(
|
|
7567
7905
|
(opts) => runCommand(async () => {
|
|
7568
7906
|
const { workspaceRootDir } = await getWorkspace();
|
|
7569
7907
|
const existing = getFixtureFiles(workspaceRootDir);
|
|
@@ -7592,7 +7930,7 @@ var generate2 = new Command55("generate").description("generate fixture data").o
|
|
|
7592
7930
|
seed: opts.seed
|
|
7593
7931
|
});
|
|
7594
7932
|
});
|
|
7595
|
-
for (const warning of result.warnings)
|
|
7933
|
+
for (const warning of result.warnings) p37.log.warn(warning);
|
|
7596
7934
|
if (result.writtenFiles.length === 0) {
|
|
7597
7935
|
reportResult({
|
|
7598
7936
|
summary: "No eligible collections found to generate fixtures for.",
|
|
@@ -7616,8 +7954,8 @@ var generate2 = new Command55("generate").description("generate fixture data").o
|
|
|
7616
7954
|
);
|
|
7617
7955
|
|
|
7618
7956
|
// src/commands/fixtures/regen.ts
|
|
7619
|
-
import { Command as
|
|
7620
|
-
import * as
|
|
7957
|
+
import { Command as Command57, InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
7958
|
+
import * as p38 from "@clack/prompts";
|
|
7621
7959
|
function parseCount2(value) {
|
|
7622
7960
|
const n = parseInt(value, 10);
|
|
7623
7961
|
if (!Number.isFinite(n) || n <= 0 || n > 999) {
|
|
@@ -7632,7 +7970,7 @@ function parseSeed2(value) {
|
|
|
7632
7970
|
}
|
|
7633
7971
|
return n;
|
|
7634
7972
|
}
|
|
7635
|
-
var regen = new
|
|
7973
|
+
var regen = new Command57("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(
|
|
7636
7974
|
(opts) => runCommand(async () => {
|
|
7637
7975
|
const { workspaceRootDir } = await getWorkspace();
|
|
7638
7976
|
let cleared = [];
|
|
@@ -7646,7 +7984,7 @@ var regen = new Command56("regen").description("clear the database, regenerate f
|
|
|
7646
7984
|
});
|
|
7647
7985
|
loaded = await loadFixtures(pb, workspaceRootDir);
|
|
7648
7986
|
});
|
|
7649
|
-
for (const warning of result.warnings)
|
|
7987
|
+
for (const warning of result.warnings) p38.log.warn(warning);
|
|
7650
7988
|
reportResult({
|
|
7651
7989
|
summary: `Regenerated fixtures (${loaded.length} collection(s) reloaded).`,
|
|
7652
7990
|
filesCreated: result.writtenFiles,
|
|
@@ -7661,14 +7999,14 @@ var regen = new Command56("regen").description("clear the database, regenerate f
|
|
|
7661
7999
|
);
|
|
7662
8000
|
|
|
7663
8001
|
// src/commands/fixtures.ts
|
|
7664
|
-
var fixtures = new
|
|
8002
|
+
var fixtures = new Command58("fixtures").description("manage fixture data").configureHelp(helpConfig).addCommand(generate2).addCommand(load).addCommand(clear).addCommand(reset).addCommand(regen);
|
|
7665
8003
|
|
|
7666
8004
|
// src/commands/seeds.ts
|
|
7667
|
-
import { Command as
|
|
8005
|
+
import { Command as Command62 } from "commander";
|
|
7668
8006
|
|
|
7669
8007
|
// src/commands/seeds/load.ts
|
|
7670
|
-
import { Command as
|
|
7671
|
-
var load2 = new
|
|
8008
|
+
import { Command as Command59 } from "commander";
|
|
8009
|
+
var load2 = new Command59("load").description("load seeds into the database").option("-f, --force", "load even if target collections already have records").configureHelp(helpConfig).action(
|
|
7672
8010
|
(opts) => runCommand(async () => {
|
|
7673
8011
|
const { workspaceRootDir } = await getWorkspace();
|
|
7674
8012
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -7707,7 +8045,7 @@ var load2 = new Command58("load").description("load seeds into the database").op
|
|
|
7707
8045
|
// src/commands/seeds/save.ts
|
|
7708
8046
|
import fs30 from "node:fs";
|
|
7709
8047
|
import path27 from "node:path";
|
|
7710
|
-
import { Command as
|
|
8048
|
+
import { Command as Command60 } from "commander";
|
|
7711
8049
|
var padZeros2 = (num, length) => num.toString().padStart(length, "0");
|
|
7712
8050
|
function filterSystemFields(record, systemFieldNames) {
|
|
7713
8051
|
const out = {};
|
|
@@ -7718,7 +8056,7 @@ function filterSystemFields(record, systemFieldNames) {
|
|
|
7718
8056
|
}
|
|
7719
8057
|
return out;
|
|
7720
8058
|
}
|
|
7721
|
-
var save = new
|
|
8059
|
+
var save = new Command60("save").description("save the current data as seeds").option("-f, --force", "overwrite existing seed files").configureHelp(helpConfig).action(
|
|
7722
8060
|
(opts) => runCommand(async () => {
|
|
7723
8061
|
const { workspaceRootDir } = await getWorkspace();
|
|
7724
8062
|
const seedsPath = dataDir(workspaceRootDir, "seeds");
|
|
@@ -7790,8 +8128,8 @@ var save = new Command59("save").description("save the current data as seeds").o
|
|
|
7790
8128
|
);
|
|
7791
8129
|
|
|
7792
8130
|
// src/commands/seeds/clear.ts
|
|
7793
|
-
import { Command as
|
|
7794
|
-
var clear2 = new
|
|
8131
|
+
import { Command as Command61 } from "commander";
|
|
8132
|
+
var clear2 = new Command61("clear").description("clear seeded records").configureHelp(helpConfig).action(
|
|
7795
8133
|
() => runCommand(async () => {
|
|
7796
8134
|
const { workspaceRootDir } = await getWorkspace();
|
|
7797
8135
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -7822,91 +8160,18 @@ var clear2 = new Command60("clear").description("clear seeded records").configur
|
|
|
7822
8160
|
);
|
|
7823
8161
|
|
|
7824
8162
|
// src/commands/seeds.ts
|
|
7825
|
-
var seeds = new
|
|
8163
|
+
var seeds = new Command62("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
|
|
7826
8164
|
|
|
7827
8165
|
// src/commands/signup.ts
|
|
7828
8166
|
import { Command as Command63 } from "commander";
|
|
7829
|
-
import * as
|
|
8167
|
+
import * as p39 from "@clack/prompts";
|
|
7830
8168
|
import makeFetchCookie2 from "fetch-cookie";
|
|
7831
|
-
|
|
7832
|
-
// src/commands/login.ts
|
|
7833
|
-
import os4 from "node:os";
|
|
7834
|
-
import { Command as Command62 } from "commander";
|
|
7835
|
-
import * as p37 from "@clack/prompts";
|
|
7836
|
-
import makeFetchCookie from "fetch-cookie";
|
|
7837
|
-
var login = new Command62("login").description("login to velastack.dev").configureHelp(helpConfig).action(
|
|
7838
|
-
() => runCommand(async () => {
|
|
7839
|
-
const { email: email3, password: password11 } = await p37.group({
|
|
7840
|
-
email: () => p37.text({ message: "Email" }),
|
|
7841
|
-
password: () => p37.password({ message: "Password" })
|
|
7842
|
-
});
|
|
7843
|
-
const fetchCookie = makeFetchCookie(fetch);
|
|
7844
|
-
const loginRes = await fetchCookie(`${API_URL}/login`, {
|
|
7845
|
-
method: "POST",
|
|
7846
|
-
headers: {
|
|
7847
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
7848
|
-
Origin: API_URL
|
|
7849
|
-
},
|
|
7850
|
-
body: new URLSearchParams({
|
|
7851
|
-
type: "password",
|
|
7852
|
-
email: email3,
|
|
7853
|
-
password: password11
|
|
7854
|
-
}).toString()
|
|
7855
|
-
});
|
|
7856
|
-
if (!loginRes.headers.get("Set-Cookie")) {
|
|
7857
|
-
throw new Error(
|
|
7858
|
-
"Run `vela signup` to create an account or reset at https://velastack.dev/reset"
|
|
7859
|
-
);
|
|
7860
|
-
}
|
|
7861
|
-
const apiKey = await issueApiKey(fetchCookie);
|
|
7862
|
-
writeConfig({ apiKey });
|
|
7863
|
-
p37.log.success("Logged in to velastack.dev");
|
|
7864
|
-
}, "Failed to login.")
|
|
7865
|
-
);
|
|
7866
|
-
async function issueApiKey(fetchCookie) {
|
|
7867
|
-
const label4 = `CLI - ${os4.hostname()}`;
|
|
7868
|
-
await fetchCookie(`${API_URL}/api-keys/new`, {
|
|
7869
|
-
method: "POST",
|
|
7870
|
-
headers: {
|
|
7871
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
7872
|
-
Origin: API_URL
|
|
7873
|
-
},
|
|
7874
|
-
body: new URLSearchParams({ label: label4 }).toString()
|
|
7875
|
-
});
|
|
7876
|
-
const cookie = await fetchCookie.cookieJar.getCookieString(API_URL);
|
|
7877
|
-
const apiKey = extractApiKey(cookie);
|
|
7878
|
-
if (!apiKey) {
|
|
7879
|
-
throw new Error("Failed to create API key. Try again or contact support.");
|
|
7880
|
-
}
|
|
7881
|
-
const [id] = apiKey.split(".");
|
|
7882
|
-
const res = await fetchCookie(`${API_URL}/api/collections/api_keys/records`, {
|
|
7883
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
7884
|
-
});
|
|
7885
|
-
const data = await res.json();
|
|
7886
|
-
for (const item of data.items) {
|
|
7887
|
-
if (item.label === label4 && item.id !== id) {
|
|
7888
|
-
await fetchCookie(`${API_URL}/api/collections/api_keys/records/${item.id}`, {
|
|
7889
|
-
method: "DELETE",
|
|
7890
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
7891
|
-
});
|
|
7892
|
-
}
|
|
7893
|
-
}
|
|
7894
|
-
return apiKey;
|
|
7895
|
-
}
|
|
7896
|
-
function extractApiKey(cookie) {
|
|
7897
|
-
const flashCookie = cookie.split(";").find((c) => c.trim().startsWith("flash="));
|
|
7898
|
-
if (!flashCookie) return null;
|
|
7899
|
-
const decoded = decodeURIComponent(flashCookie.split("=")[1]);
|
|
7900
|
-
return JSON.parse(decoded).apiKey;
|
|
7901
|
-
}
|
|
7902
|
-
|
|
7903
|
-
// src/commands/signup.ts
|
|
7904
8169
|
var signup = new Command63("signup").description("signup to velastack.dev").configureHelp(helpConfig).action(
|
|
7905
8170
|
() => runCommand(async () => {
|
|
7906
|
-
const { email: email3, password: password11, passwordConfirm } = await
|
|
7907
|
-
email: () =>
|
|
7908
|
-
password: () =>
|
|
7909
|
-
passwordConfirm: () =>
|
|
8171
|
+
const { email: email3, password: password11, passwordConfirm } = await p39.group({
|
|
8172
|
+
email: () => p39.text({ message: "Email" }),
|
|
8173
|
+
password: () => p39.password({ message: "Password" }),
|
|
8174
|
+
passwordConfirm: () => p39.password({ message: "Confirm password" })
|
|
7910
8175
|
});
|
|
7911
8176
|
if (password11 !== passwordConfirm) {
|
|
7912
8177
|
throw new Error("Passwords do not match.");
|
|
@@ -7930,33 +8195,33 @@ var signup = new Command63("signup").description("signup to velastack.dev").conf
|
|
|
7930
8195
|
}
|
|
7931
8196
|
const apiKey = await issueApiKey(fetchCookie);
|
|
7932
8197
|
writeConfig({ apiKey });
|
|
7933
|
-
|
|
7934
|
-
|
|
8198
|
+
p39.log.success("Signed up to velastack.dev");
|
|
8199
|
+
p39.log.info("Check your email for a confirmation link.");
|
|
7935
8200
|
}, "Failed to signup.")
|
|
7936
8201
|
);
|
|
7937
8202
|
|
|
7938
8203
|
// src/commands/logout.ts
|
|
7939
8204
|
import { Command as Command64 } from "commander";
|
|
7940
|
-
import * as
|
|
8205
|
+
import * as p40 from "@clack/prompts";
|
|
7941
8206
|
var logout = new Command64("logout").alias("signout").description("logout from velastack.dev").configureHelp(helpConfig).action(
|
|
7942
8207
|
() => runCommand(() => {
|
|
7943
8208
|
if (!readConfig()) {
|
|
7944
|
-
|
|
8209
|
+
p40.log.info("Not logged in");
|
|
7945
8210
|
return;
|
|
7946
8211
|
}
|
|
7947
8212
|
clearConfig();
|
|
7948
|
-
|
|
8213
|
+
p40.log.success("Logged out of velastack.dev");
|
|
7949
8214
|
})
|
|
7950
8215
|
);
|
|
7951
8216
|
|
|
7952
8217
|
// src/commands/whoami.ts
|
|
7953
8218
|
import { Command as Command65 } from "commander";
|
|
7954
|
-
import * as
|
|
8219
|
+
import * as p41 from "@clack/prompts";
|
|
7955
8220
|
var whoami = new Command65("whoami").description("show the current user").configureHelp(helpConfig).action(
|
|
7956
8221
|
() => runCommand(async () => {
|
|
7957
8222
|
const apiKey = readConfig()?.apiKey;
|
|
7958
8223
|
if (!apiKey) {
|
|
7959
|
-
|
|
8224
|
+
p41.log.info("Not logged in. Run `vela login` to login.");
|
|
7960
8225
|
return;
|
|
7961
8226
|
}
|
|
7962
8227
|
const res = await fetch(`${API_URL}/api/collections/users/records`, {
|
|
@@ -7964,7 +8229,7 @@ var whoami = new Command65("whoami").description("show the current user").config
|
|
|
7964
8229
|
});
|
|
7965
8230
|
const data = await res.json();
|
|
7966
8231
|
if (!data.items.length) throw new Error("No user found. Run `vela login` to login.");
|
|
7967
|
-
|
|
8232
|
+
p41.log.success(`Logged in as ${data.items[0].email}`);
|
|
7968
8233
|
})
|
|
7969
8234
|
);
|
|
7970
8235
|
|
|
@@ -7976,10 +8241,10 @@ import { Command as Command66 } from "commander";
|
|
|
7976
8241
|
|
|
7977
8242
|
// src/lib/migrate.ts
|
|
7978
8243
|
import path28 from "node:path";
|
|
7979
|
-
import
|
|
8244
|
+
import process23 from "node:process";
|
|
7980
8245
|
import { x as x2 } from "tinyexec";
|
|
7981
8246
|
async function runPocketbaseMigrate(args) {
|
|
7982
|
-
const cwd =
|
|
8247
|
+
const cwd = process23.cwd();
|
|
7983
8248
|
const { getBinaryPath } = await import("pocketbase-server");
|
|
7984
8249
|
const binaryPath = getBinaryPath();
|
|
7985
8250
|
await x2(
|
|
@@ -8038,11 +8303,11 @@ var down = new Command67("down").alias("rollback").description("revert the last
|
|
|
8038
8303
|
// src/commands/migrate/create.ts
|
|
8039
8304
|
import fs31 from "node:fs";
|
|
8040
8305
|
import path29 from "node:path";
|
|
8041
|
-
import
|
|
8306
|
+
import process24 from "node:process";
|
|
8042
8307
|
import { Command as Command68 } from "commander";
|
|
8043
8308
|
var create2 = new Command68("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
|
|
8044
8309
|
(name) => runCommand(async () => {
|
|
8045
|
-
const cwd =
|
|
8310
|
+
const cwd = process24.cwd();
|
|
8046
8311
|
const before = listMigrationFiles(cwd);
|
|
8047
8312
|
await runPocketbaseMigrate(["create", name]);
|
|
8048
8313
|
const after = listMigrationFiles(cwd);
|
|
@@ -8066,11 +8331,11 @@ function listMigrationFiles(cwd) {
|
|
|
8066
8331
|
// src/commands/migrate/collections.ts
|
|
8067
8332
|
import fs32 from "node:fs";
|
|
8068
8333
|
import path30 from "node:path";
|
|
8069
|
-
import
|
|
8334
|
+
import process25 from "node:process";
|
|
8070
8335
|
import { Command as Command69 } from "commander";
|
|
8071
8336
|
var collections = new Command69("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
|
|
8072
8337
|
() => runCommand(async () => {
|
|
8073
|
-
const cwd =
|
|
8338
|
+
const cwd = process25.cwd();
|
|
8074
8339
|
const before = listMigrationFiles2(cwd);
|
|
8075
8340
|
await runPocketbaseMigrate(["collections"]);
|
|
8076
8341
|
const after = listMigrationFiles2(cwd);
|
|
@@ -8116,7 +8381,7 @@ var migrate = new Command71("migrate").description("manage database migrations")
|
|
|
8116
8381
|
// src/commands/dev.ts
|
|
8117
8382
|
import fs33 from "node:fs";
|
|
8118
8383
|
import path32 from "node:path";
|
|
8119
|
-
import
|
|
8384
|
+
import process27 from "node:process";
|
|
8120
8385
|
import { performance } from "node:perf_hooks";
|
|
8121
8386
|
import { Command as Command72, InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
8122
8387
|
import pc15 from "picocolors";
|
|
@@ -8124,7 +8389,7 @@ import PocketBase4 from "pocketbase";
|
|
|
8124
8389
|
|
|
8125
8390
|
// src/lib/vite.ts
|
|
8126
8391
|
import path31 from "node:path";
|
|
8127
|
-
import
|
|
8392
|
+
import process26 from "node:process";
|
|
8128
8393
|
import { createRequire as createRequire2 } from "node:module";
|
|
8129
8394
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
8130
8395
|
import pc14 from "picocolors";
|
|
@@ -8148,13 +8413,13 @@ function resolveProjectVite(cwd) {
|
|
|
8148
8413
|
return null;
|
|
8149
8414
|
}
|
|
8150
8415
|
}
|
|
8151
|
-
async function loadVite(cwd =
|
|
8416
|
+
async function loadVite(cwd = process26.cwd()) {
|
|
8152
8417
|
const entry = resolveProjectVite(cwd);
|
|
8153
8418
|
const vite = entry ? await import(pathToFileURL2(entry).href) : await import("vite");
|
|
8154
8419
|
const error = viteVersionError(vite.version);
|
|
8155
8420
|
if (error) {
|
|
8156
8421
|
console.error(`${pc14.redBright("\u2717")} ${error}`);
|
|
8157
|
-
|
|
8422
|
+
process26.exit(1);
|
|
8158
8423
|
}
|
|
8159
8424
|
return vite;
|
|
8160
8425
|
}
|
|
@@ -8168,15 +8433,15 @@ function parsePort(value) {
|
|
|
8168
8433
|
return port;
|
|
8169
8434
|
}
|
|
8170
8435
|
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 =
|
|
8172
|
-
|
|
8436
|
+
const cwd = process27.cwd();
|
|
8437
|
+
process27.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
8173
8438
|
const startTime = performance.now();
|
|
8174
8439
|
const { createServer, version } = await loadVite(cwd);
|
|
8175
8440
|
const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
|
|
8176
8441
|
const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
|
|
8177
8442
|
let pbProc;
|
|
8178
8443
|
const backend3 = hasBackend(cwd);
|
|
8179
|
-
const needsStart = backend3 && !
|
|
8444
|
+
const needsStart = backend3 && !process27.env.POCKETBASE_URL;
|
|
8180
8445
|
const cleanup = () => {
|
|
8181
8446
|
if (pbProc?.pid) pbProc.kill();
|
|
8182
8447
|
if (fs33.existsSync(viteMetadataFile)) fs33.rmSync(viteMetadataFile);
|
|
@@ -8191,15 +8456,15 @@ var dev = new Command72("dev").description("start the development server").optio
|
|
|
8191
8456
|
stdio: "pipe"
|
|
8192
8457
|
});
|
|
8193
8458
|
pbProc = started.proc;
|
|
8194
|
-
|
|
8195
|
-
pbProc.stdout?.pipe(
|
|
8196
|
-
pbProc.stderr?.pipe(
|
|
8459
|
+
process27.env.POCKETBASE_URL = started.url;
|
|
8460
|
+
pbProc.stdout?.pipe(process27.stdout);
|
|
8461
|
+
pbProc.stderr?.pipe(process27.stderr);
|
|
8197
8462
|
pbProc.on("error", (err) => console.error("PocketBase error:", err));
|
|
8198
8463
|
pbProc.on("exit", (code) => console.log(`PocketBase exited with code ${code}`));
|
|
8199
|
-
|
|
8200
|
-
|
|
8464
|
+
process27.on("exit", cleanup);
|
|
8465
|
+
process27.on("SIGINT", () => {
|
|
8201
8466
|
cleanup();
|
|
8202
|
-
|
|
8467
|
+
process27.exit(0);
|
|
8203
8468
|
});
|
|
8204
8469
|
}
|
|
8205
8470
|
const serverOptions = {};
|
|
@@ -8221,21 +8486,21 @@ var dev = new Command72("dev").description("start the development server").optio
|
|
|
8221
8486
|
await fs33.promises.writeFile(
|
|
8222
8487
|
viteMetadataFile,
|
|
8223
8488
|
JSON.stringify({
|
|
8224
|
-
pocketbaseUrl:
|
|
8489
|
+
pocketbaseUrl: process27.env.POCKETBASE_URL,
|
|
8225
8490
|
vitePort,
|
|
8226
8491
|
viteHost
|
|
8227
8492
|
})
|
|
8228
8493
|
);
|
|
8229
|
-
const pb = new PocketBase4(
|
|
8494
|
+
const pb = new PocketBase4(process27.env.POCKETBASE_URL);
|
|
8230
8495
|
await pb.collection("_superusers").authWithPassword(
|
|
8231
|
-
|
|
8232
|
-
|
|
8496
|
+
process27.env.POCKETBASE_SUPERUSER_EMAIL,
|
|
8497
|
+
process27.env.POCKETBASE_SUPERUSER_PASSWORD
|
|
8233
8498
|
);
|
|
8234
8499
|
await pb.settings.update({ meta: { appURL: `http://${viteHost}:${vitePort}` } });
|
|
8235
8500
|
await startWatchingTypes(cwd, pb);
|
|
8236
8501
|
});
|
|
8237
8502
|
await server.listen();
|
|
8238
|
-
const hasExistingLogs =
|
|
8503
|
+
const hasExistingLogs = process27.stdout.bytesWritten > 0 || process27.stderr.bytesWritten > 0;
|
|
8239
8504
|
const startupDurationString = pc15.dim(
|
|
8240
8505
|
`ready in ${pc15.reset(pc15.bold(Math.ceil(performance.now() - startTime)))} ms`
|
|
8241
8506
|
);
|
|
@@ -8275,9 +8540,9 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
8275
8540
|
// src/commands/build.ts
|
|
8276
8541
|
import fs34 from "node:fs";
|
|
8277
8542
|
import path33 from "node:path";
|
|
8278
|
-
import
|
|
8543
|
+
import process29 from "node:process";
|
|
8279
8544
|
import { Command as Command73 } from "commander";
|
|
8280
|
-
import * as
|
|
8545
|
+
import * as p42 from "@clack/prompts";
|
|
8281
8546
|
import pc16 from "picocolors";
|
|
8282
8547
|
import { x as x3 } from "tinyexec";
|
|
8283
8548
|
import { detect as detect5 } from "package-manager-detector";
|
|
@@ -8290,10 +8555,10 @@ function applyBuildEnv(cwd, env2 = process.env) {
|
|
|
8290
8555
|
}
|
|
8291
8556
|
|
|
8292
8557
|
// src/lib/origin.ts
|
|
8293
|
-
import
|
|
8558
|
+
import process28 from "node:process";
|
|
8294
8559
|
function resolveOrigin(workspaceRootDir, envTag, config = {}) {
|
|
8295
8560
|
return normalizeOrigin(
|
|
8296
|
-
|
|
8561
|
+
process28.env.VELA_ORIGIN ?? readBinding(workspaceRootDir, envTag)?.domain ?? config.deploy?.domain
|
|
8297
8562
|
);
|
|
8298
8563
|
}
|
|
8299
8564
|
function normalizeOrigin(value) {
|
|
@@ -8314,12 +8579,12 @@ function splitHosts(value) {
|
|
|
8314
8579
|
// src/commands/build.ts
|
|
8315
8580
|
var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
|
|
8316
8581
|
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 =
|
|
8582
|
+
const cwd = process29.cwd();
|
|
8318
8583
|
applyBuildEnv(cwd);
|
|
8319
8584
|
const origin = await originForBuild(cwd, options.target);
|
|
8320
|
-
if (origin)
|
|
8585
|
+
if (origin) process29.env.VELA_ORIGIN = origin;
|
|
8321
8586
|
let pbProc;
|
|
8322
|
-
const needsStart = hasBackend(cwd) && !
|
|
8587
|
+
const needsStart = hasBackend(cwd) && !process29.env.POCKETBASE_URL;
|
|
8323
8588
|
const cleanup = () => {
|
|
8324
8589
|
if (pbProc?.pid) pbProc.kill();
|
|
8325
8590
|
};
|
|
@@ -8333,11 +8598,11 @@ var build = new Command73("build").description("build the app").configureHelp(he
|
|
|
8333
8598
|
dev: true
|
|
8334
8599
|
});
|
|
8335
8600
|
pbProc = started.proc;
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8601
|
+
process29.env.POCKETBASE_URL = started.url;
|
|
8602
|
+
process29.on("exit", cleanup);
|
|
8603
|
+
process29.on("SIGINT", () => {
|
|
8339
8604
|
cleanup();
|
|
8340
|
-
|
|
8605
|
+
process29.exit(0);
|
|
8341
8606
|
});
|
|
8342
8607
|
}
|
|
8343
8608
|
try {
|
|
@@ -8370,7 +8635,7 @@ async function originForBuild(cwd, target) {
|
|
|
8370
8635
|
function warnIfPrerendered(cwd) {
|
|
8371
8636
|
const dir = path33.join(cwd, PRERENDERED_DIR);
|
|
8372
8637
|
if (!fs34.existsSync(dir) || fs34.readdirSync(dir).length === 0) return;
|
|
8373
|
-
|
|
8638
|
+
p42.log.warn(
|
|
8374
8639
|
`Prerendered pages were built with no domain configured, so their canonical
|
|
8375
8640
|
links point at SvelteKit's placeholder host rather than at this site.
|
|
8376
8641
|
|
|
@@ -8380,16 +8645,16 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
|
|
|
8380
8645
|
|
|
8381
8646
|
// src/commands/preview.ts
|
|
8382
8647
|
import path34 from "node:path";
|
|
8383
|
-
import
|
|
8648
|
+
import process30 from "node:process";
|
|
8384
8649
|
import { Command as Command74 } from "commander";
|
|
8385
8650
|
import { x as x4 } from "tinyexec";
|
|
8386
8651
|
import { detect as detect6 } from "package-manager-detector";
|
|
8387
8652
|
import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
|
|
8388
8653
|
var preview = new Command74("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
|
|
8389
|
-
const cwd =
|
|
8390
|
-
|
|
8654
|
+
const cwd = process30.cwd();
|
|
8655
|
+
process30.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
8391
8656
|
let pbProc;
|
|
8392
|
-
const needsStart = hasBackend(cwd) && !
|
|
8657
|
+
const needsStart = hasBackend(cwd) && !process30.env.POCKETBASE_URL;
|
|
8393
8658
|
const cleanup = () => {
|
|
8394
8659
|
if (pbProc?.pid) pbProc.kill();
|
|
8395
8660
|
};
|
|
@@ -8402,11 +8667,11 @@ var preview = new Command74("preview").description("preview the built app").conf
|
|
|
8402
8667
|
dev: true
|
|
8403
8668
|
});
|
|
8404
8669
|
pbProc = started.proc;
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8670
|
+
process30.env.POCKETBASE_URL = started.url;
|
|
8671
|
+
process30.on("exit", cleanup);
|
|
8672
|
+
process30.on("SIGINT", () => {
|
|
8408
8673
|
cleanup();
|
|
8409
|
-
|
|
8674
|
+
process30.exit(0);
|
|
8410
8675
|
});
|
|
8411
8676
|
}
|
|
8412
8677
|
try {
|
|
@@ -8440,7 +8705,7 @@ var sync = new Command75("sync").description("sync types from the database").con
|
|
|
8440
8705
|
|
|
8441
8706
|
// src/commands/provision.ts
|
|
8442
8707
|
import { Command as Command76 } from "commander";
|
|
8443
|
-
import * as
|
|
8708
|
+
import * as p43 from "@clack/prompts";
|
|
8444
8709
|
import pc17 from "picocolors";
|
|
8445
8710
|
import * as v7 from "valibot";
|
|
8446
8711
|
var OptionsSchema2 = v7.object({
|
|
@@ -8454,19 +8719,19 @@ var provision = addSshOptions(
|
|
|
8454
8719
|
(target, raw) => runCommand(async () => {
|
|
8455
8720
|
const options = parseOptions(OptionsSchema2, raw);
|
|
8456
8721
|
const pbVersion = options.pbVersion ?? pocketbaseVersion();
|
|
8457
|
-
|
|
8458
|
-
|
|
8722
|
+
p43.intro(pc17.bgCyan(pc17.black(" vela provision ")));
|
|
8723
|
+
p43.log.info(`Target ${pc17.cyan(target)}`);
|
|
8459
8724
|
await withSsh(target, sshOptionsFrom(options), async (session) => {
|
|
8460
8725
|
await session.detectElevation();
|
|
8461
8726
|
const existing = await readServerInfo(session);
|
|
8462
8727
|
if (existing) {
|
|
8463
|
-
|
|
8728
|
+
p43.log.info(
|
|
8464
8729
|
`Already provisioned by vela ${existing.cliVersion} on ${existing.provisionedAt}. Bringing it up to date.`
|
|
8465
8730
|
);
|
|
8466
8731
|
}
|
|
8467
|
-
|
|
8732
|
+
p43.log.step("Uploading server scripts");
|
|
8468
8733
|
await syncServerScripts(session);
|
|
8469
|
-
|
|
8734
|
+
p43.log.step("Running provision");
|
|
8470
8735
|
const result = await runServerScript(session, "provision.sh", {
|
|
8471
8736
|
args: [
|
|
8472
8737
|
"--pb-version",
|
|
@@ -8478,7 +8743,7 @@ var provision = addSshOptions(
|
|
|
8478
8743
|
],
|
|
8479
8744
|
stream: true
|
|
8480
8745
|
});
|
|
8481
|
-
|
|
8746
|
+
p43.log.success(
|
|
8482
8747
|
`${target} is ready.
|
|
8483
8748
|
|
|
8484
8749
|
Node ${result?.node ?? "installed"}
|
|
@@ -8486,7 +8751,7 @@ var provision = addSshOptions(
|
|
|
8486
8751
|
PocketBase ${result?.pocketbase ?? pbVersion}`
|
|
8487
8752
|
);
|
|
8488
8753
|
});
|
|
8489
|
-
|
|
8754
|
+
p43.outro(`Deploy with ${pc17.cyan(`vela deploy --server ${target}`)}`);
|
|
8490
8755
|
}, "Failed to provision.")
|
|
8491
8756
|
);
|
|
8492
8757
|
|
|
@@ -8494,21 +8759,21 @@ var provision = addSshOptions(
|
|
|
8494
8759
|
import path38 from "node:path";
|
|
8495
8760
|
import fs37 from "node:fs";
|
|
8496
8761
|
import { Command as Command77, Option as Option2 } from "commander";
|
|
8497
|
-
import * as
|
|
8762
|
+
import * as p44 from "@clack/prompts";
|
|
8498
8763
|
import pc18 from "picocolors";
|
|
8499
8764
|
import * as v8 from "valibot";
|
|
8500
8765
|
|
|
8501
8766
|
// src/lib/pocketbase-settings.ts
|
|
8502
8767
|
import fs35 from "node:fs";
|
|
8503
8768
|
import path36 from "node:path";
|
|
8504
|
-
import
|
|
8769
|
+
import process31 from "node:process";
|
|
8505
8770
|
import PocketBase5 from "pocketbase";
|
|
8506
8771
|
var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
|
|
8507
8772
|
async function readLocalMeta(cwd) {
|
|
8508
8773
|
const dataDir2 = path36.join(cwd, DATA_DIR);
|
|
8509
8774
|
if (!fs35.existsSync(dataDir2)) return null;
|
|
8510
|
-
const email3 =
|
|
8511
|
-
const password11 =
|
|
8775
|
+
const email3 = process31.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
8776
|
+
const password11 = process31.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
8512
8777
|
if (!email3 || !password11) return null;
|
|
8513
8778
|
let proc;
|
|
8514
8779
|
try {
|
|
@@ -8853,7 +9118,7 @@ var deploy = addLockWaitOption(
|
|
|
8853
9118
|
(raw) => runCommand(async () => {
|
|
8854
9119
|
const options = parseOptions(OptionsSchema3, raw);
|
|
8855
9120
|
const backend3 = hasBackend();
|
|
8856
|
-
|
|
9121
|
+
p44.intro(pc18.bgCyan(pc18.black(" vela deploy ")));
|
|
8857
9122
|
if (options.build !== false) {
|
|
8858
9123
|
const { workspaceRootDir } = await getWorkspace();
|
|
8859
9124
|
await prepareAdapter(workspaceRootDir);
|
|
@@ -8863,7 +9128,7 @@ var deploy = addLockWaitOption(
|
|
|
8863
9128
|
{
|
|
8864
9129
|
remote: async (ctx) => {
|
|
8865
9130
|
const { session, instance, workspaceRootDir, config } = ctx;
|
|
8866
|
-
|
|
9131
|
+
p44.log.info(
|
|
8867
9132
|
`${pc18.cyan(ctx.appName)} ${pc18.dim("\u2192")} ${pc18.cyan(ctx.targetName)} ${pc18.dim(`(${ctx.server})`)}`
|
|
8868
9133
|
);
|
|
8869
9134
|
const [existing] = await readInstanceStates(session, instance);
|
|
@@ -8873,7 +9138,7 @@ var deploy = addLockWaitOption(
|
|
|
8873
9138
|
const askedForRemoteDb = options.remoteDb ?? config.deploy?.buildAgainstRemote;
|
|
8874
9139
|
const remoteDb = askedForRemoteDb ?? instanceHasBackend(existing);
|
|
8875
9140
|
if (existing && instanceHasBackend(existing) !== backend3) {
|
|
8876
|
-
|
|
9141
|
+
p44.log.info(
|
|
8877
9142
|
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
9143
|
);
|
|
8879
9144
|
}
|
|
@@ -8916,7 +9181,7 @@ with DNS of your own pointing at ${ctx.server}.`
|
|
|
8916
9181
|
tunnel = await openDatabaseTunnel(session, instance, existing);
|
|
8917
9182
|
} catch (err) {
|
|
8918
9183
|
if (askedForRemoteDb) throw err;
|
|
8919
|
-
|
|
9184
|
+
p44.log.warn(
|
|
8920
9185
|
`Could not build against the ${pc18.cyan(ctx.targetName)} database, using a local one instead.
|
|
8921
9186
|
${pc18.dim(String(err))}`
|
|
8922
9187
|
);
|
|
@@ -8924,13 +9189,13 @@ ${pc18.dim(String(err))}`
|
|
|
8924
9189
|
}
|
|
8925
9190
|
if (tunnel) {
|
|
8926
9191
|
buildEnv = { ...buildEnv, ...tunnel.env };
|
|
8927
|
-
|
|
9192
|
+
p44.log.info(
|
|
8928
9193
|
`Building against the ${pc18.cyan(ctx.targetName)} database on ${ctx.server} ${pc18.dim(`(port ${tunnel.pbPort})`)}`
|
|
8929
9194
|
);
|
|
8930
9195
|
} else if (backend3) {
|
|
8931
9196
|
await ensureSuperuser(workspaceRootDir);
|
|
8932
9197
|
}
|
|
8933
|
-
|
|
9198
|
+
p44.log.step("Building");
|
|
8934
9199
|
try {
|
|
8935
9200
|
await runBuild(workspaceRootDir, config.deploy?.buildCommand, buildEnv);
|
|
8936
9201
|
} finally {
|
|
@@ -8938,9 +9203,9 @@ ${pc18.dim(String(err))}`
|
|
|
8938
9203
|
}
|
|
8939
9204
|
}
|
|
8940
9205
|
const entries = collectArtifact(workspaceRootDir, config.deploy ?? {});
|
|
8941
|
-
|
|
9206
|
+
p44.log.step(`Uploading release ${pc18.dim(release)}`);
|
|
8942
9207
|
await uploadRelease(session, instance, release, entries);
|
|
8943
|
-
|
|
9208
|
+
p44.log.step("Activating");
|
|
8944
9209
|
result = await runServerScript(session, "apply.sh", {
|
|
8945
9210
|
args: [
|
|
8946
9211
|
instance,
|
|
@@ -8991,7 +9256,7 @@ ${pc18.dim(String(err))}`
|
|
|
8991
9256
|
url: primaryHost ? url : void 0
|
|
8992
9257
|
});
|
|
8993
9258
|
const redirects = started?.environment.redirects ?? [];
|
|
8994
|
-
|
|
9259
|
+
p44.log.success(
|
|
8995
9260
|
`Deployed ${pc18.cyan(ctx.appName)} ${pc18.dim(release)}
|
|
8996
9261
|
|
|
8997
9262
|
URL ${url}
|
|
@@ -8999,7 +9264,7 @@ ${pc18.dim(String(err))}`
|
|
|
8999
9264
|
` : "") + ` Port ${result?.webPort ?? "?"}${backend3 ? ` (PocketBase ${result?.pbPort ?? "?"})` : ""}`
|
|
9000
9265
|
);
|
|
9001
9266
|
if (managed && managed !== existing?.managed) {
|
|
9002
|
-
|
|
9267
|
+
p44.log.info(`${pc18.cyan(managed)} goes live within a minute.`);
|
|
9003
9268
|
}
|
|
9004
9269
|
if (result?.superuserCreated) {
|
|
9005
9270
|
await copyLocalBranding(
|
|
@@ -9008,7 +9273,7 @@ ${pc18.dim(String(err))}`
|
|
|
9008
9273
|
workspaceRootDir,
|
|
9009
9274
|
primaryHost ? result?.url ?? "" : ""
|
|
9010
9275
|
);
|
|
9011
|
-
|
|
9276
|
+
p44.log.info(
|
|
9012
9277
|
`Created the PocketBase superuser this app authenticates as.
|
|
9013
9278
|
|
|
9014
9279
|
Its credentials are stored in the environment on the server. To use
|
|
@@ -9019,7 +9284,7 @@ and deploy again.`
|
|
|
9019
9284
|
await reportAppURLDrift(session, instance, primaryHost);
|
|
9020
9285
|
}
|
|
9021
9286
|
if (!primaryHost) {
|
|
9022
|
-
|
|
9287
|
+
p44.log.warn(
|
|
9023
9288
|
`No domain configured, so nothing is proxied to this app yet.
|
|
9024
9289
|
Redeploy with ${pc18.cyan("--domain example.com")} once DNS points at ${ctx.server}` + (reporter.enabled ? "" : `,
|
|
9025
9290
|
or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
@@ -9029,7 +9294,7 @@ or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
|
9029
9294
|
},
|
|
9030
9295
|
{ project: options.project, askDomain: true, label: "deploy" }
|
|
9031
9296
|
);
|
|
9032
|
-
|
|
9297
|
+
p44.outro(`${pc18.cyan("vela status")} to see what is running`);
|
|
9033
9298
|
}, "Failed to deploy.")
|
|
9034
9299
|
);
|
|
9035
9300
|
async function prepareAdapter(workspaceRootDir) {
|
|
@@ -9048,8 +9313,8 @@ ${pc18.cyan(err.snippet)}` : err.message);
|
|
|
9048
9313
|
outcome.packageJsonChanged ? "package.json" : void 0
|
|
9049
9314
|
].filter((f) => Boolean(f));
|
|
9050
9315
|
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
|
-
|
|
9052
|
-
|
|
9316
|
+
p44.log.step(`Switching the adapter to ${pc18.cyan(ADAPTER_NODE)}`);
|
|
9317
|
+
p44.log.info(
|
|
9053
9318
|
`${why}, and vela deploy runs the app as a Node server.
|
|
9054
9319
|
|
|
9055
9320
|
Changed ${changed.join(", ")}` + (outcome.removedDeps.length ? `
|
|
@@ -9062,14 +9327,14 @@ ${pc18.cyan(err.snippet)}` : err.message);
|
|
|
9062
9327
|
rethrow(err);
|
|
9063
9328
|
}
|
|
9064
9329
|
}
|
|
9065
|
-
|
|
9330
|
+
p44.log.warn(`Commit ${changed.join(", ")} so every deploy builds the same way.`);
|
|
9066
9331
|
}
|
|
9067
9332
|
async function reportAppURLDrift(session, instance, domain) {
|
|
9068
9333
|
const expected = normalizeOrigin(domain);
|
|
9069
9334
|
if (!expected) return;
|
|
9070
9335
|
const current = await readRemoteAppURL(session, instance);
|
|
9071
9336
|
if (!current || normalizeOrigin(current) === expected) return;
|
|
9072
|
-
|
|
9337
|
+
p44.log.warn(
|
|
9073
9338
|
`This app's PocketBase ${pc18.cyan("appURL")} is ${pc18.dim(current)}, but it is served on ${pc18.dim(expected)}.
|
|
9074
9339
|
|
|
9075
9340
|
Emails and anything else PocketBase links to will use the former. Update it in
|
|
@@ -9084,15 +9349,15 @@ async function copyLocalBranding(session, instance, workspaceRootDir, appURL) {
|
|
|
9084
9349
|
if (copied.length === 0) return;
|
|
9085
9350
|
const outcome = await restartInstance(session, instance);
|
|
9086
9351
|
if (outcome.deployed && !outcome.restarted) {
|
|
9087
|
-
|
|
9352
|
+
p44.log.warn(
|
|
9088
9353
|
`Copied ${copied.join(", ")}, but the app did not restart to pick them up.
|
|
9089
9354
|
${pc18.dim(outcome.error ?? "")}`
|
|
9090
9355
|
);
|
|
9091
9356
|
return;
|
|
9092
9357
|
}
|
|
9093
|
-
|
|
9358
|
+
p44.log.success(`Copied ${copied.join(", ")} from this project's database`);
|
|
9094
9359
|
} catch (err) {
|
|
9095
|
-
|
|
9360
|
+
p44.log.warn(
|
|
9096
9361
|
`Could not copy this project's PocketBase settings across.
|
|
9097
9362
|
Set them in the admin panel instead. ${pc18.dim(String(err))}`
|
|
9098
9363
|
);
|
|
@@ -9185,7 +9450,7 @@ async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
|
9185
9450
|
const remote = await readRemoteEnv(session, instance);
|
|
9186
9451
|
if (Object.keys(remote).length > 0) return;
|
|
9187
9452
|
if (!fs37.existsSync(path38.join(workspaceRootDir, ".env"))) return;
|
|
9188
|
-
|
|
9453
|
+
p44.log.warn(
|
|
9189
9454
|
`This app has no production environment variables yet.
|
|
9190
9455
|
|
|
9191
9456
|
Local ${pc18.cyan(".env")} values are not uploaded by a deploy. Set them with
|
|
@@ -9196,53 +9461,43 @@ async function serverTimeOrLocal(session) {
|
|
|
9196
9461
|
try {
|
|
9197
9462
|
return await serverTime(session);
|
|
9198
9463
|
} catch {
|
|
9199
|
-
|
|
9464
|
+
p44.log.warn("Could not read the clock on the server; stamping this release from this machine.");
|
|
9200
9465
|
return /* @__PURE__ */ new Date();
|
|
9201
9466
|
}
|
|
9202
9467
|
}
|
|
9203
9468
|
|
|
9204
9469
|
// src/commands/link.ts
|
|
9205
9470
|
import path39 from "node:path";
|
|
9206
|
-
import
|
|
9471
|
+
import process32 from "node:process";
|
|
9207
9472
|
import { Command as Command78 } from "commander";
|
|
9208
|
-
import * as
|
|
9473
|
+
import * as p45 from "@clack/prompts";
|
|
9209
9474
|
var CREATE_NEW = "__new__";
|
|
9210
9475
|
var link = new Command78("link").description("link this project to a velastack.dev project").configureHelp(helpConfig).action(() => runCommand(linkProject, "Failed to link the project."));
|
|
9211
9476
|
async function linkProject() {
|
|
9212
9477
|
const { workspaceRootDir } = await getWorkspace();
|
|
9213
9478
|
const existing = readProjectConfig(workspaceRootDir);
|
|
9214
9479
|
if (existing) {
|
|
9215
|
-
|
|
9480
|
+
p45.log.success(`Linked to ${existing.projectName}.`);
|
|
9216
9481
|
return;
|
|
9217
9482
|
}
|
|
9218
9483
|
const apiKey = requireApiKey();
|
|
9219
|
-
const [
|
|
9220
|
-
getCurrentUser(apiKey),
|
|
9221
|
-
listTeams(apiKey),
|
|
9222
|
-
listProjects(apiKey)
|
|
9223
|
-
]);
|
|
9224
|
-
let projectId;
|
|
9225
|
-
let teamId;
|
|
9226
|
-
let projectName;
|
|
9484
|
+
const [teams3, projects] = await Promise.all([listTeams(apiKey), listProjects(apiKey)]);
|
|
9227
9485
|
const picked = projects.length > 0 ? await pickExistingProject(projects) : CREATE_NEW;
|
|
9486
|
+
let linked;
|
|
9228
9487
|
if (picked !== CREATE_NEW) {
|
|
9229
9488
|
const project = projects.find((pr) => pr.id === picked);
|
|
9230
|
-
|
|
9231
|
-
teamId = project.team;
|
|
9232
|
-
projectName = project.name;
|
|
9489
|
+
linked = toLinked(project, project.expand?.team);
|
|
9233
9490
|
} else {
|
|
9234
9491
|
const team = await pickTeam(teams3);
|
|
9235
9492
|
const name = await promptProjectName(workspaceRootDir);
|
|
9236
|
-
|
|
9237
|
-
projectId = created.id;
|
|
9238
|
-
teamId = team.id;
|
|
9239
|
-
projectName = created.name;
|
|
9493
|
+
linked = await linkNewProject(apiKey, { name, teamId: team.id, interactive: true });
|
|
9240
9494
|
}
|
|
9495
|
+
const { projectId, teamId, projectName } = linked;
|
|
9241
9496
|
writeProjectConfig(workspaceRootDir, { projectId, teamId, projectName });
|
|
9242
|
-
|
|
9497
|
+
p45.log.success(`Linked to ${projectName} (${linked.dashboardUrl}).`);
|
|
9243
9498
|
}
|
|
9244
9499
|
async function pickExistingProject(projects) {
|
|
9245
|
-
const choice = await
|
|
9500
|
+
const choice = await p45.select({
|
|
9246
9501
|
message: "Select a project",
|
|
9247
9502
|
options: [
|
|
9248
9503
|
...projects.map((pr) => ({
|
|
@@ -9252,39 +9507,24 @@ async function pickExistingProject(projects) {
|
|
|
9252
9507
|
{ value: CREATE_NEW, label: "Create a new project" }
|
|
9253
9508
|
]
|
|
9254
9509
|
});
|
|
9255
|
-
if (
|
|
9256
|
-
|
|
9257
|
-
|
|
9510
|
+
if (p45.isCancel(choice)) {
|
|
9511
|
+
p45.cancel("Operation cancelled.");
|
|
9512
|
+
process32.exit(0);
|
|
9258
9513
|
}
|
|
9259
9514
|
return choice;
|
|
9260
9515
|
}
|
|
9261
|
-
async function pickTeam(teams3) {
|
|
9262
|
-
if (teams3.length === 1) return teams3[0];
|
|
9263
|
-
const choice = await p44.select({
|
|
9264
|
-
message: "Select a team",
|
|
9265
|
-
options: teams3.map((team) => ({
|
|
9266
|
-
value: team.id,
|
|
9267
|
-
label: team.is_personal ? `${team.name} (personal)` : team.name
|
|
9268
|
-
}))
|
|
9269
|
-
});
|
|
9270
|
-
if (p44.isCancel(choice)) {
|
|
9271
|
-
p44.cancel("Operation cancelled.");
|
|
9272
|
-
process30.exit(0);
|
|
9273
|
-
}
|
|
9274
|
-
return teams3.find((team) => team.id === choice);
|
|
9275
|
-
}
|
|
9276
9516
|
async function promptProjectName(workspaceRootDir) {
|
|
9277
9517
|
const defaultValue = defaultProjectName2(workspaceRootDir);
|
|
9278
|
-
const value = await
|
|
9518
|
+
const value = await p45.text({
|
|
9279
9519
|
message: "Project name",
|
|
9280
9520
|
defaultValue,
|
|
9281
9521
|
initialValue: defaultValue,
|
|
9282
9522
|
placeholder: defaultValue,
|
|
9283
9523
|
validate: (v10) => !v10?.trim() ? "Required" : void 0
|
|
9284
9524
|
});
|
|
9285
|
-
if (
|
|
9286
|
-
|
|
9287
|
-
|
|
9525
|
+
if (p45.isCancel(value)) {
|
|
9526
|
+
p45.cancel("Operation cancelled.");
|
|
9527
|
+
process32.exit(0);
|
|
9288
9528
|
}
|
|
9289
9529
|
return value.trim();
|
|
9290
9530
|
}
|
|
@@ -9303,7 +9543,7 @@ import { Command as Command83 } from "commander";
|
|
|
9303
9543
|
|
|
9304
9544
|
// src/commands/env/list.ts
|
|
9305
9545
|
import { Command as Command79 } from "commander";
|
|
9306
|
-
import * as
|
|
9546
|
+
import * as p46 from "@clack/prompts";
|
|
9307
9547
|
import pc19 from "picocolors";
|
|
9308
9548
|
var envList = addTargetOptions(
|
|
9309
9549
|
new Command79("list").description("list environment variable names").configureHelp(helpConfig),
|
|
@@ -9328,10 +9568,10 @@ var envList = addTargetOptions(
|
|
|
9328
9568
|
);
|
|
9329
9569
|
function report(keys, where) {
|
|
9330
9570
|
if (keys.length === 0) {
|
|
9331
|
-
|
|
9571
|
+
p46.log.info(`No environment variables configured ${pc19.dim(`(${where})`)}.`);
|
|
9332
9572
|
return;
|
|
9333
9573
|
}
|
|
9334
|
-
|
|
9574
|
+
p46.log.info(
|
|
9335
9575
|
`Environment ${pc19.dim(`(${where})`)}
|
|
9336
9576
|
|
|
9337
9577
|
` + keys.sort().map((key) => ` ${key}`).join("\n")
|
|
@@ -9339,9 +9579,9 @@ function report(keys, where) {
|
|
|
9339
9579
|
}
|
|
9340
9580
|
|
|
9341
9581
|
// src/commands/env/set.ts
|
|
9342
|
-
import
|
|
9582
|
+
import process33 from "node:process";
|
|
9343
9583
|
import { Command as Command80 } from "commander";
|
|
9344
|
-
import * as
|
|
9584
|
+
import * as p47 from "@clack/prompts";
|
|
9345
9585
|
import pc20 from "picocolors";
|
|
9346
9586
|
var envSet = addTargetOptions(
|
|
9347
9587
|
new Command80("set").description("set an environment variable").argument("<key>", "variable name").argument("[value]", "value \u2014 prompted for, without echo, when omitted").configureHelp(helpConfig),
|
|
@@ -9354,14 +9594,14 @@ var envSet = addTargetOptions(
|
|
|
9354
9594
|
local: async (ctx) => {
|
|
9355
9595
|
const resolved = await resolveValue(key, value);
|
|
9356
9596
|
setLocalEnv(ctx.envFile, key, resolved);
|
|
9357
|
-
|
|
9597
|
+
p47.log.success(`${key} updated ${pc20.dim("(local)")}`);
|
|
9358
9598
|
await applyLocalEnvChange(ctx, [key]);
|
|
9359
9599
|
},
|
|
9360
9600
|
remote: async (ctx) => {
|
|
9361
9601
|
const resolved = await resolveValue(key, value);
|
|
9362
9602
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
9363
9603
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...env2, [key]: resolved });
|
|
9364
|
-
|
|
9604
|
+
p47.log.success(`${key} updated ${pc20.dim(`(${ctx.targetName})`)}`);
|
|
9365
9605
|
await applyEnvRestart(ctx, [key]);
|
|
9366
9606
|
}
|
|
9367
9607
|
},
|
|
@@ -9375,20 +9615,20 @@ async function resolveValue(key, value) {
|
|
|
9375
9615
|
return value ?? await promptValue(key);
|
|
9376
9616
|
}
|
|
9377
9617
|
async function promptValue(key) {
|
|
9378
|
-
const value = await
|
|
9618
|
+
const value = await p47.password({
|
|
9379
9619
|
message: `Value for ${pc20.cyan(key)}`,
|
|
9380
9620
|
validate: (input) => !input?.length ? "Required" : void 0
|
|
9381
9621
|
});
|
|
9382
|
-
if (
|
|
9383
|
-
|
|
9384
|
-
|
|
9622
|
+
if (p47.isCancel(value)) {
|
|
9623
|
+
p47.cancel("Operation cancelled.");
|
|
9624
|
+
process33.exit(0);
|
|
9385
9625
|
}
|
|
9386
9626
|
return value;
|
|
9387
9627
|
}
|
|
9388
9628
|
|
|
9389
9629
|
// src/commands/env/unset.ts
|
|
9390
9630
|
import { Command as Command81 } from "commander";
|
|
9391
|
-
import * as
|
|
9631
|
+
import * as p48 from "@clack/prompts";
|
|
9392
9632
|
import pc21 from "picocolors";
|
|
9393
9633
|
var envUnset = addTargetOptions(
|
|
9394
9634
|
new Command81("unset").description("remove an environment variable").argument("<key>", "variable name").configureHelp(helpConfig),
|
|
@@ -9400,22 +9640,22 @@ var envUnset = addTargetOptions(
|
|
|
9400
9640
|
{
|
|
9401
9641
|
local: async (ctx) => {
|
|
9402
9642
|
if (!(key in readLocalEnv(ctx.envFile))) {
|
|
9403
|
-
|
|
9643
|
+
p48.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
9404
9644
|
return;
|
|
9405
9645
|
}
|
|
9406
9646
|
unsetLocalEnv(ctx.envFile, key);
|
|
9407
|
-
|
|
9647
|
+
p48.log.success(`${key} removed ${pc21.dim("(local)")}`);
|
|
9408
9648
|
await applyLocalEnvChange(ctx, [key]);
|
|
9409
9649
|
},
|
|
9410
9650
|
remote: async (ctx) => {
|
|
9411
9651
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
9412
9652
|
if (!(key in env2)) {
|
|
9413
|
-
|
|
9653
|
+
p48.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
9414
9654
|
return;
|
|
9415
9655
|
}
|
|
9416
9656
|
delete env2[key];
|
|
9417
9657
|
await writeRemoteEnv(ctx.session, ctx.instance, env2);
|
|
9418
|
-
|
|
9658
|
+
p48.log.success(`${key} removed ${pc21.dim(`(${ctx.targetName})`)}`);
|
|
9419
9659
|
await applyEnvRestart(ctx, [key]);
|
|
9420
9660
|
}
|
|
9421
9661
|
},
|
|
@@ -9428,9 +9668,9 @@ var envUnset = addTargetOptions(
|
|
|
9428
9668
|
// src/commands/env/import.ts
|
|
9429
9669
|
import fs38 from "node:fs";
|
|
9430
9670
|
import path40 from "node:path";
|
|
9431
|
-
import
|
|
9671
|
+
import process34 from "node:process";
|
|
9432
9672
|
import { Command as Command82 } from "commander";
|
|
9433
|
-
import * as
|
|
9673
|
+
import * as p49 from "@clack/prompts";
|
|
9434
9674
|
import pc22 from "picocolors";
|
|
9435
9675
|
var envImport = addTargetOptions(
|
|
9436
9676
|
new Command82("import").description("merge a dotenv file into the environment").argument("<file>", "dotenv file to read").configureHelp(helpConfig),
|
|
@@ -9448,22 +9688,22 @@ var envImport = addTargetOptions(
|
|
|
9448
9688
|
const incoming = read(source, file);
|
|
9449
9689
|
const keys = Object.keys(incoming);
|
|
9450
9690
|
if (keys.length === 0) return;
|
|
9451
|
-
|
|
9691
|
+
p49.log.step(`Importing ${keys.length} variable(s) from ${pc22.cyan(file)}`);
|
|
9452
9692
|
editLocalEnv(
|
|
9453
9693
|
ctx.envFile,
|
|
9454
9694
|
(content) => keys.reduce((acc, key) => upsertEnvVar(acc, key, incoming[key]), content)
|
|
9455
9695
|
);
|
|
9456
|
-
|
|
9696
|
+
p49.log.success(`${keys.length} variable(s) updated ${pc22.dim("(local)")}`);
|
|
9457
9697
|
await applyLocalEnvChange(ctx, keys);
|
|
9458
9698
|
},
|
|
9459
9699
|
remote: async (ctx) => {
|
|
9460
9700
|
const incoming = read(resolve(file), file);
|
|
9461
9701
|
const keys = Object.keys(incoming);
|
|
9462
9702
|
if (keys.length === 0) return;
|
|
9463
|
-
|
|
9703
|
+
p49.log.step(`Importing ${keys.length} variable(s) from ${pc22.cyan(file)}`);
|
|
9464
9704
|
const existing = await readRemoteEnv(ctx.session, ctx.instance);
|
|
9465
9705
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...existing, ...incoming });
|
|
9466
|
-
|
|
9706
|
+
p49.log.success(`${keys.length} variable(s) updated ${pc22.dim(`(${ctx.targetName})`)}`);
|
|
9467
9707
|
await applyEnvRestart(ctx, keys);
|
|
9468
9708
|
}
|
|
9469
9709
|
},
|
|
@@ -9473,12 +9713,12 @@ var envImport = addTargetOptions(
|
|
|
9473
9713
|
)
|
|
9474
9714
|
);
|
|
9475
9715
|
function resolve(file) {
|
|
9476
|
-
return path40.resolve(
|
|
9716
|
+
return path40.resolve(process34.cwd(), file);
|
|
9477
9717
|
}
|
|
9478
9718
|
function read(resolved, shown) {
|
|
9479
9719
|
if (!fs38.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
9480
9720
|
const incoming = readLocalEnvFile(resolved);
|
|
9481
|
-
if (Object.keys(incoming).length === 0)
|
|
9721
|
+
if (Object.keys(incoming).length === 0) p49.log.info(`${shown} has no variables to import.`);
|
|
9482
9722
|
return incoming;
|
|
9483
9723
|
}
|
|
9484
9724
|
|
|
@@ -9487,7 +9727,7 @@ var env = new Command83("env").description("manage environment variables, locall
|
|
|
9487
9727
|
|
|
9488
9728
|
// src/commands/status.ts
|
|
9489
9729
|
import { Command as Command84 } from "commander";
|
|
9490
|
-
import * as
|
|
9730
|
+
import * as p50 from "@clack/prompts";
|
|
9491
9731
|
import pc23 from "picocolors";
|
|
9492
9732
|
var status = addTargetOptions(
|
|
9493
9733
|
new Command84("status").description("show what is deployed").configureHelp(helpConfig),
|
|
@@ -9521,11 +9761,11 @@ function report2(states, json) {
|
|
|
9521
9761
|
return;
|
|
9522
9762
|
}
|
|
9523
9763
|
if (states.length === 0) {
|
|
9524
|
-
|
|
9764
|
+
p50.log.info("Nothing is deployed here yet.");
|
|
9525
9765
|
return;
|
|
9526
9766
|
}
|
|
9527
9767
|
for (const state of states) {
|
|
9528
|
-
|
|
9768
|
+
p50.log.info(describe2(state));
|
|
9529
9769
|
}
|
|
9530
9770
|
}
|
|
9531
9771
|
function describe2(state) {
|
|
@@ -9550,7 +9790,7 @@ function describe2(state) {
|
|
|
9550
9790
|
|
|
9551
9791
|
// src/commands/rollback.ts
|
|
9552
9792
|
import { Command as Command85 } from "commander";
|
|
9553
|
-
import * as
|
|
9793
|
+
import * as p51 from "@clack/prompts";
|
|
9554
9794
|
import pc24 from "picocolors";
|
|
9555
9795
|
var rollback = addLockWaitOption(
|
|
9556
9796
|
addTargetOptions(
|
|
@@ -9564,7 +9804,7 @@ var rollback = addLockWaitOption(
|
|
|
9564
9804
|
raw,
|
|
9565
9805
|
{
|
|
9566
9806
|
remote: async (ctx) => {
|
|
9567
|
-
|
|
9807
|
+
p51.log.step(
|
|
9568
9808
|
`Rolling back ${pc24.cyan(ctx.appName)} ${pc24.dim(`(${ctx.targetName})`)} on ${ctx.server}`
|
|
9569
9809
|
);
|
|
9570
9810
|
const result = await runServerScript(
|
|
@@ -9579,7 +9819,7 @@ var rollback = addLockWaitOption(
|
|
|
9579
9819
|
stream: true
|
|
9580
9820
|
}
|
|
9581
9821
|
);
|
|
9582
|
-
|
|
9822
|
+
p51.log.success(
|
|
9583
9823
|
`Rolled back to ${pc24.cyan(result?.release ?? "the previous release")}` + (result?.from ? ` ${pc24.dim(`(was ${result.from})`)}` : "")
|
|
9584
9824
|
);
|
|
9585
9825
|
}
|
|
@@ -9632,9 +9872,9 @@ var logs = addTargetOptions(
|
|
|
9632
9872
|
import { Command as Command88 } from "commander";
|
|
9633
9873
|
|
|
9634
9874
|
// src/commands/admin/create.ts
|
|
9635
|
-
import
|
|
9875
|
+
import process35 from "node:process";
|
|
9636
9876
|
import { Command as Command87 } from "commander";
|
|
9637
|
-
import * as
|
|
9877
|
+
import * as p52 from "@clack/prompts";
|
|
9638
9878
|
import pc25 from "picocolors";
|
|
9639
9879
|
var MIN_PASSWORD = 10;
|
|
9640
9880
|
var adminCreate = addTargetOptions(
|
|
@@ -9666,7 +9906,7 @@ var adminCreate = addTargetOptions(
|
|
|
9666
9906
|
const metadata = getPocketbaseMetadata(ctx.workspaceRootDir);
|
|
9667
9907
|
if (metadata) signIn = `http://${metadata.viteHost}:${metadata.vitePort}`;
|
|
9668
9908
|
}
|
|
9669
|
-
|
|
9909
|
+
p52.log.info(
|
|
9670
9910
|
signIn ? `Sign in at ${pc25.cyan(`${signIn}/admin`)}` : `Sign in at ${pc25.cyan("/admin")} once ${pc25.cyan("vela dev")} is running.`
|
|
9671
9911
|
);
|
|
9672
9912
|
},
|
|
@@ -9680,7 +9920,7 @@ var adminCreate = addTargetOptions(
|
|
|
9680
9920
|
(pb) => upsertSuperuser(pb, address, password11)
|
|
9681
9921
|
);
|
|
9682
9922
|
const base2 = state?.domain ? `https://${state.domain.split(",")[0].trim()}` : "";
|
|
9683
|
-
|
|
9923
|
+
p52.log.info(
|
|
9684
9924
|
base2 ? `Sign in at ${pc25.cyan(`${base2}/admin`)}` : `Sign in at ${pc25.cyan("/admin")} once a domain is configured for this target.`
|
|
9685
9925
|
);
|
|
9686
9926
|
}
|
|
@@ -9693,20 +9933,20 @@ var adminCreate = addTargetOptions(
|
|
|
9693
9933
|
async function upsertSuperuser(pb, email3, password11) {
|
|
9694
9934
|
const existing = await findSuperuser(pb, email3);
|
|
9695
9935
|
if (existing) {
|
|
9696
|
-
const confirmed = await
|
|
9936
|
+
const confirmed = await p52.confirm({
|
|
9697
9937
|
message: `${email3} already has an account, update its password?`,
|
|
9698
9938
|
initialValue: false
|
|
9699
9939
|
});
|
|
9700
|
-
if (
|
|
9701
|
-
|
|
9702
|
-
|
|
9940
|
+
if (p52.isCancel(confirmed) || !confirmed) {
|
|
9941
|
+
p52.cancel("Operation cancelled.");
|
|
9942
|
+
process35.exit(0);
|
|
9703
9943
|
}
|
|
9704
9944
|
await pb.collection("_superusers").update(existing, { password: password11, passwordConfirm: password11 });
|
|
9705
|
-
|
|
9945
|
+
p52.log.success(`Password updated for ${pc25.cyan(email3)}, you can sign in now`);
|
|
9706
9946
|
return;
|
|
9707
9947
|
}
|
|
9708
9948
|
await pb.collection("_superusers").create({ email: email3, password: password11, passwordConfirm: password11 });
|
|
9709
|
-
|
|
9949
|
+
p52.log.success(`${pc25.cyan(email3)} can now sign in`);
|
|
9710
9950
|
}
|
|
9711
9951
|
async function findSuperuser(pb, email3) {
|
|
9712
9952
|
try {
|
|
@@ -9717,32 +9957,32 @@ async function findSuperuser(pb, email3) {
|
|
|
9717
9957
|
}
|
|
9718
9958
|
}
|
|
9719
9959
|
async function promptEmail() {
|
|
9720
|
-
const value = await
|
|
9960
|
+
const value = await p52.text({
|
|
9721
9961
|
message: "Email to sign in with",
|
|
9722
9962
|
validate: (input) => input?.includes("@") ? void 0 : "An email address is required"
|
|
9723
9963
|
});
|
|
9724
|
-
if (
|
|
9725
|
-
|
|
9726
|
-
|
|
9964
|
+
if (p52.isCancel(value)) {
|
|
9965
|
+
p52.cancel("Operation cancelled.");
|
|
9966
|
+
process35.exit(0);
|
|
9727
9967
|
}
|
|
9728
9968
|
return value.trim();
|
|
9729
9969
|
}
|
|
9730
9970
|
async function promptPassword2() {
|
|
9731
|
-
const value = await
|
|
9971
|
+
const value = await p52.password({
|
|
9732
9972
|
message: "Password",
|
|
9733
9973
|
validate: (input) => (input?.length ?? 0) >= MIN_PASSWORD ? void 0 : `At least ${MIN_PASSWORD} characters is required`
|
|
9734
9974
|
});
|
|
9735
|
-
if (
|
|
9736
|
-
|
|
9737
|
-
|
|
9975
|
+
if (p52.isCancel(value)) {
|
|
9976
|
+
p52.cancel("Operation cancelled.");
|
|
9977
|
+
process35.exit(0);
|
|
9738
9978
|
}
|
|
9739
|
-
const again = await
|
|
9979
|
+
const again = await p52.password({
|
|
9740
9980
|
message: "Password again",
|
|
9741
9981
|
validate: (input) => input === value ? void 0 : "The two do not match"
|
|
9742
9982
|
});
|
|
9743
|
-
if (
|
|
9744
|
-
|
|
9745
|
-
|
|
9983
|
+
if (p52.isCancel(again)) {
|
|
9984
|
+
p52.cancel("Operation cancelled.");
|
|
9985
|
+
process35.exit(0);
|
|
9746
9986
|
}
|
|
9747
9987
|
return value;
|
|
9748
9988
|
}
|
|
@@ -9757,7 +9997,7 @@ import { Command as Command94 } from "commander";
|
|
|
9757
9997
|
import fs39 from "node:fs";
|
|
9758
9998
|
import path41 from "node:path";
|
|
9759
9999
|
import { Command as Command89 } from "commander";
|
|
9760
|
-
import * as
|
|
10000
|
+
import * as p53 from "@clack/prompts";
|
|
9761
10001
|
import pc26 from "picocolors";
|
|
9762
10002
|
|
|
9763
10003
|
// src/lib/backups.ts
|
|
@@ -9861,7 +10101,7 @@ Backup names are lowercase letters, digits, ${pc26.cyan("-")} and ${pc26.cyan("_
|
|
|
9861
10101
|
}
|
|
9862
10102
|
const storage = await readStorageSettings(ctx.pb);
|
|
9863
10103
|
if (storage.s3Enabled) {
|
|
9864
|
-
|
|
10104
|
+
p53.log.warn(
|
|
9865
10105
|
`Uploads are stored in S3, so this archive holds the database only.
|
|
9866
10106
|
|
|
9867
10107
|
PocketBase leaves ${pc26.cyan("storage/")} out of a backup whenever S3 is on.
|
|
@@ -9869,7 +10109,7 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
9869
10109
|
);
|
|
9870
10110
|
}
|
|
9871
10111
|
if (ctx.session) await checkpointAppDatabases(ctx.session, ctx.instance);
|
|
9872
|
-
const spinner7 =
|
|
10112
|
+
const spinner7 = p53.spinner();
|
|
9873
10113
|
spinner7.start(`Backing up ${ctx.targetName}`);
|
|
9874
10114
|
try {
|
|
9875
10115
|
await createBackup(ctx.pb, key);
|
|
@@ -9916,7 +10156,7 @@ async function download(ctx, key, outputDir) {
|
|
|
9916
10156
|
fs39.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9917
10157
|
return path41.relative(ctx.workspaceRootDir, destination);
|
|
9918
10158
|
}
|
|
9919
|
-
const spinner7 =
|
|
10159
|
+
const spinner7 = p53.spinner();
|
|
9920
10160
|
spinner7.start(`Downloading ${key}`);
|
|
9921
10161
|
try {
|
|
9922
10162
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
@@ -9930,7 +10170,7 @@ async function download(ctx, key, outputDir) {
|
|
|
9930
10170
|
|
|
9931
10171
|
// src/commands/backup/list.ts
|
|
9932
10172
|
import { Command as Command90 } from "commander";
|
|
9933
|
-
import * as
|
|
10173
|
+
import * as p54 from "@clack/prompts";
|
|
9934
10174
|
import pc27 from "picocolors";
|
|
9935
10175
|
var backupList = addTargetOptions(
|
|
9936
10176
|
new Command90("list").description("list the backups on a target").configureHelp(helpConfig),
|
|
@@ -9940,7 +10180,7 @@ var backupList = addTargetOptions(
|
|
|
9940
10180
|
() => withBackupTarget(raw, "backup list", async (ctx) => {
|
|
9941
10181
|
const backups = await listBackups(ctx.pb);
|
|
9942
10182
|
if (backups.length === 0) {
|
|
9943
|
-
|
|
10183
|
+
p54.log.info(
|
|
9944
10184
|
`${pc27.cyan(ctx.targetName)} has no backups yet.
|
|
9945
10185
|
|
|
9946
10186
|
Take one with ${pc27.cyan("vela backup create")}.`
|
|
@@ -9948,7 +10188,7 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9948
10188
|
return;
|
|
9949
10189
|
}
|
|
9950
10190
|
const width = Math.max(...backups.map((b) => b.key.length));
|
|
9951
|
-
|
|
10191
|
+
p54.log.message(
|
|
9952
10192
|
backups.map(
|
|
9953
10193
|
(b) => `${b.key.padEnd(width)} ${pc27.dim(formatBytes(b.size).padStart(8))} ${pc27.dim(b.modified)}`
|
|
9954
10194
|
).join("\n")
|
|
@@ -9962,7 +10202,7 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9962
10202
|
import fs40 from "node:fs";
|
|
9963
10203
|
import path42 from "node:path";
|
|
9964
10204
|
import { Command as Command91 } from "commander";
|
|
9965
|
-
import * as
|
|
10205
|
+
import * as p55 from "@clack/prompts";
|
|
9966
10206
|
import pc28 from "picocolors";
|
|
9967
10207
|
var backupDownload = addTargetOptions(
|
|
9968
10208
|
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),
|
|
@@ -9993,7 +10233,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9993
10233
|
if (!ctx.session) {
|
|
9994
10234
|
fs40.copyFileSync(path42.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9995
10235
|
} else {
|
|
9996
|
-
const spinner7 =
|
|
10236
|
+
const spinner7 = p55.spinner();
|
|
9997
10237
|
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
9998
10238
|
try {
|
|
9999
10239
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
@@ -10012,9 +10252,9 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
10012
10252
|
);
|
|
10013
10253
|
|
|
10014
10254
|
// src/commands/backup/delete.ts
|
|
10015
|
-
import
|
|
10255
|
+
import process36 from "node:process";
|
|
10016
10256
|
import { Command as Command92 } from "commander";
|
|
10017
|
-
import * as
|
|
10257
|
+
import * as p56 from "@clack/prompts";
|
|
10018
10258
|
import pc29 from "picocolors";
|
|
10019
10259
|
var backupDelete = addTargetOptions(
|
|
10020
10260
|
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),
|
|
@@ -10032,13 +10272,13 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
10032
10272
|
);
|
|
10033
10273
|
}
|
|
10034
10274
|
if (!options.yes) {
|
|
10035
|
-
const confirmed = await
|
|
10275
|
+
const confirmed = await p56.confirm({
|
|
10036
10276
|
message: `Delete ${key} (${formatBytes(found.size)}) from ${ctx.targetName}?`,
|
|
10037
10277
|
initialValue: false
|
|
10038
10278
|
});
|
|
10039
|
-
if (
|
|
10040
|
-
|
|
10041
|
-
|
|
10279
|
+
if (p56.isCancel(confirmed) || !confirmed) {
|
|
10280
|
+
p56.cancel("Operation cancelled.");
|
|
10281
|
+
process36.exit(0);
|
|
10042
10282
|
}
|
|
10043
10283
|
}
|
|
10044
10284
|
await ctx.pb.backups.delete(key);
|
|
@@ -10049,7 +10289,7 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
10049
10289
|
|
|
10050
10290
|
// src/commands/backup/schedule.ts
|
|
10051
10291
|
import { Command as Command93 } from "commander";
|
|
10052
|
-
import * as
|
|
10292
|
+
import * as p57 from "@clack/prompts";
|
|
10053
10293
|
import pc30 from "picocolors";
|
|
10054
10294
|
var DEFAULT_KEEP = 7;
|
|
10055
10295
|
var backupSchedule = addTargetOptions(
|
|
@@ -10066,7 +10306,7 @@ var backupSchedule = addTargetOptions(
|
|
|
10066
10306
|
}
|
|
10067
10307
|
if (!cron) {
|
|
10068
10308
|
const current = await readSchedule(ctx.pb);
|
|
10069
|
-
|
|
10309
|
+
p57.log.info(
|
|
10070
10310
|
current.cron ? `${ctx.targetName} backs up on ${pc30.cyan(current.cron)}, keeping ${current.maxKeep}.` : `${ctx.targetName} has no backup schedule.
|
|
10071
10311
|
|
|
10072
10312
|
Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
@@ -10102,9 +10342,9 @@ var backup = new Command94("backup").description("back up the database and uploa
|
|
|
10102
10342
|
// src/commands/restore.ts
|
|
10103
10343
|
import fs41 from "node:fs";
|
|
10104
10344
|
import path43 from "node:path";
|
|
10105
|
-
import
|
|
10345
|
+
import process37 from "node:process";
|
|
10106
10346
|
import { Command as Command95 } from "commander";
|
|
10107
|
-
import * as
|
|
10347
|
+
import * as p58 from "@clack/prompts";
|
|
10108
10348
|
import pc31 from "picocolors";
|
|
10109
10349
|
var restore = addLockWaitOption(
|
|
10110
10350
|
addTargetOptions(
|
|
@@ -10145,18 +10385,18 @@ var restore = addLockWaitOption(
|
|
|
10145
10385
|
],
|
|
10146
10386
|
stream: true
|
|
10147
10387
|
});
|
|
10148
|
-
|
|
10388
|
+
p58.log.success(
|
|
10149
10389
|
`Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
|
|
10150
10390
|
local ? path43.basename(local) : key
|
|
10151
10391
|
)}.`
|
|
10152
10392
|
);
|
|
10153
10393
|
if (result?.storageCarriedOver) {
|
|
10154
|
-
|
|
10394
|
+
p58.log.info(
|
|
10155
10395
|
"The archive held no uploads, so the files already on the server were kept."
|
|
10156
10396
|
);
|
|
10157
10397
|
}
|
|
10158
10398
|
if (result?.previousDataDir) {
|
|
10159
|
-
|
|
10399
|
+
p58.log.info(
|
|
10160
10400
|
`The database this replaced is at ${pc31.cyan(result.previousDataDir)}.
|
|
10161
10401
|
|
|
10162
10402
|
It is the only way back. Remove it once you are satisfied with the restore.`
|
|
@@ -10197,7 +10437,7 @@ Run ${pc31.cyan("vela backup list")} to see what it does have.`
|
|
|
10197
10437
|
Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive on this machine.`
|
|
10198
10438
|
);
|
|
10199
10439
|
}
|
|
10200
|
-
const chosen = await
|
|
10440
|
+
const chosen = await p58.select({
|
|
10201
10441
|
message: `Which backup should ${ctx.targetName} be restored from?`,
|
|
10202
10442
|
options: backups.map((b) => ({
|
|
10203
10443
|
value: b.key,
|
|
@@ -10205,16 +10445,16 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
|
|
|
10205
10445
|
hint: `${formatBytes(b.size)}, ${b.modified}`
|
|
10206
10446
|
}))
|
|
10207
10447
|
});
|
|
10208
|
-
if (
|
|
10209
|
-
|
|
10210
|
-
|
|
10448
|
+
if (p58.isCancel(chosen)) {
|
|
10449
|
+
p58.cancel("Operation cancelled.");
|
|
10450
|
+
process37.exit(0);
|
|
10211
10451
|
}
|
|
10212
10452
|
return chosen;
|
|
10213
10453
|
}
|
|
10214
10454
|
async function stage(ctx, file) {
|
|
10215
10455
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
10216
10456
|
const remote = `${dir}/${path43.basename(file)}`;
|
|
10217
|
-
const spinner7 =
|
|
10457
|
+
const spinner7 = p58.spinner();
|
|
10218
10458
|
spinner7.start(`Uploading ${path43.basename(file)}`);
|
|
10219
10459
|
try {
|
|
10220
10460
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
@@ -10229,29 +10469,29 @@ async function stage(ctx, file) {
|
|
|
10229
10469
|
async function confirm13(appName, targetName, envTag, from) {
|
|
10230
10470
|
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path43.basename(from))}`;
|
|
10231
10471
|
if (isProd(envTag)) {
|
|
10232
|
-
const answer = await
|
|
10472
|
+
const answer = await p58.text({
|
|
10233
10473
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
10234
10474
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
10235
10475
|
});
|
|
10236
|
-
if (
|
|
10237
|
-
|
|
10238
|
-
|
|
10476
|
+
if (p58.isCancel(answer)) {
|
|
10477
|
+
p58.cancel("Operation cancelled.");
|
|
10478
|
+
process37.exit(0);
|
|
10239
10479
|
}
|
|
10240
10480
|
return;
|
|
10241
10481
|
}
|
|
10242
|
-
const ok = await
|
|
10482
|
+
const ok = await p58.confirm({
|
|
10243
10483
|
message: `Replace the database and uploads of ${what}?`,
|
|
10244
10484
|
initialValue: false
|
|
10245
10485
|
});
|
|
10246
|
-
if (
|
|
10247
|
-
|
|
10248
|
-
|
|
10486
|
+
if (p58.isCancel(ok) || !ok) {
|
|
10487
|
+
p58.cancel("Operation cancelled.");
|
|
10488
|
+
process37.exit(0);
|
|
10249
10489
|
}
|
|
10250
10490
|
}
|
|
10251
10491
|
|
|
10252
10492
|
// src/commands/targets.ts
|
|
10253
10493
|
import { Command as Command96 } from "commander";
|
|
10254
|
-
import * as
|
|
10494
|
+
import * as p59 from "@clack/prompts";
|
|
10255
10495
|
import pc32 from "picocolors";
|
|
10256
10496
|
import * as v9 from "valibot";
|
|
10257
10497
|
var OptionsSchema4 = v9.object({
|
|
@@ -10326,11 +10566,11 @@ function report3(rows, offline) {
|
|
|
10326
10566
|
const lines = rows.map(
|
|
10327
10567
|
(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}`
|
|
10328
10568
|
);
|
|
10329
|
-
|
|
10569
|
+
p59.log.info(`${pc32.dim(header)}
|
|
10330
10570
|
${lines.join("\n")}`);
|
|
10331
10571
|
const unreachable = rows.filter((row) => row.kind === "remote" && !row.reachable);
|
|
10332
10572
|
if (!offline && unreachable.length > 0) {
|
|
10333
|
-
|
|
10573
|
+
p59.log.warn(
|
|
10334
10574
|
`Could not reach ${unreachable.map((row) => row.server).join(", ")}.
|
|
10335
10575
|
Release and domain are shown from what this project recorded.`
|
|
10336
10576
|
);
|
|
@@ -10339,7 +10579,7 @@ Release and domain are shown from what this project recorded.`
|
|
|
10339
10579
|
|
|
10340
10580
|
// src/commands/test.ts
|
|
10341
10581
|
import path44 from "node:path";
|
|
10342
|
-
import
|
|
10582
|
+
import process38 from "node:process";
|
|
10343
10583
|
import { Command as Command97 } from "commander";
|
|
10344
10584
|
import PocketBase6 from "pocketbase";
|
|
10345
10585
|
import pc33 from "picocolors";
|
|
@@ -10348,7 +10588,7 @@ import { detect as detect8 } from "package-manager-detector";
|
|
|
10348
10588
|
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
10349
10589
|
import fs42 from "node:fs";
|
|
10350
10590
|
var testServer = new Command97("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
10351
|
-
const cwd =
|
|
10591
|
+
const cwd = process38.cwd();
|
|
10352
10592
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
10353
10593
|
const password11 = "password";
|
|
10354
10594
|
const testDataDir = path44.join(cwd, "test-data");
|
|
@@ -10363,11 +10603,11 @@ var testServer = new Command97("test:server").description("run server tests").al
|
|
|
10363
10603
|
email: email3,
|
|
10364
10604
|
password: password11
|
|
10365
10605
|
});
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10606
|
+
process38.env.POCKETBASE_URL = url;
|
|
10607
|
+
process38.env.POCKETBASE_SUPERUSER_EMAIL = email3;
|
|
10608
|
+
process38.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
|
|
10609
|
+
process38.env.VELA_DATA_DIR = testDataDir;
|
|
10610
|
+
process38.env.TEST = "true";
|
|
10371
10611
|
console.log(`${pc33.greenBright("\u2713")} Created test database`);
|
|
10372
10612
|
let vite;
|
|
10373
10613
|
let cleanedUp = false;
|
|
@@ -10386,12 +10626,12 @@ var testServer = new Command97("test:server").description("run server tests").al
|
|
|
10386
10626
|
const fail = async (message) => {
|
|
10387
10627
|
console.error(`${pc33.redBright("\u2717")} ${message}`);
|
|
10388
10628
|
await cleanup();
|
|
10389
|
-
|
|
10629
|
+
process38.exit(1);
|
|
10390
10630
|
};
|
|
10391
|
-
|
|
10392
|
-
|
|
10631
|
+
process38.on("exit", cleanupSync);
|
|
10632
|
+
process38.on("SIGINT", () => {
|
|
10393
10633
|
cleanupSync();
|
|
10394
|
-
|
|
10634
|
+
process38.exit(130);
|
|
10395
10635
|
});
|
|
10396
10636
|
const pb = new PocketBase6(url);
|
|
10397
10637
|
try {
|
|
@@ -10419,7 +10659,7 @@ var testServer = new Command97("test:server").description("run server tests").al
|
|
|
10419
10659
|
});
|
|
10420
10660
|
const vitePort = await findFreePort();
|
|
10421
10661
|
await vite.listen(vitePort);
|
|
10422
|
-
|
|
10662
|
+
process38.env.VITE_TEST_URL = `http://localhost:${vitePort}`;
|
|
10423
10663
|
console.log(`${pc33.greenBright("\u2713")} Started Vite: http://localhost:${vitePort}`);
|
|
10424
10664
|
console.log(`${pc33.greenBright("\u2713")} Started PocketBase: ${url}`);
|
|
10425
10665
|
const extraArgs = (cmd.parent?.args ?? []).slice(1);
|
|
@@ -10438,12 +10678,12 @@ var testServer = new Command97("test:server").description("run server tests").al
|
|
|
10438
10678
|
const resolvedArgs = resolved.args.slice();
|
|
10439
10679
|
if (pm === "npm") resolvedArgs.unshift("--yes");
|
|
10440
10680
|
const result = await x5(resolved.command, resolvedArgs, {
|
|
10441
|
-
nodeOptions: { cwd, stdio: "inherit", env: { ...
|
|
10681
|
+
nodeOptions: { cwd, stdio: "inherit", env: { ...process38.env, CI: "1" } }
|
|
10442
10682
|
});
|
|
10443
|
-
|
|
10683
|
+
process38.exitCode = result.exitCode ?? 1;
|
|
10444
10684
|
} catch (e) {
|
|
10445
10685
|
console.error(`${pc33.redBright("\u2717")} ${e.message}`);
|
|
10446
|
-
|
|
10686
|
+
process38.exitCode = 1;
|
|
10447
10687
|
} finally {
|
|
10448
10688
|
await cleanup();
|
|
10449
10689
|
}
|
|
@@ -10562,13 +10802,13 @@ function printTable(routes2) {
|
|
|
10562
10802
|
}
|
|
10563
10803
|
|
|
10564
10804
|
// src/commands/i18n.ts
|
|
10565
|
-
import
|
|
10805
|
+
import process39 from "node:process";
|
|
10566
10806
|
import { Command as Command99 } from "commander";
|
|
10567
10807
|
import { x as x6 } from "tinyexec";
|
|
10568
10808
|
import { detect as detect9 } from "package-manager-detector";
|
|
10569
10809
|
import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
|
|
10570
10810
|
async function runWuchale(extraArgs) {
|
|
10571
|
-
const cwd =
|
|
10811
|
+
const cwd = process39.cwd();
|
|
10572
10812
|
const pm = (await detect9({ cwd }))?.name ?? "npm";
|
|
10573
10813
|
const resolved = resolveCommand8(pm, "execute", ["wuchale", ...extraArgs]);
|
|
10574
10814
|
const args = resolved.args.slice();
|
|
@@ -10599,13 +10839,13 @@ import { Command as Command103 } from "commander";
|
|
|
10599
10839
|
// src/commands/cms/editor/add.ts
|
|
10600
10840
|
import { randomBytes } from "node:crypto";
|
|
10601
10841
|
import { Command as Command100 } from "commander";
|
|
10602
|
-
import * as
|
|
10842
|
+
import * as p60 from "@clack/prompts";
|
|
10603
10843
|
import pc35 from "picocolors";
|
|
10604
10844
|
|
|
10605
10845
|
// src/lib/cms-backend.ts
|
|
10606
10846
|
import { createRequire as createRequire3 } from "node:module";
|
|
10607
10847
|
import path46 from "node:path";
|
|
10608
|
-
import
|
|
10848
|
+
import process40 from "node:process";
|
|
10609
10849
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
10610
10850
|
import pc34 from "picocolors";
|
|
10611
10851
|
var DEFAULT_PROJECT = "default";
|
|
@@ -10622,7 +10862,7 @@ Run ${pc34.cyan("vela enable cms")} first.`
|
|
|
10622
10862
|
}
|
|
10623
10863
|
return await import(pathToFileURL3(entry).href);
|
|
10624
10864
|
}
|
|
10625
|
-
async function withCmsBackend(fn, cwd =
|
|
10865
|
+
async function withCmsBackend(fn, cwd = process40.cwd()) {
|
|
10626
10866
|
const root = findWorkspaceRoot(cwd);
|
|
10627
10867
|
if (!root) {
|
|
10628
10868
|
throw new Error("Could not find workspace root (no package.json found)");
|
|
@@ -10652,8 +10892,8 @@ var editorAdd = new Command100("add").description("create an editor who can sign
|
|
|
10652
10892
|
if (generated) {
|
|
10653
10893
|
lines.push("", `Password: ${pc35.bold(password11)}`, "", "It is shown once; copy it now.");
|
|
10654
10894
|
}
|
|
10655
|
-
|
|
10656
|
-
|
|
10895
|
+
p60.log.success(lines.join("\n"));
|
|
10896
|
+
p60.log.info(
|
|
10657
10897
|
`Run ${pc35.cyan("vela dev")}, open any page with ${pc35.cyan("?edit")} on the URL (or press ${pc35.cyan("Ctrl+E")}), and sign in.`
|
|
10658
10898
|
);
|
|
10659
10899
|
}, "Failed to add the editor.")
|
|
@@ -10661,12 +10901,12 @@ var editorAdd = new Command100("add").description("create an editor who can sign
|
|
|
10661
10901
|
|
|
10662
10902
|
// src/commands/cms/editor/password.ts
|
|
10663
10903
|
import { Command as Command101 } from "commander";
|
|
10664
|
-
import * as
|
|
10904
|
+
import * as p61 from "@clack/prompts";
|
|
10665
10905
|
import pc36 from "picocolors";
|
|
10666
10906
|
var editorPassword = new Command101("password").description("set an editor's password").argument("<email>", "email of the editor").argument("<password>", "new password").configureHelp(helpConfig).action(
|
|
10667
10907
|
(email3, password11) => runCommand(async () => {
|
|
10668
10908
|
await withCmsBackend((cms3) => cms3.editors.setPassword(email3, password11));
|
|
10669
|
-
|
|
10909
|
+
p61.log.success(
|
|
10670
10910
|
`Updated the password for ${pc36.cyan(email3)}. Existing sessions were signed out.`
|
|
10671
10911
|
);
|
|
10672
10912
|
}, "Failed to set the password.")
|
|
@@ -10674,7 +10914,7 @@ var editorPassword = new Command101("password").description("set an editor's pas
|
|
|
10674
10914
|
|
|
10675
10915
|
// src/commands/cms/editor/list.ts
|
|
10676
10916
|
import { Command as Command102 } from "commander";
|
|
10677
|
-
import * as
|
|
10917
|
+
import * as p62 from "@clack/prompts";
|
|
10678
10918
|
import pc37 from "picocolors";
|
|
10679
10919
|
var editorList = new Command102("list").description("list editors and the projects they may edit").configureHelp(helpConfig).action(
|
|
10680
10920
|
() => runCommand(async () => {
|
|
@@ -10685,11 +10925,11 @@ var editorList = new Command102("list").description("list editors and the projec
|
|
|
10685
10925
|
}))
|
|
10686
10926
|
);
|
|
10687
10927
|
if (rows.length === 0) {
|
|
10688
|
-
|
|
10928
|
+
p62.log.info(`No editors yet. Add one with ${pc37.cyan("vela cms editor add <email>")}.`);
|
|
10689
10929
|
return;
|
|
10690
10930
|
}
|
|
10691
10931
|
const width = Math.max(...rows.map((row) => row.email.length));
|
|
10692
|
-
|
|
10932
|
+
p62.log.info(
|
|
10693
10933
|
`Editors
|
|
10694
10934
|
|
|
10695
10935
|
` + rows.map(
|
|
@@ -10746,7 +10986,7 @@ var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
|
|
|
10746
10986
|
var program = new Command105().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
|
|
10747
10987
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
10748
10988
|
if (isStub(actionCommand)) return;
|
|
10749
|
-
const envRoot = findWorkspaceRoot() ??
|
|
10989
|
+
const envRoot = findWorkspaceRoot() ?? process41.cwd();
|
|
10750
10990
|
dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
|
|
10751
10991
|
const path47 = getCommandPath(actionCommand);
|
|
10752
10992
|
if (NO_BACKEND_COMMMANDS.has(path47)) return;
|
|
@@ -10754,20 +10994,20 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
|
10754
10994
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
10755
10995
|
if (!hasBackend()) {
|
|
10756
10996
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
10757
|
-
|
|
10997
|
+
p63.log.error(
|
|
10758
10998
|
`${pc38.cyan(`vela ${path47}`)} needs a backend, and this project does not have one.
|
|
10759
10999
|
|
|
10760
11000
|
Static projects have no database to talk to.
|
|
10761
11001
|
|
|
10762
11002
|
To add a backend to this project, run ${pc38.cyan("vela bless")}.`
|
|
10763
11003
|
);
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
11004
|
+
p63.log.message();
|
|
11005
|
+
p63.cancel("Operation failed.");
|
|
11006
|
+
process41.exit(1);
|
|
10767
11007
|
}
|
|
10768
11008
|
if (SELF_CREDENTIALED_COMMANDS.has(path47)) return;
|
|
10769
|
-
if (!
|
|
10770
|
-
|
|
11009
|
+
if (!process41.env.POCKETBASE_SUPERUSER_EMAIL || !process41.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
11010
|
+
p63.log.error(
|
|
10771
11011
|
`PocketBase superuser credentials are required.
|
|
10772
11012
|
|
|
10773
11013
|
Set ${pc38.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc38.cyan("POCKETBASE_SUPERUSER_PASSWORD")} in your .env file.
|
|
@@ -10775,9 +11015,9 @@ Set ${pc38.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc38.cyan("POCKETBASE_SUPER
|
|
|
10775
11015
|
To set up a new project, run ${pc38.cyan("vela create")}.
|
|
10776
11016
|
To set up an existing project, run ${pc38.cyan("vela bless")}.`
|
|
10777
11017
|
);
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
11018
|
+
p63.log.message();
|
|
11019
|
+
p63.cancel("Operation failed.");
|
|
11020
|
+
process41.exit(1);
|
|
10781
11021
|
}
|
|
10782
11022
|
});
|
|
10783
11023
|
function getCommandPath(cmd) {
|
|
@@ -10831,5 +11071,5 @@ for (const command of [
|
|
|
10831
11071
|
}
|
|
10832
11072
|
|
|
10833
11073
|
// src/bin.ts
|
|
10834
|
-
program.parse(normalizeArgv(
|
|
11074
|
+
program.parse(normalizeArgv(process42.argv.slice(2)), { from: "user" });
|
|
10835
11075
|
//# sourceMappingURL=bin.js.map
|