vela 0.11.5 → 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 +1357 -977
- package/dist/bin.js.map +4 -4
- package/package.json +3 -3
- 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,9 +11,9 @@ function normalizeArgv(argv) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// src/program.ts
|
|
14
|
-
import
|
|
15
|
-
import * as
|
|
16
|
-
import { Command as
|
|
14
|
+
import process41 from "node:process";
|
|
15
|
+
import * as p63 from "@clack/prompts";
|
|
16
|
+
import { Command as Command105 } from "commander";
|
|
17
17
|
import nodePath from "node:path";
|
|
18
18
|
import dotenv2 from "dotenv";
|
|
19
19
|
import pc38 from "picocolors";
|
|
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.
|
|
24
|
+
version: "0.12.0",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -57,7 +57,7 @@ var package_default = {
|
|
|
57
57
|
dependencies: {
|
|
58
58
|
"@clack/prompts": "^1.7.0",
|
|
59
59
|
"@faker-js/faker": "^10.6.0",
|
|
60
|
-
"@velastack/patterns": "^0.2.
|
|
60
|
+
"@velastack/patterns": "^0.2.5",
|
|
61
61
|
"@velastack/pocketbase-codegen": "^0.1.0",
|
|
62
62
|
"annotate-json-schema": "^0.1.0",
|
|
63
63
|
commander: "^13.1.0",
|
|
@@ -66,7 +66,7 @@ var package_default = {
|
|
|
66
66
|
dotenv: "^17.4.2",
|
|
67
67
|
"fetch-cookie": "^3.2.0",
|
|
68
68
|
"json-schema-faker": "^0.6.3",
|
|
69
|
-
"magic-string": "^
|
|
69
|
+
"magic-string": "^1.2.3",
|
|
70
70
|
"package-manager-detector": "^1.8.0",
|
|
71
71
|
picocolors: "^1.1.1",
|
|
72
72
|
pocketbase: "^0.28.0",
|
|
@@ -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}$/)),
|
|
@@ -593,10 +602,10 @@ function writeCachedIndex(cached2) {
|
|
|
593
602
|
fs5.mkdirSync(cacheRoot(), { recursive: true });
|
|
594
603
|
fs5.writeFileSync(indexCachePath(), JSON.stringify(cached2, null, 2));
|
|
595
604
|
}
|
|
596
|
-
function parseTemplateIndex(
|
|
605
|
+
function parseTemplateIndex(text19, url) {
|
|
597
606
|
let parsed;
|
|
598
607
|
try {
|
|
599
|
-
parsed = JSON.parse(
|
|
608
|
+
parsed = JSON.parse(text19);
|
|
600
609
|
} catch (e) {
|
|
601
610
|
throw new Error(`Template index at ${url} is not valid JSON: ${e.message}`);
|
|
602
611
|
}
|
|
@@ -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,37 +1923,493 @@ function printNextSteps(projectPath, packageManager2) {
|
|
|
1912
1923
|
}
|
|
1913
1924
|
|
|
1914
1925
|
// src/commands/create.ts
|
|
1926
|
+
import fs17 from "node:fs";
|
|
1927
|
+
import path15 from "node:path";
|
|
1928
|
+
import process11 from "node:process";
|
|
1929
|
+
import * as v4 from "valibot";
|
|
1930
|
+
import { Command as Command4 } from "commander";
|
|
1931
|
+
import * as p8 from "@clack/prompts";
|
|
1932
|
+
import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
1933
|
+
|
|
1934
|
+
// src/lib/providers.ts
|
|
1935
|
+
import process8 from "node:process";
|
|
1936
|
+
import * as p5 from "@clack/prompts";
|
|
1937
|
+
import { bySlug } from "@velastack/patterns";
|
|
1938
|
+
function capabilityName(slug2) {
|
|
1939
|
+
return slug2.replace(/^enable-/, "");
|
|
1940
|
+
}
|
|
1941
|
+
function choices(providers) {
|
|
1942
|
+
return `--provider <${providers.map((provider) => provider.id).join("|")}>`;
|
|
1943
|
+
}
|
|
1944
|
+
function unknownProviderMessage(name, raw, providers) {
|
|
1945
|
+
return [
|
|
1946
|
+
`Unknown provider "${raw}" for ${name}.`,
|
|
1947
|
+
"",
|
|
1948
|
+
"Available providers:",
|
|
1949
|
+
...providers.map((provider) => ` ${provider.id}`)
|
|
1950
|
+
].join("\n");
|
|
1951
|
+
}
|
|
1952
|
+
function decideProvider(request) {
|
|
1953
|
+
const { patternName, providers, flagValue, interactive } = request;
|
|
1954
|
+
if (flagValue !== void 0) {
|
|
1955
|
+
const provider = providers.find((candidate) => candidate.id === flagValue);
|
|
1956
|
+
if (!provider) {
|
|
1957
|
+
return { kind: "error", message: unknownProviderMessage(patternName, flagValue, providers) };
|
|
1958
|
+
}
|
|
1959
|
+
return { kind: "use", provider };
|
|
1960
|
+
}
|
|
1961
|
+
if (interactive) return { kind: "prompt" };
|
|
1962
|
+
return {
|
|
1963
|
+
kind: "error",
|
|
1964
|
+
message: `Choose ${article(patternName)} ${patternName} provider: pass ${choices(providers)}. There is no terminal to ask on.`
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
function article(word) {
|
|
1968
|
+
return /^[aeiou]/i.test(word) ? "an" : "a";
|
|
1969
|
+
}
|
|
1970
|
+
function isInteractive() {
|
|
1971
|
+
return Boolean(process8.stdout.isTTY) && !process8.env.CI;
|
|
1972
|
+
}
|
|
1973
|
+
function providerFlagInArgv(argv) {
|
|
1974
|
+
return argv.some((arg) => arg === "--provider" || arg.startsWith("--provider="));
|
|
1975
|
+
}
|
|
1976
|
+
function checkProviderInput(pattern, argv, input) {
|
|
1977
|
+
const providers = pattern.providers ?? [];
|
|
1978
|
+
if (providers.length > 0) {
|
|
1979
|
+
if (typeof input.provider !== "string" || input.provider.length === 0) {
|
|
1980
|
+
throw new Error(`${pattern.title} needs a provider. Pass ${choices(providers)}.`);
|
|
1981
|
+
}
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
if (providerFlagInArgv(argv)) {
|
|
1985
|
+
throw new Error(`${pattern.title} does not support --provider.`);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
async function resolveProvider(slug2, flagValue) {
|
|
1989
|
+
const pattern = bySlug[slug2];
|
|
1990
|
+
const providers = pattern.providers ?? [];
|
|
1991
|
+
if (providers.length === 0) {
|
|
1992
|
+
throw new Error(`${pattern.title} does not support --provider.`);
|
|
1993
|
+
}
|
|
1994
|
+
const patternName = capabilityName(slug2);
|
|
1995
|
+
const decision = decideProvider({
|
|
1996
|
+
patternName,
|
|
1997
|
+
providers,
|
|
1998
|
+
flagValue,
|
|
1999
|
+
interactive: isInteractive()
|
|
2000
|
+
});
|
|
2001
|
+
if (decision.kind === "error") throw new Error(decision.message);
|
|
2002
|
+
if (decision.kind === "use") return decision.provider;
|
|
2003
|
+
const selected = await p5.select({
|
|
2004
|
+
message: `Select ${patternName} provider`,
|
|
2005
|
+
options: providers.map((provider) => ({ value: provider.id, label: provider.label }))
|
|
2006
|
+
});
|
|
2007
|
+
if (p5.isCancel(selected)) {
|
|
2008
|
+
p5.cancel("Operation cancelled.");
|
|
2009
|
+
process8.exit(0);
|
|
2010
|
+
}
|
|
2011
|
+
return providers.find((provider) => provider.id === selected);
|
|
2012
|
+
}
|
|
2013
|
+
async function collectProviderEnv(provider) {
|
|
2014
|
+
const values = {};
|
|
2015
|
+
const interactive = isInteractive();
|
|
2016
|
+
for (const variable of provider.env ?? []) {
|
|
2017
|
+
const existing = process8.env[variable.key];
|
|
2018
|
+
if (existing) {
|
|
2019
|
+
values[variable.key] = existing;
|
|
2020
|
+
continue;
|
|
2021
|
+
}
|
|
2022
|
+
if (!interactive) {
|
|
2023
|
+
values[variable.key] = variable.default ?? "";
|
|
2024
|
+
continue;
|
|
2025
|
+
}
|
|
2026
|
+
const value = await p5.text({
|
|
2027
|
+
message: variable.label,
|
|
2028
|
+
placeholder: variable.placeholder,
|
|
2029
|
+
initialValue: variable.default
|
|
2030
|
+
});
|
|
2031
|
+
if (p5.isCancel(value)) {
|
|
2032
|
+
p5.cancel("Operation cancelled.");
|
|
2033
|
+
process8.exit(0);
|
|
2034
|
+
}
|
|
2035
|
+
values[variable.key] = (value ?? "").trim();
|
|
2036
|
+
}
|
|
2037
|
+
return values;
|
|
2038
|
+
}
|
|
2039
|
+
function missingEnvKeys(provider, values) {
|
|
2040
|
+
return (provider.env ?? []).filter((variable) => !(values[variable.key] ?? "").trim() && !variable.default).map((variable) => variable.key);
|
|
2041
|
+
}
|
|
2042
|
+
|
|
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
|
+
);
|
|
2081
|
+
}
|
|
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.");
|
|
2088
|
+
}
|
|
2089
|
+
return steps;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
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
|
+
}
|
|
2237
|
+
|
|
2238
|
+
// src/lib/project-config.ts
|
|
1915
2239
|
import fs16 from "node:fs";
|
|
1916
2240
|
import path14 from "node:path";
|
|
1917
|
-
|
|
1918
|
-
|
|
2241
|
+
function projectConfigPath(workspaceRootDir) {
|
|
2242
|
+
return path14.join(workspaceRootDir, ".vela", "project.json");
|
|
2243
|
+
}
|
|
2244
|
+
function readProjectConfig(workspaceRootDir) {
|
|
2245
|
+
const file = projectConfigPath(workspaceRootDir);
|
|
2246
|
+
if (!fs16.existsSync(file)) return null;
|
|
2247
|
+
try {
|
|
2248
|
+
const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
2249
|
+
if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
|
|
2250
|
+
return null;
|
|
2251
|
+
}
|
|
2252
|
+
return {
|
|
2253
|
+
projectId: parsed.projectId,
|
|
2254
|
+
teamId: parsed.teamId,
|
|
2255
|
+
projectName: parsed.projectName
|
|
2256
|
+
};
|
|
2257
|
+
} catch {
|
|
2258
|
+
return null;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
function writeProjectConfig(workspaceRootDir, config) {
|
|
2262
|
+
const file = projectConfigPath(workspaceRootDir);
|
|
2263
|
+
fs16.mkdirSync(path14.dirname(file), { recursive: true });
|
|
2264
|
+
let existing = {};
|
|
2265
|
+
if (fs16.existsSync(file)) {
|
|
2266
|
+
try {
|
|
2267
|
+
existing = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
2268
|
+
} catch {
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
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";
|
|
1919
2277
|
import { Command as Command3 } from "commander";
|
|
1920
|
-
import * as
|
|
1921
|
-
import
|
|
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
|
|
1922
2355
|
function optionsSchema2(listing) {
|
|
1923
2356
|
const names = listing.templates.map((template) => template.name);
|
|
1924
|
-
let
|
|
2357
|
+
let choices2 = `must be one of: ${templateChoicesMessage(listing.templates)}`;
|
|
1925
2358
|
if (listing.registryError) {
|
|
1926
|
-
|
|
2359
|
+
choices2 += ` (could not reach the template registry: ${listing.registryError})`;
|
|
1927
2360
|
}
|
|
1928
2361
|
return v4.strictObject({
|
|
1929
2362
|
install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
|
|
1930
|
-
template: v4.optional(v4.picklist(names,
|
|
2363
|
+
template: v4.optional(v4.picklist(names, choices2)),
|
|
1931
2364
|
name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
|
|
1932
2365
|
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")))
|
|
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
|
+
)
|
|
1934
2380
|
});
|
|
1935
2381
|
}
|
|
1936
|
-
|
|
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) => {
|
|
1937
2404
|
return runCommand(async () => {
|
|
1938
2405
|
const listing = await listAllTemplates();
|
|
1939
2406
|
const options = parseOptions(optionsSchema2(listing), rawOpts);
|
|
1940
|
-
const { directory, packageManager: packageManager2, name, template } = await
|
|
2407
|
+
const { directory, packageManager: packageManager2, name, template, link: link2 } = await createProject2(
|
|
1941
2408
|
projectPath,
|
|
1942
2409
|
options,
|
|
1943
2410
|
listing
|
|
1944
2411
|
);
|
|
1945
|
-
const relative =
|
|
2412
|
+
const relative = path15.relative(process11.cwd(), directory);
|
|
1946
2413
|
const pm = packageManager2 ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
1947
2414
|
const nextSteps = [];
|
|
1948
2415
|
if (relative !== "") {
|
|
@@ -1973,6 +2440,7 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1973
2440
|
);
|
|
1974
2441
|
nextSteps.push("Run `vela ui add <component>` to add UI components.");
|
|
1975
2442
|
}
|
|
2443
|
+
nextSteps.push(...linkNextSteps(link2));
|
|
1976
2444
|
nextSteps.push("Stuck? Visit https://docs.velastack.dev");
|
|
1977
2445
|
reportResult({
|
|
1978
2446
|
summary: `Created ${name} at ${directory}.`,
|
|
@@ -1980,42 +2448,38 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1980
2448
|
});
|
|
1981
2449
|
}, "Failed to create project.");
|
|
1982
2450
|
});
|
|
1983
|
-
async function
|
|
2451
|
+
async function createProject2(cwdArg, options, listing) {
|
|
1984
2452
|
const onCancel2 = () => {
|
|
1985
|
-
|
|
1986
|
-
|
|
2453
|
+
p8.cancel("Operation cancelled.");
|
|
2454
|
+
process11.exit(0);
|
|
1987
2455
|
};
|
|
1988
2456
|
const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
|
|
1989
|
-
|
|
1990
|
-
throw new Error(
|
|
1991
|
-
`--email and --password don't apply to the ${template.name} template \u2014 it has no backend.`
|
|
1992
|
-
);
|
|
1993
|
-
}
|
|
2457
|
+
checkFlagsForTemplate(template, options);
|
|
1994
2458
|
let directory;
|
|
1995
2459
|
if (cwdArg) {
|
|
1996
|
-
directory =
|
|
2460
|
+
directory = path15.resolve(cwdArg);
|
|
1997
2461
|
} else {
|
|
1998
|
-
const answer = await
|
|
2462
|
+
const answer = await p8.text({
|
|
1999
2463
|
message: "Where would you like your project to be created?",
|
|
2000
2464
|
placeholder: " (hit Enter to use current directory)",
|
|
2001
2465
|
defaultValue: "./"
|
|
2002
2466
|
});
|
|
2003
|
-
if (
|
|
2004
|
-
directory =
|
|
2467
|
+
if (p8.isCancel(answer)) onCancel2();
|
|
2468
|
+
directory = path15.resolve(answer);
|
|
2005
2469
|
}
|
|
2006
|
-
if (
|
|
2007
|
-
const force = await
|
|
2470
|
+
if (fs17.existsSync(directory) && fs17.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
|
|
2471
|
+
const force = await p8.confirm({
|
|
2008
2472
|
message: "Directory not empty. Continue?",
|
|
2009
2473
|
initialValue: false
|
|
2010
2474
|
});
|
|
2011
|
-
if (
|
|
2475
|
+
if (p8.isCancel(force) || !force) onCancel2();
|
|
2012
2476
|
}
|
|
2013
|
-
const dirName =
|
|
2014
|
-
const { name } = await
|
|
2477
|
+
const dirName = path15.basename(directory);
|
|
2478
|
+
const { name } = await p8.group(
|
|
2015
2479
|
{
|
|
2016
2480
|
name: () => {
|
|
2017
2481
|
if (options.name) return Promise.resolve(options.name);
|
|
2018
|
-
return
|
|
2482
|
+
return p8.text({
|
|
2019
2483
|
message: "App name (used for emails, etc)",
|
|
2020
2484
|
initialValue: dirName || "SvelteKit",
|
|
2021
2485
|
validate: (value) => value?.trim() ? void 0 : "App name is required"
|
|
@@ -2025,19 +2489,28 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2025
2489
|
{ onCancel: onCancel2 }
|
|
2026
2490
|
);
|
|
2027
2491
|
const credentials = template.backend ? await promptCredentials(options, onCancel2) : void 0;
|
|
2492
|
+
const link2 = await linkOnCreate(name, template, options, onCancel2);
|
|
2028
2493
|
const projectPath = directory;
|
|
2029
|
-
if (template.source === "remote")
|
|
2494
|
+
if (template.source === "remote") p8.log.step(`Downloading template ${template.name}...`);
|
|
2030
2495
|
const resolved = await resolveTemplate(template);
|
|
2031
2496
|
try {
|
|
2032
2497
|
copyTemplate(resolved, projectPath);
|
|
2033
|
-
applyTemplateFiles(projectPath, {
|
|
2498
|
+
applyTemplateFiles(projectPath, {
|
|
2499
|
+
appName: name,
|
|
2500
|
+
cliVersion: package_default.version,
|
|
2501
|
+
cmsEndpoint: link2.cmsEndpoint
|
|
2502
|
+
});
|
|
2034
2503
|
} finally {
|
|
2035
2504
|
resolved.cleanup();
|
|
2036
2505
|
}
|
|
2037
|
-
if (!
|
|
2506
|
+
if (!fs17.existsSync(path15.join(projectPath, "package.json"))) {
|
|
2038
2507
|
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
2039
2508
|
}
|
|
2040
|
-
|
|
2509
|
+
if (link2.linked) {
|
|
2510
|
+
const { projectId, teamId, projectName } = link2.linked;
|
|
2511
|
+
writeProjectConfig(projectPath, { projectId, teamId, projectName });
|
|
2512
|
+
}
|
|
2513
|
+
p8.log.success("Project created");
|
|
2041
2514
|
let packageManager2;
|
|
2042
2515
|
if (options.install !== false) {
|
|
2043
2516
|
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
@@ -2050,7 +2523,7 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2050
2523
|
}
|
|
2051
2524
|
if (credentials) {
|
|
2052
2525
|
const { email: email3, password: password11 } = credentials;
|
|
2053
|
-
|
|
2526
|
+
p8.log.step("Initializing PocketBase...");
|
|
2054
2527
|
await createSuperuser(projectPath, email3, password11);
|
|
2055
2528
|
await withPocketbase(
|
|
2056
2529
|
projectPath,
|
|
@@ -2069,16 +2542,99 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2069
2542
|
},
|
|
2070
2543
|
["PocketBase superuser credentials \u2014 used by `vela` commands"]
|
|
2071
2544
|
);
|
|
2072
|
-
|
|
2545
|
+
p8.log.success("PocketBase initialized");
|
|
2073
2546
|
}
|
|
2074
|
-
return { directory: projectPath, packageManager: packageManager2, name, template };
|
|
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) };
|
|
2075
2631
|
}
|
|
2076
2632
|
function promptCredentials(options, onCancel2) {
|
|
2077
|
-
return
|
|
2633
|
+
return p8.group(
|
|
2078
2634
|
{
|
|
2079
2635
|
email: () => {
|
|
2080
2636
|
if (options.email) return Promise.resolve(options.email);
|
|
2081
|
-
return
|
|
2637
|
+
return p8.text({
|
|
2082
2638
|
message: "Enter an email for the admin user",
|
|
2083
2639
|
initialValue: "admin@example.com",
|
|
2084
2640
|
validate: (value) => !value ? "Email is required" : !value.includes("@") ? "Invalid email" : void 0
|
|
@@ -2086,7 +2642,7 @@ function promptCredentials(options, onCancel2) {
|
|
|
2086
2642
|
},
|
|
2087
2643
|
password: () => {
|
|
2088
2644
|
if (options.password) return Promise.resolve(options.password);
|
|
2089
|
-
return
|
|
2645
|
+
return p8.password({
|
|
2090
2646
|
message: "Enter a password for the admin user (at least 8 characters)",
|
|
2091
2647
|
validate: (value) => !value ? "Password is required" : value.length < 8 ? "Password must be at least 8 characters long" : void 0
|
|
2092
2648
|
});
|
|
@@ -2097,27 +2653,28 @@ function promptCredentials(options, onCancel2) {
|
|
|
2097
2653
|
}
|
|
2098
2654
|
|
|
2099
2655
|
// src/commands/generate.ts
|
|
2100
|
-
import { Command as
|
|
2656
|
+
import { Command as Command10 } from "commander";
|
|
2101
2657
|
|
|
2102
2658
|
// src/commands/generate/form.ts
|
|
2103
|
-
import { Command as
|
|
2104
|
-
import * as
|
|
2659
|
+
import { Command as Command5 } from "commander";
|
|
2660
|
+
import * as p14 from "@clack/prompts";
|
|
2105
2661
|
|
|
2106
2662
|
// src/lib/pattern-runner.ts
|
|
2107
|
-
import
|
|
2108
|
-
import * as
|
|
2109
|
-
import { bySlug } from "@velastack/patterns";
|
|
2663
|
+
import path16 from "node:path";
|
|
2664
|
+
import * as p9 from "@clack/prompts";
|
|
2665
|
+
import { bySlug as bySlug2 } from "@velastack/patterns";
|
|
2110
2666
|
function toRelative(root, filePath) {
|
|
2111
|
-
return
|
|
2667
|
+
return path16.isAbsolute(filePath) ? path16.relative(root, filePath) : filePath;
|
|
2112
2668
|
}
|
|
2113
2669
|
var isSuccess = (f) => (f.status ?? "success") === "success";
|
|
2114
2670
|
async function runPattern(slug2, argv, input, report4) {
|
|
2115
|
-
const pattern =
|
|
2671
|
+
const pattern = bySlug2[slug2];
|
|
2116
2672
|
if (!pattern) {
|
|
2117
2673
|
throw new Error(`Unknown pattern: ${slug2}`);
|
|
2118
2674
|
}
|
|
2675
|
+
checkProviderInput(pattern, argv, input);
|
|
2119
2676
|
const { workspaceRootDir, features } = await getWorkspace();
|
|
2120
|
-
const log45 =
|
|
2677
|
+
const log45 = p9.taskLog({ title: report4.task.title });
|
|
2121
2678
|
let result;
|
|
2122
2679
|
try {
|
|
2123
2680
|
result = await pattern.generate({
|
|
@@ -2156,7 +2713,7 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
2156
2713
|
const deleted = result.deletes.filter(isSuccess);
|
|
2157
2714
|
const totalChanges = created.length + modified.length + deleted.length + result.components.length + result.packages.length + result.collections.length;
|
|
2158
2715
|
if (totalChanges === 0 && failures.length === 0) {
|
|
2159
|
-
|
|
2716
|
+
p9.log.info(`${pattern.title ?? slug2} produced no changes.`);
|
|
2160
2717
|
return;
|
|
2161
2718
|
}
|
|
2162
2719
|
reportResult({
|
|
@@ -2177,45 +2734,9 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
2177
2734
|
// src/lib/ai-flow.ts
|
|
2178
2735
|
import fs18 from "node:fs";
|
|
2179
2736
|
import path17 from "node:path";
|
|
2180
|
-
import * as
|
|
2737
|
+
import * as p13 from "@clack/prompts";
|
|
2181
2738
|
import pc4 from "picocolors";
|
|
2182
2739
|
|
|
2183
|
-
// src/lib/project-config.ts
|
|
2184
|
-
import fs17 from "node:fs";
|
|
2185
|
-
import path16 from "node:path";
|
|
2186
|
-
function projectConfigPath(workspaceRootDir) {
|
|
2187
|
-
return path16.join(workspaceRootDir, ".vela", "project.json");
|
|
2188
|
-
}
|
|
2189
|
-
function readProjectConfig(workspaceRootDir) {
|
|
2190
|
-
const file = projectConfigPath(workspaceRootDir);
|
|
2191
|
-
if (!fs17.existsSync(file)) return null;
|
|
2192
|
-
try {
|
|
2193
|
-
const parsed = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
2194
|
-
if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
|
|
2195
|
-
return null;
|
|
2196
|
-
}
|
|
2197
|
-
return {
|
|
2198
|
-
projectId: parsed.projectId,
|
|
2199
|
-
teamId: parsed.teamId,
|
|
2200
|
-
projectName: parsed.projectName
|
|
2201
|
-
};
|
|
2202
|
-
} catch {
|
|
2203
|
-
return null;
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2206
|
-
function writeProjectConfig(workspaceRootDir, config) {
|
|
2207
|
-
const file = projectConfigPath(workspaceRootDir);
|
|
2208
|
-
fs17.mkdirSync(path16.dirname(file), { recursive: true });
|
|
2209
|
-
let existing = {};
|
|
2210
|
-
if (fs17.existsSync(file)) {
|
|
2211
|
-
try {
|
|
2212
|
-
existing = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
2213
|
-
} catch {
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
|
-
fs17.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
2740
|
// src/lib/ai-client.ts
|
|
2220
2741
|
async function aiPost(workspaceRootDir, endpoint, body) {
|
|
2221
2742
|
const apiKey = requireApiKey();
|
|
@@ -2250,14 +2771,14 @@ var aiSchema = (workspaceRootDir, body) => aiPost(workspaceRootDir, "schema", bo
|
|
|
2250
2771
|
var aiForm = (workspaceRootDir, body) => aiPost(workspaceRootDir, "form", body);
|
|
2251
2772
|
|
|
2252
2773
|
// src/lib/ai-loop.ts
|
|
2253
|
-
import * as
|
|
2774
|
+
import * as p10 from "@clack/prompts";
|
|
2254
2775
|
async function aiLoop(opts) {
|
|
2255
2776
|
let prompt = opts.initialPrompt;
|
|
2256
2777
|
let history = [];
|
|
2257
2778
|
let attempt = 0;
|
|
2258
2779
|
while (true) {
|
|
2259
2780
|
attempt++;
|
|
2260
|
-
const spinner7 =
|
|
2781
|
+
const spinner7 = p10.spinner();
|
|
2261
2782
|
spinner7.start(`${opts.stageLabel} (${attempt > 1 ? "iteration " + attempt : "first pass"})\u2026`);
|
|
2262
2783
|
let result;
|
|
2263
2784
|
let turn;
|
|
@@ -2271,12 +2792,12 @@ async function aiLoop(opts) {
|
|
|
2271
2792
|
throw e;
|
|
2272
2793
|
}
|
|
2273
2794
|
opts.renderPreview(result);
|
|
2274
|
-
const next = await
|
|
2795
|
+
const next = await p10.text({
|
|
2275
2796
|
message: "Refine the result, or press Enter to apply.",
|
|
2276
2797
|
placeholder: opts.refinePlaceholder,
|
|
2277
2798
|
defaultValue: ""
|
|
2278
2799
|
});
|
|
2279
|
-
if (
|
|
2800
|
+
if (p10.isCancel(next)) return null;
|
|
2280
2801
|
const trimmed = (typeof next === "string" ? next : "").trim();
|
|
2281
2802
|
if (trimmed === "") return result;
|
|
2282
2803
|
history = turn;
|
|
@@ -2285,7 +2806,7 @@ async function aiLoop(opts) {
|
|
|
2285
2806
|
}
|
|
2286
2807
|
|
|
2287
2808
|
// src/lib/ai-existing-models.ts
|
|
2288
|
-
import * as
|
|
2809
|
+
import * as p11 from "@clack/prompts";
|
|
2289
2810
|
async function loadExistingModels(workspaceRootDir) {
|
|
2290
2811
|
let result = [];
|
|
2291
2812
|
try {
|
|
@@ -2310,7 +2831,7 @@ async function loadExistingModels(workspaceRootDir) {
|
|
|
2310
2831
|
});
|
|
2311
2832
|
} catch (e) {
|
|
2312
2833
|
const msg = e instanceof Error ? e.message : String(e);
|
|
2313
|
-
|
|
2834
|
+
p11.log.warn(
|
|
2314
2835
|
`Could not load existing schema from PocketBase (${msg}). The AI agent will design without that context.`
|
|
2315
2836
|
);
|
|
2316
2837
|
return [];
|
|
@@ -2319,7 +2840,7 @@ async function loadExistingModels(workspaceRootDir) {
|
|
|
2319
2840
|
}
|
|
2320
2841
|
|
|
2321
2842
|
// src/lib/ai-to-argv.ts
|
|
2322
|
-
import * as
|
|
2843
|
+
import * as p12 from "@clack/prompts";
|
|
2323
2844
|
var PRIMITIVE_TYPES = /* @__PURE__ */ new Set(["text", "number", "bool", "email", "date", "url", "file"]);
|
|
2324
2845
|
function singularize(name) {
|
|
2325
2846
|
if (name.endsWith("ies") && name.length > 3) return `${name.slice(0, -3)}y`;
|
|
@@ -2342,7 +2863,7 @@ function collectionSpecToArgv(spec) {
|
|
|
2342
2863
|
for (const field of spec.fields) {
|
|
2343
2864
|
const type = typeArg(field);
|
|
2344
2865
|
if (type === null) {
|
|
2345
|
-
|
|
2866
|
+
p12.log.warn(
|
|
2346
2867
|
`Skipping field "${field.name}" (type "${field.type}" cannot be represented as a pattern argument)`
|
|
2347
2868
|
);
|
|
2348
2869
|
continue;
|
|
@@ -2445,10 +2966,10 @@ function renderModel(spec) {
|
|
|
2445
2966
|
const tail = extra.length > 0 ? " " + pc4.dim(extra.join(" ")) : "";
|
|
2446
2967
|
lines.push(` ${f.name.padEnd(nameWidth)} ${f.type.padEnd(typeWidth)} ${required}${tail}`);
|
|
2447
2968
|
}
|
|
2448
|
-
|
|
2969
|
+
p13.log.message(lines.join("\n"));
|
|
2449
2970
|
}
|
|
2450
2971
|
function renderLayout(layout) {
|
|
2451
|
-
|
|
2972
|
+
p13.log.message(renderGrid(layout));
|
|
2452
2973
|
}
|
|
2453
2974
|
async function runSchemaStage(opts) {
|
|
2454
2975
|
const { workspaceRootDir } = await getWorkspace();
|
|
@@ -2495,7 +3016,7 @@ function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
|
|
|
2495
3016
|
}
|
|
2496
3017
|
|
|
2497
3018
|
// src/commands/generate/form.ts
|
|
2498
|
-
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(
|
|
2499
3020
|
"--route <route>",
|
|
2500
3021
|
'place the form at a custom route (e.g. "(app)/[team_id]/projects/new"). Defaults to the model name under (app)/(public).'
|
|
2501
3022
|
).option(
|
|
@@ -2512,12 +3033,12 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2512
3033
|
}
|
|
2513
3034
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "form" });
|
|
2514
3035
|
if (!stage2) {
|
|
2515
|
-
|
|
3036
|
+
p14.cancel("Aborted before any files were written.");
|
|
2516
3037
|
return;
|
|
2517
3038
|
}
|
|
2518
3039
|
const layout = await runLayoutStage(stage2.workspaceRootDir, stage2.model);
|
|
2519
3040
|
if (!layout) {
|
|
2520
|
-
|
|
3041
|
+
p14.cancel("Aborted before any files were written.");
|
|
2521
3042
|
return;
|
|
2522
3043
|
}
|
|
2523
3044
|
argv = specToArgv(stage2.model);
|
|
@@ -2558,9 +3079,9 @@ var form = new Command4("form").description("generate a form from a model").argu
|
|
|
2558
3079
|
);
|
|
2559
3080
|
|
|
2560
3081
|
// src/commands/generate/schema.ts
|
|
2561
|
-
import { Command as
|
|
2562
|
-
import * as
|
|
2563
|
-
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(
|
|
2564
3085
|
(model, fields, options) => runCommand(async () => {
|
|
2565
3086
|
let argv;
|
|
2566
3087
|
let modelName;
|
|
@@ -2570,7 +3091,7 @@ var schema = new Command5("schema").description("generate a schema from a model"
|
|
|
2570
3091
|
}
|
|
2571
3092
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "schema" });
|
|
2572
3093
|
if (!stage2) {
|
|
2573
|
-
|
|
3094
|
+
p15.cancel("Aborted before any files were written.");
|
|
2574
3095
|
return;
|
|
2575
3096
|
}
|
|
2576
3097
|
argv = specToArgv(stage2.model);
|
|
@@ -2603,8 +3124,8 @@ var schema = new Command5("schema").description("generate a schema from a model"
|
|
|
2603
3124
|
);
|
|
2604
3125
|
|
|
2605
3126
|
// src/commands/generate/resource.ts
|
|
2606
|
-
import { Command as
|
|
2607
|
-
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(
|
|
2608
3129
|
(model, fields) => runCommand(
|
|
2609
3130
|
() => runPattern(
|
|
2610
3131
|
"generate-resource",
|
|
@@ -2629,9 +3150,9 @@ var resource = new Command6("resource").description("generate a resource (model
|
|
|
2629
3150
|
);
|
|
2630
3151
|
|
|
2631
3152
|
// src/commands/generate/scaffold.ts
|
|
2632
|
-
import { Command as
|
|
2633
|
-
import * as
|
|
2634
|
-
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(
|
|
2635
3156
|
"--route <route>",
|
|
2636
3157
|
'place the scaffold at a custom route (e.g. "(app)/[team_id]/projects"). Defaults to the pluralized model name under (app)/(public).'
|
|
2637
3158
|
).option(
|
|
@@ -2648,12 +3169,12 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2648
3169
|
}
|
|
2649
3170
|
const stage2 = await runSchemaStage({ prompt: options.ai, useCase: "scaffold" });
|
|
2650
3171
|
if (!stage2) {
|
|
2651
|
-
|
|
3172
|
+
p16.cancel("Aborted before any files were written.");
|
|
2652
3173
|
return;
|
|
2653
3174
|
}
|
|
2654
3175
|
const layout = await runLayoutStage(stage2.workspaceRootDir, stage2.model);
|
|
2655
3176
|
if (!layout) {
|
|
2656
|
-
|
|
3177
|
+
p16.cancel("Aborted before any files were written.");
|
|
2657
3178
|
return;
|
|
2658
3179
|
}
|
|
2659
3180
|
argv = specToArgv(stage2.model);
|
|
@@ -2695,8 +3216,8 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
|
|
|
2695
3216
|
);
|
|
2696
3217
|
|
|
2697
3218
|
// src/commands/generate/migration.ts
|
|
2698
|
-
import { Command as
|
|
2699
|
-
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(
|
|
2700
3221
|
(collection, op, args) => runCommand(
|
|
2701
3222
|
() => runPattern(
|
|
2702
3223
|
"generate-migration",
|
|
@@ -2720,14 +3241,45 @@ var migration = new Command8("migration").description("generate a migration for
|
|
|
2720
3241
|
);
|
|
2721
3242
|
|
|
2722
3243
|
// src/commands/generate.ts
|
|
2723
|
-
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);
|
|
2724
3245
|
|
|
2725
3246
|
// src/commands/enable.ts
|
|
2726
|
-
import { Command as
|
|
3247
|
+
import { Command as Command26 } from "commander";
|
|
3248
|
+
|
|
3249
|
+
// src/commands/enable/analytics.ts
|
|
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(
|
|
3252
|
+
(opts, cmd) => runCommand(async () => {
|
|
3253
|
+
const provider = await resolveProvider("enable-analytics", opts.provider);
|
|
3254
|
+
const providerEnv = await collectProviderEnv(provider);
|
|
3255
|
+
const blank = missingEnvKeys(provider, providerEnv);
|
|
3256
|
+
await runPattern(
|
|
3257
|
+
"enable-analytics",
|
|
3258
|
+
cmd.args,
|
|
3259
|
+
{ provider: provider.id, providerEnv },
|
|
3260
|
+
{
|
|
3261
|
+
summary: `Enabled analytics with ${provider.label}.`,
|
|
3262
|
+
nextSteps: [
|
|
3263
|
+
...blank.map(
|
|
3264
|
+
(key) => `Set ${key} in .env; the analytics component renders nothing until it is set.`
|
|
3265
|
+
),
|
|
3266
|
+
`Run \`vela dev\` and look for a page view in ${provider.label}.`,
|
|
3267
|
+
"Set the same PUBLIC_* variables on each deploy target with `vela env set`.",
|
|
3268
|
+
"The component lives in src/lib/components/analytics/analytics.svelte; edit it freely."
|
|
3269
|
+
],
|
|
3270
|
+
task: {
|
|
3271
|
+
title: "Enabling analytics",
|
|
3272
|
+
success: `Enabled analytics with ${provider.label}`,
|
|
3273
|
+
error: "Failed to enable analytics"
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
);
|
|
3277
|
+
}, "Failed to enable analytics.")
|
|
3278
|
+
);
|
|
2727
3279
|
|
|
2728
3280
|
// src/commands/enable/auth.ts
|
|
2729
|
-
import { Command as
|
|
2730
|
-
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(
|
|
2731
3283
|
(_opts, cmd) => runCommand(
|
|
2732
3284
|
() => runPattern(
|
|
2733
3285
|
"enable-auth",
|
|
@@ -2752,8 +3304,8 @@ var auth = new Command10("auth").description("enable authentication (email/passw
|
|
|
2752
3304
|
);
|
|
2753
3305
|
|
|
2754
3306
|
// src/commands/enable/api.ts
|
|
2755
|
-
import { Command as
|
|
2756
|
-
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(
|
|
2757
3309
|
(_opts, cmd) => runCommand(
|
|
2758
3310
|
() => runPattern(
|
|
2759
3311
|
"enable-api",
|
|
@@ -2778,8 +3330,8 @@ var api = new Command11("api").description("enable the PocketBase REST API").all
|
|
|
2778
3330
|
);
|
|
2779
3331
|
|
|
2780
3332
|
// src/commands/enable/api-keys.ts
|
|
2781
|
-
import { Command as
|
|
2782
|
-
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(
|
|
2783
3335
|
(_opts, cmd) => runCommand(
|
|
2784
3336
|
() => runPattern(
|
|
2785
3337
|
"enable-api-keys",
|
|
@@ -2804,8 +3356,8 @@ var apiKeys = new Command12("api-keys").description("enable API key management")
|
|
|
2804
3356
|
);
|
|
2805
3357
|
|
|
2806
3358
|
// src/commands/enable/backend.ts
|
|
2807
|
-
import { Command as
|
|
2808
|
-
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(
|
|
2809
3361
|
(_opts, cmd) => runCommand(
|
|
2810
3362
|
() => runPattern(
|
|
2811
3363
|
"enable-backend",
|
|
@@ -2830,8 +3382,8 @@ var backend = new Command13("backend").description("enable the PocketBase backen
|
|
|
2830
3382
|
);
|
|
2831
3383
|
|
|
2832
3384
|
// src/commands/enable/i18n.ts
|
|
2833
|
-
import { Command as
|
|
2834
|
-
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(
|
|
2835
3387
|
(_opts, cmd) => runCommand(
|
|
2836
3388
|
() => runPattern(
|
|
2837
3389
|
"enable-i18n",
|
|
@@ -2856,8 +3408,8 @@ var i18n = new Command14("i18n").description("enable internationalization").allo
|
|
|
2856
3408
|
);
|
|
2857
3409
|
|
|
2858
3410
|
// src/commands/enable/teams.ts
|
|
2859
|
-
import { Command as
|
|
2860
|
-
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(
|
|
2861
3413
|
(_opts, cmd) => runCommand(
|
|
2862
3414
|
() => runPattern(
|
|
2863
3415
|
"enable-teams",
|
|
@@ -2882,13 +3434,13 @@ var teams = new Command15("teams").description("enable team / multi-tenant suppo
|
|
|
2882
3434
|
);
|
|
2883
3435
|
|
|
2884
3436
|
// src/commands/enable/payments.ts
|
|
2885
|
-
import
|
|
2886
|
-
import { Command as
|
|
2887
|
-
import * as
|
|
3437
|
+
import process12 from "node:process";
|
|
3438
|
+
import { Command as Command18 } from "commander";
|
|
3439
|
+
import * as p17 from "@clack/prompts";
|
|
2888
3440
|
var PROVIDERS = [{ value: "stripe", label: "Stripe" }];
|
|
2889
|
-
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(
|
|
2890
3442
|
(opts, cmd) => runCommand(async () => {
|
|
2891
|
-
const provider = await
|
|
3443
|
+
const provider = await resolveProvider2(opts.provider, cmd.getOptionValueSource("provider"));
|
|
2892
3444
|
const input = {
|
|
2893
3445
|
provider,
|
|
2894
3446
|
stripeSecretKey: await ensureKey("STRIPE_SECRET_KEY", "Stripe secret key (sk_...)"),
|
|
@@ -2914,28 +3466,28 @@ var payments = new Command16("payments").description("enable payments").option("
|
|
|
2914
3466
|
});
|
|
2915
3467
|
}, "Failed to enable payments.")
|
|
2916
3468
|
);
|
|
2917
|
-
async function
|
|
3469
|
+
async function resolveProvider2(value, source) {
|
|
2918
3470
|
if (source && source !== "default") {
|
|
2919
3471
|
if (!PROVIDERS.some((o) => o.value === value)) {
|
|
2920
3472
|
throw new Error(`Unknown payment provider: ${value}`);
|
|
2921
3473
|
}
|
|
2922
3474
|
return value;
|
|
2923
3475
|
}
|
|
2924
|
-
const selected = await
|
|
3476
|
+
const selected = await p17.select({
|
|
2925
3477
|
message: "Which payment provider?",
|
|
2926
3478
|
options: PROVIDERS,
|
|
2927
3479
|
initialValue: "stripe"
|
|
2928
3480
|
});
|
|
2929
|
-
if (
|
|
2930
|
-
|
|
2931
|
-
|
|
3481
|
+
if (p17.isCancel(selected)) {
|
|
3482
|
+
p17.cancel("Operation cancelled.");
|
|
3483
|
+
process12.exit(0);
|
|
2932
3484
|
}
|
|
2933
3485
|
return selected;
|
|
2934
3486
|
}
|
|
2935
3487
|
async function ensureWebhookSecret() {
|
|
2936
|
-
const existing =
|
|
3488
|
+
const existing = process12.env.STRIPE_WEBHOOK_SECRET;
|
|
2937
3489
|
if (existing) return existing;
|
|
2938
|
-
|
|
3490
|
+
p17.note(
|
|
2939
3491
|
[
|
|
2940
3492
|
"Download the Stripe CLI (https://stripe.com/docs/stripe-cli), then run:",
|
|
2941
3493
|
" stripe listen --forward-to localhost:5173/webhooks/stripe",
|
|
@@ -2947,7 +3499,7 @@ async function ensureWebhookSecret() {
|
|
|
2947
3499
|
return promptPassword("Stripe webhook signing secret (whsec_...)");
|
|
2948
3500
|
}
|
|
2949
3501
|
async function ensurePriceId() {
|
|
2950
|
-
|
|
3502
|
+
p17.note(
|
|
2951
3503
|
[
|
|
2952
3504
|
"Stripe checkout requires a product and price_id.",
|
|
2953
3505
|
"If you have a demo product price_id, enter it below, or leave blank to create a demo one for you."
|
|
@@ -2955,36 +3507,36 @@ async function ensurePriceId() {
|
|
|
2955
3507
|
"Stripe demo product",
|
|
2956
3508
|
{ format: (line) => line }
|
|
2957
3509
|
);
|
|
2958
|
-
const value = await
|
|
3510
|
+
const value = await p17.text({
|
|
2959
3511
|
message: "Stripe price_id (price_...)",
|
|
2960
3512
|
placeholder: "leave blank to create a demo product"
|
|
2961
3513
|
});
|
|
2962
|
-
if (
|
|
2963
|
-
|
|
2964
|
-
|
|
3514
|
+
if (p17.isCancel(value)) {
|
|
3515
|
+
p17.cancel("Operation cancelled.");
|
|
3516
|
+
process12.exit(0);
|
|
2965
3517
|
}
|
|
2966
3518
|
return (value ?? "").trim();
|
|
2967
3519
|
}
|
|
2968
3520
|
async function ensureKey(envVar, message) {
|
|
2969
|
-
const existing =
|
|
3521
|
+
const existing = process12.env[envVar];
|
|
2970
3522
|
if (existing) return existing;
|
|
2971
3523
|
return promptPassword(message);
|
|
2972
3524
|
}
|
|
2973
3525
|
async function promptPassword(message) {
|
|
2974
|
-
const value = await
|
|
3526
|
+
const value = await p17.password({
|
|
2975
3527
|
message,
|
|
2976
3528
|
validate: (v10) => v10 && v10.length ? void 0 : "Required"
|
|
2977
3529
|
});
|
|
2978
|
-
if (
|
|
2979
|
-
|
|
2980
|
-
|
|
3530
|
+
if (p17.isCancel(value)) {
|
|
3531
|
+
p17.cancel("Operation cancelled.");
|
|
3532
|
+
process12.exit(0);
|
|
2981
3533
|
}
|
|
2982
3534
|
return value;
|
|
2983
3535
|
}
|
|
2984
3536
|
|
|
2985
3537
|
// src/commands/enable/subscriptions.ts
|
|
2986
|
-
import { Command as
|
|
2987
|
-
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(
|
|
2988
3540
|
(_opts, cmd) => runCommand(
|
|
2989
3541
|
() => runPattern(
|
|
2990
3542
|
"enable-subscriptions",
|
|
@@ -3009,8 +3561,8 @@ var subscriptions = new Command17("subscriptions").description("enable Stripe su
|
|
|
3009
3561
|
);
|
|
3010
3562
|
|
|
3011
3563
|
// src/commands/enable/notifications.ts
|
|
3012
|
-
import { Command as
|
|
3013
|
-
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(
|
|
3014
3566
|
(_opts, cmd) => runCommand(
|
|
3015
3567
|
() => runPattern(
|
|
3016
3568
|
"enable-notifications",
|
|
@@ -3035,15 +3587,15 @@ var notifications = new Command18("notifications").description("enable in-app no
|
|
|
3035
3587
|
);
|
|
3036
3588
|
|
|
3037
3589
|
// src/commands/enable/s3.ts
|
|
3038
|
-
import
|
|
3039
|
-
import { Command as
|
|
3040
|
-
import * as
|
|
3590
|
+
import process16 from "node:process";
|
|
3591
|
+
import { Command as Command21 } from "commander";
|
|
3592
|
+
import * as p20 from "@clack/prompts";
|
|
3041
3593
|
import pc8 from "picocolors";
|
|
3042
3594
|
|
|
3043
3595
|
// src/lib/server-command.ts
|
|
3044
|
-
import
|
|
3596
|
+
import process15 from "node:process";
|
|
3045
3597
|
import * as v6 from "valibot";
|
|
3046
|
-
import * as
|
|
3598
|
+
import * as p18 from "@clack/prompts";
|
|
3047
3599
|
import pc5 from "picocolors";
|
|
3048
3600
|
|
|
3049
3601
|
// src/lib/deploy-config.ts
|
|
@@ -3217,10 +3769,10 @@ import { resolveCommand as resolveCommand4 } from "package-manager-detector/comm
|
|
|
3217
3769
|
|
|
3218
3770
|
// src/lib/ssh.ts
|
|
3219
3771
|
import fs20 from "node:fs";
|
|
3220
|
-
import
|
|
3772
|
+
import os4 from "node:os";
|
|
3221
3773
|
import path19 from "node:path";
|
|
3222
3774
|
import crypto3 from "node:crypto";
|
|
3223
|
-
import
|
|
3775
|
+
import process13 from "node:process";
|
|
3224
3776
|
import { spawn as spawn2 } from "node:child_process";
|
|
3225
3777
|
var RemoteCommandError = class extends Error {
|
|
3226
3778
|
exitCode;
|
|
@@ -3261,7 +3813,7 @@ var SshSession = class {
|
|
|
3261
3813
|
}
|
|
3262
3814
|
async open() {
|
|
3263
3815
|
if (this.controlPath) return;
|
|
3264
|
-
const dir = path19.join(
|
|
3816
|
+
const dir = path19.join(os4.tmpdir(), "vela-ssh");
|
|
3265
3817
|
fs20.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3266
3818
|
const socket = path19.join(dir, `${crypto3.randomBytes(6).toString("hex")}.sock`);
|
|
3267
3819
|
this.controlPath = socket;
|
|
@@ -3498,17 +4050,17 @@ function spawnCapture(command, args, opts = {}) {
|
|
|
3498
4050
|
const child = spawn2(command, args, {
|
|
3499
4051
|
stdio,
|
|
3500
4052
|
cwd: opts.cwd,
|
|
3501
|
-
env: opts.env ? { ...
|
|
4053
|
+
env: opts.env ? { ...process13.env, ...opts.env } : void 0
|
|
3502
4054
|
});
|
|
3503
4055
|
let stdout = "";
|
|
3504
4056
|
let stderr = "";
|
|
3505
4057
|
child.stdout?.on("data", (chunk) => {
|
|
3506
4058
|
stdout += chunk;
|
|
3507
|
-
if (opts.streamStdout)
|
|
4059
|
+
if (opts.streamStdout) process13.stdout.write(chunk);
|
|
3508
4060
|
});
|
|
3509
4061
|
child.stderr?.on("data", (chunk) => {
|
|
3510
4062
|
stderr += chunk;
|
|
3511
|
-
if (opts.stream)
|
|
4063
|
+
if (opts.stream) process13.stderr.write(chunk);
|
|
3512
4064
|
});
|
|
3513
4065
|
child.on("error", reject);
|
|
3514
4066
|
child.on("close", (code) => resolve2({ stdout, stderr, exitCode: code ?? 1 }));
|
|
@@ -3615,7 +4167,7 @@ function sshOptionsFrom(options) {
|
|
|
3615
4167
|
import crypto4 from "node:crypto";
|
|
3616
4168
|
import fs22 from "node:fs";
|
|
3617
4169
|
import path21 from "node:path";
|
|
3618
|
-
import
|
|
4170
|
+
import process14 from "node:process";
|
|
3619
4171
|
var VELA_ROOT = "/var/lib/vela";
|
|
3620
4172
|
var VELA_ETC = "/etc/vela";
|
|
3621
4173
|
var VELA_USER = "vela";
|
|
@@ -3652,7 +4204,7 @@ async function syncServerScripts(session) {
|
|
|
3652
4204
|
const dir = `${SCRIPT_VERSIONS_DIR}/${digest}`;
|
|
3653
4205
|
const present = await session.script(`[ -d "$1" ] && echo yes || echo no`, { args: [dir] });
|
|
3654
4206
|
if (present.stdout.trim() !== "yes") {
|
|
3655
|
-
const incoming = `${SCRIPT_VERSIONS_DIR}/.incoming.${digest}.${
|
|
4207
|
+
const incoming = `${SCRIPT_VERSIONS_DIR}/.incoming.${digest}.${process14.pid}.${Date.now()}`;
|
|
3656
4208
|
await session.script(`mkdir -p "$1" && chmod 0755 "$(dirname "$1")" "$1"`, {
|
|
3657
4209
|
args: [incoming]
|
|
3658
4210
|
});
|
|
@@ -3911,8 +4463,8 @@ function describeTarget(target) {
|
|
|
3911
4463
|
return target.name;
|
|
3912
4464
|
}
|
|
3913
4465
|
}
|
|
3914
|
-
function bold(
|
|
3915
|
-
return `\`${
|
|
4466
|
+
function bold(text19) {
|
|
4467
|
+
return `\`${text19}\``;
|
|
3916
4468
|
}
|
|
3917
4469
|
|
|
3918
4470
|
// src/lib/server-command.ts
|
|
@@ -4016,7 +4568,7 @@ async function ensureBinding(workspaceRootDir, target, request = {}) {
|
|
|
4016
4568
|
writeBinding(workspaceRootDir, key, binding);
|
|
4017
4569
|
}
|
|
4018
4570
|
if (moving) {
|
|
4019
|
-
|
|
4571
|
+
p18.log.warn(
|
|
4020
4572
|
`${pc5.cyan(bindingName(target))} now points at ${pc5.cyan(server)}.
|
|
4021
4573
|
|
|
4022
4574
|
Whatever is running on ${existing.server} is left there, and this project can no
|
|
@@ -4027,7 +4579,7 @@ longer reach it. Remove it there first if that was not intended.`
|
|
|
4027
4579
|
}
|
|
4028
4580
|
async function confirmMove(target, from, to) {
|
|
4029
4581
|
const name = bindingName(target);
|
|
4030
|
-
if (!
|
|
4582
|
+
if (!process15.stdout.isTTY || process15.env.CI) {
|
|
4031
4583
|
throw new Error(
|
|
4032
4584
|
`${pc5.cyan(`--server ${to}`)} does not match the server recorded for ${pc5.cyan(name)}, ${pc5.cyan(from)}.
|
|
4033
4585
|
|
|
@@ -4035,13 +4587,13 @@ Drop ${pc5.cyan("--server")} to use the recorded one, or move the binding on pur
|
|
|
4035
4587
|
this command once from a terminal (or editing .vela/project.json).`
|
|
4036
4588
|
);
|
|
4037
4589
|
}
|
|
4038
|
-
const ok = await
|
|
4590
|
+
const ok = await p18.confirm({
|
|
4039
4591
|
message: `${name} ${target.kind === "preview" ? "run" : "runs"} on ${from}. Point ${name} at ${to} instead?`,
|
|
4040
4592
|
initialValue: false
|
|
4041
4593
|
});
|
|
4042
|
-
if (
|
|
4043
|
-
|
|
4044
|
-
|
|
4594
|
+
if (p18.isCancel(ok) || !ok) {
|
|
4595
|
+
p18.cancel("Operation cancelled.");
|
|
4596
|
+
process15.exit(0);
|
|
4045
4597
|
}
|
|
4046
4598
|
}
|
|
4047
4599
|
function bindingName(target) {
|
|
@@ -4049,7 +4601,7 @@ function bindingName(target) {
|
|
|
4049
4601
|
}
|
|
4050
4602
|
async function promptServer(target) {
|
|
4051
4603
|
const name = bindingName(target);
|
|
4052
|
-
if (!
|
|
4604
|
+
if (!process15.stdout.isTTY || process15.env.CI) {
|
|
4053
4605
|
throw new Error(
|
|
4054
4606
|
`${name} ${target.kind === "preview" ? "are" : "is"} not bound to a server yet, and there is no terminal to ask on.
|
|
4055
4607
|
|
|
@@ -4057,29 +4609,29 @@ Pass ${pc5.cyan("--server user@host")}, or run the command once from your own ma
|
|
|
4057
4609
|
and commit ${pc5.cyan(".vela/project.json")}.`
|
|
4058
4610
|
);
|
|
4059
4611
|
}
|
|
4060
|
-
|
|
4612
|
+
p18.log.info(
|
|
4061
4613
|
`${pc5.cyan(name)} ${target.kind === "preview" ? "are" : "is"} not bound to a server yet.`
|
|
4062
4614
|
);
|
|
4063
|
-
const value = await
|
|
4615
|
+
const value = await p18.text({
|
|
4064
4616
|
message: `Which server should ${name} run on?`,
|
|
4065
4617
|
placeholder: "root@203.0.113.10",
|
|
4066
4618
|
validate: (input) => input?.trim() ? void 0 : "An ssh_config alias, or user@host"
|
|
4067
4619
|
});
|
|
4068
|
-
if (
|
|
4069
|
-
|
|
4070
|
-
|
|
4620
|
+
if (p18.isCancel(value)) {
|
|
4621
|
+
p18.cancel("Operation cancelled.");
|
|
4622
|
+
process15.exit(0);
|
|
4071
4623
|
}
|
|
4072
4624
|
return value.trim();
|
|
4073
4625
|
}
|
|
4074
4626
|
async function promptDomain(target) {
|
|
4075
|
-
if (!
|
|
4076
|
-
const value = await
|
|
4627
|
+
if (!process15.stdout.isTTY || process15.env.CI) return void 0;
|
|
4628
|
+
const value = await p18.text({
|
|
4077
4629
|
message: `Which hostname should ${target.name} be served on?`,
|
|
4078
4630
|
placeholder: "example.com \u2014 leave blank to decide later"
|
|
4079
4631
|
});
|
|
4080
|
-
if (
|
|
4081
|
-
|
|
4082
|
-
|
|
4632
|
+
if (p18.isCancel(value)) {
|
|
4633
|
+
p18.cancel("Operation cancelled.");
|
|
4634
|
+
process15.exit(0);
|
|
4083
4635
|
}
|
|
4084
4636
|
return value.trim() || void 0;
|
|
4085
4637
|
}
|
|
@@ -4087,10 +4639,10 @@ async function applyRestart(ctx) {
|
|
|
4087
4639
|
const outcome = await restartInstance(ctx.session, ctx.instance);
|
|
4088
4640
|
if (!outcome.deployed) return;
|
|
4089
4641
|
if (outcome.restarted) {
|
|
4090
|
-
|
|
4642
|
+
p18.log.success("App restarted");
|
|
4091
4643
|
return;
|
|
4092
4644
|
}
|
|
4093
|
-
|
|
4645
|
+
p18.log.error(
|
|
4094
4646
|
`App restart failed.
|
|
4095
4647
|
|
|
4096
4648
|
The new value is stored and will be used the next time the app starts.
|
|
@@ -4099,7 +4651,7 @@ ${pc5.dim(outcome.error ?? "")}`
|
|
|
4099
4651
|
}
|
|
4100
4652
|
async function applyEnvRestart(ctx, changed) {
|
|
4101
4653
|
if (touchesSuperuser(changed)) {
|
|
4102
|
-
|
|
4654
|
+
p18.log.warn(
|
|
4103
4655
|
`PocketBase superuser credentials changed.
|
|
4104
4656
|
|
|
4105
4657
|
The database still holds the old ones, so the app has not been restarted.
|
|
@@ -4136,7 +4688,7 @@ import pc7 from "picocolors";
|
|
|
4136
4688
|
|
|
4137
4689
|
// src/lib/local-env.ts
|
|
4138
4690
|
import fs24 from "node:fs";
|
|
4139
|
-
import * as
|
|
4691
|
+
import * as p19 from "@clack/prompts";
|
|
4140
4692
|
import pc6 from "picocolors";
|
|
4141
4693
|
function readLocalEnv(envFile) {
|
|
4142
4694
|
if (!fs24.existsSync(envFile)) return {};
|
|
@@ -4162,16 +4714,16 @@ async function applyLocalEnvChange(ctx, changed) {
|
|
|
4162
4714
|
process.env.POCKETBASE_SUPERUSER_EMAIL = email3;
|
|
4163
4715
|
process.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
|
|
4164
4716
|
await ensureSuperuser(ctx.workspaceRootDir);
|
|
4165
|
-
|
|
4717
|
+
p19.log.success("Local superuser updated to match");
|
|
4166
4718
|
} else {
|
|
4167
|
-
|
|
4719
|
+
p19.log.warn(
|
|
4168
4720
|
`The local database still has the old superuser.
|
|
4169
4721
|
Set both ${pc6.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc6.cyan("POCKETBASE_SUPERUSER_PASSWORD")} to reconcile it.`
|
|
4170
4722
|
);
|
|
4171
4723
|
}
|
|
4172
4724
|
}
|
|
4173
4725
|
if (getPocketbaseMetadata(ctx.workspaceRootDir)) {
|
|
4174
|
-
|
|
4726
|
+
p19.log.info(`Restart ${pc6.cyan("vela dev")} to pick this up.`);
|
|
4175
4727
|
}
|
|
4176
4728
|
}
|
|
4177
4729
|
|
|
@@ -4335,7 +4887,7 @@ function hasFile(dir) {
|
|
|
4335
4887
|
|
|
4336
4888
|
// src/commands/enable/s3.ts
|
|
4337
4889
|
var s3 = addTargetOptions(
|
|
4338
|
-
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),
|
|
4339
4891
|
"local"
|
|
4340
4892
|
).action(
|
|
4341
4893
|
(raw) => runCommand(() => {
|
|
@@ -4353,7 +4905,7 @@ var s3 = addTargetOptions(
|
|
|
4353
4905
|
failure = error instanceof Error ? error.message : String(error);
|
|
4354
4906
|
}
|
|
4355
4907
|
if (failure) {
|
|
4356
|
-
|
|
4908
|
+
p20.log.warn(
|
|
4357
4909
|
`The connection test failed \u2014 the settings are saved but may be wrong.
|
|
4358
4910
|
|
|
4359
4911
|
${pc8.dim(failure)}
|
|
@@ -4397,64 +4949,64 @@ Do that first, then re-run with ${pc8.cyan("--force")}.`
|
|
|
4397
4949
|
);
|
|
4398
4950
|
}
|
|
4399
4951
|
async function promptConfig(options, existing) {
|
|
4400
|
-
const endpoint = options.endpoint ?? await
|
|
4401
|
-
const bucket = options.bucket ?? await
|
|
4402
|
-
const region = options.region ?? await
|
|
4403
|
-
const accessKey = options.accessKey ?? await
|
|
4404
|
-
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");
|
|
4405
4957
|
const forcePathStyle = options.forcePathStyle ?? await confirm4(
|
|
4406
4958
|
"Address the bucket in the path? (MinIO, Ceph and most self-hosted gateways need this)",
|
|
4407
4959
|
defaultForcePathStyle(endpoint)
|
|
4408
4960
|
);
|
|
4409
4961
|
return { endpoint, bucket, region, accessKey, secret, forcePathStyle };
|
|
4410
4962
|
}
|
|
4411
|
-
async function
|
|
4412
|
-
const value = await
|
|
4963
|
+
async function text9(message, initialValue = "") {
|
|
4964
|
+
const value = await p20.text({
|
|
4413
4965
|
message,
|
|
4414
4966
|
initialValue,
|
|
4415
4967
|
validate: (input) => input?.trim() ? void 0 : `${message} is required`
|
|
4416
4968
|
});
|
|
4417
|
-
if (
|
|
4418
|
-
|
|
4419
|
-
|
|
4969
|
+
if (p20.isCancel(value)) {
|
|
4970
|
+
p20.cancel("Operation cancelled.");
|
|
4971
|
+
process16.exit(0);
|
|
4420
4972
|
}
|
|
4421
4973
|
return value.trim();
|
|
4422
4974
|
}
|
|
4423
|
-
async function
|
|
4424
|
-
const value = await
|
|
4975
|
+
async function password6(message) {
|
|
4976
|
+
const value = await p20.password({
|
|
4425
4977
|
message,
|
|
4426
4978
|
validate: (input) => input ? void 0 : `${message} is required`
|
|
4427
4979
|
});
|
|
4428
|
-
if (
|
|
4429
|
-
|
|
4430
|
-
|
|
4980
|
+
if (p20.isCancel(value)) {
|
|
4981
|
+
p20.cancel("Operation cancelled.");
|
|
4982
|
+
process16.exit(0);
|
|
4431
4983
|
}
|
|
4432
4984
|
return value;
|
|
4433
4985
|
}
|
|
4434
4986
|
async function confirm4(message, initialValue) {
|
|
4435
|
-
const value = await
|
|
4436
|
-
if (
|
|
4437
|
-
|
|
4438
|
-
|
|
4987
|
+
const value = await p20.confirm({ message, initialValue });
|
|
4988
|
+
if (p20.isCancel(value)) {
|
|
4989
|
+
p20.cancel("Operation cancelled.");
|
|
4990
|
+
process16.exit(0);
|
|
4439
4991
|
}
|
|
4440
4992
|
return value;
|
|
4441
4993
|
}
|
|
4442
4994
|
|
|
4443
4995
|
// src/commands/enable/smtp.ts
|
|
4444
|
-
import
|
|
4445
|
-
import { Command as
|
|
4446
|
-
import * as
|
|
4447
|
-
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(
|
|
4448
5000
|
() => runCommand(async () => {
|
|
4449
5001
|
const { workspaceRootDir } = await getWorkspace();
|
|
4450
|
-
const config = await
|
|
5002
|
+
const config = await p21.group(
|
|
4451
5003
|
{
|
|
4452
|
-
host: () =>
|
|
5004
|
+
host: () => p21.text({
|
|
4453
5005
|
message: "SMTP host",
|
|
4454
5006
|
placeholder: "smtp.example.com",
|
|
4455
5007
|
validate: (v10) => v10 ? void 0 : "Host is required"
|
|
4456
5008
|
}),
|
|
4457
|
-
port: () =>
|
|
5009
|
+
port: () => p21.text({
|
|
4458
5010
|
message: "SMTP port",
|
|
4459
5011
|
initialValue: "587",
|
|
4460
5012
|
validate: (v10) => {
|
|
@@ -4464,13 +5016,13 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
|
|
|
4464
5016
|
return void 0;
|
|
4465
5017
|
}
|
|
4466
5018
|
}),
|
|
4467
|
-
username: () =>
|
|
4468
|
-
password: () =>
|
|
5019
|
+
username: () => p21.text({ message: "SMTP username" }),
|
|
5020
|
+
password: () => p21.password({ message: "SMTP password" })
|
|
4469
5021
|
},
|
|
4470
5022
|
{
|
|
4471
5023
|
onCancel: () => {
|
|
4472
|
-
|
|
4473
|
-
|
|
5024
|
+
p21.cancel("Operation cancelled.");
|
|
5025
|
+
process17.exit(0);
|
|
4474
5026
|
}
|
|
4475
5027
|
}
|
|
4476
5028
|
);
|
|
@@ -4497,24 +5049,24 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
|
|
|
4497
5049
|
);
|
|
4498
5050
|
|
|
4499
5051
|
// src/commands/enable/cms.ts
|
|
4500
|
-
import
|
|
4501
|
-
import { Command as
|
|
4502
|
-
import * as
|
|
5052
|
+
import process18 from "node:process";
|
|
5053
|
+
import { Command as Command23 } from "commander";
|
|
5054
|
+
import * as p22 from "@clack/prompts";
|
|
4503
5055
|
import pc9 from "picocolors";
|
|
4504
|
-
var cms = new
|
|
5056
|
+
var cms = new Command23("cms").description("enable an inline-editing CMS with an admin bar").option(
|
|
4505
5057
|
"--endpoint <url>",
|
|
4506
5058
|
"read from a hosted CMS at this URL instead of installing the backend in this app"
|
|
4507
5059
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
4508
5060
|
(opts, cmd) => runCommand(async () => {
|
|
4509
5061
|
if (!opts.endpoint && !hasBackend()) {
|
|
4510
|
-
|
|
5062
|
+
p22.log.error(
|
|
4511
5063
|
`${pc9.cyan("vela enable cms")} needs a server to host the CMS backend, and this project is static.
|
|
4512
5064
|
|
|
4513
5065
|
Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${pc9.cyan("vela enable cms --endpoint <url>")}.`
|
|
4514
5066
|
);
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
5067
|
+
p22.log.message();
|
|
5068
|
+
p22.cancel("Operation failed.");
|
|
5069
|
+
process18.exitCode = 1;
|
|
4518
5070
|
return;
|
|
4519
5071
|
}
|
|
4520
5072
|
await runPattern("enable-cms", cmd.args, opts.endpoint ? { endpoint: opts.endpoint } : {}, {
|
|
@@ -4534,8 +5086,8 @@ Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${
|
|
|
4534
5086
|
);
|
|
4535
5087
|
|
|
4536
5088
|
// src/commands/enable/blog.ts
|
|
4537
|
-
import { Command as
|
|
4538
|
-
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(
|
|
4539
5091
|
(_opts, cmd) => runCommand(
|
|
4540
5092
|
() => runPattern(
|
|
4541
5093
|
"enable-blog",
|
|
@@ -4560,8 +5112,8 @@ var blog = new Command22("blog").description("enable an mdsvex blog with posts,
|
|
|
4560
5112
|
);
|
|
4561
5113
|
|
|
4562
5114
|
// src/commands/enable/content-negotiation.ts
|
|
4563
|
-
import { Command as
|
|
4564
|
-
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(
|
|
4565
5117
|
(_opts, cmd) => runCommand(
|
|
4566
5118
|
() => runPattern(
|
|
4567
5119
|
"enable-content-negotiation",
|
|
@@ -4585,33 +5137,33 @@ var contentNegotiation = new Command23("content-negotiation").description("enabl
|
|
|
4585
5137
|
);
|
|
4586
5138
|
|
|
4587
5139
|
// src/commands/enable.ts
|
|
4588
|
-
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);
|
|
4589
5141
|
|
|
4590
5142
|
// src/commands/disable.ts
|
|
4591
|
-
import { Command as
|
|
5143
|
+
import { Command as Command37 } from "commander";
|
|
4592
5144
|
|
|
4593
5145
|
// src/commands/disable/auth.ts
|
|
4594
|
-
import { Command as
|
|
5146
|
+
import { Command as Command27 } from "commander";
|
|
4595
5147
|
|
|
4596
5148
|
// src/commands/disable/_shared.ts
|
|
4597
|
-
import
|
|
4598
|
-
import * as
|
|
5149
|
+
import process19 from "node:process";
|
|
5150
|
+
import * as p23 from "@clack/prompts";
|
|
4599
5151
|
async function runDisable(opts, flags, cmdArgs) {
|
|
4600
5152
|
if (!flags.yes) {
|
|
4601
|
-
const ok = await
|
|
5153
|
+
const ok = await p23.confirm({
|
|
4602
5154
|
message: opts.confirmMessage,
|
|
4603
5155
|
initialValue: false
|
|
4604
5156
|
});
|
|
4605
|
-
if (
|
|
4606
|
-
|
|
4607
|
-
|
|
5157
|
+
if (p23.isCancel(ok) || !ok) {
|
|
5158
|
+
p23.cancel("Operation cancelled.");
|
|
5159
|
+
process19.exit(0);
|
|
4608
5160
|
}
|
|
4609
5161
|
}
|
|
4610
5162
|
await runPattern(opts.slug, cmdArgs, { destructive: true }, opts.report);
|
|
4611
5163
|
}
|
|
4612
5164
|
|
|
4613
5165
|
// src/commands/disable/auth.ts
|
|
4614
|
-
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(
|
|
4615
5167
|
(opts, cmd) => runCommand(
|
|
4616
5168
|
() => runDisable(
|
|
4617
5169
|
{
|
|
@@ -4637,8 +5189,8 @@ var auth2 = new Command25("auth").description("disable authentication").option("
|
|
|
4637
5189
|
);
|
|
4638
5190
|
|
|
4639
5191
|
// src/commands/disable/api.ts
|
|
4640
|
-
import { Command as
|
|
4641
|
-
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(
|
|
4642
5194
|
(opts, cmd) => runCommand(
|
|
4643
5195
|
() => runDisable(
|
|
4644
5196
|
{
|
|
@@ -4661,8 +5213,8 @@ var api2 = new Command26("api").description("disable the REST API").option("-y,
|
|
|
4661
5213
|
);
|
|
4662
5214
|
|
|
4663
5215
|
// src/commands/disable/api-keys.ts
|
|
4664
|
-
import { Command as
|
|
4665
|
-
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(
|
|
4666
5218
|
(opts, cmd) => runCommand(
|
|
4667
5219
|
() => runDisable(
|
|
4668
5220
|
{
|
|
@@ -4685,8 +5237,8 @@ var apiKeys2 = new Command27("api-keys").description("disable API key management
|
|
|
4685
5237
|
);
|
|
4686
5238
|
|
|
4687
5239
|
// src/commands/disable/backend.ts
|
|
4688
|
-
import { Command as
|
|
4689
|
-
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(
|
|
4690
5242
|
(opts, cmd) => runCommand(
|
|
4691
5243
|
() => runDisable(
|
|
4692
5244
|
{
|
|
@@ -4709,8 +5261,8 @@ var backend2 = new Command28("backend").description("disable the PocketBase back
|
|
|
4709
5261
|
);
|
|
4710
5262
|
|
|
4711
5263
|
// src/commands/disable/content-negotiation.ts
|
|
4712
|
-
import { Command as
|
|
4713
|
-
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(
|
|
4714
5266
|
(opts, cmd) => runCommand(
|
|
4715
5267
|
() => runDisable(
|
|
4716
5268
|
{
|
|
@@ -4733,8 +5285,8 @@ var contentNegotiation2 = new Command29("content-negotiation").description("disa
|
|
|
4733
5285
|
);
|
|
4734
5286
|
|
|
4735
5287
|
// src/commands/disable/i18n.ts
|
|
4736
|
-
import { Command as
|
|
4737
|
-
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(
|
|
4738
5290
|
(opts, cmd) => runCommand(
|
|
4739
5291
|
() => runDisable(
|
|
4740
5292
|
{
|
|
@@ -4760,8 +5312,8 @@ var i18n2 = new Command30("i18n").description("disable internationalization").op
|
|
|
4760
5312
|
);
|
|
4761
5313
|
|
|
4762
5314
|
// src/commands/disable/teams.ts
|
|
4763
|
-
import { Command as
|
|
4764
|
-
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(
|
|
4765
5317
|
(opts, cmd) => runCommand(
|
|
4766
5318
|
() => runDisable(
|
|
4767
5319
|
{
|
|
@@ -4787,8 +5339,8 @@ var teams2 = new Command31("teams").description("disable teams").option("-y, --y
|
|
|
4787
5339
|
);
|
|
4788
5340
|
|
|
4789
5341
|
// src/commands/disable/payments.ts
|
|
4790
|
-
import { Command as
|
|
4791
|
-
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(
|
|
4792
5344
|
(opts, cmd) => runCommand(
|
|
4793
5345
|
() => runDisable(
|
|
4794
5346
|
{
|
|
@@ -4815,11 +5367,11 @@ var payments2 = new Command32("payments").description("disable payments").option
|
|
|
4815
5367
|
);
|
|
4816
5368
|
|
|
4817
5369
|
// src/commands/disable/s3.ts
|
|
4818
|
-
import { Command as
|
|
4819
|
-
import * as
|
|
5370
|
+
import { Command as Command35 } from "commander";
|
|
5371
|
+
import * as p24 from "@clack/prompts";
|
|
4820
5372
|
import pc10 from "picocolors";
|
|
4821
5373
|
var s32 = addTargetOptions(
|
|
4822
|
-
new
|
|
5374
|
+
new Command35("s3").description("disable S3 file storage").option("--backups", "keep backups on the server again, rather than uploads").configureHelp(helpConfig),
|
|
4823
5375
|
"local"
|
|
4824
5376
|
).action(
|
|
4825
5377
|
(raw) => runCommand(() => {
|
|
@@ -4828,7 +5380,7 @@ var s32 = addTargetOptions(
|
|
|
4828
5380
|
return withBackupTarget(raw, "disable s3", async (ctx) => {
|
|
4829
5381
|
const existing = await readS3(ctx.pb, filesystem);
|
|
4830
5382
|
if (!existing.enabled) {
|
|
4831
|
-
|
|
5383
|
+
p24.log.info(`S3 ${label2(filesystem)} is already off for ${ctx.targetName}.`);
|
|
4832
5384
|
return;
|
|
4833
5385
|
}
|
|
4834
5386
|
await disableS3(ctx.pb, filesystem);
|
|
@@ -4848,8 +5400,8 @@ function label2(filesystem) {
|
|
|
4848
5400
|
}
|
|
4849
5401
|
|
|
4850
5402
|
// src/commands/disable/smtp.ts
|
|
4851
|
-
import { Command as
|
|
4852
|
-
var smtp2 = new
|
|
5403
|
+
import { Command as Command36 } from "commander";
|
|
5404
|
+
var smtp2 = new Command36("smtp").description("disable SMTP configuration").configureHelp(helpConfig).action(
|
|
4853
5405
|
() => runCommand(async () => {
|
|
4854
5406
|
const { workspaceRootDir } = await getWorkspace();
|
|
4855
5407
|
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
@@ -4866,30 +5418,30 @@ var smtp2 = new Command34("smtp").description("disable SMTP configuration").conf
|
|
|
4866
5418
|
);
|
|
4867
5419
|
|
|
4868
5420
|
// src/commands/disable.ts
|
|
4869
|
-
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);
|
|
4870
5422
|
|
|
4871
5423
|
// src/commands/destroy.ts
|
|
4872
|
-
import { Command as
|
|
5424
|
+
import { Command as Command43 } from "commander";
|
|
4873
5425
|
|
|
4874
5426
|
// src/commands/destroy/form.ts
|
|
4875
|
-
import { Command as
|
|
5427
|
+
import { Command as Command38 } from "commander";
|
|
4876
5428
|
|
|
4877
5429
|
// src/commands/destroy/_shared.ts
|
|
4878
|
-
import
|
|
4879
|
-
import * as
|
|
5430
|
+
import process20 from "node:process";
|
|
5431
|
+
import * as p25 from "@clack/prompts";
|
|
4880
5432
|
async function runDestroy(slug2, model, confirmMessage, report4, flags) {
|
|
4881
5433
|
if (!flags.yes) {
|
|
4882
|
-
const ok = await
|
|
4883
|
-
if (
|
|
4884
|
-
|
|
4885
|
-
|
|
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);
|
|
4886
5438
|
}
|
|
4887
5439
|
}
|
|
4888
5440
|
await runPattern(slug2, [model], { destructive: true, route: flags.route }, report4);
|
|
4889
5441
|
}
|
|
4890
5442
|
|
|
4891
5443
|
// src/commands/destroy/form.ts
|
|
4892
|
-
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(
|
|
4893
5445
|
"--route <route>",
|
|
4894
5446
|
"custom route the form was generated at (must match the --route used at generation)"
|
|
4895
5447
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
@@ -4913,8 +5465,8 @@ var form2 = new Command36("form").description("destroy a form generated by `vela
|
|
|
4913
5465
|
);
|
|
4914
5466
|
|
|
4915
5467
|
// src/commands/destroy/schema.ts
|
|
4916
|
-
import { Command as
|
|
4917
|
-
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(
|
|
4918
5470
|
(model, opts) => runCommand(
|
|
4919
5471
|
() => runDestroy(
|
|
4920
5472
|
"destroy-schema",
|
|
@@ -4935,8 +5487,8 @@ var schema2 = new Command37("schema").description("destroy a zod schema generate
|
|
|
4935
5487
|
);
|
|
4936
5488
|
|
|
4937
5489
|
// src/commands/destroy/resource.ts
|
|
4938
|
-
import { Command as
|
|
4939
|
-
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(
|
|
4940
5492
|
(model, opts) => runCommand(
|
|
4941
5493
|
() => runDestroy(
|
|
4942
5494
|
"destroy-resource",
|
|
@@ -4957,8 +5509,8 @@ var resource2 = new Command38("resource").description("destroy a resource genera
|
|
|
4957
5509
|
);
|
|
4958
5510
|
|
|
4959
5511
|
// src/commands/destroy/scaffold.ts
|
|
4960
|
-
import { Command as
|
|
4961
|
-
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(
|
|
4962
5514
|
"--route <route>",
|
|
4963
5515
|
"custom route the scaffold was generated at (must match the --route used at generation)"
|
|
4964
5516
|
).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
|
|
@@ -4985,9 +5537,9 @@ var scaffold2 = new Command39("scaffold").description("destroy a scaffold genera
|
|
|
4985
5537
|
);
|
|
4986
5538
|
|
|
4987
5539
|
// src/commands/destroy/deployment.ts
|
|
4988
|
-
import
|
|
4989
|
-
import { Command as
|
|
4990
|
-
import * as
|
|
5540
|
+
import process21 from "node:process";
|
|
5541
|
+
import { Command as Command42 } from "commander";
|
|
5542
|
+
import * as p28 from "@clack/prompts";
|
|
4991
5543
|
import pc13 from "picocolors";
|
|
4992
5544
|
|
|
4993
5545
|
// src/lib/destroy-guard.ts
|
|
@@ -5035,88 +5587,12 @@ function describe({ appName, envTag, purge }) {
|
|
|
5035
5587
|
}
|
|
5036
5588
|
|
|
5037
5589
|
// src/lib/deploy-report.ts
|
|
5038
|
-
import * as
|
|
5590
|
+
import * as p27 from "@clack/prompts";
|
|
5039
5591
|
import pc12 from "picocolors";
|
|
5040
5592
|
|
|
5041
5593
|
// src/lib/server-identity.ts
|
|
5042
|
-
import * as
|
|
5594
|
+
import * as p26 from "@clack/prompts";
|
|
5043
5595
|
import pc11 from "picocolors";
|
|
5044
|
-
|
|
5045
|
-
// src/lib/velastack-api.ts
|
|
5046
|
-
async function apiFetch(apiKey, pathAndQuery, init) {
|
|
5047
|
-
const headers = new Headers(init?.headers);
|
|
5048
|
-
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
5049
|
-
if (init?.body && !headers.has("Content-Type")) {
|
|
5050
|
-
headers.set("Content-Type", "application/json");
|
|
5051
|
-
}
|
|
5052
|
-
const res = await fetch(`${API_URL}${pathAndQuery}`, { ...init, headers });
|
|
5053
|
-
if (res.status === 401) {
|
|
5054
|
-
throw new Error("API key invalid \u2014 run `vela login`");
|
|
5055
|
-
}
|
|
5056
|
-
if (res.status === 403) {
|
|
5057
|
-
const body = await res.text().catch(() => "");
|
|
5058
|
-
throw new Error(`velastack.dev refused this key (${body || "forbidden"}) \u2014 run \`vela login\``);
|
|
5059
|
-
}
|
|
5060
|
-
if (!res.ok) {
|
|
5061
|
-
const body = await res.text().catch(() => "");
|
|
5062
|
-
throw new Error(`Velastack API error (${res.status}): ${body || res.statusText}`);
|
|
5063
|
-
}
|
|
5064
|
-
return await res.json();
|
|
5065
|
-
}
|
|
5066
|
-
async function getCurrentUser(apiKey) {
|
|
5067
|
-
const data = await apiFetch(
|
|
5068
|
-
apiKey,
|
|
5069
|
-
"/api/collections/users/records?perPage=1"
|
|
5070
|
-
);
|
|
5071
|
-
const user = data.items[0];
|
|
5072
|
-
if (!user) throw new Error("No user found. Run `vela login` to login.");
|
|
5073
|
-
return user;
|
|
5074
|
-
}
|
|
5075
|
-
async function listTeams(apiKey) {
|
|
5076
|
-
const data = await apiFetch(
|
|
5077
|
-
apiKey,
|
|
5078
|
-
"/api/collections/teams/records?perPage=200"
|
|
5079
|
-
);
|
|
5080
|
-
return data.items;
|
|
5081
|
-
}
|
|
5082
|
-
async function listProjects(apiKey) {
|
|
5083
|
-
const data = await apiFetch(
|
|
5084
|
-
apiKey,
|
|
5085
|
-
"/api/collections/projects/records?perPage=200&expand=team"
|
|
5086
|
-
);
|
|
5087
|
-
return data.items;
|
|
5088
|
-
}
|
|
5089
|
-
async function createProject2(apiKey, args) {
|
|
5090
|
-
return apiFetch(apiKey, "/api/collections/projects/records", {
|
|
5091
|
-
method: "POST",
|
|
5092
|
-
body: JSON.stringify({ name: args.name, team: args.teamId, user: args.userId })
|
|
5093
|
-
});
|
|
5094
|
-
}
|
|
5095
|
-
async function registerServer(apiKey, input) {
|
|
5096
|
-
return apiFetch(apiKey, "/v1/servers", {
|
|
5097
|
-
method: "POST",
|
|
5098
|
-
body: JSON.stringify(input)
|
|
5099
|
-
});
|
|
5100
|
-
}
|
|
5101
|
-
async function startDeployment(apiKey, projectId, input) {
|
|
5102
|
-
return apiFetch(apiKey, `/v1/projects/${projectId}/deployments`, {
|
|
5103
|
-
method: "POST",
|
|
5104
|
-
body: JSON.stringify(input)
|
|
5105
|
-
});
|
|
5106
|
-
}
|
|
5107
|
-
async function finishDeployment(apiKey, projectId, deploymentId, input) {
|
|
5108
|
-
return apiFetch(apiKey, `/v1/projects/${projectId}/deployments/${deploymentId}`, {
|
|
5109
|
-
method: "PATCH",
|
|
5110
|
-
body: JSON.stringify(input)
|
|
5111
|
-
});
|
|
5112
|
-
}
|
|
5113
|
-
async function destroyEnvironment(apiKey, projectId, envTag) {
|
|
5114
|
-
return apiFetch(apiKey, `/v1/projects/${projectId}/environments/${encodeURIComponent(envTag)}`, {
|
|
5115
|
-
method: "DELETE"
|
|
5116
|
-
});
|
|
5117
|
-
}
|
|
5118
|
-
|
|
5119
|
-
// src/lib/server-identity.ts
|
|
5120
5596
|
var IPV4 = /^\d{1,3}(?:\.\d{1,3}){3}$/;
|
|
5121
5597
|
async function ensureServerIdentity(session, apiKey) {
|
|
5122
5598
|
const existing = await readServerIdentity(session);
|
|
@@ -5129,7 +5605,7 @@ async function ensureServerIdentity(session, apiKey) {
|
|
|
5129
5605
|
if (!existing || existing.serverId !== registered.serverId || existing.originHost !== registered.originHost || existing.token !== registered.token) {
|
|
5130
5606
|
await writeServerIdentity(session, registered);
|
|
5131
5607
|
if (existing) {
|
|
5132
|
-
|
|
5608
|
+
p26.log.info(`${pc11.cyan(session.target)} was re-registered with velastack.dev.`);
|
|
5133
5609
|
}
|
|
5134
5610
|
}
|
|
5135
5611
|
await runServerScript(session, "origin.sh");
|
|
@@ -5169,7 +5645,7 @@ function createDeployReporter(workspaceRootDir) {
|
|
|
5169
5645
|
const link2 = readProjectConfig(workspaceRootDir);
|
|
5170
5646
|
const apiKey = link2 ? readApiKey() : null;
|
|
5171
5647
|
if (link2 && !apiKey) {
|
|
5172
|
-
|
|
5648
|
+
p27.log.warn(
|
|
5173
5649
|
`This project is linked to ${pc12.cyan(link2.projectName)} on velastack.dev, but there is no
|
|
5174
5650
|
API key here, so this deploy will not be recorded. Run ${pc12.cyan("vela login")}, or set
|
|
5175
5651
|
${pc12.cyan("VELA_API_KEY")}.`
|
|
@@ -5219,7 +5695,7 @@ async function reportEnvironmentDestroyed(workspaceRootDir, envTag) {
|
|
|
5219
5695
|
}
|
|
5220
5696
|
}
|
|
5221
5697
|
function warn(what, err) {
|
|
5222
|
-
|
|
5698
|
+
p27.log.warn(
|
|
5223
5699
|
`velastack.dev could not ${what}.
|
|
5224
5700
|
${pc12.dim(err instanceof Error ? err.message : String(err))}`
|
|
5225
5701
|
);
|
|
@@ -5228,7 +5704,7 @@ ${pc12.dim(err instanceof Error ? err.message : String(err))}`
|
|
|
5228
5704
|
// src/commands/destroy/deployment.ts
|
|
5229
5705
|
var deployment = addLockWaitOption(
|
|
5230
5706
|
addTargetOptions(
|
|
5231
|
-
new
|
|
5707
|
+
new Command42("deployment").description("remove a deployed environment from its server").configureHelp(helpConfig),
|
|
5232
5708
|
"production"
|
|
5233
5709
|
)
|
|
5234
5710
|
).option("--purge", "also delete the database and uploaded files").option("-y, --yes", "skip the confirmation prompt").option(
|
|
@@ -5247,7 +5723,7 @@ var deployment = addLockWaitOption(
|
|
|
5247
5723
|
purge: options.purge === true,
|
|
5248
5724
|
yes: options.yes === true,
|
|
5249
5725
|
confirm: options.confirm,
|
|
5250
|
-
interactive: Boolean(
|
|
5726
|
+
interactive: Boolean(process21.stdin.isTTY && process21.stdout.isTTY)
|
|
5251
5727
|
});
|
|
5252
5728
|
if (decision.kind === "refuse") throw new Error(decision.message);
|
|
5253
5729
|
if (decision.kind === "prompt") {
|
|
@@ -5262,13 +5738,13 @@ var deployment = addLockWaitOption(
|
|
|
5262
5738
|
stream: true
|
|
5263
5739
|
});
|
|
5264
5740
|
if (result?.existed === false) {
|
|
5265
|
-
|
|
5741
|
+
p28.log.info(
|
|
5266
5742
|
`Nothing named ${pc13.cyan(`${ctx.appName} (${ctx.targetName})`)} on ${ctx.server}; nothing to remove.`
|
|
5267
5743
|
);
|
|
5268
5744
|
return;
|
|
5269
5745
|
}
|
|
5270
5746
|
await reportEnvironmentDestroyed(ctx.workspaceRootDir, ctx.envTag);
|
|
5271
|
-
|
|
5747
|
+
p28.log.success(
|
|
5272
5748
|
`Removed ${pc13.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${ctx.server}.` + (result?.purged ? result.trash ? `
|
|
5273
5749
|
|
|
5274
5750
|
A snapshot of its data is at ${pc13.cyan(result.trash)} on the server for two weeks.` : "" : `
|
|
@@ -5286,35 +5762,35 @@ The database and uploads are still in the instance's shared directory. Pass ${pc
|
|
|
5286
5762
|
);
|
|
5287
5763
|
async function confirm8(appName, targetName, byName) {
|
|
5288
5764
|
if (byName) {
|
|
5289
|
-
const answer = await
|
|
5765
|
+
const answer = await p28.text({
|
|
5290
5766
|
message: `This removes ${pc13.cyan(`${appName} (${targetName})`)}. Type the app name to confirm`,
|
|
5291
5767
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
5292
5768
|
});
|
|
5293
|
-
if (
|
|
5294
|
-
|
|
5295
|
-
|
|
5769
|
+
if (p28.isCancel(answer)) {
|
|
5770
|
+
p28.cancel("Operation cancelled.");
|
|
5771
|
+
process21.exit(0);
|
|
5296
5772
|
}
|
|
5297
5773
|
return;
|
|
5298
5774
|
}
|
|
5299
|
-
const ok = await
|
|
5775
|
+
const ok = await p28.confirm({
|
|
5300
5776
|
message: `Remove ${appName} (${targetName})?`,
|
|
5301
5777
|
initialValue: false
|
|
5302
5778
|
});
|
|
5303
|
-
if (
|
|
5304
|
-
|
|
5305
|
-
|
|
5779
|
+
if (p28.isCancel(ok) || !ok) {
|
|
5780
|
+
p28.cancel("Operation cancelled.");
|
|
5781
|
+
process21.exit(0);
|
|
5306
5782
|
}
|
|
5307
5783
|
}
|
|
5308
5784
|
|
|
5309
5785
|
// src/commands/destroy.ts
|
|
5310
|
-
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);
|
|
5311
5787
|
|
|
5312
5788
|
// src/commands/ui.ts
|
|
5313
|
-
import { Command as
|
|
5789
|
+
import { Command as Command49 } from "commander";
|
|
5314
5790
|
|
|
5315
5791
|
// src/commands/ui/add.ts
|
|
5316
|
-
import { Command as
|
|
5317
|
-
import * as
|
|
5792
|
+
import { Command as Command44 } from "commander";
|
|
5793
|
+
import * as p29 from "@clack/prompts";
|
|
5318
5794
|
import { installComponents } from "@velastack/patterns";
|
|
5319
5795
|
|
|
5320
5796
|
// src/lib/ui-add.ts
|
|
@@ -5363,10 +5839,10 @@ function uiAddReport(requested, outcome) {
|
|
|
5363
5839
|
}
|
|
5364
5840
|
|
|
5365
5841
|
// src/commands/ui/add.ts
|
|
5366
|
-
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(
|
|
5367
5843
|
(components, options) => runCommand(async () => {
|
|
5368
5844
|
const { workspaceRootDir } = await getWorkspace();
|
|
5369
|
-
const log45 =
|
|
5845
|
+
const log45 = p29.taskLog({ title: "Adding UI components..." });
|
|
5370
5846
|
let outcome;
|
|
5371
5847
|
try {
|
|
5372
5848
|
outcome = await installComponents({
|
|
@@ -5385,13 +5861,13 @@ var add = new Command42("add").description("add ui components (shadcn-svelte ite
|
|
|
5385
5861
|
);
|
|
5386
5862
|
|
|
5387
5863
|
// src/commands/ui/base.ts
|
|
5388
|
-
import { Command as
|
|
5389
|
-
import * as
|
|
5864
|
+
import { Command as Command45 } from "commander";
|
|
5865
|
+
import * as p30 from "@clack/prompts";
|
|
5390
5866
|
import { applyBaseColor } from "@velastack/patterns";
|
|
5391
|
-
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(
|
|
5392
5868
|
(color) => runCommand(async () => {
|
|
5393
5869
|
const { workspaceRootDir } = await getWorkspace();
|
|
5394
|
-
const log45 =
|
|
5870
|
+
const log45 = p30.taskLog({ title: `Applying the ${color} palette...` });
|
|
5395
5871
|
let outcome;
|
|
5396
5872
|
try {
|
|
5397
5873
|
outcome = await applyBaseColor({ root: workspaceRootDir, color });
|
|
@@ -5413,8 +5889,8 @@ var base = new Command43("base").description("change the base (gray) palette").a
|
|
|
5413
5889
|
);
|
|
5414
5890
|
|
|
5415
5891
|
// src/commands/ui/list.ts
|
|
5416
|
-
import { Command as
|
|
5417
|
-
import * as
|
|
5892
|
+
import { Command as Command46 } from "commander";
|
|
5893
|
+
import * as p31 from "@clack/prompts";
|
|
5418
5894
|
import { listComponents } from "@velastack/patterns";
|
|
5419
5895
|
|
|
5420
5896
|
// src/lib/ui-list.ts
|
|
@@ -5445,7 +5921,7 @@ function uiListReport(result) {
|
|
|
5445
5921
|
}
|
|
5446
5922
|
|
|
5447
5923
|
// src/commands/ui/list.ts
|
|
5448
|
-
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(
|
|
5449
5925
|
(options) => runCommand(async () => {
|
|
5450
5926
|
const { workspaceRootDir } = await getWorkspace();
|
|
5451
5927
|
if (options.json) {
|
|
@@ -5453,7 +5929,7 @@ var list = new Command44("list").description("list installed ui components, vela
|
|
|
5453
5929
|
console.log(JSON.stringify(result2, null, 2));
|
|
5454
5930
|
return;
|
|
5455
5931
|
}
|
|
5456
|
-
const spinner7 =
|
|
5932
|
+
const spinner7 = p31.spinner();
|
|
5457
5933
|
spinner7.start("Reading the registry...");
|
|
5458
5934
|
let result;
|
|
5459
5935
|
try {
|
|
@@ -5465,15 +5941,15 @@ var list = new Command44("list").description("list installed ui components, vela
|
|
|
5465
5941
|
spinner7.stop(`Read the ${result.style} registry`);
|
|
5466
5942
|
reportResult(uiListReport(result));
|
|
5467
5943
|
if (result.registryUnavailable) {
|
|
5468
|
-
|
|
5944
|
+
p31.log.warn(`${result.registryUnavailable}
|
|
5469
5945
|
Registry components are not listed.`);
|
|
5470
5946
|
}
|
|
5471
5947
|
}, "Failed to list UI components.")
|
|
5472
5948
|
);
|
|
5473
5949
|
|
|
5474
5950
|
// src/commands/ui/style.ts
|
|
5475
|
-
import { Command as
|
|
5476
|
-
import * as
|
|
5951
|
+
import { Command as Command47 } from "commander";
|
|
5952
|
+
import * as p32 from "@clack/prompts";
|
|
5477
5953
|
import { switchStyle } from "@velastack/patterns";
|
|
5478
5954
|
|
|
5479
5955
|
// src/lib/ui-style.ts
|
|
@@ -5499,10 +5975,10 @@ function uiStyleReport(result) {
|
|
|
5499
5975
|
}
|
|
5500
5976
|
|
|
5501
5977
|
// src/commands/ui/style.ts
|
|
5502
|
-
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(
|
|
5503
5979
|
(name, options) => runCommand(async () => {
|
|
5504
5980
|
const { workspaceRootDir } = await getWorkspace();
|
|
5505
|
-
const spinner7 =
|
|
5981
|
+
const spinner7 = p32.spinner();
|
|
5506
5982
|
spinner7.start(`Reading the ${name} registry...`);
|
|
5507
5983
|
let log45;
|
|
5508
5984
|
let outcome;
|
|
@@ -5515,20 +5991,20 @@ var style = new Command45("style").description("switch the shadcn-svelte style,
|
|
|
5515
5991
|
confirm: async (components) => {
|
|
5516
5992
|
spinner7.stop(`Read the ${name} registry`);
|
|
5517
5993
|
if (components.length > 0) {
|
|
5518
|
-
|
|
5994
|
+
p32.log.info(
|
|
5519
5995
|
`Re-adds ${components.length} component(s) from the ${name} registry; local edits to their files are lost:
|
|
5520
5996
|
${components.map((c) => `- ${c}`).join("\n")}`
|
|
5521
5997
|
);
|
|
5522
5998
|
} else {
|
|
5523
|
-
|
|
5999
|
+
p32.log.info(
|
|
5524
6000
|
`No installed component comes from the registry; only the config changes.`
|
|
5525
6001
|
);
|
|
5526
6002
|
}
|
|
5527
6003
|
if (!options.yes) {
|
|
5528
|
-
const ok = await
|
|
5529
|
-
if (
|
|
6004
|
+
const ok = await p32.confirm({ message: `Switch to ${name}?`, initialValue: false });
|
|
6005
|
+
if (p32.isCancel(ok) || !ok) return false;
|
|
5530
6006
|
}
|
|
5531
|
-
log45 =
|
|
6007
|
+
log45 = p32.taskLog({ title: `Switching to the ${name} style...` });
|
|
5532
6008
|
return true;
|
|
5533
6009
|
}
|
|
5534
6010
|
});
|
|
@@ -5539,11 +6015,11 @@ ${components.map((c) => `- ${c}`).join("\n")}`
|
|
|
5539
6015
|
}
|
|
5540
6016
|
spinner7.stop(`Read the ${name} registry`);
|
|
5541
6017
|
if (outcome.status === "unchanged") {
|
|
5542
|
-
|
|
6018
|
+
p32.log.info(`Already using the ${name} style.`);
|
|
5543
6019
|
return;
|
|
5544
6020
|
}
|
|
5545
6021
|
if (outcome.status === "cancelled") {
|
|
5546
|
-
|
|
6022
|
+
p32.cancel("Operation cancelled.");
|
|
5547
6023
|
return;
|
|
5548
6024
|
}
|
|
5549
6025
|
log45?.success("Style switched");
|
|
@@ -5552,13 +6028,13 @@ ${components.map((c) => `- ${c}`).join("\n")}`
|
|
|
5552
6028
|
);
|
|
5553
6029
|
|
|
5554
6030
|
// src/commands/ui/theme.ts
|
|
5555
|
-
import { Command as
|
|
5556
|
-
import * as
|
|
6031
|
+
import { Command as Command48 } from "commander";
|
|
6032
|
+
import * as p33 from "@clack/prompts";
|
|
5557
6033
|
import { applyTheme } from "@velastack/patterns";
|
|
5558
|
-
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(
|
|
5559
6035
|
(accent) => runCommand(async () => {
|
|
5560
6036
|
const { workspaceRootDir } = await getWorkspace();
|
|
5561
|
-
const log45 =
|
|
6037
|
+
const log45 = p33.taskLog({ title: `Applying the ${accent} accent...` });
|
|
5562
6038
|
let outcome;
|
|
5563
6039
|
try {
|
|
5564
6040
|
outcome = await applyTheme({ root: workspaceRootDir, theme: accent });
|
|
@@ -5580,22 +6056,22 @@ var theme = new Command46("theme").description("change the accent color, keeping
|
|
|
5580
6056
|
);
|
|
5581
6057
|
|
|
5582
6058
|
// src/commands/ui.ts
|
|
5583
|
-
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);
|
|
5584
6060
|
|
|
5585
6061
|
// src/commands/legal.ts
|
|
5586
|
-
import { Command as
|
|
6062
|
+
import { Command as Command52 } from "commander";
|
|
5587
6063
|
|
|
5588
6064
|
// src/commands/legal/terms.ts
|
|
5589
6065
|
import fs26 from "node:fs";
|
|
5590
6066
|
import path23 from "node:path";
|
|
5591
|
-
import { Command as
|
|
5592
|
-
import * as
|
|
6067
|
+
import { Command as Command50 } from "commander";
|
|
6068
|
+
import * as p35 from "@clack/prompts";
|
|
5593
6069
|
|
|
5594
6070
|
// src/commands/legal/shared.ts
|
|
5595
|
-
import
|
|
5596
|
-
import * as
|
|
6071
|
+
import process22 from "node:process";
|
|
6072
|
+
import * as p34 from "@clack/prompts";
|
|
5597
6073
|
var sharedFields = {
|
|
5598
|
-
websiteUrl: () =>
|
|
6074
|
+
websiteUrl: () => p34.text({
|
|
5599
6075
|
message: "What is your website URL?",
|
|
5600
6076
|
placeholder: "http://www.mysite.com",
|
|
5601
6077
|
validate: (value) => {
|
|
@@ -5604,7 +6080,7 @@ var sharedFields = {
|
|
|
5604
6080
|
}
|
|
5605
6081
|
}
|
|
5606
6082
|
}),
|
|
5607
|
-
websiteName: () =>
|
|
6083
|
+
websiteName: () => p34.text({
|
|
5608
6084
|
message: "What is your website name?",
|
|
5609
6085
|
placeholder: "My Site",
|
|
5610
6086
|
validate: (value) => {
|
|
@@ -5613,7 +6089,7 @@ var sharedFields = {
|
|
|
5613
6089
|
}
|
|
5614
6090
|
}
|
|
5615
6091
|
}),
|
|
5616
|
-
entityType: () =>
|
|
6092
|
+
entityType: () => p34.select({
|
|
5617
6093
|
message: "Entity type",
|
|
5618
6094
|
options: [
|
|
5619
6095
|
{
|
|
@@ -5624,7 +6100,7 @@ var sharedFields = {
|
|
|
5624
6100
|
{ value: "individual", label: "I'm an Individual" }
|
|
5625
6101
|
]
|
|
5626
6102
|
}),
|
|
5627
|
-
businessName: ({ results }) => results?.entityType === "business" ?
|
|
6103
|
+
businessName: ({ results }) => results?.entityType === "business" ? p34.text({
|
|
5628
6104
|
message: "What is the name of the business?",
|
|
5629
6105
|
placeholder: "My Company LLC",
|
|
5630
6106
|
validate: (value) => {
|
|
@@ -5633,7 +6109,7 @@ var sharedFields = {
|
|
|
5633
6109
|
}
|
|
5634
6110
|
}
|
|
5635
6111
|
}) : void 0,
|
|
5636
|
-
businessAddress: ({ results }) => results?.entityType === "business" ?
|
|
6112
|
+
businessAddress: ({ results }) => results?.entityType === "business" ? p34.text({
|
|
5637
6113
|
message: "What is the address of the business?",
|
|
5638
6114
|
placeholder: "1 Cupertino, CA 95014",
|
|
5639
6115
|
validate: (value) => {
|
|
@@ -5642,7 +6118,7 @@ var sharedFields = {
|
|
|
5642
6118
|
}
|
|
5643
6119
|
}
|
|
5644
6120
|
}) : void 0,
|
|
5645
|
-
country: () =>
|
|
6121
|
+
country: () => p34.text({
|
|
5646
6122
|
message: "Enter the country",
|
|
5647
6123
|
validate: (value) => {
|
|
5648
6124
|
if (!value) {
|
|
@@ -5650,7 +6126,7 @@ var sharedFields = {
|
|
|
5650
6126
|
}
|
|
5651
6127
|
}
|
|
5652
6128
|
}),
|
|
5653
|
-
state: () =>
|
|
6129
|
+
state: () => p34.text({
|
|
5654
6130
|
message: "Enter the state",
|
|
5655
6131
|
validate: (value) => {
|
|
5656
6132
|
if (!value) {
|
|
@@ -5660,11 +6136,11 @@ var sharedFields = {
|
|
|
5660
6136
|
})
|
|
5661
6137
|
};
|
|
5662
6138
|
var onCancel = () => {
|
|
5663
|
-
|
|
5664
|
-
|
|
6139
|
+
p34.cancel("Operation cancelled.");
|
|
6140
|
+
process22.exit(0);
|
|
5665
6141
|
};
|
|
5666
6142
|
async function contactMethods(type) {
|
|
5667
|
-
const selection = await
|
|
6143
|
+
const selection = await p34.multiselect({
|
|
5668
6144
|
message: `How can users contact you for any questions regarding your ${type === "privacy" ? "Privacy Policy" : "Terms & Conditions"}? Check all that apply`,
|
|
5669
6145
|
options: [
|
|
5670
6146
|
{ value: "email", label: "By email" },
|
|
@@ -5673,11 +6149,11 @@ async function contactMethods(type) {
|
|
|
5673
6149
|
{ value: "mail", label: "By sending post mail" }
|
|
5674
6150
|
]
|
|
5675
6151
|
});
|
|
5676
|
-
if (
|
|
6152
|
+
if (p34.isCancel(selection)) onCancel();
|
|
5677
6153
|
const contact = selection;
|
|
5678
6154
|
const details = {};
|
|
5679
6155
|
if (contact.includes("email")) {
|
|
5680
|
-
const email3 = await
|
|
6156
|
+
const email3 = await p34.text({
|
|
5681
6157
|
message: "What's the email?",
|
|
5682
6158
|
placeholder: "office@mycompany.com",
|
|
5683
6159
|
validate: (value) => {
|
|
@@ -5686,11 +6162,11 @@ async function contactMethods(type) {
|
|
|
5686
6162
|
}
|
|
5687
6163
|
}
|
|
5688
6164
|
});
|
|
5689
|
-
if (
|
|
6165
|
+
if (p34.isCancel(email3)) onCancel();
|
|
5690
6166
|
details.email = email3;
|
|
5691
6167
|
}
|
|
5692
6168
|
if (contact.includes("page")) {
|
|
5693
|
-
const page = await
|
|
6169
|
+
const page = await p34.text({
|
|
5694
6170
|
message: "What's the link?",
|
|
5695
6171
|
placeholder: "http://www.mycompany.com/contact",
|
|
5696
6172
|
validate: (value) => {
|
|
@@ -5699,11 +6175,11 @@ async function contactMethods(type) {
|
|
|
5699
6175
|
}
|
|
5700
6176
|
}
|
|
5701
6177
|
});
|
|
5702
|
-
if (
|
|
6178
|
+
if (p34.isCancel(page)) onCancel();
|
|
5703
6179
|
details.page = page;
|
|
5704
6180
|
}
|
|
5705
6181
|
if (contact.includes("phone")) {
|
|
5706
|
-
const phone = await
|
|
6182
|
+
const phone = await p34.text({
|
|
5707
6183
|
message: "What's the phone number?",
|
|
5708
6184
|
placeholder: "408.996.1010",
|
|
5709
6185
|
validate: (value) => {
|
|
@@ -5712,11 +6188,11 @@ async function contactMethods(type) {
|
|
|
5712
6188
|
}
|
|
5713
6189
|
}
|
|
5714
6190
|
});
|
|
5715
|
-
if (
|
|
6191
|
+
if (p34.isCancel(phone)) onCancel();
|
|
5716
6192
|
details.phone = phone;
|
|
5717
6193
|
}
|
|
5718
6194
|
if (contact.includes("mail")) {
|
|
5719
|
-
const address = await
|
|
6195
|
+
const address = await p34.text({
|
|
5720
6196
|
message: "What's the address?",
|
|
5721
6197
|
placeholder: "767 Fifth Avenue New York, NY 10153, United States",
|
|
5722
6198
|
validate: (value) => {
|
|
@@ -5725,7 +6201,7 @@ async function contactMethods(type) {
|
|
|
5725
6201
|
}
|
|
5726
6202
|
}
|
|
5727
6203
|
});
|
|
5728
|
-
if (
|
|
6204
|
+
if (p34.isCancel(address)) onCancel();
|
|
5729
6205
|
details.address = address;
|
|
5730
6206
|
}
|
|
5731
6207
|
return { methods: contact, details };
|
|
@@ -6121,7 +6597,7 @@ var generateTermsHtml = (answers) => {
|
|
|
6121
6597
|
};
|
|
6122
6598
|
async function termsAction() {
|
|
6123
6599
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
6124
|
-
const core = await
|
|
6600
|
+
const core = await p35.group(
|
|
6125
6601
|
{
|
|
6126
6602
|
websiteUrl: sharedFields.websiteUrl,
|
|
6127
6603
|
websiteName: sharedFields.websiteName,
|
|
@@ -6133,25 +6609,25 @@ async function termsAction() {
|
|
|
6133
6609
|
},
|
|
6134
6610
|
{ onCancel }
|
|
6135
6611
|
);
|
|
6136
|
-
const accounts = await
|
|
6612
|
+
const accounts = await p35.select({
|
|
6137
6613
|
message: "Can users create accounts?",
|
|
6138
6614
|
options: [
|
|
6139
6615
|
{ value: "yes", label: "Yes, users can create accounts" },
|
|
6140
6616
|
{ value: "no", label: "No" }
|
|
6141
6617
|
]
|
|
6142
6618
|
});
|
|
6143
|
-
if (
|
|
6144
|
-
const userContent = await
|
|
6619
|
+
if (p35.isCancel(accounts)) onCancel();
|
|
6620
|
+
const userContent = await p35.select({
|
|
6145
6621
|
message: "Can users create and/or upload content (ie. text, images)?",
|
|
6146
6622
|
options: [
|
|
6147
6623
|
{ value: "yes", label: "Yes, users can create and/or upload content" },
|
|
6148
6624
|
{ value: "no", label: "No" }
|
|
6149
6625
|
]
|
|
6150
6626
|
});
|
|
6151
|
-
if (
|
|
6627
|
+
if (p35.isCancel(userContent)) onCancel();
|
|
6152
6628
|
let infringementEmail;
|
|
6153
6629
|
if (userContent === "yes") {
|
|
6154
|
-
const email3 = await
|
|
6630
|
+
const email3 = await p35.text({
|
|
6155
6631
|
message: "What's the email address where you will receive infringements notices?",
|
|
6156
6632
|
placeholder: "dmca@website.com",
|
|
6157
6633
|
validate: (value) => {
|
|
@@ -6160,10 +6636,10 @@ async function termsAction() {
|
|
|
6160
6636
|
}
|
|
6161
6637
|
}
|
|
6162
6638
|
});
|
|
6163
|
-
if (
|
|
6639
|
+
if (p35.isCancel(email3)) onCancel();
|
|
6164
6640
|
infringementEmail = email3;
|
|
6165
6641
|
}
|
|
6166
|
-
const canBuyGoods = await
|
|
6642
|
+
const canBuyGoods = await p35.select({
|
|
6167
6643
|
message: "Can users buy goods (products, items)?",
|
|
6168
6644
|
options: [
|
|
6169
6645
|
{
|
|
@@ -6173,28 +6649,28 @@ async function termsAction() {
|
|
|
6173
6649
|
{ value: "no", label: "No" }
|
|
6174
6650
|
]
|
|
6175
6651
|
});
|
|
6176
|
-
if (
|
|
6177
|
-
const subscriptions2 = await
|
|
6652
|
+
if (p35.isCancel(canBuyGoods)) onCancel();
|
|
6653
|
+
const subscriptions2 = await p35.select({
|
|
6178
6654
|
message: "Do you offer subscription plans?",
|
|
6179
6655
|
options: [
|
|
6180
6656
|
{ value: "yes", label: "Yes, we offer subscription plans" },
|
|
6181
6657
|
{ value: "no", label: "No" }
|
|
6182
6658
|
]
|
|
6183
6659
|
});
|
|
6184
|
-
if (
|
|
6660
|
+
if (p35.isCancel(subscriptions2)) onCancel();
|
|
6185
6661
|
let freeTrial;
|
|
6186
6662
|
if (subscriptions2 === "yes") {
|
|
6187
|
-
const ft = await
|
|
6663
|
+
const ft = await p35.select({
|
|
6188
6664
|
message: "Do you offer a free trial?",
|
|
6189
6665
|
options: [
|
|
6190
6666
|
{ value: "yes", label: "Yes" },
|
|
6191
6667
|
{ value: "no", label: "No" }
|
|
6192
6668
|
]
|
|
6193
6669
|
});
|
|
6194
|
-
if (
|
|
6670
|
+
if (p35.isCancel(ft)) onCancel();
|
|
6195
6671
|
freeTrial = ft;
|
|
6196
6672
|
}
|
|
6197
|
-
const exclusiveContent = await
|
|
6673
|
+
const exclusiveContent = await p35.select({
|
|
6198
6674
|
message: "Do you want to make it clear that your own content & trademarks are your exclusive property?",
|
|
6199
6675
|
options: [
|
|
6200
6676
|
{
|
|
@@ -6204,24 +6680,24 @@ async function termsAction() {
|
|
|
6204
6680
|
{ value: "no", label: "No" }
|
|
6205
6681
|
]
|
|
6206
6682
|
});
|
|
6207
|
-
if (
|
|
6208
|
-
const feedbackReuse = await
|
|
6683
|
+
if (p35.isCancel(exclusiveContent)) onCancel();
|
|
6684
|
+
const feedbackReuse = await p35.select({
|
|
6209
6685
|
message: "If users provide you feedback & suggestions, do you want to use this feedback without compensation or credits given?",
|
|
6210
6686
|
options: [
|
|
6211
6687
|
{ value: "yes", label: "Yes, we may implement any feedback or suggestions we receive" },
|
|
6212
6688
|
{ value: "no", label: "No" }
|
|
6213
6689
|
]
|
|
6214
6690
|
});
|
|
6215
|
-
if (
|
|
6216
|
-
const promotions = await
|
|
6691
|
+
if (p35.isCancel(feedbackReuse)) onCancel();
|
|
6692
|
+
const promotions = await p35.select({
|
|
6217
6693
|
message: "Do you plan to offer promotions, contests, sweepstakes?",
|
|
6218
6694
|
options: [
|
|
6219
6695
|
{ value: "yes", label: "Yes, we may offer promotions, contests, sweepstakes" },
|
|
6220
6696
|
{ value: "no", label: "No" }
|
|
6221
6697
|
]
|
|
6222
6698
|
});
|
|
6223
|
-
if (
|
|
6224
|
-
const mobileAppRaw = await
|
|
6699
|
+
if (p35.isCancel(promotions)) onCancel();
|
|
6700
|
+
const mobileAppRaw = await p35.multiselect({
|
|
6225
6701
|
message: "Is the Service distributed through any mobile app stores? Check all that apply",
|
|
6226
6702
|
options: [
|
|
6227
6703
|
{ value: "apple", label: "Apple App Store" },
|
|
@@ -6229,7 +6705,7 @@ async function termsAction() {
|
|
|
6229
6705
|
],
|
|
6230
6706
|
required: false
|
|
6231
6707
|
});
|
|
6232
|
-
if (
|
|
6708
|
+
if (p35.isCancel(mobileAppRaw)) onCancel();
|
|
6233
6709
|
const mobileApp = mobileAppRaw ?? [];
|
|
6234
6710
|
const contact = await contactMethods("terms");
|
|
6235
6711
|
const html = generateTermsHtml({
|
|
@@ -6272,13 +6748,13 @@ async function termsAction() {
|
|
|
6272
6748
|
]
|
|
6273
6749
|
});
|
|
6274
6750
|
}
|
|
6275
|
-
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."));
|
|
6276
6752
|
|
|
6277
6753
|
// src/commands/legal/privacy.ts
|
|
6278
6754
|
import fs27 from "node:fs";
|
|
6279
6755
|
import path24 from "node:path";
|
|
6280
|
-
import { Command as
|
|
6281
|
-
import * as
|
|
6756
|
+
import { Command as Command51 } from "commander";
|
|
6757
|
+
import * as p36 from "@clack/prompts";
|
|
6282
6758
|
var mapLabels = {
|
|
6283
6759
|
personalInfo: {
|
|
6284
6760
|
email: "Email address",
|
|
@@ -6696,12 +7172,12 @@ var generatePrivacyHtml = (answers) => {
|
|
|
6696
7172
|
return `<section data-role="content">${sections.join("")}</section>`;
|
|
6697
7173
|
};
|
|
6698
7174
|
async function promptWithCustom(message, options, customMessage) {
|
|
6699
|
-
const selection = await
|
|
6700
|
-
if (
|
|
7175
|
+
const selection = await p36.multiselect({ message, options });
|
|
7176
|
+
if (p36.isCancel(selection)) onCancel();
|
|
6701
7177
|
const values = selection;
|
|
6702
7178
|
if (values.includes("custom")) {
|
|
6703
|
-
const custom = await
|
|
6704
|
-
if (
|
|
7179
|
+
const custom = await p36.text({ message: customMessage });
|
|
7180
|
+
if (p36.isCancel(custom)) onCancel();
|
|
6705
7181
|
const idx = values.indexOf("custom");
|
|
6706
7182
|
if (idx !== -1) values.splice(idx, 1);
|
|
6707
7183
|
if (custom) values.push(String(custom));
|
|
@@ -6710,7 +7186,7 @@ async function promptWithCustom(message, options, customMessage) {
|
|
|
6710
7186
|
}
|
|
6711
7187
|
async function privacyAction() {
|
|
6712
7188
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
6713
|
-
const core = await
|
|
7189
|
+
const core = await p36.group(
|
|
6714
7190
|
{
|
|
6715
7191
|
websiteUrl: sharedFields.websiteUrl,
|
|
6716
7192
|
websiteName: sharedFields.websiteName,
|
|
@@ -6722,7 +7198,7 @@ async function privacyAction() {
|
|
|
6722
7198
|
},
|
|
6723
7199
|
{ onCancel }
|
|
6724
7200
|
);
|
|
6725
|
-
const personalInfo = await
|
|
7201
|
+
const personalInfo = await p36.multiselect({
|
|
6726
7202
|
message: "What kind of personal information do you collect from users? Check all that apply",
|
|
6727
7203
|
options: [
|
|
6728
7204
|
{ value: "email", label: "Email address" },
|
|
@@ -6737,16 +7213,16 @@ async function privacyAction() {
|
|
|
6737
7213
|
],
|
|
6738
7214
|
required: false
|
|
6739
7215
|
});
|
|
6740
|
-
if (
|
|
7216
|
+
if (p36.isCancel(personalInfo)) onCancel();
|
|
6741
7217
|
const contact = await contactMethods("privacy");
|
|
6742
|
-
const tracking = await
|
|
7218
|
+
const tracking = await p36.select({
|
|
6743
7219
|
message: "Do you use tracking and/or analytics tools, such as Google Analytics?",
|
|
6744
7220
|
options: [
|
|
6745
7221
|
{ value: "yes", label: "Yes, we use Google Analytics or other related tools" },
|
|
6746
7222
|
{ value: "no", label: "No" }
|
|
6747
7223
|
]
|
|
6748
7224
|
});
|
|
6749
|
-
if (
|
|
7225
|
+
if (p36.isCancel(tracking)) onCancel();
|
|
6750
7226
|
let trackingTools;
|
|
6751
7227
|
if (tracking === "yes") {
|
|
6752
7228
|
trackingTools = await promptWithCustom(
|
|
@@ -6765,7 +7241,7 @@ async function privacyAction() {
|
|
|
6765
7241
|
"Enter your custom tracking/analytics tool name"
|
|
6766
7242
|
);
|
|
6767
7243
|
}
|
|
6768
|
-
const sendEmails = await
|
|
7244
|
+
const sendEmails = await p36.select({
|
|
6769
7245
|
message: "Do you send emails to users?",
|
|
6770
7246
|
options: [
|
|
6771
7247
|
{
|
|
@@ -6775,7 +7251,7 @@ async function privacyAction() {
|
|
|
6775
7251
|
{ value: "no", label: "No" }
|
|
6776
7252
|
]
|
|
6777
7253
|
});
|
|
6778
|
-
if (
|
|
7254
|
+
if (p36.isCancel(sendEmails)) onCancel();
|
|
6779
7255
|
let emailPlatforms;
|
|
6780
7256
|
if (sendEmails === "yes") {
|
|
6781
7257
|
emailPlatforms = await promptWithCustom(
|
|
@@ -6790,14 +7266,14 @@ async function privacyAction() {
|
|
|
6790
7266
|
"Enter your custom email platform"
|
|
6791
7267
|
);
|
|
6792
7268
|
}
|
|
6793
|
-
const showAds = await
|
|
7269
|
+
const showAds = await p36.select({
|
|
6794
7270
|
message: "Do you show ads?",
|
|
6795
7271
|
options: [
|
|
6796
7272
|
{ value: "yes", label: "Yes, we show ads" },
|
|
6797
7273
|
{ value: "no", label: "No" }
|
|
6798
7274
|
]
|
|
6799
7275
|
});
|
|
6800
|
-
if (
|
|
7276
|
+
if (p36.isCancel(showAds)) onCancel();
|
|
6801
7277
|
let adsPlatforms;
|
|
6802
7278
|
if (showAds === "yes") {
|
|
6803
7279
|
adsPlatforms = await promptWithCustom(
|
|
@@ -6820,7 +7296,7 @@ async function privacyAction() {
|
|
|
6820
7296
|
"Enter your custom ads platform"
|
|
6821
7297
|
);
|
|
6822
7298
|
}
|
|
6823
|
-
const canPay = await
|
|
7299
|
+
const canPay = await p36.select({
|
|
6824
7300
|
message: "Can users pay for products or services?",
|
|
6825
7301
|
options: [
|
|
6826
7302
|
{ value: "yes", label: "Yes, users can pay for our products/services" },
|
|
@@ -6830,7 +7306,7 @@ async function privacyAction() {
|
|
|
6830
7306
|
}
|
|
6831
7307
|
]
|
|
6832
7308
|
});
|
|
6833
|
-
if (
|
|
7309
|
+
if (p36.isCancel(canPay)) onCancel();
|
|
6834
7310
|
let paymentProcessors;
|
|
6835
7311
|
if (canPay === "yes") {
|
|
6836
7312
|
paymentProcessors = await promptWithCustom(
|
|
@@ -6861,14 +7337,14 @@ async function privacyAction() {
|
|
|
6861
7337
|
"Enter your custom payment processor/method"
|
|
6862
7338
|
);
|
|
6863
7339
|
}
|
|
6864
|
-
const remarketing = await
|
|
7340
|
+
const remarketing = await p36.select({
|
|
6865
7341
|
message: "Do you use remarketing services for marketing & advertising purposes?",
|
|
6866
7342
|
options: [
|
|
6867
7343
|
{ value: "yes", label: "Yes, we use remarketing services to advertise our business" },
|
|
6868
7344
|
{ value: "no", label: "No" }
|
|
6869
7345
|
]
|
|
6870
7346
|
});
|
|
6871
|
-
if (
|
|
7347
|
+
if (p36.isCancel(remarketing)) onCancel();
|
|
6872
7348
|
let remarketingPlatforms;
|
|
6873
7349
|
if (remarketing === "yes") {
|
|
6874
7350
|
remarketingPlatforms = await promptWithCustom(
|
|
@@ -6887,7 +7363,7 @@ async function privacyAction() {
|
|
|
6887
7363
|
"Enter your custom remarketing platform"
|
|
6888
7364
|
);
|
|
6889
7365
|
}
|
|
6890
|
-
const providersRaw = await
|
|
7366
|
+
const providersRaw = await p36.multiselect({
|
|
6891
7367
|
message: "Select if you use any of the following providers",
|
|
6892
7368
|
options: [
|
|
6893
7369
|
{ value: "recaptcha", label: "Invisible reCAPTCHA" },
|
|
@@ -6898,16 +7374,16 @@ async function privacyAction() {
|
|
|
6898
7374
|
],
|
|
6899
7375
|
required: false
|
|
6900
7376
|
});
|
|
6901
|
-
if (
|
|
7377
|
+
if (p36.isCancel(providersRaw)) onCancel();
|
|
6902
7378
|
const providers = providersRaw;
|
|
6903
7379
|
if (providers.includes("custom")) {
|
|
6904
|
-
const custom = await
|
|
6905
|
-
if (
|
|
7380
|
+
const custom = await p36.text({ message: "Enter your custom provider" });
|
|
7381
|
+
if (p36.isCancel(custom)) onCancel();
|
|
6906
7382
|
const idx = providers.indexOf("custom");
|
|
6907
7383
|
if (idx !== -1) providers.splice(idx, 1);
|
|
6908
7384
|
if (custom) providers.push(String(custom));
|
|
6909
7385
|
}
|
|
6910
|
-
const usStates = await
|
|
7386
|
+
const usStates = await p36.select({
|
|
6911
7387
|
message: "Include U.S. state privacy rights (CCPA/CPRA, VCDPA, CPA, CTDPA, UCPA, TX, OR, etc.)?",
|
|
6912
7388
|
options: [
|
|
6913
7389
|
{
|
|
@@ -6918,55 +7394,55 @@ async function privacyAction() {
|
|
|
6918
7394
|
],
|
|
6919
7395
|
initialValue: "yes"
|
|
6920
7396
|
});
|
|
6921
|
-
if (
|
|
6922
|
-
const gdpr = await
|
|
7397
|
+
if (p36.isCancel(usStates)) onCancel();
|
|
7398
|
+
const gdpr = await p36.select({
|
|
6923
7399
|
message: "Do you want your Privacy Policy to include GDPR / UK GDPR wording?",
|
|
6924
7400
|
options: [
|
|
6925
7401
|
{ value: "yes", label: "Yes. Include GDPR rights for EEA, UK, and Swiss residents" },
|
|
6926
7402
|
{ value: "no", label: "No" }
|
|
6927
7403
|
]
|
|
6928
7404
|
});
|
|
6929
|
-
if (
|
|
7405
|
+
if (p36.isCancel(gdpr)) onCancel();
|
|
6930
7406
|
let facebookFanPage = "no";
|
|
6931
7407
|
const facebookDetails = { name: "", url: "" };
|
|
6932
7408
|
if (gdpr === "yes") {
|
|
6933
|
-
const fan = await
|
|
7409
|
+
const fan = await p36.select({
|
|
6934
7410
|
message: "Do you have a Facebook Fan Page?",
|
|
6935
7411
|
options: [
|
|
6936
7412
|
{ value: "yes", label: "Yes, we have a Facebook Fan Page" },
|
|
6937
7413
|
{ value: "no", label: "No" }
|
|
6938
7414
|
]
|
|
6939
7415
|
});
|
|
6940
|
-
if (
|
|
7416
|
+
if (p36.isCancel(fan)) onCancel();
|
|
6941
7417
|
facebookFanPage = fan;
|
|
6942
7418
|
if (facebookFanPage === "yes") {
|
|
6943
|
-
const name = await
|
|
7419
|
+
const name = await p36.text({
|
|
6944
7420
|
message: "What is the name of the Facebook Fan Page?",
|
|
6945
7421
|
placeholder: "My Facebook Page"
|
|
6946
7422
|
});
|
|
6947
|
-
if (
|
|
7423
|
+
if (p36.isCancel(name)) onCancel();
|
|
6948
7424
|
facebookDetails.name = name;
|
|
6949
|
-
const url = await
|
|
7425
|
+
const url = await p36.text({
|
|
6950
7426
|
message: "What is the URL of the Facebook Fan Page?",
|
|
6951
7427
|
placeholder: "https://facebook.com/my-facebook-page"
|
|
6952
7428
|
});
|
|
6953
|
-
if (
|
|
7429
|
+
if (p36.isCancel(url)) onCancel();
|
|
6954
7430
|
facebookDetails.url = url;
|
|
6955
7431
|
}
|
|
6956
7432
|
}
|
|
6957
|
-
const kids = await
|
|
7433
|
+
const kids = await p36.select({
|
|
6958
7434
|
message: "Do you collect information from kids under the age of 13?",
|
|
6959
7435
|
options: [
|
|
6960
7436
|
{ value: "yes", label: "Yes. We collect information from children under the age of 13" },
|
|
6961
7437
|
{ value: "no", label: "No" }
|
|
6962
7438
|
]
|
|
6963
7439
|
});
|
|
6964
|
-
if (
|
|
6965
|
-
const retention = await
|
|
7440
|
+
if (p36.isCancel(kids)) onCancel();
|
|
7441
|
+
const retention = await p36.text({
|
|
6966
7442
|
message: "How long do you retain personal information? (leave blank for default wording)",
|
|
6967
7443
|
placeholder: "e.g. 12 months after account closure"
|
|
6968
7444
|
});
|
|
6969
|
-
if (
|
|
7445
|
+
if (p36.isCancel(retention)) onCancel();
|
|
6970
7446
|
const html = generatePrivacyHtml({
|
|
6971
7447
|
core,
|
|
6972
7448
|
personalInfo: personalInfo ?? [],
|
|
@@ -7021,16 +7497,16 @@ async function privacyAction() {
|
|
|
7021
7497
|
]
|
|
7022
7498
|
});
|
|
7023
7499
|
}
|
|
7024
|
-
var privacy = new
|
|
7500
|
+
var privacy = new Command51("privacy").description("generate placeholder privacy policy").configureHelp(helpConfig).action(() => runCommand(privacyAction, "Failed to generate privacy policy."));
|
|
7025
7501
|
|
|
7026
7502
|
// src/commands/legal.ts
|
|
7027
|
-
var legal = new
|
|
7503
|
+
var legal = new Command52("legal").description("generate placeholder legal documents").configureHelp(helpConfig).addCommand(terms).addCommand(privacy);
|
|
7028
7504
|
|
|
7029
7505
|
// src/commands/fixtures.ts
|
|
7030
|
-
import { Command as
|
|
7506
|
+
import { Command as Command58 } from "commander";
|
|
7031
7507
|
|
|
7032
7508
|
// src/commands/fixtures/load.ts
|
|
7033
|
-
import { Command as
|
|
7509
|
+
import { Command as Command53 } from "commander";
|
|
7034
7510
|
|
|
7035
7511
|
// src/lib/data.ts
|
|
7036
7512
|
import fs28 from "node:fs";
|
|
@@ -7220,7 +7696,7 @@ async function hasLoadedFixtures(pb) {
|
|
|
7220
7696
|
}
|
|
7221
7697
|
|
|
7222
7698
|
// src/commands/fixtures/load.ts
|
|
7223
|
-
var load = new
|
|
7699
|
+
var load = new Command53("load").description("load fixtures into the database").configureHelp(helpConfig).action(
|
|
7224
7700
|
() => runCommand(async () => {
|
|
7225
7701
|
const { workspaceRootDir } = await getWorkspace();
|
|
7226
7702
|
let loaded = [];
|
|
@@ -7246,8 +7722,8 @@ var load = new Command51("load").description("load fixtures into the database").
|
|
|
7246
7722
|
);
|
|
7247
7723
|
|
|
7248
7724
|
// src/commands/fixtures/clear.ts
|
|
7249
|
-
import { Command as
|
|
7250
|
-
var clear = new
|
|
7725
|
+
import { Command as Command54 } from "commander";
|
|
7726
|
+
var clear = new Command54("clear").description("clear loaded fixtures").configureHelp(helpConfig).action(
|
|
7251
7727
|
() => runCommand(async () => {
|
|
7252
7728
|
const { workspaceRootDir } = await getWorkspace();
|
|
7253
7729
|
let cleared = [];
|
|
@@ -7276,8 +7752,8 @@ var clear = new Command52("clear").description("clear loaded fixtures").configur
|
|
|
7276
7752
|
);
|
|
7277
7753
|
|
|
7278
7754
|
// src/commands/fixtures/reset.ts
|
|
7279
|
-
import { Command as
|
|
7280
|
-
var reset = new
|
|
7755
|
+
import { Command as Command55 } from "commander";
|
|
7756
|
+
var reset = new Command55("reset").description("clear and reload fixtures").configureHelp(helpConfig).action(
|
|
7281
7757
|
() => runCommand(async () => {
|
|
7282
7758
|
const { workspaceRootDir } = await getWorkspace();
|
|
7283
7759
|
let cleared = [];
|
|
@@ -7309,8 +7785,8 @@ var reset = new Command53("reset").description("clear and reload fixtures").conf
|
|
|
7309
7785
|
// src/commands/fixtures/generate.ts
|
|
7310
7786
|
import fs29 from "node:fs";
|
|
7311
7787
|
import path26 from "node:path";
|
|
7312
|
-
import { Command as
|
|
7313
|
-
import * as
|
|
7788
|
+
import { Command as Command56, InvalidArgumentError } from "commander";
|
|
7789
|
+
import * as p37 from "@clack/prompts";
|
|
7314
7790
|
import { annotate } from "annotate-json-schema";
|
|
7315
7791
|
import { createGenerator } from "json-schema-faker";
|
|
7316
7792
|
import { faker } from "@faker-js/faker";
|
|
@@ -7420,7 +7896,7 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
|
7420
7896
|
}
|
|
7421
7897
|
return { writtenFiles, warnings };
|
|
7422
7898
|
}
|
|
7423
|
-
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(
|
|
7424
7900
|
(opts) => runCommand(async () => {
|
|
7425
7901
|
const { workspaceRootDir } = await getWorkspace();
|
|
7426
7902
|
const existing = getFixtureFiles(workspaceRootDir);
|
|
@@ -7449,7 +7925,7 @@ var generate2 = new Command54("generate").description("generate fixture data").o
|
|
|
7449
7925
|
seed: opts.seed
|
|
7450
7926
|
});
|
|
7451
7927
|
});
|
|
7452
|
-
for (const warning of result.warnings)
|
|
7928
|
+
for (const warning of result.warnings) p37.log.warn(warning);
|
|
7453
7929
|
if (result.writtenFiles.length === 0) {
|
|
7454
7930
|
reportResult({
|
|
7455
7931
|
summary: "No eligible collections found to generate fixtures for.",
|
|
@@ -7473,8 +7949,8 @@ var generate2 = new Command54("generate").description("generate fixture data").o
|
|
|
7473
7949
|
);
|
|
7474
7950
|
|
|
7475
7951
|
// src/commands/fixtures/regen.ts
|
|
7476
|
-
import { Command as
|
|
7477
|
-
import * as
|
|
7952
|
+
import { Command as Command57, InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
7953
|
+
import * as p38 from "@clack/prompts";
|
|
7478
7954
|
function parseCount2(value) {
|
|
7479
7955
|
const n = parseInt(value, 10);
|
|
7480
7956
|
if (!Number.isFinite(n) || n <= 0 || n > 999) {
|
|
@@ -7489,7 +7965,7 @@ function parseSeed2(value) {
|
|
|
7489
7965
|
}
|
|
7490
7966
|
return n;
|
|
7491
7967
|
}
|
|
7492
|
-
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(
|
|
7493
7969
|
(opts) => runCommand(async () => {
|
|
7494
7970
|
const { workspaceRootDir } = await getWorkspace();
|
|
7495
7971
|
let cleared = [];
|
|
@@ -7503,7 +7979,7 @@ var regen = new Command55("regen").description("clear the database, regenerate f
|
|
|
7503
7979
|
});
|
|
7504
7980
|
loaded = await loadFixtures(pb, workspaceRootDir);
|
|
7505
7981
|
});
|
|
7506
|
-
for (const warning of result.warnings)
|
|
7982
|
+
for (const warning of result.warnings) p38.log.warn(warning);
|
|
7507
7983
|
reportResult({
|
|
7508
7984
|
summary: `Regenerated fixtures (${loaded.length} collection(s) reloaded).`,
|
|
7509
7985
|
filesCreated: result.writtenFiles,
|
|
@@ -7518,14 +7994,14 @@ var regen = new Command55("regen").description("clear the database, regenerate f
|
|
|
7518
7994
|
);
|
|
7519
7995
|
|
|
7520
7996
|
// src/commands/fixtures.ts
|
|
7521
|
-
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);
|
|
7522
7998
|
|
|
7523
7999
|
// src/commands/seeds.ts
|
|
7524
|
-
import { Command as
|
|
8000
|
+
import { Command as Command62 } from "commander";
|
|
7525
8001
|
|
|
7526
8002
|
// src/commands/seeds/load.ts
|
|
7527
|
-
import { Command as
|
|
7528
|
-
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(
|
|
7529
8005
|
(opts) => runCommand(async () => {
|
|
7530
8006
|
const { workspaceRootDir } = await getWorkspace();
|
|
7531
8007
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -7564,7 +8040,7 @@ var load2 = new Command57("load").description("load seeds into the database").op
|
|
|
7564
8040
|
// src/commands/seeds/save.ts
|
|
7565
8041
|
import fs30 from "node:fs";
|
|
7566
8042
|
import path27 from "node:path";
|
|
7567
|
-
import { Command as
|
|
8043
|
+
import { Command as Command60 } from "commander";
|
|
7568
8044
|
var padZeros2 = (num, length) => num.toString().padStart(length, "0");
|
|
7569
8045
|
function filterSystemFields(record, systemFieldNames) {
|
|
7570
8046
|
const out = {};
|
|
@@ -7575,7 +8051,7 @@ function filterSystemFields(record, systemFieldNames) {
|
|
|
7575
8051
|
}
|
|
7576
8052
|
return out;
|
|
7577
8053
|
}
|
|
7578
|
-
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(
|
|
7579
8055
|
(opts) => runCommand(async () => {
|
|
7580
8056
|
const { workspaceRootDir } = await getWorkspace();
|
|
7581
8057
|
const seedsPath = dataDir(workspaceRootDir, "seeds");
|
|
@@ -7647,123 +8123,50 @@ var save = new Command58("save").description("save the current data as seeds").o
|
|
|
7647
8123
|
);
|
|
7648
8124
|
|
|
7649
8125
|
// src/commands/seeds/clear.ts
|
|
7650
|
-
import { Command as
|
|
7651
|
-
var clear2 = new
|
|
8126
|
+
import { Command as Command61 } from "commander";
|
|
8127
|
+
var clear2 = new Command61("clear").description("clear seeded records").configureHelp(helpConfig).action(
|
|
7652
8128
|
() => runCommand(async () => {
|
|
7653
8129
|
const { workspaceRootDir } = await getWorkspace();
|
|
7654
8130
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
7655
8131
|
if (seedFiles.length === 0) {
|
|
7656
|
-
reportResult({
|
|
7657
|
-
summary: "No seed files found in data/seeds.",
|
|
7658
|
-
nextSteps: ["Run `vela seeds save` to create seed files from the current database."]
|
|
7659
|
-
});
|
|
7660
|
-
return;
|
|
7661
|
-
}
|
|
7662
|
-
let cleared = [];
|
|
7663
|
-
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
7664
|
-
cleared = await clearSeeds(pb, workspaceRootDir, seedFiles);
|
|
7665
|
-
});
|
|
7666
|
-
if (cleared.length === 0) {
|
|
7667
|
-
reportResult({
|
|
7668
|
-
summary: "No seeded records found to clear.",
|
|
7669
|
-
nextSteps: ["Run `vela seeds load` to load seed records into the database."]
|
|
7670
|
-
});
|
|
7671
|
-
return;
|
|
7672
|
-
}
|
|
7673
|
-
reportResult({
|
|
7674
|
-
summary: `Cleared ${cleared.length} seed file(s) worth of records.`,
|
|
7675
|
-
recordsCleared: cleared,
|
|
7676
|
-
nextSteps: ["Run `vela seeds load` to reload seeds from the files in data/seeds."]
|
|
7677
|
-
});
|
|
7678
|
-
}, "Failed to clear seeds.")
|
|
7679
|
-
);
|
|
7680
|
-
|
|
7681
|
-
// src/commands/seeds.ts
|
|
7682
|
-
var seeds = new Command60("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
|
|
7683
|
-
|
|
7684
|
-
// src/commands/signup.ts
|
|
7685
|
-
import { Command as Command62 } from "commander";
|
|
7686
|
-
import * as p37 from "@clack/prompts";
|
|
7687
|
-
import makeFetchCookie2 from "fetch-cookie";
|
|
7688
|
-
|
|
7689
|
-
// src/commands/login.ts
|
|
7690
|
-
import os4 from "node:os";
|
|
7691
|
-
import { Command as Command61 } from "commander";
|
|
7692
|
-
import * as p36 from "@clack/prompts";
|
|
7693
|
-
import makeFetchCookie from "fetch-cookie";
|
|
7694
|
-
var login = new Command61("login").description("login to velastack.dev").configureHelp(helpConfig).action(
|
|
7695
|
-
() => runCommand(async () => {
|
|
7696
|
-
const { email: email3, password: password11 } = await p36.group({
|
|
7697
|
-
email: () => p36.text({ message: "Email" }),
|
|
7698
|
-
password: () => p36.password({ message: "Password" })
|
|
7699
|
-
});
|
|
7700
|
-
const fetchCookie = makeFetchCookie(fetch);
|
|
7701
|
-
const loginRes = await fetchCookie(`${API_URL}/login`, {
|
|
7702
|
-
method: "POST",
|
|
7703
|
-
headers: {
|
|
7704
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
7705
|
-
Origin: API_URL
|
|
7706
|
-
},
|
|
7707
|
-
body: new URLSearchParams({
|
|
7708
|
-
type: "password",
|
|
7709
|
-
email: email3,
|
|
7710
|
-
password: password11
|
|
7711
|
-
}).toString()
|
|
7712
|
-
});
|
|
7713
|
-
if (!loginRes.headers.get("Set-Cookie")) {
|
|
7714
|
-
throw new Error(
|
|
7715
|
-
"Run `vela signup` to create an account or reset at https://velastack.dev/reset"
|
|
7716
|
-
);
|
|
8132
|
+
reportResult({
|
|
8133
|
+
summary: "No seed files found in data/seeds.",
|
|
8134
|
+
nextSteps: ["Run `vela seeds save` to create seed files from the current database."]
|
|
8135
|
+
});
|
|
8136
|
+
return;
|
|
7717
8137
|
}
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
)
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
method: "POST",
|
|
7727
|
-
headers: {
|
|
7728
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
7729
|
-
Origin: API_URL
|
|
7730
|
-
},
|
|
7731
|
-
body: new URLSearchParams({ label: label4 }).toString()
|
|
7732
|
-
});
|
|
7733
|
-
const cookie = await fetchCookie.cookieJar.getCookieString(API_URL);
|
|
7734
|
-
const apiKey = extractApiKey(cookie);
|
|
7735
|
-
if (!apiKey) {
|
|
7736
|
-
throw new Error("Failed to create API key. Try again or contact support.");
|
|
7737
|
-
}
|
|
7738
|
-
const [id] = apiKey.split(".");
|
|
7739
|
-
const res = await fetchCookie(`${API_URL}/api/collections/api_keys/records`, {
|
|
7740
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
7741
|
-
});
|
|
7742
|
-
const data = await res.json();
|
|
7743
|
-
for (const item of data.items) {
|
|
7744
|
-
if (item.label === label4 && item.id !== id) {
|
|
7745
|
-
await fetchCookie(`${API_URL}/api/collections/api_keys/records/${item.id}`, {
|
|
7746
|
-
method: "DELETE",
|
|
7747
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
8138
|
+
let cleared = [];
|
|
8139
|
+
await withPocketbase(workspaceRootDir, async (pb) => {
|
|
8140
|
+
cleared = await clearSeeds(pb, workspaceRootDir, seedFiles);
|
|
8141
|
+
});
|
|
8142
|
+
if (cleared.length === 0) {
|
|
8143
|
+
reportResult({
|
|
8144
|
+
summary: "No seeded records found to clear.",
|
|
8145
|
+
nextSteps: ["Run `vela seeds load` to load seed records into the database."]
|
|
7748
8146
|
});
|
|
8147
|
+
return;
|
|
7749
8148
|
}
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
8149
|
+
reportResult({
|
|
8150
|
+
summary: `Cleared ${cleared.length} seed file(s) worth of records.`,
|
|
8151
|
+
recordsCleared: cleared,
|
|
8152
|
+
nextSteps: ["Run `vela seeds load` to reload seeds from the files in data/seeds."]
|
|
8153
|
+
});
|
|
8154
|
+
}, "Failed to clear seeds.")
|
|
8155
|
+
);
|
|
8156
|
+
|
|
8157
|
+
// src/commands/seeds.ts
|
|
8158
|
+
var seeds = new Command62("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
|
|
7759
8159
|
|
|
7760
8160
|
// src/commands/signup.ts
|
|
7761
|
-
|
|
8161
|
+
import { Command as Command63 } from "commander";
|
|
8162
|
+
import * as p39 from "@clack/prompts";
|
|
8163
|
+
import makeFetchCookie2 from "fetch-cookie";
|
|
8164
|
+
var signup = new Command63("signup").description("signup to velastack.dev").configureHelp(helpConfig).action(
|
|
7762
8165
|
() => runCommand(async () => {
|
|
7763
|
-
const { email: email3, password: password11, passwordConfirm } = await
|
|
7764
|
-
email: () =>
|
|
7765
|
-
password: () =>
|
|
7766
|
-
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" })
|
|
7767
8170
|
});
|
|
7768
8171
|
if (password11 !== passwordConfirm) {
|
|
7769
8172
|
throw new Error("Passwords do not match.");
|
|
@@ -7787,33 +8190,33 @@ var signup = new Command62("signup").description("signup to velastack.dev").conf
|
|
|
7787
8190
|
}
|
|
7788
8191
|
const apiKey = await issueApiKey(fetchCookie);
|
|
7789
8192
|
writeConfig({ apiKey });
|
|
7790
|
-
|
|
7791
|
-
|
|
8193
|
+
p39.log.success("Signed up to velastack.dev");
|
|
8194
|
+
p39.log.info("Check your email for a confirmation link.");
|
|
7792
8195
|
}, "Failed to signup.")
|
|
7793
8196
|
);
|
|
7794
8197
|
|
|
7795
8198
|
// src/commands/logout.ts
|
|
7796
|
-
import { Command as
|
|
7797
|
-
import * as
|
|
7798
|
-
var logout = new
|
|
8199
|
+
import { Command as Command64 } from "commander";
|
|
8200
|
+
import * as p40 from "@clack/prompts";
|
|
8201
|
+
var logout = new Command64("logout").alias("signout").description("logout from velastack.dev").configureHelp(helpConfig).action(
|
|
7799
8202
|
() => runCommand(() => {
|
|
7800
8203
|
if (!readConfig()) {
|
|
7801
|
-
|
|
8204
|
+
p40.log.info("Not logged in");
|
|
7802
8205
|
return;
|
|
7803
8206
|
}
|
|
7804
8207
|
clearConfig();
|
|
7805
|
-
|
|
8208
|
+
p40.log.success("Logged out of velastack.dev");
|
|
7806
8209
|
})
|
|
7807
8210
|
);
|
|
7808
8211
|
|
|
7809
8212
|
// src/commands/whoami.ts
|
|
7810
|
-
import { Command as
|
|
7811
|
-
import * as
|
|
7812
|
-
var whoami = new
|
|
8213
|
+
import { Command as Command65 } from "commander";
|
|
8214
|
+
import * as p41 from "@clack/prompts";
|
|
8215
|
+
var whoami = new Command65("whoami").description("show the current user").configureHelp(helpConfig).action(
|
|
7813
8216
|
() => runCommand(async () => {
|
|
7814
8217
|
const apiKey = readConfig()?.apiKey;
|
|
7815
8218
|
if (!apiKey) {
|
|
7816
|
-
|
|
8219
|
+
p41.log.info("Not logged in. Run `vela login` to login.");
|
|
7817
8220
|
return;
|
|
7818
8221
|
}
|
|
7819
8222
|
const res = await fetch(`${API_URL}/api/collections/users/records`, {
|
|
@@ -7821,22 +8224,22 @@ var whoami = new Command64("whoami").description("show the current user").config
|
|
|
7821
8224
|
});
|
|
7822
8225
|
const data = await res.json();
|
|
7823
8226
|
if (!data.items.length) throw new Error("No user found. Run `vela login` to login.");
|
|
7824
|
-
|
|
8227
|
+
p41.log.success(`Logged in as ${data.items[0].email}`);
|
|
7825
8228
|
})
|
|
7826
8229
|
);
|
|
7827
8230
|
|
|
7828
8231
|
// src/commands/migrate.ts
|
|
7829
|
-
import { Command as
|
|
8232
|
+
import { Command as Command71 } from "commander";
|
|
7830
8233
|
|
|
7831
8234
|
// src/commands/migrate/up.ts
|
|
7832
|
-
import { Command as
|
|
8235
|
+
import { Command as Command66 } from "commander";
|
|
7833
8236
|
|
|
7834
8237
|
// src/lib/migrate.ts
|
|
7835
8238
|
import path28 from "node:path";
|
|
7836
|
-
import
|
|
8239
|
+
import process23 from "node:process";
|
|
7837
8240
|
import { x as x2 } from "tinyexec";
|
|
7838
8241
|
async function runPocketbaseMigrate(args) {
|
|
7839
|
-
const cwd =
|
|
8242
|
+
const cwd = process23.cwd();
|
|
7840
8243
|
const { getBinaryPath } = await import("pocketbase-server");
|
|
7841
8244
|
const binaryPath = getBinaryPath();
|
|
7842
8245
|
await x2(
|
|
@@ -7868,10 +8271,10 @@ async function runMigrateUp() {
|
|
|
7868
8271
|
]
|
|
7869
8272
|
});
|
|
7870
8273
|
}
|
|
7871
|
-
var up = new
|
|
8274
|
+
var up = new Command66("up").description("apply all pending migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations."));
|
|
7872
8275
|
|
|
7873
8276
|
// src/commands/migrate/down.ts
|
|
7874
|
-
import { Command as
|
|
8277
|
+
import { Command as Command67, InvalidArgumentError as InvalidArgumentError3 } from "commander";
|
|
7875
8278
|
function parseSteps(value) {
|
|
7876
8279
|
const n = parseInt(value, 10);
|
|
7877
8280
|
if (!Number.isFinite(n) || n <= 0) {
|
|
@@ -7879,7 +8282,7 @@ function parseSteps(value) {
|
|
|
7879
8282
|
}
|
|
7880
8283
|
return n;
|
|
7881
8284
|
}
|
|
7882
|
-
var down = new
|
|
8285
|
+
var down = new Command67("down").alias("rollback").description("revert the last N applied migrations").argument("[number]", "how many migrations to revert", parseSteps, 1).configureHelp(helpConfig).action(
|
|
7883
8286
|
(n) => runCommand(async () => {
|
|
7884
8287
|
await runPocketbaseMigrate(["down", String(n)]);
|
|
7885
8288
|
reportResult({
|
|
@@ -7895,11 +8298,11 @@ var down = new Command66("down").alias("rollback").description("revert the last
|
|
|
7895
8298
|
// src/commands/migrate/create.ts
|
|
7896
8299
|
import fs31 from "node:fs";
|
|
7897
8300
|
import path29 from "node:path";
|
|
7898
|
-
import
|
|
7899
|
-
import { Command as
|
|
7900
|
-
var create2 = new
|
|
8301
|
+
import process24 from "node:process";
|
|
8302
|
+
import { Command as Command68 } from "commander";
|
|
8303
|
+
var create2 = new Command68("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
|
|
7901
8304
|
(name) => runCommand(async () => {
|
|
7902
|
-
const cwd =
|
|
8305
|
+
const cwd = process24.cwd();
|
|
7903
8306
|
const before = listMigrationFiles(cwd);
|
|
7904
8307
|
await runPocketbaseMigrate(["create", name]);
|
|
7905
8308
|
const after = listMigrationFiles(cwd);
|
|
@@ -7923,11 +8326,11 @@ function listMigrationFiles(cwd) {
|
|
|
7923
8326
|
// src/commands/migrate/collections.ts
|
|
7924
8327
|
import fs32 from "node:fs";
|
|
7925
8328
|
import path30 from "node:path";
|
|
7926
|
-
import
|
|
7927
|
-
import { Command as
|
|
7928
|
-
var collections = new
|
|
8329
|
+
import process25 from "node:process";
|
|
8330
|
+
import { Command as Command69 } from "commander";
|
|
8331
|
+
var collections = new Command69("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
|
|
7929
8332
|
() => runCommand(async () => {
|
|
7930
|
-
const cwd =
|
|
8333
|
+
const cwd = process25.cwd();
|
|
7931
8334
|
const before = listMigrationFiles2(cwd);
|
|
7932
8335
|
await runPocketbaseMigrate(["collections"]);
|
|
7933
8336
|
const after = listMigrationFiles2(cwd);
|
|
@@ -7956,8 +8359,8 @@ function listMigrationFiles2(cwd) {
|
|
|
7956
8359
|
}
|
|
7957
8360
|
|
|
7958
8361
|
// src/commands/migrate/history-sync.ts
|
|
7959
|
-
import { Command as
|
|
7960
|
-
var historySync = new
|
|
8362
|
+
import { Command as Command70 } from "commander";
|
|
8363
|
+
var historySync = new Command70("history-sync").description("drop _migrations rows whose files no longer exist").configureHelp(helpConfig).action(
|
|
7961
8364
|
() => runCommand(async () => {
|
|
7962
8365
|
await runPocketbaseMigrate(["history-sync"]);
|
|
7963
8366
|
reportResult({
|
|
@@ -7968,20 +8371,20 @@ var historySync = new Command69("history-sync").description("drop _migrations ro
|
|
|
7968
8371
|
);
|
|
7969
8372
|
|
|
7970
8373
|
// src/commands/migrate.ts
|
|
7971
|
-
var migrate = new
|
|
8374
|
+
var migrate = new Command71("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
|
|
7972
8375
|
|
|
7973
8376
|
// src/commands/dev.ts
|
|
7974
8377
|
import fs33 from "node:fs";
|
|
7975
8378
|
import path32 from "node:path";
|
|
7976
|
-
import
|
|
8379
|
+
import process27 from "node:process";
|
|
7977
8380
|
import { performance } from "node:perf_hooks";
|
|
7978
|
-
import { Command as
|
|
8381
|
+
import { Command as Command72, InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
7979
8382
|
import pc15 from "picocolors";
|
|
7980
8383
|
import PocketBase4 from "pocketbase";
|
|
7981
8384
|
|
|
7982
8385
|
// src/lib/vite.ts
|
|
7983
8386
|
import path31 from "node:path";
|
|
7984
|
-
import
|
|
8387
|
+
import process26 from "node:process";
|
|
7985
8388
|
import { createRequire as createRequire2 } from "node:module";
|
|
7986
8389
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
7987
8390
|
import pc14 from "picocolors";
|
|
@@ -8005,13 +8408,13 @@ function resolveProjectVite(cwd) {
|
|
|
8005
8408
|
return null;
|
|
8006
8409
|
}
|
|
8007
8410
|
}
|
|
8008
|
-
async function loadVite(cwd =
|
|
8411
|
+
async function loadVite(cwd = process26.cwd()) {
|
|
8009
8412
|
const entry = resolveProjectVite(cwd);
|
|
8010
8413
|
const vite = entry ? await import(pathToFileURL2(entry).href) : await import("vite");
|
|
8011
8414
|
const error = viteVersionError(vite.version);
|
|
8012
8415
|
if (error) {
|
|
8013
8416
|
console.error(`${pc14.redBright("\u2717")} ${error}`);
|
|
8014
|
-
|
|
8417
|
+
process26.exit(1);
|
|
8015
8418
|
}
|
|
8016
8419
|
return vite;
|
|
8017
8420
|
}
|
|
@@ -8024,16 +8427,16 @@ function parsePort(value) {
|
|
|
8024
8427
|
}
|
|
8025
8428
|
return port;
|
|
8026
8429
|
}
|
|
8027
|
-
var dev = new
|
|
8028
|
-
const cwd =
|
|
8029
|
-
|
|
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) => {
|
|
8431
|
+
const cwd = process27.cwd();
|
|
8432
|
+
process27.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
8030
8433
|
const startTime = performance.now();
|
|
8031
8434
|
const { createServer, version } = await loadVite(cwd);
|
|
8032
8435
|
const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
|
|
8033
8436
|
const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
|
|
8034
8437
|
let pbProc;
|
|
8035
8438
|
const backend3 = hasBackend(cwd);
|
|
8036
|
-
const needsStart = backend3 && !
|
|
8439
|
+
const needsStart = backend3 && !process27.env.POCKETBASE_URL;
|
|
8037
8440
|
const cleanup = () => {
|
|
8038
8441
|
if (pbProc?.pid) pbProc.kill();
|
|
8039
8442
|
if (fs33.existsSync(viteMetadataFile)) fs33.rmSync(viteMetadataFile);
|
|
@@ -8048,15 +8451,15 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
8048
8451
|
stdio: "pipe"
|
|
8049
8452
|
});
|
|
8050
8453
|
pbProc = started.proc;
|
|
8051
|
-
|
|
8052
|
-
pbProc.stdout?.pipe(
|
|
8053
|
-
pbProc.stderr?.pipe(
|
|
8454
|
+
process27.env.POCKETBASE_URL = started.url;
|
|
8455
|
+
pbProc.stdout?.pipe(process27.stdout);
|
|
8456
|
+
pbProc.stderr?.pipe(process27.stderr);
|
|
8054
8457
|
pbProc.on("error", (err) => console.error("PocketBase error:", err));
|
|
8055
8458
|
pbProc.on("exit", (code) => console.log(`PocketBase exited with code ${code}`));
|
|
8056
|
-
|
|
8057
|
-
|
|
8459
|
+
process27.on("exit", cleanup);
|
|
8460
|
+
process27.on("SIGINT", () => {
|
|
8058
8461
|
cleanup();
|
|
8059
|
-
|
|
8462
|
+
process27.exit(0);
|
|
8060
8463
|
});
|
|
8061
8464
|
}
|
|
8062
8465
|
const serverOptions = {};
|
|
@@ -8078,21 +8481,21 @@ var dev = new Command71("dev").description("start the development server").optio
|
|
|
8078
8481
|
await fs33.promises.writeFile(
|
|
8079
8482
|
viteMetadataFile,
|
|
8080
8483
|
JSON.stringify({
|
|
8081
|
-
pocketbaseUrl:
|
|
8484
|
+
pocketbaseUrl: process27.env.POCKETBASE_URL,
|
|
8082
8485
|
vitePort,
|
|
8083
8486
|
viteHost
|
|
8084
8487
|
})
|
|
8085
8488
|
);
|
|
8086
|
-
const pb = new PocketBase4(
|
|
8489
|
+
const pb = new PocketBase4(process27.env.POCKETBASE_URL);
|
|
8087
8490
|
await pb.collection("_superusers").authWithPassword(
|
|
8088
|
-
|
|
8089
|
-
|
|
8491
|
+
process27.env.POCKETBASE_SUPERUSER_EMAIL,
|
|
8492
|
+
process27.env.POCKETBASE_SUPERUSER_PASSWORD
|
|
8090
8493
|
);
|
|
8091
8494
|
await pb.settings.update({ meta: { appURL: `http://${viteHost}:${vitePort}` } });
|
|
8092
8495
|
await startWatchingTypes(cwd, pb);
|
|
8093
8496
|
});
|
|
8094
8497
|
await server.listen();
|
|
8095
|
-
const hasExistingLogs =
|
|
8498
|
+
const hasExistingLogs = process27.stdout.bytesWritten > 0 || process27.stderr.bytesWritten > 0;
|
|
8096
8499
|
const startupDurationString = pc15.dim(
|
|
8097
8500
|
`ready in ${pc15.reset(pc15.bold(Math.ceil(performance.now() - startTime)))} ms`
|
|
8098
8501
|
);
|
|
@@ -8132,9 +8535,9 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
8132
8535
|
// src/commands/build.ts
|
|
8133
8536
|
import fs34 from "node:fs";
|
|
8134
8537
|
import path33 from "node:path";
|
|
8135
|
-
import
|
|
8136
|
-
import { Command as
|
|
8137
|
-
import * as
|
|
8538
|
+
import process29 from "node:process";
|
|
8539
|
+
import { Command as Command73 } from "commander";
|
|
8540
|
+
import * as p42 from "@clack/prompts";
|
|
8138
8541
|
import pc16 from "picocolors";
|
|
8139
8542
|
import { x as x3 } from "tinyexec";
|
|
8140
8543
|
import { detect as detect5 } from "package-manager-detector";
|
|
@@ -8147,10 +8550,10 @@ function applyBuildEnv(cwd, env2 = process.env) {
|
|
|
8147
8550
|
}
|
|
8148
8551
|
|
|
8149
8552
|
// src/lib/origin.ts
|
|
8150
|
-
import
|
|
8553
|
+
import process28 from "node:process";
|
|
8151
8554
|
function resolveOrigin(workspaceRootDir, envTag, config = {}) {
|
|
8152
8555
|
return normalizeOrigin(
|
|
8153
|
-
|
|
8556
|
+
process28.env.VELA_ORIGIN ?? readBinding(workspaceRootDir, envTag)?.domain ?? config.deploy?.domain
|
|
8154
8557
|
);
|
|
8155
8558
|
}
|
|
8156
8559
|
function normalizeOrigin(value) {
|
|
@@ -8170,13 +8573,13 @@ function splitHosts(value) {
|
|
|
8170
8573
|
|
|
8171
8574
|
// src/commands/build.ts
|
|
8172
8575
|
var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
|
|
8173
|
-
var build = new
|
|
8174
|
-
const cwd =
|
|
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) => {
|
|
8577
|
+
const cwd = process29.cwd();
|
|
8175
8578
|
applyBuildEnv(cwd);
|
|
8176
8579
|
const origin = await originForBuild(cwd, options.target);
|
|
8177
|
-
if (origin)
|
|
8580
|
+
if (origin) process29.env.VELA_ORIGIN = origin;
|
|
8178
8581
|
let pbProc;
|
|
8179
|
-
const needsStart = hasBackend(cwd) && !
|
|
8582
|
+
const needsStart = hasBackend(cwd) && !process29.env.POCKETBASE_URL;
|
|
8180
8583
|
const cleanup = () => {
|
|
8181
8584
|
if (pbProc?.pid) pbProc.kill();
|
|
8182
8585
|
};
|
|
@@ -8190,11 +8593,11 @@ var build = new Command72("build").description("build the app").configureHelp(he
|
|
|
8190
8593
|
dev: true
|
|
8191
8594
|
});
|
|
8192
8595
|
pbProc = started.proc;
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8596
|
+
process29.env.POCKETBASE_URL = started.url;
|
|
8597
|
+
process29.on("exit", cleanup);
|
|
8598
|
+
process29.on("SIGINT", () => {
|
|
8196
8599
|
cleanup();
|
|
8197
|
-
|
|
8600
|
+
process29.exit(0);
|
|
8198
8601
|
});
|
|
8199
8602
|
}
|
|
8200
8603
|
try {
|
|
@@ -8227,7 +8630,7 @@ async function originForBuild(cwd, target) {
|
|
|
8227
8630
|
function warnIfPrerendered(cwd) {
|
|
8228
8631
|
const dir = path33.join(cwd, PRERENDERED_DIR);
|
|
8229
8632
|
if (!fs34.existsSync(dir) || fs34.readdirSync(dir).length === 0) return;
|
|
8230
|
-
|
|
8633
|
+
p42.log.warn(
|
|
8231
8634
|
`Prerendered pages were built with no domain configured, so their canonical
|
|
8232
8635
|
links point at SvelteKit's placeholder host rather than at this site.
|
|
8233
8636
|
|
|
@@ -8237,16 +8640,16 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
|
|
|
8237
8640
|
|
|
8238
8641
|
// src/commands/preview.ts
|
|
8239
8642
|
import path34 from "node:path";
|
|
8240
|
-
import
|
|
8241
|
-
import { Command as
|
|
8643
|
+
import process30 from "node:process";
|
|
8644
|
+
import { Command as Command74 } from "commander";
|
|
8242
8645
|
import { x as x4 } from "tinyexec";
|
|
8243
8646
|
import { detect as detect6 } from "package-manager-detector";
|
|
8244
8647
|
import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
|
|
8245
|
-
var preview = new
|
|
8246
|
-
const cwd =
|
|
8247
|
-
|
|
8648
|
+
var preview = new Command74("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
|
|
8649
|
+
const cwd = process30.cwd();
|
|
8650
|
+
process30.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
8248
8651
|
let pbProc;
|
|
8249
|
-
const needsStart = hasBackend(cwd) && !
|
|
8652
|
+
const needsStart = hasBackend(cwd) && !process30.env.POCKETBASE_URL;
|
|
8250
8653
|
const cleanup = () => {
|
|
8251
8654
|
if (pbProc?.pid) pbProc.kill();
|
|
8252
8655
|
};
|
|
@@ -8259,11 +8662,11 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
8259
8662
|
dev: true
|
|
8260
8663
|
});
|
|
8261
8664
|
pbProc = started.proc;
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8665
|
+
process30.env.POCKETBASE_URL = started.url;
|
|
8666
|
+
process30.on("exit", cleanup);
|
|
8667
|
+
process30.on("SIGINT", () => {
|
|
8265
8668
|
cleanup();
|
|
8266
|
-
|
|
8669
|
+
process30.exit(0);
|
|
8267
8670
|
});
|
|
8268
8671
|
}
|
|
8269
8672
|
try {
|
|
@@ -8282,8 +8685,8 @@ var preview = new Command73("preview").description("preview the built app").conf
|
|
|
8282
8685
|
|
|
8283
8686
|
// src/commands/sync.ts
|
|
8284
8687
|
import path35 from "node:path";
|
|
8285
|
-
import { Command as
|
|
8286
|
-
var sync = new
|
|
8688
|
+
import { Command as Command75 } from "commander";
|
|
8689
|
+
var sync = new Command75("sync").description("sync types from the database").configureHelp(helpConfig).action(
|
|
8287
8690
|
() => runCommand(async () => {
|
|
8288
8691
|
const { workspaceRootDir } = await getWorkspace();
|
|
8289
8692
|
const typesDir = path35.join(workspaceRootDir, ".svelte-kit", "types");
|
|
@@ -8296,8 +8699,8 @@ var sync = new Command74("sync").description("sync types from the database").con
|
|
|
8296
8699
|
);
|
|
8297
8700
|
|
|
8298
8701
|
// src/commands/provision.ts
|
|
8299
|
-
import { Command as
|
|
8300
|
-
import * as
|
|
8702
|
+
import { Command as Command76 } from "commander";
|
|
8703
|
+
import * as p43 from "@clack/prompts";
|
|
8301
8704
|
import pc17 from "picocolors";
|
|
8302
8705
|
import * as v7 from "valibot";
|
|
8303
8706
|
var OptionsSchema2 = v7.object({
|
|
@@ -8306,24 +8709,24 @@ var OptionsSchema2 = v7.object({
|
|
|
8306
8709
|
nodeMajor: v7.optional(v7.string())
|
|
8307
8710
|
});
|
|
8308
8711
|
var provision = addSshOptions(
|
|
8309
|
-
new
|
|
8712
|
+
new Command76("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
|
|
8310
8713
|
).option("--pb-version <version>", "PocketBase version to install").option("--node-major <version>", "Node.js major version to install", "22").action(
|
|
8311
8714
|
(target, raw) => runCommand(async () => {
|
|
8312
8715
|
const options = parseOptions(OptionsSchema2, raw);
|
|
8313
8716
|
const pbVersion = options.pbVersion ?? pocketbaseVersion();
|
|
8314
|
-
|
|
8315
|
-
|
|
8717
|
+
p43.intro(pc17.bgCyan(pc17.black(" vela provision ")));
|
|
8718
|
+
p43.log.info(`Target ${pc17.cyan(target)}`);
|
|
8316
8719
|
await withSsh(target, sshOptionsFrom(options), async (session) => {
|
|
8317
8720
|
await session.detectElevation();
|
|
8318
8721
|
const existing = await readServerInfo(session);
|
|
8319
8722
|
if (existing) {
|
|
8320
|
-
|
|
8723
|
+
p43.log.info(
|
|
8321
8724
|
`Already provisioned by vela ${existing.cliVersion} on ${existing.provisionedAt}. Bringing it up to date.`
|
|
8322
8725
|
);
|
|
8323
8726
|
}
|
|
8324
|
-
|
|
8727
|
+
p43.log.step("Uploading server scripts");
|
|
8325
8728
|
await syncServerScripts(session);
|
|
8326
|
-
|
|
8729
|
+
p43.log.step("Running provision");
|
|
8327
8730
|
const result = await runServerScript(session, "provision.sh", {
|
|
8328
8731
|
args: [
|
|
8329
8732
|
"--pb-version",
|
|
@@ -8335,7 +8738,7 @@ var provision = addSshOptions(
|
|
|
8335
8738
|
],
|
|
8336
8739
|
stream: true
|
|
8337
8740
|
});
|
|
8338
|
-
|
|
8741
|
+
p43.log.success(
|
|
8339
8742
|
`${target} is ready.
|
|
8340
8743
|
|
|
8341
8744
|
Node ${result?.node ?? "installed"}
|
|
@@ -8343,29 +8746,29 @@ var provision = addSshOptions(
|
|
|
8343
8746
|
PocketBase ${result?.pocketbase ?? pbVersion}`
|
|
8344
8747
|
);
|
|
8345
8748
|
});
|
|
8346
|
-
|
|
8749
|
+
p43.outro(`Deploy with ${pc17.cyan(`vela deploy --server ${target}`)}`);
|
|
8347
8750
|
}, "Failed to provision.")
|
|
8348
8751
|
);
|
|
8349
8752
|
|
|
8350
8753
|
// src/commands/deploy.ts
|
|
8351
8754
|
import path38 from "node:path";
|
|
8352
8755
|
import fs37 from "node:fs";
|
|
8353
|
-
import { Command as
|
|
8354
|
-
import * as
|
|
8756
|
+
import { Command as Command77, Option as Option2 } from "commander";
|
|
8757
|
+
import * as p44 from "@clack/prompts";
|
|
8355
8758
|
import pc18 from "picocolors";
|
|
8356
8759
|
import * as v8 from "valibot";
|
|
8357
8760
|
|
|
8358
8761
|
// src/lib/pocketbase-settings.ts
|
|
8359
8762
|
import fs35 from "node:fs";
|
|
8360
8763
|
import path36 from "node:path";
|
|
8361
|
-
import
|
|
8764
|
+
import process31 from "node:process";
|
|
8362
8765
|
import PocketBase5 from "pocketbase";
|
|
8363
8766
|
var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
|
|
8364
8767
|
async function readLocalMeta(cwd) {
|
|
8365
8768
|
const dataDir2 = path36.join(cwd, DATA_DIR);
|
|
8366
8769
|
if (!fs35.existsSync(dataDir2)) return null;
|
|
8367
|
-
const email3 =
|
|
8368
|
-
const password11 =
|
|
8770
|
+
const email3 = process31.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
8771
|
+
const password11 = process31.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
8369
8772
|
if (!email3 || !password11) return null;
|
|
8370
8773
|
let proc;
|
|
8371
8774
|
try {
|
|
@@ -8694,7 +9097,7 @@ var OptionsSchema3 = v8.object({
|
|
|
8694
9097
|
});
|
|
8695
9098
|
var deploy = addLockWaitOption(
|
|
8696
9099
|
addTargetOptions(
|
|
8697
|
-
new
|
|
9100
|
+
new Command77("deploy").description("deploy the app").configureHelp(helpConfig),
|
|
8698
9101
|
"production"
|
|
8699
9102
|
)
|
|
8700
9103
|
).option("--project <name>", "override the project name").option("--domain <hosts>", "hostname(s) to serve on, comma separated").option("--health-path <path>", "path the health check requests").option("--keep <count>", "how many old releases to keep on the server").option("--pb-version <version>", "PocketBase version to run").option("--no-build", "deploy the existing build output without rebuilding").addOption(
|
|
@@ -8710,7 +9113,7 @@ var deploy = addLockWaitOption(
|
|
|
8710
9113
|
(raw) => runCommand(async () => {
|
|
8711
9114
|
const options = parseOptions(OptionsSchema3, raw);
|
|
8712
9115
|
const backend3 = hasBackend();
|
|
8713
|
-
|
|
9116
|
+
p44.intro(pc18.bgCyan(pc18.black(" vela deploy ")));
|
|
8714
9117
|
if (options.build !== false) {
|
|
8715
9118
|
const { workspaceRootDir } = await getWorkspace();
|
|
8716
9119
|
await prepareAdapter(workspaceRootDir);
|
|
@@ -8720,7 +9123,7 @@ var deploy = addLockWaitOption(
|
|
|
8720
9123
|
{
|
|
8721
9124
|
remote: async (ctx) => {
|
|
8722
9125
|
const { session, instance, workspaceRootDir, config } = ctx;
|
|
8723
|
-
|
|
9126
|
+
p44.log.info(
|
|
8724
9127
|
`${pc18.cyan(ctx.appName)} ${pc18.dim("\u2192")} ${pc18.cyan(ctx.targetName)} ${pc18.dim(`(${ctx.server})`)}`
|
|
8725
9128
|
);
|
|
8726
9129
|
const [existing] = await readInstanceStates(session, instance);
|
|
@@ -8730,7 +9133,7 @@ var deploy = addLockWaitOption(
|
|
|
8730
9133
|
const askedForRemoteDb = options.remoteDb ?? config.deploy?.buildAgainstRemote;
|
|
8731
9134
|
const remoteDb = askedForRemoteDb ?? instanceHasBackend(existing);
|
|
8732
9135
|
if (existing && instanceHasBackend(existing) !== backend3) {
|
|
8733
|
-
|
|
9136
|
+
p44.log.info(
|
|
8734
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.`
|
|
8735
9138
|
);
|
|
8736
9139
|
}
|
|
@@ -8773,7 +9176,7 @@ with DNS of your own pointing at ${ctx.server}.`
|
|
|
8773
9176
|
tunnel = await openDatabaseTunnel(session, instance, existing);
|
|
8774
9177
|
} catch (err) {
|
|
8775
9178
|
if (askedForRemoteDb) throw err;
|
|
8776
|
-
|
|
9179
|
+
p44.log.warn(
|
|
8777
9180
|
`Could not build against the ${pc18.cyan(ctx.targetName)} database, using a local one instead.
|
|
8778
9181
|
${pc18.dim(String(err))}`
|
|
8779
9182
|
);
|
|
@@ -8781,13 +9184,13 @@ ${pc18.dim(String(err))}`
|
|
|
8781
9184
|
}
|
|
8782
9185
|
if (tunnel) {
|
|
8783
9186
|
buildEnv = { ...buildEnv, ...tunnel.env };
|
|
8784
|
-
|
|
9187
|
+
p44.log.info(
|
|
8785
9188
|
`Building against the ${pc18.cyan(ctx.targetName)} database on ${ctx.server} ${pc18.dim(`(port ${tunnel.pbPort})`)}`
|
|
8786
9189
|
);
|
|
8787
9190
|
} else if (backend3) {
|
|
8788
9191
|
await ensureSuperuser(workspaceRootDir);
|
|
8789
9192
|
}
|
|
8790
|
-
|
|
9193
|
+
p44.log.step("Building");
|
|
8791
9194
|
try {
|
|
8792
9195
|
await runBuild(workspaceRootDir, config.deploy?.buildCommand, buildEnv);
|
|
8793
9196
|
} finally {
|
|
@@ -8795,9 +9198,9 @@ ${pc18.dim(String(err))}`
|
|
|
8795
9198
|
}
|
|
8796
9199
|
}
|
|
8797
9200
|
const entries = collectArtifact(workspaceRootDir, config.deploy ?? {});
|
|
8798
|
-
|
|
9201
|
+
p44.log.step(`Uploading release ${pc18.dim(release)}`);
|
|
8799
9202
|
await uploadRelease(session, instance, release, entries);
|
|
8800
|
-
|
|
9203
|
+
p44.log.step("Activating");
|
|
8801
9204
|
result = await runServerScript(session, "apply.sh", {
|
|
8802
9205
|
args: [
|
|
8803
9206
|
instance,
|
|
@@ -8848,7 +9251,7 @@ ${pc18.dim(String(err))}`
|
|
|
8848
9251
|
url: primaryHost ? url : void 0
|
|
8849
9252
|
});
|
|
8850
9253
|
const redirects = started?.environment.redirects ?? [];
|
|
8851
|
-
|
|
9254
|
+
p44.log.success(
|
|
8852
9255
|
`Deployed ${pc18.cyan(ctx.appName)} ${pc18.dim(release)}
|
|
8853
9256
|
|
|
8854
9257
|
URL ${url}
|
|
@@ -8856,7 +9259,7 @@ ${pc18.dim(String(err))}`
|
|
|
8856
9259
|
` : "") + ` Port ${result?.webPort ?? "?"}${backend3 ? ` (PocketBase ${result?.pbPort ?? "?"})` : ""}`
|
|
8857
9260
|
);
|
|
8858
9261
|
if (managed && managed !== existing?.managed) {
|
|
8859
|
-
|
|
9262
|
+
p44.log.info(`${pc18.cyan(managed)} goes live within a minute.`);
|
|
8860
9263
|
}
|
|
8861
9264
|
if (result?.superuserCreated) {
|
|
8862
9265
|
await copyLocalBranding(
|
|
@@ -8865,7 +9268,7 @@ ${pc18.dim(String(err))}`
|
|
|
8865
9268
|
workspaceRootDir,
|
|
8866
9269
|
primaryHost ? result?.url ?? "" : ""
|
|
8867
9270
|
);
|
|
8868
|
-
|
|
9271
|
+
p44.log.info(
|
|
8869
9272
|
`Created the PocketBase superuser this app authenticates as.
|
|
8870
9273
|
|
|
8871
9274
|
Its credentials are stored in the environment on the server. To use
|
|
@@ -8876,7 +9279,7 @@ and deploy again.`
|
|
|
8876
9279
|
await reportAppURLDrift(session, instance, primaryHost);
|
|
8877
9280
|
}
|
|
8878
9281
|
if (!primaryHost) {
|
|
8879
|
-
|
|
9282
|
+
p44.log.warn(
|
|
8880
9283
|
`No domain configured, so nothing is proxied to this app yet.
|
|
8881
9284
|
Redeploy with ${pc18.cyan("--domain example.com")} once DNS points at ${ctx.server}` + (reporter.enabled ? "" : `,
|
|
8882
9285
|
or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
@@ -8886,7 +9289,7 @@ or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
|
8886
9289
|
},
|
|
8887
9290
|
{ project: options.project, askDomain: true, label: "deploy" }
|
|
8888
9291
|
);
|
|
8889
|
-
|
|
9292
|
+
p44.outro(`${pc18.cyan("vela status")} to see what is running`);
|
|
8890
9293
|
}, "Failed to deploy.")
|
|
8891
9294
|
);
|
|
8892
9295
|
async function prepareAdapter(workspaceRootDir) {
|
|
@@ -8905,8 +9308,8 @@ ${pc18.cyan(err.snippet)}` : err.message);
|
|
|
8905
9308
|
outcome.packageJsonChanged ? "package.json" : void 0
|
|
8906
9309
|
].filter((f) => Boolean(f));
|
|
8907
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`;
|
|
8908
|
-
|
|
8909
|
-
|
|
9311
|
+
p44.log.step(`Switching the adapter to ${pc18.cyan(ADAPTER_NODE)}`);
|
|
9312
|
+
p44.log.info(
|
|
8910
9313
|
`${why}, and vela deploy runs the app as a Node server.
|
|
8911
9314
|
|
|
8912
9315
|
Changed ${changed.join(", ")}` + (outcome.removedDeps.length ? `
|
|
@@ -8919,14 +9322,14 @@ ${pc18.cyan(err.snippet)}` : err.message);
|
|
|
8919
9322
|
rethrow(err);
|
|
8920
9323
|
}
|
|
8921
9324
|
}
|
|
8922
|
-
|
|
9325
|
+
p44.log.warn(`Commit ${changed.join(", ")} so every deploy builds the same way.`);
|
|
8923
9326
|
}
|
|
8924
9327
|
async function reportAppURLDrift(session, instance, domain) {
|
|
8925
9328
|
const expected = normalizeOrigin(domain);
|
|
8926
9329
|
if (!expected) return;
|
|
8927
9330
|
const current = await readRemoteAppURL(session, instance);
|
|
8928
9331
|
if (!current || normalizeOrigin(current) === expected) return;
|
|
8929
|
-
|
|
9332
|
+
p44.log.warn(
|
|
8930
9333
|
`This app's PocketBase ${pc18.cyan("appURL")} is ${pc18.dim(current)}, but it is served on ${pc18.dim(expected)}.
|
|
8931
9334
|
|
|
8932
9335
|
Emails and anything else PocketBase links to will use the former. Update it in
|
|
@@ -8941,15 +9344,15 @@ async function copyLocalBranding(session, instance, workspaceRootDir, appURL) {
|
|
|
8941
9344
|
if (copied.length === 0) return;
|
|
8942
9345
|
const outcome = await restartInstance(session, instance);
|
|
8943
9346
|
if (outcome.deployed && !outcome.restarted) {
|
|
8944
|
-
|
|
9347
|
+
p44.log.warn(
|
|
8945
9348
|
`Copied ${copied.join(", ")}, but the app did not restart to pick them up.
|
|
8946
9349
|
${pc18.dim(outcome.error ?? "")}`
|
|
8947
9350
|
);
|
|
8948
9351
|
return;
|
|
8949
9352
|
}
|
|
8950
|
-
|
|
9353
|
+
p44.log.success(`Copied ${copied.join(", ")} from this project's database`);
|
|
8951
9354
|
} catch (err) {
|
|
8952
|
-
|
|
9355
|
+
p44.log.warn(
|
|
8953
9356
|
`Could not copy this project's PocketBase settings across.
|
|
8954
9357
|
Set them in the admin panel instead. ${pc18.dim(String(err))}`
|
|
8955
9358
|
);
|
|
@@ -9042,7 +9445,7 @@ async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
|
9042
9445
|
const remote = await readRemoteEnv(session, instance);
|
|
9043
9446
|
if (Object.keys(remote).length > 0) return;
|
|
9044
9447
|
if (!fs37.existsSync(path38.join(workspaceRootDir, ".env"))) return;
|
|
9045
|
-
|
|
9448
|
+
p44.log.warn(
|
|
9046
9449
|
`This app has no production environment variables yet.
|
|
9047
9450
|
|
|
9048
9451
|
Local ${pc18.cyan(".env")} values are not uploaded by a deploy. Set them with
|
|
@@ -9053,53 +9456,43 @@ async function serverTimeOrLocal(session) {
|
|
|
9053
9456
|
try {
|
|
9054
9457
|
return await serverTime(session);
|
|
9055
9458
|
} catch {
|
|
9056
|
-
|
|
9459
|
+
p44.log.warn("Could not read the clock on the server; stamping this release from this machine.");
|
|
9057
9460
|
return /* @__PURE__ */ new Date();
|
|
9058
9461
|
}
|
|
9059
9462
|
}
|
|
9060
9463
|
|
|
9061
9464
|
// src/commands/link.ts
|
|
9062
9465
|
import path39 from "node:path";
|
|
9063
|
-
import
|
|
9064
|
-
import { Command as
|
|
9065
|
-
import * as
|
|
9466
|
+
import process32 from "node:process";
|
|
9467
|
+
import { Command as Command78 } from "commander";
|
|
9468
|
+
import * as p45 from "@clack/prompts";
|
|
9066
9469
|
var CREATE_NEW = "__new__";
|
|
9067
|
-
var link = new
|
|
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."));
|
|
9068
9471
|
async function linkProject() {
|
|
9069
9472
|
const { workspaceRootDir } = await getWorkspace();
|
|
9070
9473
|
const existing = readProjectConfig(workspaceRootDir);
|
|
9071
9474
|
if (existing) {
|
|
9072
|
-
|
|
9475
|
+
p45.log.success(`Linked to ${existing.projectName}.`);
|
|
9073
9476
|
return;
|
|
9074
9477
|
}
|
|
9075
9478
|
const apiKey = requireApiKey();
|
|
9076
|
-
const [
|
|
9077
|
-
getCurrentUser(apiKey),
|
|
9078
|
-
listTeams(apiKey),
|
|
9079
|
-
listProjects(apiKey)
|
|
9080
|
-
]);
|
|
9081
|
-
let projectId;
|
|
9082
|
-
let teamId;
|
|
9083
|
-
let projectName;
|
|
9479
|
+
const [teams3, projects] = await Promise.all([listTeams(apiKey), listProjects(apiKey)]);
|
|
9084
9480
|
const picked = projects.length > 0 ? await pickExistingProject(projects) : CREATE_NEW;
|
|
9481
|
+
let linked;
|
|
9085
9482
|
if (picked !== CREATE_NEW) {
|
|
9086
9483
|
const project = projects.find((pr) => pr.id === picked);
|
|
9087
|
-
|
|
9088
|
-
teamId = project.team;
|
|
9089
|
-
projectName = project.name;
|
|
9484
|
+
linked = toLinked(project, project.expand?.team);
|
|
9090
9485
|
} else {
|
|
9091
9486
|
const team = await pickTeam(teams3);
|
|
9092
9487
|
const name = await promptProjectName(workspaceRootDir);
|
|
9093
|
-
|
|
9094
|
-
projectId = created.id;
|
|
9095
|
-
teamId = team.id;
|
|
9096
|
-
projectName = created.name;
|
|
9488
|
+
linked = await linkNewProject(apiKey, { name, teamId: team.id, interactive: true });
|
|
9097
9489
|
}
|
|
9490
|
+
const { projectId, teamId, projectName } = linked;
|
|
9098
9491
|
writeProjectConfig(workspaceRootDir, { projectId, teamId, projectName });
|
|
9099
|
-
|
|
9492
|
+
p45.log.success(`Linked to ${projectName} (${linked.dashboardUrl}).`);
|
|
9100
9493
|
}
|
|
9101
9494
|
async function pickExistingProject(projects) {
|
|
9102
|
-
const choice = await
|
|
9495
|
+
const choice = await p45.select({
|
|
9103
9496
|
message: "Select a project",
|
|
9104
9497
|
options: [
|
|
9105
9498
|
...projects.map((pr) => ({
|
|
@@ -9109,39 +9502,24 @@ async function pickExistingProject(projects) {
|
|
|
9109
9502
|
{ value: CREATE_NEW, label: "Create a new project" }
|
|
9110
9503
|
]
|
|
9111
9504
|
});
|
|
9112
|
-
if (
|
|
9113
|
-
|
|
9114
|
-
|
|
9505
|
+
if (p45.isCancel(choice)) {
|
|
9506
|
+
p45.cancel("Operation cancelled.");
|
|
9507
|
+
process32.exit(0);
|
|
9115
9508
|
}
|
|
9116
9509
|
return choice;
|
|
9117
9510
|
}
|
|
9118
|
-
async function pickTeam(teams3) {
|
|
9119
|
-
if (teams3.length === 1) return teams3[0];
|
|
9120
|
-
const choice = await p43.select({
|
|
9121
|
-
message: "Select a team",
|
|
9122
|
-
options: teams3.map((team) => ({
|
|
9123
|
-
value: team.id,
|
|
9124
|
-
label: team.is_personal ? `${team.name} (personal)` : team.name
|
|
9125
|
-
}))
|
|
9126
|
-
});
|
|
9127
|
-
if (p43.isCancel(choice)) {
|
|
9128
|
-
p43.cancel("Operation cancelled.");
|
|
9129
|
-
process29.exit(0);
|
|
9130
|
-
}
|
|
9131
|
-
return teams3.find((team) => team.id === choice);
|
|
9132
|
-
}
|
|
9133
9511
|
async function promptProjectName(workspaceRootDir) {
|
|
9134
9512
|
const defaultValue = defaultProjectName2(workspaceRootDir);
|
|
9135
|
-
const value = await
|
|
9513
|
+
const value = await p45.text({
|
|
9136
9514
|
message: "Project name",
|
|
9137
9515
|
defaultValue,
|
|
9138
9516
|
initialValue: defaultValue,
|
|
9139
9517
|
placeholder: defaultValue,
|
|
9140
9518
|
validate: (v10) => !v10?.trim() ? "Required" : void 0
|
|
9141
9519
|
});
|
|
9142
|
-
if (
|
|
9143
|
-
|
|
9144
|
-
|
|
9520
|
+
if (p45.isCancel(value)) {
|
|
9521
|
+
p45.cancel("Operation cancelled.");
|
|
9522
|
+
process32.exit(0);
|
|
9145
9523
|
}
|
|
9146
9524
|
return value.trim();
|
|
9147
9525
|
}
|
|
@@ -9156,14 +9534,14 @@ function defaultProjectName2(workspaceRootDir) {
|
|
|
9156
9534
|
}
|
|
9157
9535
|
|
|
9158
9536
|
// src/commands/env.ts
|
|
9159
|
-
import { Command as
|
|
9537
|
+
import { Command as Command83 } from "commander";
|
|
9160
9538
|
|
|
9161
9539
|
// src/commands/env/list.ts
|
|
9162
|
-
import { Command as
|
|
9163
|
-
import * as
|
|
9540
|
+
import { Command as Command79 } from "commander";
|
|
9541
|
+
import * as p46 from "@clack/prompts";
|
|
9164
9542
|
import pc19 from "picocolors";
|
|
9165
9543
|
var envList = addTargetOptions(
|
|
9166
|
-
new
|
|
9544
|
+
new Command79("list").description("list environment variable names").configureHelp(helpConfig),
|
|
9167
9545
|
"local"
|
|
9168
9546
|
).action(
|
|
9169
9547
|
(raw) => runCommand(
|
|
@@ -9185,10 +9563,10 @@ var envList = addTargetOptions(
|
|
|
9185
9563
|
);
|
|
9186
9564
|
function report(keys, where) {
|
|
9187
9565
|
if (keys.length === 0) {
|
|
9188
|
-
|
|
9566
|
+
p46.log.info(`No environment variables configured ${pc19.dim(`(${where})`)}.`);
|
|
9189
9567
|
return;
|
|
9190
9568
|
}
|
|
9191
|
-
|
|
9569
|
+
p46.log.info(
|
|
9192
9570
|
`Environment ${pc19.dim(`(${where})`)}
|
|
9193
9571
|
|
|
9194
9572
|
` + keys.sort().map((key) => ` ${key}`).join("\n")
|
|
@@ -9196,12 +9574,12 @@ function report(keys, where) {
|
|
|
9196
9574
|
}
|
|
9197
9575
|
|
|
9198
9576
|
// src/commands/env/set.ts
|
|
9199
|
-
import
|
|
9200
|
-
import { Command as
|
|
9201
|
-
import * as
|
|
9577
|
+
import process33 from "node:process";
|
|
9578
|
+
import { Command as Command80 } from "commander";
|
|
9579
|
+
import * as p47 from "@clack/prompts";
|
|
9202
9580
|
import pc20 from "picocolors";
|
|
9203
9581
|
var envSet = addTargetOptions(
|
|
9204
|
-
new
|
|
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),
|
|
9205
9583
|
"local"
|
|
9206
9584
|
).action(
|
|
9207
9585
|
(key, value, raw) => runCommand(
|
|
@@ -9211,14 +9589,14 @@ var envSet = addTargetOptions(
|
|
|
9211
9589
|
local: async (ctx) => {
|
|
9212
9590
|
const resolved = await resolveValue(key, value);
|
|
9213
9591
|
setLocalEnv(ctx.envFile, key, resolved);
|
|
9214
|
-
|
|
9592
|
+
p47.log.success(`${key} updated ${pc20.dim("(local)")}`);
|
|
9215
9593
|
await applyLocalEnvChange(ctx, [key]);
|
|
9216
9594
|
},
|
|
9217
9595
|
remote: async (ctx) => {
|
|
9218
9596
|
const resolved = await resolveValue(key, value);
|
|
9219
9597
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
9220
9598
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...env2, [key]: resolved });
|
|
9221
|
-
|
|
9599
|
+
p47.log.success(`${key} updated ${pc20.dim(`(${ctx.targetName})`)}`);
|
|
9222
9600
|
await applyEnvRestart(ctx, [key]);
|
|
9223
9601
|
}
|
|
9224
9602
|
},
|
|
@@ -9232,23 +9610,23 @@ async function resolveValue(key, value) {
|
|
|
9232
9610
|
return value ?? await promptValue(key);
|
|
9233
9611
|
}
|
|
9234
9612
|
async function promptValue(key) {
|
|
9235
|
-
const value = await
|
|
9613
|
+
const value = await p47.password({
|
|
9236
9614
|
message: `Value for ${pc20.cyan(key)}`,
|
|
9237
9615
|
validate: (input) => !input?.length ? "Required" : void 0
|
|
9238
9616
|
});
|
|
9239
|
-
if (
|
|
9240
|
-
|
|
9241
|
-
|
|
9617
|
+
if (p47.isCancel(value)) {
|
|
9618
|
+
p47.cancel("Operation cancelled.");
|
|
9619
|
+
process33.exit(0);
|
|
9242
9620
|
}
|
|
9243
9621
|
return value;
|
|
9244
9622
|
}
|
|
9245
9623
|
|
|
9246
9624
|
// src/commands/env/unset.ts
|
|
9247
|
-
import { Command as
|
|
9248
|
-
import * as
|
|
9625
|
+
import { Command as Command81 } from "commander";
|
|
9626
|
+
import * as p48 from "@clack/prompts";
|
|
9249
9627
|
import pc21 from "picocolors";
|
|
9250
9628
|
var envUnset = addTargetOptions(
|
|
9251
|
-
new
|
|
9629
|
+
new Command81("unset").description("remove an environment variable").argument("<key>", "variable name").configureHelp(helpConfig),
|
|
9252
9630
|
"local"
|
|
9253
9631
|
).action(
|
|
9254
9632
|
(key, raw) => runCommand(
|
|
@@ -9257,22 +9635,22 @@ var envUnset = addTargetOptions(
|
|
|
9257
9635
|
{
|
|
9258
9636
|
local: async (ctx) => {
|
|
9259
9637
|
if (!(key in readLocalEnv(ctx.envFile))) {
|
|
9260
|
-
|
|
9638
|
+
p48.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
9261
9639
|
return;
|
|
9262
9640
|
}
|
|
9263
9641
|
unsetLocalEnv(ctx.envFile, key);
|
|
9264
|
-
|
|
9642
|
+
p48.log.success(`${key} removed ${pc21.dim("(local)")}`);
|
|
9265
9643
|
await applyLocalEnvChange(ctx, [key]);
|
|
9266
9644
|
},
|
|
9267
9645
|
remote: async (ctx) => {
|
|
9268
9646
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
9269
9647
|
if (!(key in env2)) {
|
|
9270
|
-
|
|
9648
|
+
p48.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
9271
9649
|
return;
|
|
9272
9650
|
}
|
|
9273
9651
|
delete env2[key];
|
|
9274
9652
|
await writeRemoteEnv(ctx.session, ctx.instance, env2);
|
|
9275
|
-
|
|
9653
|
+
p48.log.success(`${key} removed ${pc21.dim(`(${ctx.targetName})`)}`);
|
|
9276
9654
|
await applyEnvRestart(ctx, [key]);
|
|
9277
9655
|
}
|
|
9278
9656
|
},
|
|
@@ -9285,12 +9663,12 @@ var envUnset = addTargetOptions(
|
|
|
9285
9663
|
// src/commands/env/import.ts
|
|
9286
9664
|
import fs38 from "node:fs";
|
|
9287
9665
|
import path40 from "node:path";
|
|
9288
|
-
import
|
|
9289
|
-
import { Command as
|
|
9290
|
-
import * as
|
|
9666
|
+
import process34 from "node:process";
|
|
9667
|
+
import { Command as Command82 } from "commander";
|
|
9668
|
+
import * as p49 from "@clack/prompts";
|
|
9291
9669
|
import pc22 from "picocolors";
|
|
9292
9670
|
var envImport = addTargetOptions(
|
|
9293
|
-
new
|
|
9671
|
+
new Command82("import").description("merge a dotenv file into the environment").argument("<file>", "dotenv file to read").configureHelp(helpConfig),
|
|
9294
9672
|
"local"
|
|
9295
9673
|
).action(
|
|
9296
9674
|
(file, raw) => runCommand(
|
|
@@ -9305,22 +9683,22 @@ var envImport = addTargetOptions(
|
|
|
9305
9683
|
const incoming = read(source, file);
|
|
9306
9684
|
const keys = Object.keys(incoming);
|
|
9307
9685
|
if (keys.length === 0) return;
|
|
9308
|
-
|
|
9686
|
+
p49.log.step(`Importing ${keys.length} variable(s) from ${pc22.cyan(file)}`);
|
|
9309
9687
|
editLocalEnv(
|
|
9310
9688
|
ctx.envFile,
|
|
9311
9689
|
(content) => keys.reduce((acc, key) => upsertEnvVar(acc, key, incoming[key]), content)
|
|
9312
9690
|
);
|
|
9313
|
-
|
|
9691
|
+
p49.log.success(`${keys.length} variable(s) updated ${pc22.dim("(local)")}`);
|
|
9314
9692
|
await applyLocalEnvChange(ctx, keys);
|
|
9315
9693
|
},
|
|
9316
9694
|
remote: async (ctx) => {
|
|
9317
9695
|
const incoming = read(resolve(file), file);
|
|
9318
9696
|
const keys = Object.keys(incoming);
|
|
9319
9697
|
if (keys.length === 0) return;
|
|
9320
|
-
|
|
9698
|
+
p49.log.step(`Importing ${keys.length} variable(s) from ${pc22.cyan(file)}`);
|
|
9321
9699
|
const existing = await readRemoteEnv(ctx.session, ctx.instance);
|
|
9322
9700
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...existing, ...incoming });
|
|
9323
|
-
|
|
9701
|
+
p49.log.success(`${keys.length} variable(s) updated ${pc22.dim(`(${ctx.targetName})`)}`);
|
|
9324
9702
|
await applyEnvRestart(ctx, keys);
|
|
9325
9703
|
}
|
|
9326
9704
|
},
|
|
@@ -9330,24 +9708,24 @@ var envImport = addTargetOptions(
|
|
|
9330
9708
|
)
|
|
9331
9709
|
);
|
|
9332
9710
|
function resolve(file) {
|
|
9333
|
-
return path40.resolve(
|
|
9711
|
+
return path40.resolve(process34.cwd(), file);
|
|
9334
9712
|
}
|
|
9335
9713
|
function read(resolved, shown) {
|
|
9336
9714
|
if (!fs38.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
9337
9715
|
const incoming = readLocalEnvFile(resolved);
|
|
9338
|
-
if (Object.keys(incoming).length === 0)
|
|
9716
|
+
if (Object.keys(incoming).length === 0) p49.log.info(`${shown} has no variables to import.`);
|
|
9339
9717
|
return incoming;
|
|
9340
9718
|
}
|
|
9341
9719
|
|
|
9342
9720
|
// src/commands/env.ts
|
|
9343
|
-
var env = new
|
|
9721
|
+
var env = new Command83("env").description("manage environment variables, locally or on a target").configureHelp(helpConfig).addCommand(envList).addCommand(envSet).addCommand(envUnset).addCommand(envImport);
|
|
9344
9722
|
|
|
9345
9723
|
// src/commands/status.ts
|
|
9346
|
-
import { Command as
|
|
9347
|
-
import * as
|
|
9724
|
+
import { Command as Command84 } from "commander";
|
|
9725
|
+
import * as p50 from "@clack/prompts";
|
|
9348
9726
|
import pc23 from "picocolors";
|
|
9349
9727
|
var status = addTargetOptions(
|
|
9350
|
-
new
|
|
9728
|
+
new Command84("status").description("show what is deployed").configureHelp(helpConfig),
|
|
9351
9729
|
"production"
|
|
9352
9730
|
).option("--all", "show every app on the server, not just this project").option("--json", "print raw JSON").action(
|
|
9353
9731
|
(raw) => runCommand(async () => {
|
|
@@ -9378,11 +9756,11 @@ function report2(states, json) {
|
|
|
9378
9756
|
return;
|
|
9379
9757
|
}
|
|
9380
9758
|
if (states.length === 0) {
|
|
9381
|
-
|
|
9759
|
+
p50.log.info("Nothing is deployed here yet.");
|
|
9382
9760
|
return;
|
|
9383
9761
|
}
|
|
9384
9762
|
for (const state of states) {
|
|
9385
|
-
|
|
9763
|
+
p50.log.info(describe2(state));
|
|
9386
9764
|
}
|
|
9387
9765
|
}
|
|
9388
9766
|
function describe2(state) {
|
|
@@ -9406,12 +9784,12 @@ function describe2(state) {
|
|
|
9406
9784
|
}
|
|
9407
9785
|
|
|
9408
9786
|
// src/commands/rollback.ts
|
|
9409
|
-
import { Command as
|
|
9410
|
-
import * as
|
|
9787
|
+
import { Command as Command85 } from "commander";
|
|
9788
|
+
import * as p51 from "@clack/prompts";
|
|
9411
9789
|
import pc24 from "picocolors";
|
|
9412
9790
|
var rollback = addLockWaitOption(
|
|
9413
9791
|
addTargetOptions(
|
|
9414
|
-
new
|
|
9792
|
+
new Command85("rollback").description("put the previous release back").configureHelp(helpConfig),
|
|
9415
9793
|
"production"
|
|
9416
9794
|
)
|
|
9417
9795
|
).option("--to <release>", "roll back to a specific release instead of the previous one").action(
|
|
@@ -9421,7 +9799,7 @@ var rollback = addLockWaitOption(
|
|
|
9421
9799
|
raw,
|
|
9422
9800
|
{
|
|
9423
9801
|
remote: async (ctx) => {
|
|
9424
|
-
|
|
9802
|
+
p51.log.step(
|
|
9425
9803
|
`Rolling back ${pc24.cyan(ctx.appName)} ${pc24.dim(`(${ctx.targetName})`)} on ${ctx.server}`
|
|
9426
9804
|
);
|
|
9427
9805
|
const result = await runServerScript(
|
|
@@ -9436,7 +9814,7 @@ var rollback = addLockWaitOption(
|
|
|
9436
9814
|
stream: true
|
|
9437
9815
|
}
|
|
9438
9816
|
);
|
|
9439
|
-
|
|
9817
|
+
p51.log.success(
|
|
9440
9818
|
`Rolled back to ${pc24.cyan(result?.release ?? "the previous release")}` + (result?.from ? ` ${pc24.dim(`(was ${result.from})`)}` : "")
|
|
9441
9819
|
);
|
|
9442
9820
|
}
|
|
@@ -9450,9 +9828,9 @@ var rollback = addLockWaitOption(
|
|
|
9450
9828
|
);
|
|
9451
9829
|
|
|
9452
9830
|
// src/commands/logs.ts
|
|
9453
|
-
import { Command as
|
|
9831
|
+
import { Command as Command86 } from "commander";
|
|
9454
9832
|
var logs = addTargetOptions(
|
|
9455
|
-
new
|
|
9833
|
+
new Command86("logs").description("tail the logs of a deployed app").configureHelp(helpConfig),
|
|
9456
9834
|
"production"
|
|
9457
9835
|
).option("-f, --follow", "keep streaming new output").option("-n, --lines <count>", "how many lines of history to show", "100").option("--pocketbase", "show the PocketBase service instead of the app").action(
|
|
9458
9836
|
(raw) => runCommand(async () => {
|
|
@@ -9486,16 +9864,16 @@ var logs = addTargetOptions(
|
|
|
9486
9864
|
);
|
|
9487
9865
|
|
|
9488
9866
|
// src/commands/admin.ts
|
|
9489
|
-
import { Command as
|
|
9867
|
+
import { Command as Command88 } from "commander";
|
|
9490
9868
|
|
|
9491
9869
|
// src/commands/admin/create.ts
|
|
9492
|
-
import
|
|
9493
|
-
import { Command as
|
|
9494
|
-
import * as
|
|
9870
|
+
import process35 from "node:process";
|
|
9871
|
+
import { Command as Command87 } from "commander";
|
|
9872
|
+
import * as p52 from "@clack/prompts";
|
|
9495
9873
|
import pc25 from "picocolors";
|
|
9496
9874
|
var MIN_PASSWORD = 10;
|
|
9497
9875
|
var adminCreate = addTargetOptions(
|
|
9498
|
-
new
|
|
9876
|
+
new Command87("create").description("create a login for the admin panel").argument("[email]", "email to sign in with \u2014 prompted for when omitted").configureHelp(helpConfig),
|
|
9499
9877
|
"local"
|
|
9500
9878
|
).action(
|
|
9501
9879
|
(email3, raw) => runCommand(
|
|
@@ -9523,7 +9901,7 @@ var adminCreate = addTargetOptions(
|
|
|
9523
9901
|
const metadata = getPocketbaseMetadata(ctx.workspaceRootDir);
|
|
9524
9902
|
if (metadata) signIn = `http://${metadata.viteHost}:${metadata.vitePort}`;
|
|
9525
9903
|
}
|
|
9526
|
-
|
|
9904
|
+
p52.log.info(
|
|
9527
9905
|
signIn ? `Sign in at ${pc25.cyan(`${signIn}/admin`)}` : `Sign in at ${pc25.cyan("/admin")} once ${pc25.cyan("vela dev")} is running.`
|
|
9528
9906
|
);
|
|
9529
9907
|
},
|
|
@@ -9537,7 +9915,7 @@ var adminCreate = addTargetOptions(
|
|
|
9537
9915
|
(pb) => upsertSuperuser(pb, address, password11)
|
|
9538
9916
|
);
|
|
9539
9917
|
const base2 = state?.domain ? `https://${state.domain.split(",")[0].trim()}` : "";
|
|
9540
|
-
|
|
9918
|
+
p52.log.info(
|
|
9541
9919
|
base2 ? `Sign in at ${pc25.cyan(`${base2}/admin`)}` : `Sign in at ${pc25.cyan("/admin")} once a domain is configured for this target.`
|
|
9542
9920
|
);
|
|
9543
9921
|
}
|
|
@@ -9550,20 +9928,20 @@ var adminCreate = addTargetOptions(
|
|
|
9550
9928
|
async function upsertSuperuser(pb, email3, password11) {
|
|
9551
9929
|
const existing = await findSuperuser(pb, email3);
|
|
9552
9930
|
if (existing) {
|
|
9553
|
-
const confirmed = await
|
|
9931
|
+
const confirmed = await p52.confirm({
|
|
9554
9932
|
message: `${email3} already has an account, update its password?`,
|
|
9555
9933
|
initialValue: false
|
|
9556
9934
|
});
|
|
9557
|
-
if (
|
|
9558
|
-
|
|
9559
|
-
|
|
9935
|
+
if (p52.isCancel(confirmed) || !confirmed) {
|
|
9936
|
+
p52.cancel("Operation cancelled.");
|
|
9937
|
+
process35.exit(0);
|
|
9560
9938
|
}
|
|
9561
9939
|
await pb.collection("_superusers").update(existing, { password: password11, passwordConfirm: password11 });
|
|
9562
|
-
|
|
9940
|
+
p52.log.success(`Password updated for ${pc25.cyan(email3)}, you can sign in now`);
|
|
9563
9941
|
return;
|
|
9564
9942
|
}
|
|
9565
9943
|
await pb.collection("_superusers").create({ email: email3, password: password11, passwordConfirm: password11 });
|
|
9566
|
-
|
|
9944
|
+
p52.log.success(`${pc25.cyan(email3)} can now sign in`);
|
|
9567
9945
|
}
|
|
9568
9946
|
async function findSuperuser(pb, email3) {
|
|
9569
9947
|
try {
|
|
@@ -9574,47 +9952,47 @@ async function findSuperuser(pb, email3) {
|
|
|
9574
9952
|
}
|
|
9575
9953
|
}
|
|
9576
9954
|
async function promptEmail() {
|
|
9577
|
-
const value = await
|
|
9955
|
+
const value = await p52.text({
|
|
9578
9956
|
message: "Email to sign in with",
|
|
9579
9957
|
validate: (input) => input?.includes("@") ? void 0 : "An email address is required"
|
|
9580
9958
|
});
|
|
9581
|
-
if (
|
|
9582
|
-
|
|
9583
|
-
|
|
9959
|
+
if (p52.isCancel(value)) {
|
|
9960
|
+
p52.cancel("Operation cancelled.");
|
|
9961
|
+
process35.exit(0);
|
|
9584
9962
|
}
|
|
9585
9963
|
return value.trim();
|
|
9586
9964
|
}
|
|
9587
9965
|
async function promptPassword2() {
|
|
9588
|
-
const value = await
|
|
9966
|
+
const value = await p52.password({
|
|
9589
9967
|
message: "Password",
|
|
9590
9968
|
validate: (input) => (input?.length ?? 0) >= MIN_PASSWORD ? void 0 : `At least ${MIN_PASSWORD} characters is required`
|
|
9591
9969
|
});
|
|
9592
|
-
if (
|
|
9593
|
-
|
|
9594
|
-
|
|
9970
|
+
if (p52.isCancel(value)) {
|
|
9971
|
+
p52.cancel("Operation cancelled.");
|
|
9972
|
+
process35.exit(0);
|
|
9595
9973
|
}
|
|
9596
|
-
const again = await
|
|
9974
|
+
const again = await p52.password({
|
|
9597
9975
|
message: "Password again",
|
|
9598
9976
|
validate: (input) => input === value ? void 0 : "The two do not match"
|
|
9599
9977
|
});
|
|
9600
|
-
if (
|
|
9601
|
-
|
|
9602
|
-
|
|
9978
|
+
if (p52.isCancel(again)) {
|
|
9979
|
+
p52.cancel("Operation cancelled.");
|
|
9980
|
+
process35.exit(0);
|
|
9603
9981
|
}
|
|
9604
9982
|
return value;
|
|
9605
9983
|
}
|
|
9606
9984
|
|
|
9607
9985
|
// src/commands/admin.ts
|
|
9608
|
-
var admin = new
|
|
9986
|
+
var admin = new Command88("admin").description("manage admin panel logins").configureHelp(helpConfig).addCommand(adminCreate);
|
|
9609
9987
|
|
|
9610
9988
|
// src/commands/backup.ts
|
|
9611
|
-
import { Command as
|
|
9989
|
+
import { Command as Command94 } from "commander";
|
|
9612
9990
|
|
|
9613
9991
|
// src/commands/backup/create.ts
|
|
9614
9992
|
import fs39 from "node:fs";
|
|
9615
9993
|
import path41 from "node:path";
|
|
9616
|
-
import { Command as
|
|
9617
|
-
import * as
|
|
9994
|
+
import { Command as Command89 } from "commander";
|
|
9995
|
+
import * as p53 from "@clack/prompts";
|
|
9618
9996
|
import pc26 from "picocolors";
|
|
9619
9997
|
|
|
9620
9998
|
// src/lib/backups.ts
|
|
@@ -9702,7 +10080,7 @@ async function writeSchedule(pb, cron, maxKeep) {
|
|
|
9702
10080
|
// src/commands/backup/create.ts
|
|
9703
10081
|
var DEFAULT_BACKUP_DIR = "backups";
|
|
9704
10082
|
var backupCreate = addTargetOptions(
|
|
9705
|
-
new
|
|
10083
|
+
new Command89("create").description("take a backup of the database and uploads").argument("[name]", "name for the archive \u2014 generated when omitted").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).option("--no-download", "leave the archive on the server").configureHelp(helpConfig),
|
|
9706
10084
|
"production"
|
|
9707
10085
|
).action(
|
|
9708
10086
|
(name, raw) => runCommand(() => {
|
|
@@ -9718,7 +10096,7 @@ Backup names are lowercase letters, digits, ${pc26.cyan("-")} and ${pc26.cyan("_
|
|
|
9718
10096
|
}
|
|
9719
10097
|
const storage = await readStorageSettings(ctx.pb);
|
|
9720
10098
|
if (storage.s3Enabled) {
|
|
9721
|
-
|
|
10099
|
+
p53.log.warn(
|
|
9722
10100
|
`Uploads are stored in S3, so this archive holds the database only.
|
|
9723
10101
|
|
|
9724
10102
|
PocketBase leaves ${pc26.cyan("storage/")} out of a backup whenever S3 is on.
|
|
@@ -9726,7 +10104,7 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
9726
10104
|
);
|
|
9727
10105
|
}
|
|
9728
10106
|
if (ctx.session) await checkpointAppDatabases(ctx.session, ctx.instance);
|
|
9729
|
-
const spinner7 =
|
|
10107
|
+
const spinner7 = p53.spinner();
|
|
9730
10108
|
spinner7.start(`Backing up ${ctx.targetName}`);
|
|
9731
10109
|
try {
|
|
9732
10110
|
await createBackup(ctx.pb, key);
|
|
@@ -9773,7 +10151,7 @@ async function download(ctx, key, outputDir) {
|
|
|
9773
10151
|
fs39.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9774
10152
|
return path41.relative(ctx.workspaceRootDir, destination);
|
|
9775
10153
|
}
|
|
9776
|
-
const spinner7 =
|
|
10154
|
+
const spinner7 = p53.spinner();
|
|
9777
10155
|
spinner7.start(`Downloading ${key}`);
|
|
9778
10156
|
try {
|
|
9779
10157
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
@@ -9786,18 +10164,18 @@ async function download(ctx, key, outputDir) {
|
|
|
9786
10164
|
}
|
|
9787
10165
|
|
|
9788
10166
|
// src/commands/backup/list.ts
|
|
9789
|
-
import { Command as
|
|
9790
|
-
import * as
|
|
10167
|
+
import { Command as Command90 } from "commander";
|
|
10168
|
+
import * as p54 from "@clack/prompts";
|
|
9791
10169
|
import pc27 from "picocolors";
|
|
9792
10170
|
var backupList = addTargetOptions(
|
|
9793
|
-
new
|
|
10171
|
+
new Command90("list").description("list the backups on a target").configureHelp(helpConfig),
|
|
9794
10172
|
"production"
|
|
9795
10173
|
).action(
|
|
9796
10174
|
(raw) => runCommand(
|
|
9797
10175
|
() => withBackupTarget(raw, "backup list", async (ctx) => {
|
|
9798
10176
|
const backups = await listBackups(ctx.pb);
|
|
9799
10177
|
if (backups.length === 0) {
|
|
9800
|
-
|
|
10178
|
+
p54.log.info(
|
|
9801
10179
|
`${pc27.cyan(ctx.targetName)} has no backups yet.
|
|
9802
10180
|
|
|
9803
10181
|
Take one with ${pc27.cyan("vela backup create")}.`
|
|
@@ -9805,7 +10183,7 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9805
10183
|
return;
|
|
9806
10184
|
}
|
|
9807
10185
|
const width = Math.max(...backups.map((b) => b.key.length));
|
|
9808
|
-
|
|
10186
|
+
p54.log.message(
|
|
9809
10187
|
backups.map(
|
|
9810
10188
|
(b) => `${b.key.padEnd(width)} ${pc27.dim(formatBytes(b.size).padStart(8))} ${pc27.dim(b.modified)}`
|
|
9811
10189
|
).join("\n")
|
|
@@ -9818,11 +10196,11 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9818
10196
|
// src/commands/backup/download.ts
|
|
9819
10197
|
import fs40 from "node:fs";
|
|
9820
10198
|
import path42 from "node:path";
|
|
9821
|
-
import { Command as
|
|
9822
|
-
import * as
|
|
10199
|
+
import { Command as Command91 } from "commander";
|
|
10200
|
+
import * as p55 from "@clack/prompts";
|
|
9823
10201
|
import pc28 from "picocolors";
|
|
9824
10202
|
var backupDownload = addTargetOptions(
|
|
9825
|
-
new
|
|
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),
|
|
9826
10204
|
"production"
|
|
9827
10205
|
).action(
|
|
9828
10206
|
(key, raw) => runCommand(() => {
|
|
@@ -9850,7 +10228,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9850
10228
|
if (!ctx.session) {
|
|
9851
10229
|
fs40.copyFileSync(path42.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9852
10230
|
} else {
|
|
9853
|
-
const spinner7 =
|
|
10231
|
+
const spinner7 = p55.spinner();
|
|
9854
10232
|
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
9855
10233
|
try {
|
|
9856
10234
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
@@ -9869,12 +10247,12 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9869
10247
|
);
|
|
9870
10248
|
|
|
9871
10249
|
// src/commands/backup/delete.ts
|
|
9872
|
-
import
|
|
9873
|
-
import { Command as
|
|
9874
|
-
import * as
|
|
10250
|
+
import process36 from "node:process";
|
|
10251
|
+
import { Command as Command92 } from "commander";
|
|
10252
|
+
import * as p56 from "@clack/prompts";
|
|
9875
10253
|
import pc29 from "picocolors";
|
|
9876
10254
|
var backupDelete = addTargetOptions(
|
|
9877
|
-
new
|
|
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),
|
|
9878
10256
|
"production"
|
|
9879
10257
|
).action(
|
|
9880
10258
|
(key, raw) => runCommand(() => {
|
|
@@ -9889,13 +10267,13 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
9889
10267
|
);
|
|
9890
10268
|
}
|
|
9891
10269
|
if (!options.yes) {
|
|
9892
|
-
const confirmed = await
|
|
10270
|
+
const confirmed = await p56.confirm({
|
|
9893
10271
|
message: `Delete ${key} (${formatBytes(found.size)}) from ${ctx.targetName}?`,
|
|
9894
10272
|
initialValue: false
|
|
9895
10273
|
});
|
|
9896
|
-
if (
|
|
9897
|
-
|
|
9898
|
-
|
|
10274
|
+
if (p56.isCancel(confirmed) || !confirmed) {
|
|
10275
|
+
p56.cancel("Operation cancelled.");
|
|
10276
|
+
process36.exit(0);
|
|
9899
10277
|
}
|
|
9900
10278
|
}
|
|
9901
10279
|
await ctx.pb.backups.delete(key);
|
|
@@ -9905,12 +10283,12 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
9905
10283
|
);
|
|
9906
10284
|
|
|
9907
10285
|
// src/commands/backup/schedule.ts
|
|
9908
|
-
import { Command as
|
|
9909
|
-
import * as
|
|
10286
|
+
import { Command as Command93 } from "commander";
|
|
10287
|
+
import * as p57 from "@clack/prompts";
|
|
9910
10288
|
import pc30 from "picocolors";
|
|
9911
10289
|
var DEFAULT_KEEP = 7;
|
|
9912
10290
|
var backupSchedule = addTargetOptions(
|
|
9913
|
-
new
|
|
10291
|
+
new Command93("schedule").description("back up automatically on a schedule").argument("[cron]", "when to run, as a cron expression \u2014 shows the current one when omitted").option("--keep <n>", "how many scheduled archives to keep", String(DEFAULT_KEEP)).option("--off", "stop backing up automatically").configureHelp(helpConfig),
|
|
9914
10292
|
"production"
|
|
9915
10293
|
).action(
|
|
9916
10294
|
(cron, raw) => runCommand(() => {
|
|
@@ -9923,7 +10301,7 @@ var backupSchedule = addTargetOptions(
|
|
|
9923
10301
|
}
|
|
9924
10302
|
if (!cron) {
|
|
9925
10303
|
const current = await readSchedule(ctx.pb);
|
|
9926
|
-
|
|
10304
|
+
p57.log.info(
|
|
9927
10305
|
current.cron ? `${ctx.targetName} backs up on ${pc30.cyan(current.cron)}, keeping ${current.maxKeep}.` : `${ctx.targetName} has no backup schedule.
|
|
9928
10306
|
|
|
9929
10307
|
Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
@@ -9954,18 +10332,18 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
|
9954
10332
|
);
|
|
9955
10333
|
|
|
9956
10334
|
// src/commands/backup.ts
|
|
9957
|
-
var backup = new
|
|
10335
|
+
var backup = new Command94("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
|
|
9958
10336
|
|
|
9959
10337
|
// src/commands/restore.ts
|
|
9960
10338
|
import fs41 from "node:fs";
|
|
9961
10339
|
import path43 from "node:path";
|
|
9962
|
-
import
|
|
9963
|
-
import { Command as
|
|
9964
|
-
import * as
|
|
10340
|
+
import process37 from "node:process";
|
|
10341
|
+
import { Command as Command95 } from "commander";
|
|
10342
|
+
import * as p58 from "@clack/prompts";
|
|
9965
10343
|
import pc31 from "picocolors";
|
|
9966
10344
|
var restore = addLockWaitOption(
|
|
9967
10345
|
addTargetOptions(
|
|
9968
|
-
new
|
|
10346
|
+
new Command95("restore").description("replace a deployment\u2019s database and uploads from a backup").argument("[source]", "a backup key on the target, or a path to a local archive").configureHelp(helpConfig),
|
|
9969
10347
|
"production"
|
|
9970
10348
|
)
|
|
9971
10349
|
).option("-y, --yes", "skip the confirmation prompt").option("--no-migrate", "do not run migrations against the restored database").option("--keep-previous <n>", "how many replaced databases to keep", "1").action(
|
|
@@ -10002,18 +10380,18 @@ var restore = addLockWaitOption(
|
|
|
10002
10380
|
],
|
|
10003
10381
|
stream: true
|
|
10004
10382
|
});
|
|
10005
|
-
|
|
10383
|
+
p58.log.success(
|
|
10006
10384
|
`Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
|
|
10007
10385
|
local ? path43.basename(local) : key
|
|
10008
10386
|
)}.`
|
|
10009
10387
|
);
|
|
10010
10388
|
if (result?.storageCarriedOver) {
|
|
10011
|
-
|
|
10389
|
+
p58.log.info(
|
|
10012
10390
|
"The archive held no uploads, so the files already on the server were kept."
|
|
10013
10391
|
);
|
|
10014
10392
|
}
|
|
10015
10393
|
if (result?.previousDataDir) {
|
|
10016
|
-
|
|
10394
|
+
p58.log.info(
|
|
10017
10395
|
`The database this replaced is at ${pc31.cyan(result.previousDataDir)}.
|
|
10018
10396
|
|
|
10019
10397
|
It is the only way back. Remove it once you are satisfied with the restore.`
|
|
@@ -10054,7 +10432,7 @@ Run ${pc31.cyan("vela backup list")} to see what it does have.`
|
|
|
10054
10432
|
Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive on this machine.`
|
|
10055
10433
|
);
|
|
10056
10434
|
}
|
|
10057
|
-
const chosen = await
|
|
10435
|
+
const chosen = await p58.select({
|
|
10058
10436
|
message: `Which backup should ${ctx.targetName} be restored from?`,
|
|
10059
10437
|
options: backups.map((b) => ({
|
|
10060
10438
|
value: b.key,
|
|
@@ -10062,16 +10440,16 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
|
|
|
10062
10440
|
hint: `${formatBytes(b.size)}, ${b.modified}`
|
|
10063
10441
|
}))
|
|
10064
10442
|
});
|
|
10065
|
-
if (
|
|
10066
|
-
|
|
10067
|
-
|
|
10443
|
+
if (p58.isCancel(chosen)) {
|
|
10444
|
+
p58.cancel("Operation cancelled.");
|
|
10445
|
+
process37.exit(0);
|
|
10068
10446
|
}
|
|
10069
10447
|
return chosen;
|
|
10070
10448
|
}
|
|
10071
10449
|
async function stage(ctx, file) {
|
|
10072
10450
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
10073
10451
|
const remote = `${dir}/${path43.basename(file)}`;
|
|
10074
|
-
const spinner7 =
|
|
10452
|
+
const spinner7 = p58.spinner();
|
|
10075
10453
|
spinner7.start(`Uploading ${path43.basename(file)}`);
|
|
10076
10454
|
try {
|
|
10077
10455
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
@@ -10086,29 +10464,29 @@ async function stage(ctx, file) {
|
|
|
10086
10464
|
async function confirm13(appName, targetName, envTag, from) {
|
|
10087
10465
|
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path43.basename(from))}`;
|
|
10088
10466
|
if (isProd(envTag)) {
|
|
10089
|
-
const answer = await
|
|
10467
|
+
const answer = await p58.text({
|
|
10090
10468
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
10091
10469
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
10092
10470
|
});
|
|
10093
|
-
if (
|
|
10094
|
-
|
|
10095
|
-
|
|
10471
|
+
if (p58.isCancel(answer)) {
|
|
10472
|
+
p58.cancel("Operation cancelled.");
|
|
10473
|
+
process37.exit(0);
|
|
10096
10474
|
}
|
|
10097
10475
|
return;
|
|
10098
10476
|
}
|
|
10099
|
-
const ok = await
|
|
10477
|
+
const ok = await p58.confirm({
|
|
10100
10478
|
message: `Replace the database and uploads of ${what}?`,
|
|
10101
10479
|
initialValue: false
|
|
10102
10480
|
});
|
|
10103
|
-
if (
|
|
10104
|
-
|
|
10105
|
-
|
|
10481
|
+
if (p58.isCancel(ok) || !ok) {
|
|
10482
|
+
p58.cancel("Operation cancelled.");
|
|
10483
|
+
process37.exit(0);
|
|
10106
10484
|
}
|
|
10107
10485
|
}
|
|
10108
10486
|
|
|
10109
10487
|
// src/commands/targets.ts
|
|
10110
|
-
import { Command as
|
|
10111
|
-
import * as
|
|
10488
|
+
import { Command as Command96 } from "commander";
|
|
10489
|
+
import * as p59 from "@clack/prompts";
|
|
10112
10490
|
import pc32 from "picocolors";
|
|
10113
10491
|
import * as v9 from "valibot";
|
|
10114
10492
|
var OptionsSchema4 = v9.object({
|
|
@@ -10117,7 +10495,7 @@ var OptionsSchema4 = v9.object({
|
|
|
10117
10495
|
offline: v9.optional(v9.boolean())
|
|
10118
10496
|
});
|
|
10119
10497
|
var targets = addSshOptions(
|
|
10120
|
-
new
|
|
10498
|
+
new Command96("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
|
|
10121
10499
|
).option("--json", "print raw JSON").option("--offline", "skip connecting to servers").action(
|
|
10122
10500
|
(raw) => runCommand(async () => {
|
|
10123
10501
|
const options = parseOptions(OptionsSchema4, raw);
|
|
@@ -10183,11 +10561,11 @@ function report3(rows, offline) {
|
|
|
10183
10561
|
const lines = rows.map(
|
|
10184
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}`
|
|
10185
10563
|
);
|
|
10186
|
-
|
|
10564
|
+
p59.log.info(`${pc32.dim(header)}
|
|
10187
10565
|
${lines.join("\n")}`);
|
|
10188
10566
|
const unreachable = rows.filter((row) => row.kind === "remote" && !row.reachable);
|
|
10189
10567
|
if (!offline && unreachable.length > 0) {
|
|
10190
|
-
|
|
10568
|
+
p59.log.warn(
|
|
10191
10569
|
`Could not reach ${unreachable.map((row) => row.server).join(", ")}.
|
|
10192
10570
|
Release and domain are shown from what this project recorded.`
|
|
10193
10571
|
);
|
|
@@ -10196,16 +10574,16 @@ Release and domain are shown from what this project recorded.`
|
|
|
10196
10574
|
|
|
10197
10575
|
// src/commands/test.ts
|
|
10198
10576
|
import path44 from "node:path";
|
|
10199
|
-
import
|
|
10200
|
-
import { Command as
|
|
10577
|
+
import process38 from "node:process";
|
|
10578
|
+
import { Command as Command97 } from "commander";
|
|
10201
10579
|
import PocketBase6 from "pocketbase";
|
|
10202
10580
|
import pc33 from "picocolors";
|
|
10203
10581
|
import { x as x5 } from "tinyexec";
|
|
10204
10582
|
import { detect as detect8 } from "package-manager-detector";
|
|
10205
10583
|
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
10206
10584
|
import fs42 from "node:fs";
|
|
10207
|
-
var testServer = new
|
|
10208
|
-
const cwd =
|
|
10585
|
+
var testServer = new Command97("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
10586
|
+
const cwd = process38.cwd();
|
|
10209
10587
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
10210
10588
|
const password11 = "password";
|
|
10211
10589
|
const testDataDir = path44.join(cwd, "test-data");
|
|
@@ -10220,11 +10598,11 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
10220
10598
|
email: email3,
|
|
10221
10599
|
password: password11
|
|
10222
10600
|
});
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
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";
|
|
10228
10606
|
console.log(`${pc33.greenBright("\u2713")} Created test database`);
|
|
10229
10607
|
let vite;
|
|
10230
10608
|
let cleanedUp = false;
|
|
@@ -10243,12 +10621,12 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
10243
10621
|
const fail = async (message) => {
|
|
10244
10622
|
console.error(`${pc33.redBright("\u2717")} ${message}`);
|
|
10245
10623
|
await cleanup();
|
|
10246
|
-
|
|
10624
|
+
process38.exit(1);
|
|
10247
10625
|
};
|
|
10248
|
-
|
|
10249
|
-
|
|
10626
|
+
process38.on("exit", cleanupSync);
|
|
10627
|
+
process38.on("SIGINT", () => {
|
|
10250
10628
|
cleanupSync();
|
|
10251
|
-
|
|
10629
|
+
process38.exit(130);
|
|
10252
10630
|
});
|
|
10253
10631
|
const pb = new PocketBase6(url);
|
|
10254
10632
|
try {
|
|
@@ -10276,7 +10654,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
10276
10654
|
});
|
|
10277
10655
|
const vitePort = await findFreePort();
|
|
10278
10656
|
await vite.listen(vitePort);
|
|
10279
|
-
|
|
10657
|
+
process38.env.VITE_TEST_URL = `http://localhost:${vitePort}`;
|
|
10280
10658
|
console.log(`${pc33.greenBright("\u2713")} Started Vite: http://localhost:${vitePort}`);
|
|
10281
10659
|
console.log(`${pc33.greenBright("\u2713")} Started PocketBase: ${url}`);
|
|
10282
10660
|
const extraArgs = (cmd.parent?.args ?? []).slice(1);
|
|
@@ -10295,12 +10673,12 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
10295
10673
|
const resolvedArgs = resolved.args.slice();
|
|
10296
10674
|
if (pm === "npm") resolvedArgs.unshift("--yes");
|
|
10297
10675
|
const result = await x5(resolved.command, resolvedArgs, {
|
|
10298
|
-
nodeOptions: { cwd, stdio: "inherit", env: { ...
|
|
10676
|
+
nodeOptions: { cwd, stdio: "inherit", env: { ...process38.env, CI: "1" } }
|
|
10299
10677
|
});
|
|
10300
|
-
|
|
10678
|
+
process38.exitCode = result.exitCode ?? 1;
|
|
10301
10679
|
} catch (e) {
|
|
10302
10680
|
console.error(`${pc33.redBright("\u2717")} ${e.message}`);
|
|
10303
|
-
|
|
10681
|
+
process38.exitCode = 1;
|
|
10304
10682
|
} finally {
|
|
10305
10683
|
await cleanup();
|
|
10306
10684
|
}
|
|
@@ -10333,7 +10711,7 @@ function stubPagesPlugin() {
|
|
|
10333
10711
|
// src/commands/routes.ts
|
|
10334
10712
|
import fs43 from "node:fs";
|
|
10335
10713
|
import path45 from "node:path";
|
|
10336
|
-
import { Command as
|
|
10714
|
+
import { Command as Command98 } from "commander";
|
|
10337
10715
|
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
10338
10716
|
"GET",
|
|
10339
10717
|
"POST",
|
|
@@ -10344,7 +10722,7 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
10344
10722
|
"HEAD",
|
|
10345
10723
|
"fallback"
|
|
10346
10724
|
]);
|
|
10347
|
-
var routes = new
|
|
10725
|
+
var routes = new Command98("routes").description("list routes").configureHelp(helpConfig).action(async () => {
|
|
10348
10726
|
const { workspaceRootDir, routesDir } = await getWorkspace();
|
|
10349
10727
|
const routesRoot = path45.join(workspaceRootDir, routesDir);
|
|
10350
10728
|
const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
|
|
@@ -10419,13 +10797,13 @@ function printTable(routes2) {
|
|
|
10419
10797
|
}
|
|
10420
10798
|
|
|
10421
10799
|
// src/commands/i18n.ts
|
|
10422
|
-
import
|
|
10423
|
-
import { Command as
|
|
10800
|
+
import process39 from "node:process";
|
|
10801
|
+
import { Command as Command99 } from "commander";
|
|
10424
10802
|
import { x as x6 } from "tinyexec";
|
|
10425
10803
|
import { detect as detect9 } from "package-manager-detector";
|
|
10426
10804
|
import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
|
|
10427
10805
|
async function runWuchale(extraArgs) {
|
|
10428
|
-
const cwd =
|
|
10806
|
+
const cwd = process39.cwd();
|
|
10429
10807
|
const pm = (await detect9({ cwd }))?.name ?? "npm";
|
|
10430
10808
|
const resolved = resolveCommand8(pm, "execute", ["wuchale", ...extraArgs]);
|
|
10431
10809
|
const args = resolved.args.slice();
|
|
@@ -10435,11 +10813,11 @@ async function runWuchale(extraArgs) {
|
|
|
10435
10813
|
throwOnError: true
|
|
10436
10814
|
});
|
|
10437
10815
|
}
|
|
10438
|
-
var extract2 = new
|
|
10439
|
-
var watch = new
|
|
10440
|
-
var status2 = new
|
|
10441
|
-
var clean = new
|
|
10442
|
-
var i18n3 = new
|
|
10816
|
+
var extract2 = new Command99("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
|
|
10817
|
+
var watch = new Command99("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
|
|
10818
|
+
var status2 = new Command99("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
|
|
10819
|
+
var clean = new Command99("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--clean"]));
|
|
10820
|
+
var i18n3 = new Command99("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
|
|
10443
10821
|
|
|
10444
10822
|
// src/commands/oauth.ts
|
|
10445
10823
|
var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
@@ -10448,21 +10826,21 @@ var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
|
10448
10826
|
var schemas = stubCommand("schemas", "manage database schemas");
|
|
10449
10827
|
|
|
10450
10828
|
// src/commands/cms.ts
|
|
10451
|
-
import { Command as
|
|
10829
|
+
import { Command as Command104 } from "commander";
|
|
10452
10830
|
|
|
10453
10831
|
// src/commands/cms/editor.ts
|
|
10454
|
-
import { Command as
|
|
10832
|
+
import { Command as Command103 } from "commander";
|
|
10455
10833
|
|
|
10456
10834
|
// src/commands/cms/editor/add.ts
|
|
10457
10835
|
import { randomBytes } from "node:crypto";
|
|
10458
|
-
import { Command as
|
|
10459
|
-
import * as
|
|
10836
|
+
import { Command as Command100 } from "commander";
|
|
10837
|
+
import * as p60 from "@clack/prompts";
|
|
10460
10838
|
import pc35 from "picocolors";
|
|
10461
10839
|
|
|
10462
10840
|
// src/lib/cms-backend.ts
|
|
10463
10841
|
import { createRequire as createRequire3 } from "node:module";
|
|
10464
10842
|
import path46 from "node:path";
|
|
10465
|
-
import
|
|
10843
|
+
import process40 from "node:process";
|
|
10466
10844
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
10467
10845
|
import pc34 from "picocolors";
|
|
10468
10846
|
var DEFAULT_PROJECT = "default";
|
|
@@ -10479,7 +10857,7 @@ Run ${pc34.cyan("vela enable cms")} first.`
|
|
|
10479
10857
|
}
|
|
10480
10858
|
return await import(pathToFileURL3(entry).href);
|
|
10481
10859
|
}
|
|
10482
|
-
async function withCmsBackend(fn, cwd =
|
|
10860
|
+
async function withCmsBackend(fn, cwd = process40.cwd()) {
|
|
10483
10861
|
const root = findWorkspaceRoot(cwd);
|
|
10484
10862
|
if (!root) {
|
|
10485
10863
|
throw new Error("Could not find workspace root (no package.json found)");
|
|
@@ -10498,7 +10876,7 @@ async function withCmsBackend(fn, cwd = process37.cwd()) {
|
|
|
10498
10876
|
}
|
|
10499
10877
|
|
|
10500
10878
|
// src/commands/cms/editor/add.ts
|
|
10501
|
-
var editorAdd = new
|
|
10879
|
+
var editorAdd = new Command100("add").description("create an editor who can sign in to the admin bar").argument("<email>", "email the editor signs in with").option("--password <password>", "password to set \u2014 generated and shown once when omitted").option("--project <id>", "project the editor may edit", DEFAULT_PROJECT).configureHelp(helpConfig).action(
|
|
10502
10880
|
(email3, options) => runCommand(async () => {
|
|
10503
10881
|
const generated = options.password === void 0;
|
|
10504
10882
|
const password11 = options.password ?? randomBytes(12).toString("base64url");
|
|
@@ -10509,31 +10887,31 @@ var editorAdd = new Command99("add").description("create an editor who can sign
|
|
|
10509
10887
|
if (generated) {
|
|
10510
10888
|
lines.push("", `Password: ${pc35.bold(password11)}`, "", "It is shown once; copy it now.");
|
|
10511
10889
|
}
|
|
10512
|
-
|
|
10513
|
-
|
|
10890
|
+
p60.log.success(lines.join("\n"));
|
|
10891
|
+
p60.log.info(
|
|
10514
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.`
|
|
10515
10893
|
);
|
|
10516
10894
|
}, "Failed to add the editor.")
|
|
10517
10895
|
);
|
|
10518
10896
|
|
|
10519
10897
|
// src/commands/cms/editor/password.ts
|
|
10520
|
-
import { Command as
|
|
10521
|
-
import * as
|
|
10898
|
+
import { Command as Command101 } from "commander";
|
|
10899
|
+
import * as p61 from "@clack/prompts";
|
|
10522
10900
|
import pc36 from "picocolors";
|
|
10523
|
-
var editorPassword = new
|
|
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(
|
|
10524
10902
|
(email3, password11) => runCommand(async () => {
|
|
10525
10903
|
await withCmsBackend((cms3) => cms3.editors.setPassword(email3, password11));
|
|
10526
|
-
|
|
10904
|
+
p61.log.success(
|
|
10527
10905
|
`Updated the password for ${pc36.cyan(email3)}. Existing sessions were signed out.`
|
|
10528
10906
|
);
|
|
10529
10907
|
}, "Failed to set the password.")
|
|
10530
10908
|
);
|
|
10531
10909
|
|
|
10532
10910
|
// src/commands/cms/editor/list.ts
|
|
10533
|
-
import { Command as
|
|
10534
|
-
import * as
|
|
10911
|
+
import { Command as Command102 } from "commander";
|
|
10912
|
+
import * as p62 from "@clack/prompts";
|
|
10535
10913
|
import pc37 from "picocolors";
|
|
10536
|
-
var editorList = new
|
|
10914
|
+
var editorList = new Command102("list").description("list editors and the projects they may edit").configureHelp(helpConfig).action(
|
|
10537
10915
|
() => runCommand(async () => {
|
|
10538
10916
|
const rows = await withCmsBackend(
|
|
10539
10917
|
async (cms3) => cms3.editors.list().map((editor2) => ({
|
|
@@ -10542,11 +10920,11 @@ var editorList = new Command101("list").description("list editors and the projec
|
|
|
10542
10920
|
}))
|
|
10543
10921
|
);
|
|
10544
10922
|
if (rows.length === 0) {
|
|
10545
|
-
|
|
10923
|
+
p62.log.info(`No editors yet. Add one with ${pc37.cyan("vela cms editor add <email>")}.`);
|
|
10546
10924
|
return;
|
|
10547
10925
|
}
|
|
10548
10926
|
const width = Math.max(...rows.map((row) => row.email.length));
|
|
10549
|
-
|
|
10927
|
+
p62.log.info(
|
|
10550
10928
|
`Editors
|
|
10551
10929
|
|
|
10552
10930
|
` + rows.map(
|
|
@@ -10557,10 +10935,10 @@ var editorList = new Command101("list").description("list editors and the projec
|
|
|
10557
10935
|
);
|
|
10558
10936
|
|
|
10559
10937
|
// src/commands/cms/editor.ts
|
|
10560
|
-
var editor = new
|
|
10938
|
+
var editor = new Command103("editor").description("manage who can sign in to the admin bar").configureHelp(helpConfig).addCommand(editorAdd).addCommand(editorPassword).addCommand(editorList);
|
|
10561
10939
|
|
|
10562
10940
|
// src/commands/cms.ts
|
|
10563
|
-
var cms2 = new
|
|
10941
|
+
var cms2 = new Command104("cms").description("manage the CMS").configureHelp(helpConfig).addCommand(editor);
|
|
10564
10942
|
|
|
10565
10943
|
// src/program.ts
|
|
10566
10944
|
var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -10578,6 +10956,8 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
|
10578
10956
|
"generate form",
|
|
10579
10957
|
// The CMS keeps its own SQLite database and editors; PocketBase is never involved.
|
|
10580
10958
|
"enable cms",
|
|
10959
|
+
// Analytics only touches the root layout and .env; it must work on static sites.
|
|
10960
|
+
"enable analytics",
|
|
10581
10961
|
"cms",
|
|
10582
10962
|
// Server commands talk to a VPS over SSH, never to the local database.
|
|
10583
10963
|
"provision",
|
|
@@ -10598,10 +10978,10 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
|
10598
10978
|
]);
|
|
10599
10979
|
var BACKEND_OPTIONAL_COMMANDS = /* @__PURE__ */ new Set(["dev", "build", "preview", "deploy"]);
|
|
10600
10980
|
var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
|
|
10601
|
-
var program = new
|
|
10981
|
+
var program = new Command105().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
|
|
10602
10982
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
10603
10983
|
if (isStub(actionCommand)) return;
|
|
10604
|
-
const envRoot = findWorkspaceRoot() ??
|
|
10984
|
+
const envRoot = findWorkspaceRoot() ?? process41.cwd();
|
|
10605
10985
|
dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
|
|
10606
10986
|
const path47 = getCommandPath(actionCommand);
|
|
10607
10987
|
if (NO_BACKEND_COMMMANDS.has(path47)) return;
|
|
@@ -10609,20 +10989,20 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
|
10609
10989
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
10610
10990
|
if (!hasBackend()) {
|
|
10611
10991
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
10612
|
-
|
|
10992
|
+
p63.log.error(
|
|
10613
10993
|
`${pc38.cyan(`vela ${path47}`)} needs a backend, and this project does not have one.
|
|
10614
10994
|
|
|
10615
10995
|
Static projects have no database to talk to.
|
|
10616
10996
|
|
|
10617
10997
|
To add a backend to this project, run ${pc38.cyan("vela bless")}.`
|
|
10618
10998
|
);
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10999
|
+
p63.log.message();
|
|
11000
|
+
p63.cancel("Operation failed.");
|
|
11001
|
+
process41.exit(1);
|
|
10622
11002
|
}
|
|
10623
11003
|
if (SELF_CREDENTIALED_COMMANDS.has(path47)) return;
|
|
10624
|
-
if (!
|
|
10625
|
-
|
|
11004
|
+
if (!process41.env.POCKETBASE_SUPERUSER_EMAIL || !process41.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
11005
|
+
p63.log.error(
|
|
10626
11006
|
`PocketBase superuser credentials are required.
|
|
10627
11007
|
|
|
10628
11008
|
Set ${pc38.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc38.cyan("POCKETBASE_SUPERUSER_PASSWORD")} in your .env file.
|
|
@@ -10630,9 +11010,9 @@ Set ${pc38.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc38.cyan("POCKETBASE_SUPER
|
|
|
10630
11010
|
To set up a new project, run ${pc38.cyan("vela create")}.
|
|
10631
11011
|
To set up an existing project, run ${pc38.cyan("vela bless")}.`
|
|
10632
11012
|
);
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
11013
|
+
p63.log.message();
|
|
11014
|
+
p63.cancel("Operation failed.");
|
|
11015
|
+
process41.exit(1);
|
|
10636
11016
|
}
|
|
10637
11017
|
});
|
|
10638
11018
|
function getCommandPath(cmd) {
|
|
@@ -10686,5 +11066,5 @@ for (const command of [
|
|
|
10686
11066
|
}
|
|
10687
11067
|
|
|
10688
11068
|
// src/bin.ts
|
|
10689
|
-
program.parse(normalizeArgv(
|
|
11069
|
+
program.parse(normalizeArgv(process42.argv.slice(2)), { from: "user" });
|
|
10690
11070
|
//# sourceMappingURL=bin.js.map
|