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