vela 0.10.13 → 0.10.14
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 +5 -1
- package/dist/bin.js +959 -709
- package/dist/bin.js.map +4 -4
- package/package.json +2 -2
- package/templates/minimal/components.json +4 -2
- package/templates/minimal/package.template.json +7 -3
- package/templates/minimal/src/app.css +57 -53
- package/templates/minimal/src/lib/components/ui/button/button.svelte +22 -13
- package/templates/minimal/src/lib/components/ui/sonner/sonner.svelte +23 -2
- package/templates/minimal/src/routes/(public)/+page.svelte +5 -4
- package/templates/minimal/vite.config.ts +1 -3
- package/templates/static/components.json +4 -2
- package/templates/static/package.template.json +4 -3
- package/templates/static/src/app.css +57 -53
- package/templates/static/src/lib/components/ui/button/button.svelte +22 -13
- package/templates/static/src/lib/components/ui/sonner/sonner.svelte +23 -2
- package/templates/static/src/routes/(public)/+page.svelte +5 -4
- package/templates/ui/css/gray.css +0 -68
- package/templates/ui/css/neutral.css +0 -68
- package/templates/ui/css/slate.css +0 -68
- package/templates/ui/css/stone.css +0 -68
- package/templates/ui/css/zinc.css +0 -68
package/dist/bin.js
CHANGED
|
@@ -12,8 +12,8 @@ function normalizeArgv(argv) {
|
|
|
12
12
|
|
|
13
13
|
// src/program.ts
|
|
14
14
|
import process35 from "node:process";
|
|
15
|
-
import * as
|
|
16
|
-
import { Command as
|
|
15
|
+
import * as p59 from "@clack/prompts";
|
|
16
|
+
import { Command as Command103 } from "commander";
|
|
17
17
|
import nodePath from "node:path";
|
|
18
18
|
import dotenv2 from "dotenv";
|
|
19
19
|
import pc36 from "picocolors";
|
|
@@ -21,7 +21,7 @@ import pc36 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.10.
|
|
24
|
+
version: "0.10.14",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -55,7 +55,7 @@ var package_default = {
|
|
|
55
55
|
dependencies: {
|
|
56
56
|
"@clack/prompts": "^1.7.0",
|
|
57
57
|
"@faker-js/faker": "^10.6.0",
|
|
58
|
-
"@velastack/patterns": "^0.
|
|
58
|
+
"@velastack/patterns": "^0.2.2",
|
|
59
59
|
"@velastack/pocketbase-codegen": "^0.1.0",
|
|
60
60
|
"annotate-json-schema": "^0.1.0",
|
|
61
61
|
commander: "^13.1.0",
|
|
@@ -379,8 +379,8 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
// src/commands/bless.ts
|
|
382
|
-
import
|
|
383
|
-
import
|
|
382
|
+
import fs13 from "node:fs";
|
|
383
|
+
import path11 from "node:path";
|
|
384
384
|
import process5 from "node:process";
|
|
385
385
|
import * as v2 from "valibot";
|
|
386
386
|
import { Command as Command2 } from "commander";
|
|
@@ -866,13 +866,75 @@ function quoteEnvValue(value) {
|
|
|
866
866
|
return `"${escaped}"`;
|
|
867
867
|
}
|
|
868
868
|
|
|
869
|
-
// src/lib/
|
|
869
|
+
// src/lib/app-css.ts
|
|
870
|
+
import fs7 from "node:fs";
|
|
871
|
+
var SHADCN_TAILWIND_CSS = "shadcn-svelte/tailwind.css";
|
|
872
|
+
var SHADCN_TAILWIND_IMPORT = `@import '${SHADCN_TAILWIND_CSS}';`;
|
|
873
|
+
function hasShadcnImport(css) {
|
|
874
|
+
return css.includes(SHADCN_TAILWIND_CSS);
|
|
875
|
+
}
|
|
876
|
+
function insertShadcnImport(css) {
|
|
877
|
+
const lines = css.split("\n");
|
|
878
|
+
let lastImport = -1;
|
|
879
|
+
for (const [index, line] of lines.entries()) {
|
|
880
|
+
const trimmed = line.trim();
|
|
881
|
+
if (trimmed.startsWith("@import")) {
|
|
882
|
+
lastImport = index;
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
if (trimmed === "" || trimmed.startsWith("/*") || trimmed.startsWith("//")) continue;
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
if (lastImport === -1) {
|
|
889
|
+
return `${SHADCN_TAILWIND_IMPORT}
|
|
890
|
+
${css}`;
|
|
891
|
+
}
|
|
892
|
+
lines.splice(lastImport + 1, 0, SHADCN_TAILWIND_IMPORT);
|
|
893
|
+
return lines.join("\n");
|
|
894
|
+
}
|
|
895
|
+
function ensureShadcnImport(appCssPath) {
|
|
896
|
+
if (!fs7.existsSync(appCssPath)) return false;
|
|
897
|
+
const css = fs7.readFileSync(appCssPath, "utf8");
|
|
898
|
+
if (hasShadcnImport(css)) return false;
|
|
899
|
+
fs7.writeFileSync(appCssPath, insertShadcnImport(css));
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// src/lib/components-json.ts
|
|
870
904
|
import fs8 from "node:fs";
|
|
871
|
-
import
|
|
905
|
+
import path6 from "node:path";
|
|
906
|
+
function readComponentsJson(root) {
|
|
907
|
+
const file = path6.join(root, "components.json");
|
|
908
|
+
if (!fs8.existsSync(file)) return void 0;
|
|
909
|
+
try {
|
|
910
|
+
const parsed = JSON.parse(fs8.readFileSync(file, "utf8"));
|
|
911
|
+
return parsed && typeof parsed === "object" ? parsed : void 0;
|
|
912
|
+
} catch {
|
|
913
|
+
return void 0;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function componentsJsonHints(config) {
|
|
917
|
+
const hints = [];
|
|
918
|
+
if (!config.style) {
|
|
919
|
+
hints.push(
|
|
920
|
+
'components.json has no "style": shadcn-svelte defaults to "nova", while vela ships "vega". Add "style": "vega" so new components match.'
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
if (!config.iconLibrary) {
|
|
924
|
+
hints.push(
|
|
925
|
+
`components.json has no "iconLibrary": add "iconLibrary": "lucide", the library vela's components use.`
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
return hints;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// src/lib/config-merge.ts
|
|
932
|
+
import fs10 from "node:fs";
|
|
933
|
+
import path8 from "node:path";
|
|
872
934
|
|
|
873
935
|
// src/lib/config-target.ts
|
|
874
|
-
import
|
|
875
|
-
import
|
|
936
|
+
import fs9 from "node:fs";
|
|
937
|
+
import path7 from "node:path";
|
|
876
938
|
import {
|
|
877
939
|
Project,
|
|
878
940
|
QuoteKind,
|
|
@@ -892,8 +954,8 @@ var SVELTE_CONFIG_CANDIDATES = [
|
|
|
892
954
|
];
|
|
893
955
|
function probeFirstExisting(root, candidates) {
|
|
894
956
|
for (const rel of candidates) {
|
|
895
|
-
const abs =
|
|
896
|
-
if (
|
|
957
|
+
const abs = path7.join(root, rel);
|
|
958
|
+
if (fs9.existsSync(abs)) return abs;
|
|
897
959
|
}
|
|
898
960
|
return null;
|
|
899
961
|
}
|
|
@@ -969,7 +1031,7 @@ function mergeSvelteConfig(projectRoot) {
|
|
|
969
1031
|
};
|
|
970
1032
|
}
|
|
971
1033
|
function mergeRunesIntoViteArg(vite, arg) {
|
|
972
|
-
const file =
|
|
1034
|
+
const file = path8.basename(vite.filePath);
|
|
973
1035
|
const compilerOptions = getOrCreateObjectLiteralProperty(arg, "compilerOptions", "{}");
|
|
974
1036
|
if (!compilerOptions) {
|
|
975
1037
|
return {
|
|
@@ -988,8 +1050,8 @@ function mergeRunesIntoViteArg(vite, arg) {
|
|
|
988
1050
|
return { applied: true, reason: "added runes compilerOption", file };
|
|
989
1051
|
}
|
|
990
1052
|
function mergeRunesIntoSvelteConfig(filePath) {
|
|
991
|
-
const file =
|
|
992
|
-
const original =
|
|
1053
|
+
const file = path8.basename(filePath);
|
|
1054
|
+
const original = fs10.readFileSync(filePath, "utf8");
|
|
993
1055
|
if (/runes\s*:/m.test(original)) {
|
|
994
1056
|
return { applied: false, reason: "runes already configured", file };
|
|
995
1057
|
}
|
|
@@ -1012,11 +1074,11 @@ function mergeRunesIntoSvelteConfig(filePath) {
|
|
|
1012
1074
|
}
|
|
1013
1075
|
const insertAt = anchor.index + anchor[0].length;
|
|
1014
1076
|
const updated = original.slice(0, insertAt) + RUNES_SNIPPET + original.slice(insertAt);
|
|
1015
|
-
|
|
1077
|
+
fs10.writeFileSync(filePath, updated);
|
|
1016
1078
|
return { applied: true, reason: "added runes compilerOption", file };
|
|
1017
1079
|
}
|
|
1018
1080
|
function mergeViteConfig(filePath) {
|
|
1019
|
-
if (!
|
|
1081
|
+
if (!fs10.existsSync(filePath)) {
|
|
1020
1082
|
return {
|
|
1021
1083
|
applied: false,
|
|
1022
1084
|
reason: "vite.config.ts not found",
|
|
@@ -1024,7 +1086,7 @@ function mergeViteConfig(filePath) {
|
|
|
1024
1086
|
// then add tailwindcss() to the plugins array`
|
|
1025
1087
|
};
|
|
1026
1088
|
}
|
|
1027
|
-
const original =
|
|
1089
|
+
const original = fs10.readFileSync(filePath, "utf8");
|
|
1028
1090
|
if (original.includes("@tailwindcss/vite")) {
|
|
1029
1091
|
return { applied: false, reason: "tailwindcss plugin already present" };
|
|
1030
1092
|
}
|
|
@@ -1043,14 +1105,14 @@ function mergeViteConfig(filePath) {
|
|
|
1043
1105
|
const trailing = withImport.slice(insertAt);
|
|
1044
1106
|
const prefix = /^\s*\]/.test(trailing) ? "tailwindcss()" : "tailwindcss(), ";
|
|
1045
1107
|
const updated = withImport.slice(0, insertAt) + prefix + withImport.slice(insertAt);
|
|
1046
|
-
|
|
1108
|
+
fs10.writeFileSync(filePath, updated);
|
|
1047
1109
|
return { applied: true, reason: "added @tailwindcss/vite plugin" };
|
|
1048
1110
|
}
|
|
1049
1111
|
function mergeTsconfig(filePath) {
|
|
1050
|
-
if (!
|
|
1112
|
+
if (!fs10.existsSync(filePath)) {
|
|
1051
1113
|
return { applied: false, reason: "tsconfig.json not found" };
|
|
1052
1114
|
}
|
|
1053
|
-
const original =
|
|
1115
|
+
const original = fs10.readFileSync(filePath, "utf8");
|
|
1054
1116
|
if (/rewriteRelativeImportExtensions/.test(original)) {
|
|
1055
1117
|
return { applied: false, reason: "rewriteRelativeImportExtensions already set" };
|
|
1056
1118
|
}
|
|
@@ -1066,7 +1128,7 @@ function mergeTsconfig(filePath) {
|
|
|
1066
1128
|
const indent = detectIndent(original, insertAt);
|
|
1067
1129
|
const updated = original.slice(0, insertAt) + `
|
|
1068
1130
|
${indent}"rewriteRelativeImportExtensions": true,` + original.slice(insertAt);
|
|
1069
|
-
|
|
1131
|
+
fs10.writeFileSync(filePath, updated);
|
|
1070
1132
|
return { applied: true, reason: "added rewriteRelativeImportExtensions" };
|
|
1071
1133
|
}
|
|
1072
1134
|
var GITIGNORE_ENTRIES = [
|
|
@@ -1078,7 +1140,7 @@ var GITIGNORE_ENTRIES = [
|
|
|
1078
1140
|
"vite.config.ts.timestamp-*"
|
|
1079
1141
|
];
|
|
1080
1142
|
function mergeGitignore(filePath) {
|
|
1081
|
-
const existing =
|
|
1143
|
+
const existing = fs10.existsSync(filePath) ? fs10.readFileSync(filePath, "utf8") : "";
|
|
1082
1144
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
1083
1145
|
const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.includes(entry));
|
|
1084
1146
|
if (missing.length === 0) {
|
|
@@ -1087,7 +1149,7 @@ function mergeGitignore(filePath) {
|
|
|
1087
1149
|
const needsNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
1088
1150
|
const appended = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
|
|
1089
1151
|
`;
|
|
1090
|
-
|
|
1152
|
+
fs10.writeFileSync(filePath, appended);
|
|
1091
1153
|
return { applied: true, reason: `added ${missing.length} gitignore entries` };
|
|
1092
1154
|
}
|
|
1093
1155
|
function addImport(source, importLine) {
|
|
@@ -1112,14 +1174,14 @@ function detectIndent(source, atOffset) {
|
|
|
1112
1174
|
}
|
|
1113
1175
|
|
|
1114
1176
|
// src/lib/scaffold-detect.ts
|
|
1115
|
-
import
|
|
1116
|
-
import
|
|
1177
|
+
import fs11 from "node:fs";
|
|
1178
|
+
import path9 from "node:path";
|
|
1117
1179
|
var VANILLA_MARKER = "Welcome to SvelteKit";
|
|
1118
|
-
var PAGE_REL =
|
|
1180
|
+
var PAGE_REL = path9.join("src", "routes", "+page.svelte");
|
|
1119
1181
|
function isVanillaRoutes(cwd) {
|
|
1120
|
-
const pagePath =
|
|
1121
|
-
if (!
|
|
1122
|
-
return
|
|
1182
|
+
const pagePath = path9.join(cwd, PAGE_REL);
|
|
1183
|
+
if (!fs11.existsSync(pagePath)) return false;
|
|
1184
|
+
return fs11.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
|
|
1123
1185
|
}
|
|
1124
1186
|
|
|
1125
1187
|
// src/lib/result-report.ts
|
|
@@ -1167,41 +1229,41 @@ ${failure.message}` : headline);
|
|
|
1167
1229
|
}
|
|
1168
1230
|
|
|
1169
1231
|
// src/lib/template-files.ts
|
|
1170
|
-
import
|
|
1171
|
-
import
|
|
1232
|
+
import fs12 from "node:fs";
|
|
1233
|
+
import path10 from "node:path";
|
|
1172
1234
|
var PUBLISH_SAFE_NAMES = {
|
|
1173
1235
|
".gitignore": "_gitignore",
|
|
1174
1236
|
".npmrc": "_npmrc"
|
|
1175
1237
|
};
|
|
1176
1238
|
function templateName(projectRelPath) {
|
|
1177
|
-
const safe = PUBLISH_SAFE_NAMES[
|
|
1239
|
+
const safe = PUBLISH_SAFE_NAMES[path10.basename(projectRelPath)];
|
|
1178
1240
|
if (!safe) return projectRelPath;
|
|
1179
|
-
const dir =
|
|
1180
|
-
return dir === "." ? safe :
|
|
1241
|
+
const dir = path10.dirname(projectRelPath);
|
|
1242
|
+
return dir === "." ? safe : path10.join(dir, safe);
|
|
1181
1243
|
}
|
|
1182
1244
|
function restoreTemplateNames(target) {
|
|
1183
1245
|
for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
|
|
1184
|
-
const from =
|
|
1185
|
-
if (!
|
|
1186
|
-
|
|
1246
|
+
const from = path10.join(target, safe);
|
|
1247
|
+
if (!fs12.existsSync(from)) continue;
|
|
1248
|
+
fs12.renameSync(from, path10.join(target, real));
|
|
1187
1249
|
}
|
|
1188
1250
|
}
|
|
1189
1251
|
var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
|
|
1190
1252
|
function applyTemplateFiles(target, values) {
|
|
1191
1253
|
const written = [];
|
|
1192
1254
|
for (const source of findTemplateSources(target)) {
|
|
1193
|
-
const raw =
|
|
1255
|
+
const raw = fs12.readFileSync(source, "utf8");
|
|
1194
1256
|
const dest = source.replace(TEMPLATE_SOURCE, ".$1");
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
written.push(
|
|
1257
|
+
fs12.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
|
|
1258
|
+
fs12.unlinkSync(source);
|
|
1259
|
+
written.push(path10.relative(target, dest));
|
|
1198
1260
|
}
|
|
1199
1261
|
return written.sort();
|
|
1200
1262
|
}
|
|
1201
1263
|
function findTemplateSources(dir) {
|
|
1202
1264
|
const found = [];
|
|
1203
|
-
for (const entry of
|
|
1204
|
-
const full =
|
|
1265
|
+
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
1266
|
+
const full = path10.join(dir, entry.name);
|
|
1205
1267
|
if (entry.isDirectory()) {
|
|
1206
1268
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
1207
1269
|
found.push(...findTemplateSources(full));
|
|
@@ -1229,10 +1291,16 @@ var VELA_ONLY_FILES = [
|
|
|
1229
1291
|
path: "src/hooks.server.ts",
|
|
1230
1292
|
adds: "the handlePocketbase hook \u2014 the backend is not wired up without it"
|
|
1231
1293
|
},
|
|
1232
|
-
{
|
|
1294
|
+
{
|
|
1295
|
+
path: "src/app.css",
|
|
1296
|
+
adds: "vela's Tailwind imports, theme tokens and the shadcn-svelte/tailwind.css import"
|
|
1297
|
+
},
|
|
1233
1298
|
{ path: "src/lib/index.ts", adds: "a $lib placeholder comment" },
|
|
1234
1299
|
{ path: "src/lib/utils.ts", adds: "the cn helper and the component type utilities" },
|
|
1235
|
-
{
|
|
1300
|
+
{
|
|
1301
|
+
path: "components.json",
|
|
1302
|
+
adds: "the shadcn-svelte config (vega style, lucide icons) that `vela ui add` reads"
|
|
1303
|
+
},
|
|
1236
1304
|
{ path: ".npmrc", adds: "engine-strict=true" },
|
|
1237
1305
|
{ path: ".ignore", adds: "search ignores for generated files" }
|
|
1238
1306
|
];
|
|
@@ -1277,6 +1345,8 @@ async function blessProject(cwdArg, options) {
|
|
|
1277
1345
|
);
|
|
1278
1346
|
mergeDependencies(projectPath, templateDir);
|
|
1279
1347
|
copyVelaOnlyFiles(templateDir, projectPath);
|
|
1348
|
+
ensureShadcnCss(projectPath);
|
|
1349
|
+
hintComponentsJson(projectPath);
|
|
1280
1350
|
mergeConfigFiles(projectPath);
|
|
1281
1351
|
mergeAppDts(templateDir, projectPath);
|
|
1282
1352
|
maybeReplaceRoutes(projectPath, templateDir, options);
|
|
@@ -1303,23 +1373,35 @@ async function blessProject(cwdArg, options) {
|
|
|
1303
1373
|
p4.log.success("PocketBase initialized");
|
|
1304
1374
|
printNextSteps(projectPath, packageManager);
|
|
1305
1375
|
}
|
|
1376
|
+
function ensureShadcnCss(projectPath) {
|
|
1377
|
+
if (ensureShadcnImport(path11.join(projectPath, "src", "app.css"))) {
|
|
1378
|
+
p4.log.info(
|
|
1379
|
+
"src/app.css: added the shadcn-svelte/tailwind.css import its registry components rely on."
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
function hintComponentsJson(projectPath) {
|
|
1384
|
+
const config = readComponentsJson(projectPath);
|
|
1385
|
+
if (!config) return;
|
|
1386
|
+
for (const hint of componentsJsonHints(config)) p4.log.warn(hint);
|
|
1387
|
+
}
|
|
1306
1388
|
function resolveProjectPath(cwdArg) {
|
|
1307
|
-
const projectPath =
|
|
1308
|
-
if (!
|
|
1389
|
+
const projectPath = path11.resolve(cwdArg);
|
|
1390
|
+
if (!fs13.existsSync(projectPath)) {
|
|
1309
1391
|
throw new Error(`Path does not exist: ${projectPath}`);
|
|
1310
1392
|
}
|
|
1311
|
-
if (!
|
|
1393
|
+
if (!fs13.existsSync(path11.join(projectPath, "package.json"))) {
|
|
1312
1394
|
throw new Error(`No package.json found at ${projectPath}`);
|
|
1313
1395
|
}
|
|
1314
|
-
if (!
|
|
1396
|
+
if (!fs13.existsSync(path11.join(projectPath, "src", "routes"))) {
|
|
1315
1397
|
throw new Error(`No src/routes directory found at ${projectPath}`);
|
|
1316
1398
|
}
|
|
1317
1399
|
return projectPath;
|
|
1318
1400
|
}
|
|
1319
1401
|
function assertNotAlreadyBlessed(projectPath) {
|
|
1320
|
-
const hooksPath =
|
|
1321
|
-
if (!
|
|
1322
|
-
const content =
|
|
1402
|
+
const hooksPath = path11.join(projectPath, "src", "hooks.server.ts");
|
|
1403
|
+
if (!fs13.existsSync(hooksPath)) return;
|
|
1404
|
+
const content = fs13.readFileSync(hooksPath, "utf8");
|
|
1323
1405
|
if (content.includes("@velastack/pocketbase")) {
|
|
1324
1406
|
throw new Error(
|
|
1325
1407
|
"This project already looks blessed (src/hooks.server.ts imports @velastack/pocketbase). Run `vela sync` instead."
|
|
@@ -1327,8 +1409,8 @@ function assertNotAlreadyBlessed(projectPath) {
|
|
|
1327
1409
|
}
|
|
1328
1410
|
}
|
|
1329
1411
|
function mergeDependencies(projectPath, templateDir) {
|
|
1330
|
-
const userPkgPath =
|
|
1331
|
-
const templatePkgPath =
|
|
1412
|
+
const userPkgPath = path11.join(projectPath, "package.json");
|
|
1413
|
+
const templatePkgPath = path11.join(templateDir, "package.template.json");
|
|
1332
1414
|
const userPkg = readPackageJson(userPkgPath);
|
|
1333
1415
|
const appName = typeof userPkg.name === "string" ? userPkg.name : "sveltekit";
|
|
1334
1416
|
const templatePkg = readTemplatePackageJson(templatePkgPath, {
|
|
@@ -1360,21 +1442,21 @@ ${lines.join("\n")}`);
|
|
|
1360
1442
|
function copyVelaOnlyFiles(templateDir, projectPath) {
|
|
1361
1443
|
const kept = [];
|
|
1362
1444
|
for (const file of VELA_ONLY_FILES) {
|
|
1363
|
-
const src =
|
|
1364
|
-
const dest =
|
|
1365
|
-
if (!
|
|
1366
|
-
if (
|
|
1445
|
+
const src = path11.join(templateDir, templateName(file.path));
|
|
1446
|
+
const dest = path11.join(projectPath, file.path);
|
|
1447
|
+
if (!fs13.existsSync(src)) continue;
|
|
1448
|
+
if (fs13.existsSync(dest)) {
|
|
1367
1449
|
kept.push(file);
|
|
1368
1450
|
continue;
|
|
1369
1451
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1452
|
+
fs13.mkdirSync(path11.dirname(dest), { recursive: true });
|
|
1453
|
+
fs13.copyFileSync(src, dest);
|
|
1372
1454
|
}
|
|
1373
1455
|
reportKeptFiles(kept);
|
|
1374
1456
|
for (const rel of VELA_ONLY_DIRS) {
|
|
1375
|
-
const src =
|
|
1376
|
-
const dest =
|
|
1377
|
-
if (!
|
|
1457
|
+
const src = path11.join(templateDir, rel);
|
|
1458
|
+
const dest = path11.join(projectPath, rel);
|
|
1459
|
+
if (!fs13.existsSync(src)) continue;
|
|
1378
1460
|
copyDirShallow(src, dest);
|
|
1379
1461
|
}
|
|
1380
1462
|
}
|
|
@@ -1388,15 +1470,15 @@ ${lines.join("\n")}`
|
|
|
1388
1470
|
);
|
|
1389
1471
|
}
|
|
1390
1472
|
function copyDirShallow(src, dest) {
|
|
1391
|
-
|
|
1392
|
-
for (const entry of
|
|
1473
|
+
fs13.mkdirSync(dest, { recursive: true });
|
|
1474
|
+
for (const entry of fs13.readdirSync(src, { withFileTypes: true })) {
|
|
1393
1475
|
if (entry.name === ".DS_Store") continue;
|
|
1394
|
-
const srcChild =
|
|
1395
|
-
const destChild =
|
|
1476
|
+
const srcChild = path11.join(src, entry.name);
|
|
1477
|
+
const destChild = path11.join(dest, entry.name);
|
|
1396
1478
|
if (entry.isDirectory()) {
|
|
1397
1479
|
copyDirShallow(srcChild, destChild);
|
|
1398
|
-
} else if (entry.isFile() && !
|
|
1399
|
-
|
|
1480
|
+
} else if (entry.isFile() && !fs13.existsSync(destChild)) {
|
|
1481
|
+
fs13.copyFileSync(srcChild, destChild);
|
|
1400
1482
|
}
|
|
1401
1483
|
}
|
|
1402
1484
|
}
|
|
@@ -1404,9 +1486,9 @@ function mergeConfigFiles(projectPath) {
|
|
|
1404
1486
|
const runes = mergeSvelteConfig(projectPath);
|
|
1405
1487
|
const outcomes = [
|
|
1406
1488
|
[runes.file ?? "svelte.config", runes],
|
|
1407
|
-
["vite.config.ts", mergeViteConfig(
|
|
1408
|
-
["tsconfig.json", mergeTsconfig(
|
|
1409
|
-
[".gitignore", mergeGitignore(
|
|
1489
|
+
["vite.config.ts", mergeViteConfig(path11.join(projectPath, "vite.config.ts"))],
|
|
1490
|
+
["tsconfig.json", mergeTsconfig(path11.join(projectPath, "tsconfig.json"))],
|
|
1491
|
+
[".gitignore", mergeGitignore(path11.join(projectPath, ".gitignore"))]
|
|
1410
1492
|
];
|
|
1411
1493
|
for (const [name, outcome] of outcomes) {
|
|
1412
1494
|
if (outcome.applied) {
|
|
@@ -1423,14 +1505,14 @@ ${pc3.cyan(outcome.snippet)}`
|
|
|
1423
1505
|
}
|
|
1424
1506
|
}
|
|
1425
1507
|
function mergeAppDts(templateDir, projectPath) {
|
|
1426
|
-
const dest =
|
|
1427
|
-
const templateFile =
|
|
1428
|
-
if (!
|
|
1429
|
-
if (!
|
|
1430
|
-
|
|
1508
|
+
const dest = path11.join(projectPath, "src", "app.d.ts");
|
|
1509
|
+
const templateFile = path11.join(templateDir, "src", "app.d.ts");
|
|
1510
|
+
if (!fs13.existsSync(dest)) {
|
|
1511
|
+
if (!fs13.existsSync(templateFile)) return;
|
|
1512
|
+
fs13.copyFileSync(templateFile, dest);
|
|
1431
1513
|
return;
|
|
1432
1514
|
}
|
|
1433
|
-
const current =
|
|
1515
|
+
const current = fs13.readFileSync(dest, "utf8");
|
|
1434
1516
|
if (current.includes("namespace Superforms")) return;
|
|
1435
1517
|
const block = ` namespace Superforms {
|
|
1436
1518
|
type Message = {
|
|
@@ -1449,7 +1531,7 @@ ${pc3.cyan(block)}`
|
|
|
1449
1531
|
}
|
|
1450
1532
|
const insertAt = match.index + match[0].length;
|
|
1451
1533
|
const updated = current.slice(0, insertAt) + block + current.slice(insertAt);
|
|
1452
|
-
|
|
1534
|
+
fs13.writeFileSync(dest, updated);
|
|
1453
1535
|
}
|
|
1454
1536
|
function maybeReplaceRoutes(projectPath, templateDir, options) {
|
|
1455
1537
|
if (options.skipRoutes) {
|
|
@@ -1460,12 +1542,12 @@ function maybeReplaceRoutes(projectPath, templateDir, options) {
|
|
|
1460
1542
|
p4.log.info("Leaving src/routes alone (looks customized).");
|
|
1461
1543
|
return;
|
|
1462
1544
|
}
|
|
1463
|
-
const target =
|
|
1464
|
-
|
|
1465
|
-
const src =
|
|
1466
|
-
|
|
1545
|
+
const target = path11.join(projectPath, "src", "routes");
|
|
1546
|
+
fs13.rmSync(target, { recursive: true, force: true });
|
|
1547
|
+
const src = path11.join(templateDir, "src", "routes");
|
|
1548
|
+
fs13.cpSync(src, target, {
|
|
1467
1549
|
recursive: true,
|
|
1468
|
-
filter: (s) =>
|
|
1550
|
+
filter: (s) => path11.basename(s) !== ".DS_Store"
|
|
1469
1551
|
});
|
|
1470
1552
|
p4.log.success("Replaced src/routes with the vela template.");
|
|
1471
1553
|
}
|
|
@@ -1474,7 +1556,7 @@ function summarize(names) {
|
|
|
1474
1556
|
return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
|
|
1475
1557
|
}
|
|
1476
1558
|
function printNextSteps(projectPath, packageManager) {
|
|
1477
|
-
const relative =
|
|
1559
|
+
const relative = path11.relative(process5.cwd(), projectPath);
|
|
1478
1560
|
const pm = packageManager ?? getUserAgent() ?? "npm";
|
|
1479
1561
|
const nextSteps = [];
|
|
1480
1562
|
if (relative !== "") {
|
|
@@ -1498,8 +1580,8 @@ function printNextSteps(projectPath, packageManager) {
|
|
|
1498
1580
|
}
|
|
1499
1581
|
|
|
1500
1582
|
// src/commands/create.ts
|
|
1501
|
-
import
|
|
1502
|
-
import
|
|
1583
|
+
import fs14 from "node:fs";
|
|
1584
|
+
import path12 from "node:path";
|
|
1503
1585
|
import process6 from "node:process";
|
|
1504
1586
|
import * as v3 from "valibot";
|
|
1505
1587
|
import { Command as Command3 } from "commander";
|
|
@@ -1522,7 +1604,7 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1522
1604
|
projectPath,
|
|
1523
1605
|
options
|
|
1524
1606
|
);
|
|
1525
|
-
const relative =
|
|
1607
|
+
const relative = path12.relative(process6.cwd(), directory);
|
|
1526
1608
|
const pm = packageManager ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
1527
1609
|
const nextSteps = [];
|
|
1528
1610
|
if (relative !== "") {
|
|
@@ -1571,7 +1653,7 @@ async function createProject(cwdArg, options) {
|
|
|
1571
1653
|
}
|
|
1572
1654
|
let directory;
|
|
1573
1655
|
if (cwdArg) {
|
|
1574
|
-
directory =
|
|
1656
|
+
directory = path12.resolve(cwdArg);
|
|
1575
1657
|
} else {
|
|
1576
1658
|
const answer = await p5.text({
|
|
1577
1659
|
message: "Where would you like your project to be created?",
|
|
@@ -1579,16 +1661,16 @@ async function createProject(cwdArg, options) {
|
|
|
1579
1661
|
defaultValue: "./"
|
|
1580
1662
|
});
|
|
1581
1663
|
if (p5.isCancel(answer)) onCancel2();
|
|
1582
|
-
directory =
|
|
1664
|
+
directory = path12.resolve(answer);
|
|
1583
1665
|
}
|
|
1584
|
-
if (
|
|
1666
|
+
if (fs14.existsSync(directory) && fs14.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
|
|
1585
1667
|
const force = await p5.confirm({
|
|
1586
1668
|
message: "Directory not empty. Continue?",
|
|
1587
1669
|
initialValue: false
|
|
1588
1670
|
});
|
|
1589
1671
|
if (p5.isCancel(force) || !force) onCancel2();
|
|
1590
1672
|
}
|
|
1591
|
-
const dirName =
|
|
1673
|
+
const dirName = path12.basename(directory);
|
|
1592
1674
|
const { name } = await p5.group(
|
|
1593
1675
|
{
|
|
1594
1676
|
name: () => {
|
|
@@ -1606,7 +1688,7 @@ async function createProject(cwdArg, options) {
|
|
|
1606
1688
|
const projectPath = directory;
|
|
1607
1689
|
copyTemplate(template, projectPath);
|
|
1608
1690
|
applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
|
|
1609
|
-
if (!
|
|
1691
|
+
if (!fs14.existsSync(path12.join(projectPath, "package.json"))) {
|
|
1610
1692
|
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
1611
1693
|
}
|
|
1612
1694
|
p5.log.success("Project created");
|
|
@@ -1668,11 +1750,11 @@ function promptCredentials(options, onCancel2) {
|
|
|
1668
1750
|
);
|
|
1669
1751
|
}
|
|
1670
1752
|
function copyTemplate(template, target) {
|
|
1671
|
-
|
|
1672
|
-
|
|
1753
|
+
fs14.mkdirSync(target, { recursive: true });
|
|
1754
|
+
fs14.cpSync(template.dir, target, {
|
|
1673
1755
|
recursive: true,
|
|
1674
1756
|
// The manifest describes the template to the CLI; it isn't part of the project.
|
|
1675
|
-
filter: (src) =>
|
|
1757
|
+
filter: (src) => path12.basename(src) !== ".DS_Store" && path12.relative(template.dir, src) !== TEMPLATE_MANIFEST
|
|
1676
1758
|
});
|
|
1677
1759
|
restoreTemplateNames(target);
|
|
1678
1760
|
}
|
|
@@ -1685,11 +1767,11 @@ import { Command as Command4 } from "commander";
|
|
|
1685
1767
|
import * as p11 from "@clack/prompts";
|
|
1686
1768
|
|
|
1687
1769
|
// src/lib/pattern-runner.ts
|
|
1688
|
-
import
|
|
1770
|
+
import path13 from "node:path";
|
|
1689
1771
|
import * as p6 from "@clack/prompts";
|
|
1690
1772
|
import { bySlug } from "@velastack/patterns";
|
|
1691
1773
|
function toRelative(root, filePath) {
|
|
1692
|
-
return
|
|
1774
|
+
return path13.isAbsolute(filePath) ? path13.relative(root, filePath) : filePath;
|
|
1693
1775
|
}
|
|
1694
1776
|
var isSuccess = (f) => (f.status ?? "success") === "success";
|
|
1695
1777
|
async function runPattern(slug2, argv, input, report4) {
|
|
@@ -1698,7 +1780,7 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
1698
1780
|
throw new Error(`Unknown pattern: ${slug2}`);
|
|
1699
1781
|
}
|
|
1700
1782
|
const { workspaceRootDir, features } = await getWorkspace();
|
|
1701
|
-
const
|
|
1783
|
+
const log43 = p6.taskLog({ title: report4.task.title });
|
|
1702
1784
|
let result;
|
|
1703
1785
|
try {
|
|
1704
1786
|
result = await pattern.generate({
|
|
@@ -1718,11 +1800,11 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
1718
1800
|
});
|
|
1719
1801
|
return collections2;
|
|
1720
1802
|
},
|
|
1721
|
-
logger: { info: (message) =>
|
|
1803
|
+
logger: { info: (message) => log43.message(message) }
|
|
1722
1804
|
});
|
|
1723
|
-
|
|
1805
|
+
log43.success(report4.task.success);
|
|
1724
1806
|
} catch (e) {
|
|
1725
|
-
|
|
1807
|
+
log43.error(report4.task.error);
|
|
1726
1808
|
throw e;
|
|
1727
1809
|
}
|
|
1728
1810
|
const rel = (f) => toRelative(workspaceRootDir, f);
|
|
@@ -1756,31 +1838,31 @@ async function runPattern(slug2, argv, input, report4) {
|
|
|
1756
1838
|
}
|
|
1757
1839
|
|
|
1758
1840
|
// src/lib/ai-flow.ts
|
|
1759
|
-
import
|
|
1760
|
-
import
|
|
1841
|
+
import fs17 from "node:fs";
|
|
1842
|
+
import path16 from "node:path";
|
|
1761
1843
|
import * as p10 from "@clack/prompts";
|
|
1762
1844
|
import pc4 from "picocolors";
|
|
1763
1845
|
|
|
1764
1846
|
// src/lib/config.ts
|
|
1765
|
-
import
|
|
1847
|
+
import fs15 from "node:fs";
|
|
1766
1848
|
import os from "node:os";
|
|
1767
|
-
import
|
|
1768
|
-
var CONFIG_DIR =
|
|
1769
|
-
var CONFIG_PATH =
|
|
1849
|
+
import path14 from "node:path";
|
|
1850
|
+
var CONFIG_DIR = path14.join(os.homedir(), ".vela");
|
|
1851
|
+
var CONFIG_PATH = path14.join(CONFIG_DIR, "config.json");
|
|
1770
1852
|
function readConfig() {
|
|
1771
|
-
if (!
|
|
1853
|
+
if (!fs15.existsSync(CONFIG_PATH)) return null;
|
|
1772
1854
|
try {
|
|
1773
|
-
return JSON.parse(
|
|
1855
|
+
return JSON.parse(fs15.readFileSync(CONFIG_PATH, "utf8"));
|
|
1774
1856
|
} catch {
|
|
1775
1857
|
return null;
|
|
1776
1858
|
}
|
|
1777
1859
|
}
|
|
1778
1860
|
function writeConfig(config) {
|
|
1779
|
-
|
|
1780
|
-
|
|
1861
|
+
fs15.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
1862
|
+
fs15.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
1781
1863
|
}
|
|
1782
1864
|
function clearConfig() {
|
|
1783
|
-
if (
|
|
1865
|
+
if (fs15.existsSync(CONFIG_PATH)) fs15.unlinkSync(CONFIG_PATH);
|
|
1784
1866
|
}
|
|
1785
1867
|
function requireApiKey() {
|
|
1786
1868
|
const config = readConfig();
|
|
@@ -1791,16 +1873,16 @@ function requireApiKey() {
|
|
|
1791
1873
|
}
|
|
1792
1874
|
|
|
1793
1875
|
// src/lib/project-config.ts
|
|
1794
|
-
import
|
|
1795
|
-
import
|
|
1876
|
+
import fs16 from "node:fs";
|
|
1877
|
+
import path15 from "node:path";
|
|
1796
1878
|
function projectConfigPath(workspaceRootDir) {
|
|
1797
|
-
return
|
|
1879
|
+
return path15.join(workspaceRootDir, ".vela", "project.json");
|
|
1798
1880
|
}
|
|
1799
1881
|
function readProjectConfig(workspaceRootDir) {
|
|
1800
1882
|
const file = projectConfigPath(workspaceRootDir);
|
|
1801
|
-
if (!
|
|
1883
|
+
if (!fs16.existsSync(file)) return null;
|
|
1802
1884
|
try {
|
|
1803
|
-
const parsed = JSON.parse(
|
|
1885
|
+
const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
1804
1886
|
if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
|
|
1805
1887
|
return null;
|
|
1806
1888
|
}
|
|
@@ -1815,15 +1897,15 @@ function readProjectConfig(workspaceRootDir) {
|
|
|
1815
1897
|
}
|
|
1816
1898
|
function writeProjectConfig(workspaceRootDir, config) {
|
|
1817
1899
|
const file = projectConfigPath(workspaceRootDir);
|
|
1818
|
-
|
|
1900
|
+
fs16.mkdirSync(path15.dirname(file), { recursive: true });
|
|
1819
1901
|
let existing = {};
|
|
1820
|
-
if (
|
|
1902
|
+
if (fs16.existsSync(file)) {
|
|
1821
1903
|
try {
|
|
1822
|
-
existing = JSON.parse(
|
|
1904
|
+
existing = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
1823
1905
|
} catch {
|
|
1824
1906
|
}
|
|
1825
1907
|
}
|
|
1826
|
-
|
|
1908
|
+
fs16.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
|
|
1827
1909
|
}
|
|
1828
1910
|
|
|
1829
1911
|
// src/lib/ai-client.ts
|
|
@@ -1867,17 +1949,17 @@ async function aiLoop(opts) {
|
|
|
1867
1949
|
let attempt = 0;
|
|
1868
1950
|
while (true) {
|
|
1869
1951
|
attempt++;
|
|
1870
|
-
const
|
|
1871
|
-
|
|
1952
|
+
const spinner7 = p7.spinner();
|
|
1953
|
+
spinner7.start(`${opts.stageLabel} (${attempt > 1 ? "iteration " + attempt : "first pass"})\u2026`);
|
|
1872
1954
|
let result;
|
|
1873
1955
|
let turn;
|
|
1874
1956
|
try {
|
|
1875
1957
|
const out = await opts.call({ prompt, history });
|
|
1876
1958
|
result = out.result;
|
|
1877
1959
|
turn = out.turn;
|
|
1878
|
-
|
|
1960
|
+
spinner7.stop(`${opts.stageLabel} ready.`);
|
|
1879
1961
|
} catch (e) {
|
|
1880
|
-
|
|
1962
|
+
spinner7.stop(`${opts.stageLabel} failed.`);
|
|
1881
1963
|
throw e;
|
|
1882
1964
|
}
|
|
1883
1965
|
opts.renderPreview(result);
|
|
@@ -2097,11 +2179,11 @@ function specToArgv(spec) {
|
|
|
2097
2179
|
return collectionSpecToArgv(spec);
|
|
2098
2180
|
}
|
|
2099
2181
|
function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
|
|
2100
|
-
const dir =
|
|
2101
|
-
|
|
2102
|
-
const file =
|
|
2103
|
-
|
|
2104
|
-
return
|
|
2182
|
+
const dir = path16.join(workspaceRootDir, "data", "ai-form-layouts");
|
|
2183
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
2184
|
+
const file = path16.join(dir, `${modelName}.json`);
|
|
2185
|
+
fs17.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
|
|
2186
|
+
return path16.relative(workspaceRootDir, file);
|
|
2105
2187
|
}
|
|
2106
2188
|
|
|
2107
2189
|
// src/commands/generate/form.ts
|
|
@@ -2631,8 +2713,8 @@ import * as p15 from "@clack/prompts";
|
|
|
2631
2713
|
import pc5 from "picocolors";
|
|
2632
2714
|
|
|
2633
2715
|
// src/lib/deploy-config.ts
|
|
2634
|
-
import
|
|
2635
|
-
import
|
|
2716
|
+
import fs18 from "node:fs";
|
|
2717
|
+
import path17 from "node:path";
|
|
2636
2718
|
import crypto from "node:crypto";
|
|
2637
2719
|
import { pathToFileURL } from "node:url";
|
|
2638
2720
|
var CONFIG_BASENAMES = [
|
|
@@ -2643,8 +2725,8 @@ var CONFIG_BASENAMES = [
|
|
|
2643
2725
|
];
|
|
2644
2726
|
function findConfigFile(workspaceRootDir) {
|
|
2645
2727
|
for (const name of CONFIG_BASENAMES) {
|
|
2646
|
-
const file =
|
|
2647
|
-
if (
|
|
2728
|
+
const file = path17.join(workspaceRootDir, name);
|
|
2729
|
+
if (fs18.existsSync(file)) return file;
|
|
2648
2730
|
}
|
|
2649
2731
|
return null;
|
|
2650
2732
|
}
|
|
@@ -2652,49 +2734,49 @@ async function loadDeployConfig(workspaceRootDir) {
|
|
|
2652
2734
|
const file = findConfigFile(workspaceRootDir);
|
|
2653
2735
|
if (!file) return {};
|
|
2654
2736
|
if (file.endsWith(".json")) {
|
|
2655
|
-
return JSON.parse(
|
|
2737
|
+
return JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
2656
2738
|
}
|
|
2657
2739
|
const url = file.endsWith(".ts") ? await transpileToTemp(file) : pathToFileURL(file).href;
|
|
2658
2740
|
try {
|
|
2659
2741
|
const mod = await import(url);
|
|
2660
2742
|
const config = mod.default;
|
|
2661
2743
|
if (!config || typeof config !== "object") {
|
|
2662
|
-
throw new Error(`${
|
|
2744
|
+
throw new Error(`${path17.basename(file)} must export a config object as its default export.`);
|
|
2663
2745
|
}
|
|
2664
2746
|
return config;
|
|
2665
2747
|
} finally {
|
|
2666
|
-
if (url !== pathToFileURL(file).href)
|
|
2748
|
+
if (url !== pathToFileURL(file).href) fs18.rmSync(new URL(url), { force: true });
|
|
2667
2749
|
}
|
|
2668
2750
|
}
|
|
2669
2751
|
async function transpileToTemp(file) {
|
|
2670
2752
|
const { ts } = await import("ts-morph");
|
|
2671
|
-
const source =
|
|
2753
|
+
const source = fs18.readFileSync(file, "utf8");
|
|
2672
2754
|
const { outputText } = ts.transpileModule(source, {
|
|
2673
2755
|
compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 }
|
|
2674
2756
|
});
|
|
2675
|
-
const temp =
|
|
2676
|
-
|
|
2757
|
+
const temp = path17.join(
|
|
2758
|
+
path17.dirname(file),
|
|
2677
2759
|
`.velastack.config.${crypto.randomBytes(4).toString("hex")}.mjs`
|
|
2678
2760
|
);
|
|
2679
|
-
|
|
2761
|
+
fs18.writeFileSync(temp, outputText);
|
|
2680
2762
|
return pathToFileURL(temp).href;
|
|
2681
2763
|
}
|
|
2682
2764
|
function projectFilePath(workspaceRootDir) {
|
|
2683
|
-
return
|
|
2765
|
+
return path17.join(workspaceRootDir, ".vela", "project.json");
|
|
2684
2766
|
}
|
|
2685
2767
|
function readProjectFile(workspaceRootDir) {
|
|
2686
2768
|
const file = projectFilePath(workspaceRootDir);
|
|
2687
|
-
if (!
|
|
2769
|
+
if (!fs18.existsSync(file)) return {};
|
|
2688
2770
|
try {
|
|
2689
|
-
return JSON.parse(
|
|
2771
|
+
return JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
2690
2772
|
} catch {
|
|
2691
2773
|
return {};
|
|
2692
2774
|
}
|
|
2693
2775
|
}
|
|
2694
2776
|
function writeProjectFile(workspaceRootDir, data) {
|
|
2695
2777
|
const file = projectFilePath(workspaceRootDir);
|
|
2696
|
-
|
|
2697
|
-
|
|
2778
|
+
fs18.mkdirSync(path17.dirname(file), { recursive: true });
|
|
2779
|
+
fs18.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
|
|
2698
2780
|
}
|
|
2699
2781
|
function resolveAppIdentity(workspaceRootDir, config = {}) {
|
|
2700
2782
|
const project = readProjectFile(workspaceRootDir);
|
|
@@ -2719,11 +2801,11 @@ function readAppIdentity(workspaceRootDir, config = {}) {
|
|
|
2719
2801
|
}
|
|
2720
2802
|
function defaultProjectName(workspaceRootDir) {
|
|
2721
2803
|
try {
|
|
2722
|
-
const pkg = readPackageJson(
|
|
2804
|
+
const pkg = readPackageJson(path17.join(workspaceRootDir, "package.json"));
|
|
2723
2805
|
if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
|
|
2724
2806
|
} catch {
|
|
2725
2807
|
}
|
|
2726
|
-
return
|
|
2808
|
+
return path17.basename(workspaceRootDir);
|
|
2727
2809
|
}
|
|
2728
2810
|
function slug(value) {
|
|
2729
2811
|
return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
|
|
@@ -2802,9 +2884,9 @@ function sshOptionsFrom(options) {
|
|
|
2802
2884
|
}
|
|
2803
2885
|
|
|
2804
2886
|
// src/lib/ssh.ts
|
|
2805
|
-
import
|
|
2887
|
+
import fs19 from "node:fs";
|
|
2806
2888
|
import os2 from "node:os";
|
|
2807
|
-
import
|
|
2889
|
+
import path18 from "node:path";
|
|
2808
2890
|
import crypto2 from "node:crypto";
|
|
2809
2891
|
import process8 from "node:process";
|
|
2810
2892
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -2847,9 +2929,9 @@ var SshSession = class {
|
|
|
2847
2929
|
}
|
|
2848
2930
|
async open() {
|
|
2849
2931
|
if (this.controlPath) return;
|
|
2850
|
-
const dir =
|
|
2851
|
-
|
|
2852
|
-
const socket =
|
|
2932
|
+
const dir = path18.join(os2.tmpdir(), "vela-ssh");
|
|
2933
|
+
fs19.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2934
|
+
const socket = path18.join(dir, `${crypto2.randomBytes(6).toString("hex")}.sock`);
|
|
2853
2935
|
this.controlPath = socket;
|
|
2854
2936
|
const args = [
|
|
2855
2937
|
...this.sshArgs(),
|
|
@@ -3105,14 +3187,14 @@ function spawnCapture(command, args, opts = {}) {
|
|
|
3105
3187
|
}
|
|
3106
3188
|
|
|
3107
3189
|
// src/lib/remote.ts
|
|
3108
|
-
import
|
|
3190
|
+
import path19 from "node:path";
|
|
3109
3191
|
var VELA_ROOT = "/var/lib/vela";
|
|
3110
3192
|
var VELA_ETC = "/etc/vela";
|
|
3111
3193
|
var VELA_USER = "vela";
|
|
3112
3194
|
var SCRIPTS_DIR = `${VELA_ROOT}/scripts`;
|
|
3113
3195
|
var PROVISIONED_MARKER = `${VELA_ETC}/provisioned`;
|
|
3114
3196
|
function serverTemplatesDir() {
|
|
3115
|
-
return
|
|
3197
|
+
return path19.join(templatesDir(), "server");
|
|
3116
3198
|
}
|
|
3117
3199
|
async function syncServerScripts(session) {
|
|
3118
3200
|
await session.script(`mkdir -p "$1" && chmod 0755 "$1"`, { args: [SCRIPTS_DIR] });
|
|
@@ -3180,7 +3262,7 @@ var remotePaths = {
|
|
|
3180
3262
|
};
|
|
3181
3263
|
|
|
3182
3264
|
// src/lib/remote-env.ts
|
|
3183
|
-
import
|
|
3265
|
+
import fs20 from "node:fs";
|
|
3184
3266
|
import dotenv from "dotenv";
|
|
3185
3267
|
var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3186
3268
|
function isValidKey(key) {
|
|
@@ -3228,7 +3310,7 @@ function quote(value) {
|
|
|
3228
3310
|
return `"${escaped}"`;
|
|
3229
3311
|
}
|
|
3230
3312
|
function readLocalEnvFile(file) {
|
|
3231
|
-
const parsed = dotenv.parse(
|
|
3313
|
+
const parsed = dotenv.parse(fs20.readFileSync(file));
|
|
3232
3314
|
const result = {};
|
|
3233
3315
|
for (const [key, value] of Object.entries(parsed)) {
|
|
3234
3316
|
if (isValidKey(key)) result[key] = value;
|
|
@@ -3518,17 +3600,17 @@ function envFilePath(workspaceRootDir) {
|
|
|
3518
3600
|
import pc7 from "picocolors";
|
|
3519
3601
|
|
|
3520
3602
|
// src/lib/local-env.ts
|
|
3521
|
-
import
|
|
3603
|
+
import fs21 from "node:fs";
|
|
3522
3604
|
import * as p16 from "@clack/prompts";
|
|
3523
3605
|
import pc6 from "picocolors";
|
|
3524
3606
|
function readLocalEnv(envFile) {
|
|
3525
|
-
if (!
|
|
3607
|
+
if (!fs21.existsSync(envFile)) return {};
|
|
3526
3608
|
return readLocalEnvFile(envFile);
|
|
3527
3609
|
}
|
|
3528
3610
|
function editLocalEnv(envFile, edit) {
|
|
3529
|
-
const before =
|
|
3611
|
+
const before = fs21.existsSync(envFile) ? fs21.readFileSync(envFile, "utf8") : "";
|
|
3530
3612
|
const after = edit(before);
|
|
3531
|
-
if (after !== before)
|
|
3613
|
+
if (after !== before) fs21.writeFileSync(envFile, after);
|
|
3532
3614
|
}
|
|
3533
3615
|
function setLocalEnv(envFile, key, value) {
|
|
3534
3616
|
editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
|
|
@@ -3660,8 +3742,8 @@ Set ${pc7.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc7.cyan("POCKETBASE_SUPERUS
|
|
|
3660
3742
|
}
|
|
3661
3743
|
|
|
3662
3744
|
// src/lib/s3-settings.ts
|
|
3663
|
-
import
|
|
3664
|
-
import
|
|
3745
|
+
import fs22 from "node:fs";
|
|
3746
|
+
import path20 from "node:path";
|
|
3665
3747
|
var VIRTUAL_HOSTED = [/\.amazonaws\.com$/i, /\.r2\.cloudflarestorage\.com$/i];
|
|
3666
3748
|
function defaultForcePathStyle(endpoint) {
|
|
3667
3749
|
let host;
|
|
@@ -3699,18 +3781,18 @@ async function hasLocalUploads(session, instance, workspaceRootDir) {
|
|
|
3699
3781
|
});
|
|
3700
3782
|
return result.stdout.trim().length > 0;
|
|
3701
3783
|
}
|
|
3702
|
-
return hasFile(
|
|
3784
|
+
return hasFile(path20.join(workspaceRootDir, DATA_DIR, "storage"));
|
|
3703
3785
|
}
|
|
3704
3786
|
function hasFile(dir) {
|
|
3705
3787
|
let entries;
|
|
3706
3788
|
try {
|
|
3707
|
-
entries =
|
|
3789
|
+
entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
3708
3790
|
} catch {
|
|
3709
3791
|
return false;
|
|
3710
3792
|
}
|
|
3711
3793
|
for (const entry of entries) {
|
|
3712
3794
|
if (entry.isFile()) return true;
|
|
3713
|
-
if (entry.isDirectory() && hasFile(
|
|
3795
|
+
if (entry.isDirectory() && hasFile(path20.join(dir, entry.name))) return true;
|
|
3714
3796
|
}
|
|
3715
3797
|
return false;
|
|
3716
3798
|
}
|
|
@@ -4430,124 +4512,292 @@ async function confirm7(appName, targetName, envTag, purge) {
|
|
|
4430
4512
|
var destroy = new Command40("destroy").description("destroy scaffolding, or a deployment").configureHelp(helpConfig).addCommand(form2).addCommand(schema2).addCommand(resource2).addCommand(scaffold2).addCommand(deployment);
|
|
4431
4513
|
|
|
4432
4514
|
// src/commands/ui.ts
|
|
4433
|
-
import { Command as
|
|
4515
|
+
import { Command as Command46 } from "commander";
|
|
4434
4516
|
|
|
4435
4517
|
// src/commands/ui/add.ts
|
|
4436
4518
|
import { Command as Command41 } from "commander";
|
|
4437
|
-
import
|
|
4438
|
-
import {
|
|
4439
|
-
|
|
4440
|
-
|
|
4519
|
+
import * as p24 from "@clack/prompts";
|
|
4520
|
+
import { installComponents } from "@velastack/patterns";
|
|
4521
|
+
|
|
4522
|
+
// src/lib/ui-add.ts
|
|
4523
|
+
var STYLES = ["nova", "vega", "maia", "lyra", "mira", "luma", "sera", "rhea"];
|
|
4524
|
+
var BASE_COLORS = ["neutral", "stone", "zinc", "mauve", "olive", "mist", "taupe"];
|
|
4525
|
+
var THEMES = [
|
|
4526
|
+
...BASE_COLORS,
|
|
4527
|
+
"amber",
|
|
4528
|
+
"blue",
|
|
4529
|
+
"cyan",
|
|
4530
|
+
"emerald",
|
|
4531
|
+
"fuchsia",
|
|
4532
|
+
"green",
|
|
4533
|
+
"indigo",
|
|
4534
|
+
"lime",
|
|
4535
|
+
"orange",
|
|
4536
|
+
"pink",
|
|
4537
|
+
"purple",
|
|
4538
|
+
"red",
|
|
4539
|
+
"rose",
|
|
4540
|
+
"sky",
|
|
4541
|
+
"teal",
|
|
4542
|
+
"violet",
|
|
4543
|
+
"yellow"
|
|
4544
|
+
];
|
|
4545
|
+
var NEXT_STEPS = [
|
|
4546
|
+
"Import a component with: import { Button } from '$lib/components/ui/button';",
|
|
4547
|
+
"Tweak styling in src/lib/components/ui/<component>/*.svelte.",
|
|
4548
|
+
`Run \`vela ui base <color>\` to change the palette (${BASE_COLORS.join(", ")}), or \`vela ui list\` to see what else is available.`
|
|
4549
|
+
];
|
|
4550
|
+
function uiAddReport(requested, outcome) {
|
|
4551
|
+
const { installed, skipped, packages } = outcome;
|
|
4552
|
+
const report4 = {
|
|
4553
|
+
summary: installed.length > 0 ? `Added ${installed.length} UI component(s).` : `All ${new Set(requested).size} requested component(s) are already present.`,
|
|
4554
|
+
componentsAdded: installed,
|
|
4555
|
+
packagesInstalled: packages,
|
|
4556
|
+
nextSteps: [...NEXT_STEPS]
|
|
4557
|
+
};
|
|
4558
|
+
if (skipped.length > 0) {
|
|
4559
|
+
report4.sections = [{ label: "Already present (pass --overwrite to replace)", items: skipped }];
|
|
4560
|
+
report4.nextSteps.push(
|
|
4561
|
+
`Re-add an existing component with: vela ui add --overwrite ${skipped[0]}`
|
|
4562
|
+
);
|
|
4563
|
+
}
|
|
4564
|
+
return report4;
|
|
4565
|
+
}
|
|
4566
|
+
|
|
4567
|
+
// src/commands/ui/add.ts
|
|
4568
|
+
var add = new Command41("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(
|
|
4569
|
+
(components, options) => runCommand(async () => {
|
|
4441
4570
|
const { workspaceRootDir } = await getWorkspace();
|
|
4442
|
-
const
|
|
4443
|
-
|
|
4444
|
-
"shadcn-svelte",
|
|
4445
|
-
"add",
|
|
4446
|
-
...components
|
|
4447
|
-
]);
|
|
4448
|
-
if (!resolved) {
|
|
4449
|
-
throw new Error(`Unable to resolve execute command for ${packageManager}`);
|
|
4450
|
-
}
|
|
4451
|
-
const args = [...resolved.args];
|
|
4452
|
-
if (packageManager === "npm") args.unshift("--yes");
|
|
4571
|
+
const log43 = p24.taskLog({ title: "Adding UI components..." });
|
|
4572
|
+
let outcome;
|
|
4453
4573
|
try {
|
|
4454
|
-
await
|
|
4455
|
-
|
|
4456
|
-
|
|
4574
|
+
outcome = await installComponents({
|
|
4575
|
+
root: workspaceRootDir,
|
|
4576
|
+
components,
|
|
4577
|
+
overwrite: options.overwrite,
|
|
4578
|
+
logger: { info: (message) => log43.message(message) }
|
|
4457
4579
|
});
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4580
|
+
log43.success("UI components ready");
|
|
4581
|
+
} catch (e) {
|
|
4582
|
+
log43.error("Could not add UI components");
|
|
4583
|
+
throw e;
|
|
4584
|
+
}
|
|
4585
|
+
reportResult(uiAddReport(components, outcome));
|
|
4586
|
+
}, "Failed to add UI components.")
|
|
4587
|
+
);
|
|
4588
|
+
|
|
4589
|
+
// src/commands/ui/base.ts
|
|
4590
|
+
import { Command as Command42 } from "commander";
|
|
4591
|
+
import * as p25 from "@clack/prompts";
|
|
4592
|
+
import { applyBaseColor } from "@velastack/patterns";
|
|
4593
|
+
var base = new Command42("base").description("change the base (gray) palette").argument("<color>", `base color to use (${BASE_COLORS.join(", ")})`).configureHelp(helpConfig).action(
|
|
4594
|
+
(color) => runCommand(async () => {
|
|
4595
|
+
const { workspaceRootDir } = await getWorkspace();
|
|
4596
|
+
const log43 = p25.taskLog({ title: `Applying the ${color} palette...` });
|
|
4597
|
+
let outcome;
|
|
4598
|
+
try {
|
|
4599
|
+
outcome = await applyBaseColor({ root: workspaceRootDir, color });
|
|
4600
|
+
log43.success("Palette applied");
|
|
4601
|
+
} catch (e) {
|
|
4602
|
+
log43.error("Could not change the base color");
|
|
4603
|
+
throw e;
|
|
4464
4604
|
}
|
|
4465
4605
|
reportResult({
|
|
4466
|
-
summary: `
|
|
4467
|
-
|
|
4606
|
+
summary: `Set base color to ${outcome.baseColor}.`,
|
|
4607
|
+
filesModified: outcome.filesModified,
|
|
4468
4608
|
nextSteps: [
|
|
4469
|
-
|
|
4470
|
-
"
|
|
4471
|
-
"
|
|
4609
|
+
"Run your dev server to preview the new palette.",
|
|
4610
|
+
"Run `vela ui theme <accent>` to put an accent color on top of it.",
|
|
4611
|
+
"Tweak individual CSS variables in src/app.css if you want to customize the theme further."
|
|
4472
4612
|
]
|
|
4473
4613
|
});
|
|
4474
|
-
}, "Failed to
|
|
4614
|
+
}, "Failed to change base color.")
|
|
4475
4615
|
);
|
|
4476
4616
|
|
|
4477
|
-
// src/commands/ui/
|
|
4478
|
-
import
|
|
4479
|
-
import
|
|
4480
|
-
import {
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4617
|
+
// src/commands/ui/list.ts
|
|
4618
|
+
import { Command as Command43 } from "commander";
|
|
4619
|
+
import * as p26 from "@clack/prompts";
|
|
4620
|
+
import { listComponents } from "@velastack/patterns";
|
|
4621
|
+
|
|
4622
|
+
// src/lib/ui-list.ts
|
|
4623
|
+
function uiListReport(result) {
|
|
4624
|
+
const installed = new Set(result.installed);
|
|
4625
|
+
const registryUi = result.registry.filter((item) => item.type === "registry:ui").map((item) => item.name).sort();
|
|
4626
|
+
const sections = [
|
|
4627
|
+
{ label: `Installed (${result.installed.length})`, items: result.installed },
|
|
4628
|
+
{
|
|
4629
|
+
label: "Vela components",
|
|
4630
|
+
items: result.custom.map((name) => installed.has(name) ? `${name} (installed)` : name)
|
|
4631
|
+
}
|
|
4632
|
+
];
|
|
4633
|
+
if (!result.registryUnavailable) {
|
|
4634
|
+
sections.push({
|
|
4635
|
+
label: `shadcn-svelte ${result.style} (${registryUi.length})`,
|
|
4636
|
+
items: registryUi
|
|
4637
|
+
});
|
|
4486
4638
|
}
|
|
4487
|
-
return
|
|
4639
|
+
return {
|
|
4640
|
+
summary: `UI components for the ${result.style} style.`,
|
|
4641
|
+
sections,
|
|
4642
|
+
nextSteps: [
|
|
4643
|
+
"Add one with: vela ui add <component>",
|
|
4644
|
+
"Switch styles with `vela ui style <name>`, or the palette with `vela ui base <color>`."
|
|
4645
|
+
]
|
|
4646
|
+
};
|
|
4488
4647
|
}
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4648
|
+
|
|
4649
|
+
// src/commands/ui/list.ts
|
|
4650
|
+
var list = new Command43("list").description("list installed ui components, vela components and the style registry").option("--json", "print the result as JSON", false).configureHelp(helpConfig).action(
|
|
4651
|
+
(options) => runCommand(async () => {
|
|
4652
|
+
const { workspaceRootDir } = await getWorkspace();
|
|
4653
|
+
if (options.json) {
|
|
4654
|
+
const result2 = await listComponents({ root: workspaceRootDir });
|
|
4655
|
+
console.log(JSON.stringify(result2, null, 2));
|
|
4656
|
+
return;
|
|
4657
|
+
}
|
|
4658
|
+
const spinner7 = p26.spinner();
|
|
4659
|
+
spinner7.start("Reading the registry...");
|
|
4660
|
+
let result;
|
|
4661
|
+
try {
|
|
4662
|
+
result = await listComponents({ root: workspaceRootDir });
|
|
4663
|
+
} catch (e) {
|
|
4664
|
+
spinner7.stop("Could not list UI components");
|
|
4665
|
+
throw e;
|
|
4666
|
+
}
|
|
4667
|
+
spinner7.stop(`Read the ${result.style} registry`);
|
|
4668
|
+
reportResult(uiListReport(result));
|
|
4669
|
+
if (result.registryUnavailable) {
|
|
4670
|
+
p26.log.warn(`${result.registryUnavailable}
|
|
4671
|
+
Registry components are not listed.`);
|
|
4672
|
+
}
|
|
4673
|
+
}, "Failed to list UI components.")
|
|
4674
|
+
);
|
|
4675
|
+
|
|
4676
|
+
// src/commands/ui/style.ts
|
|
4677
|
+
import { Command as Command44 } from "commander";
|
|
4678
|
+
import * as p27 from "@clack/prompts";
|
|
4679
|
+
import { switchStyle } from "@velastack/patterns";
|
|
4680
|
+
|
|
4681
|
+
// src/lib/ui-style.ts
|
|
4682
|
+
function uiStyleReport(result) {
|
|
4683
|
+
const nextSteps = ["Run your dev server to see the new style."];
|
|
4684
|
+
if (result.reinstalled.length > 0) {
|
|
4685
|
+
nextSteps.push(
|
|
4686
|
+
"Check `git diff src/lib/components/ui` for local edits the re-added components replaced."
|
|
4687
|
+
);
|
|
4494
4688
|
}
|
|
4495
|
-
|
|
4689
|
+
nextSteps.push(...result.hints);
|
|
4690
|
+
nextSteps.push(
|
|
4691
|
+
"Run `vela ui base <color>` or `vela ui theme <accent>` to adjust the palette.",
|
|
4692
|
+
"Run `vela ui list` to see what the new style offers."
|
|
4693
|
+
);
|
|
4694
|
+
return {
|
|
4695
|
+
summary: `Switched to the ${result.style} style.`,
|
|
4696
|
+
componentsAdded: result.reinstalled,
|
|
4697
|
+
filesModified: result.filesModified,
|
|
4698
|
+
packagesInstalled: result.packages,
|
|
4699
|
+
nextSteps
|
|
4700
|
+
};
|
|
4496
4701
|
}
|
|
4497
|
-
function applyTheme(appCss, selectors) {
|
|
4498
|
-
let out = appCss;
|
|
4499
|
-
out = out.match(/:root\s*{[^}]*}/) ? out.replace(/:root\s*{[^}]*}/, selectors.root) : `${selectors.root}
|
|
4500
4702
|
|
|
4501
|
-
|
|
4502
|
-
|
|
4703
|
+
// src/commands/ui/style.ts
|
|
4704
|
+
var style = new Command44("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(
|
|
4705
|
+
(name, options) => runCommand(async () => {
|
|
4706
|
+
const { workspaceRootDir } = await getWorkspace();
|
|
4707
|
+
const spinner7 = p27.spinner();
|
|
4708
|
+
spinner7.start(`Reading the ${name} registry...`);
|
|
4709
|
+
let log43;
|
|
4710
|
+
let outcome;
|
|
4711
|
+
try {
|
|
4712
|
+
outcome = await switchStyle({
|
|
4713
|
+
root: workspaceRootDir,
|
|
4714
|
+
style: name,
|
|
4715
|
+
font: options.font,
|
|
4716
|
+
logger: { info: (message) => log43?.message(message) },
|
|
4717
|
+
confirm: async (components) => {
|
|
4718
|
+
spinner7.stop(`Read the ${name} registry`);
|
|
4719
|
+
if (components.length > 0) {
|
|
4720
|
+
p27.log.info(
|
|
4721
|
+
`Re-adds ${components.length} component(s) from the ${name} registry; local edits to their files are lost:
|
|
4722
|
+
${components.map((c) => `- ${c}`).join("\n")}`
|
|
4723
|
+
);
|
|
4724
|
+
} else {
|
|
4725
|
+
p27.log.info(
|
|
4726
|
+
`No installed component comes from the registry; only the config changes.`
|
|
4727
|
+
);
|
|
4728
|
+
}
|
|
4729
|
+
if (!options.yes) {
|
|
4730
|
+
const ok = await p27.confirm({ message: `Switch to ${name}?`, initialValue: false });
|
|
4731
|
+
if (p27.isCancel(ok) || !ok) return false;
|
|
4732
|
+
}
|
|
4733
|
+
log43 = p27.taskLog({ title: `Switching to the ${name} style...` });
|
|
4734
|
+
return true;
|
|
4735
|
+
}
|
|
4736
|
+
});
|
|
4737
|
+
} catch (e) {
|
|
4738
|
+
spinner7.stop(`Could not switch to ${name}`);
|
|
4739
|
+
log43?.error("Could not switch style");
|
|
4740
|
+
throw e;
|
|
4741
|
+
}
|
|
4742
|
+
spinner7.stop(`Read the ${name} registry`);
|
|
4743
|
+
if (outcome.status === "unchanged") {
|
|
4744
|
+
p27.log.info(`Already using the ${name} style.`);
|
|
4745
|
+
return;
|
|
4746
|
+
}
|
|
4747
|
+
if (outcome.status === "cancelled") {
|
|
4748
|
+
p27.cancel("Operation cancelled.");
|
|
4749
|
+
return;
|
|
4750
|
+
}
|
|
4751
|
+
log43?.success("Style switched");
|
|
4752
|
+
reportResult(uiStyleReport(outcome));
|
|
4753
|
+
}, "Failed to switch style.")
|
|
4754
|
+
);
|
|
4503
4755
|
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
}
|
|
4511
|
-
return value;
|
|
4512
|
-
}).configureHelp(helpConfig).action(
|
|
4513
|
-
(color) => runCommand(async () => {
|
|
4756
|
+
// src/commands/ui/theme.ts
|
|
4757
|
+
import { Command as Command45 } from "commander";
|
|
4758
|
+
import * as p28 from "@clack/prompts";
|
|
4759
|
+
import { applyTheme } from "@velastack/patterns";
|
|
4760
|
+
var theme = new Command45("theme").description("change the accent color, keeping the base palette").argument("<accent>", `accent to use (${THEMES.join(", ")})`).configureHelp(helpConfig).action(
|
|
4761
|
+
(accent) => runCommand(async () => {
|
|
4514
4762
|
const { workspaceRootDir } = await getWorkspace();
|
|
4515
|
-
const
|
|
4516
|
-
|
|
4517
|
-
|
|
4763
|
+
const log43 = p28.taskLog({ title: `Applying the ${accent} accent...` });
|
|
4764
|
+
let outcome;
|
|
4765
|
+
try {
|
|
4766
|
+
outcome = await applyTheme({ root: workspaceRootDir, theme: accent });
|
|
4767
|
+
log43.success("Accent applied");
|
|
4768
|
+
} catch (e) {
|
|
4769
|
+
log43.error("Could not change the accent");
|
|
4770
|
+
throw e;
|
|
4518
4771
|
}
|
|
4519
|
-
const themeContent = fs21.readFileSync(findThemeFile(color), "utf8");
|
|
4520
|
-
const selectors = extractSelectors(themeContent);
|
|
4521
|
-
const appCss = fs21.readFileSync(appCssPath, "utf8");
|
|
4522
|
-
fs21.writeFileSync(appCssPath, applyTheme(appCss, selectors));
|
|
4523
4772
|
reportResult({
|
|
4524
|
-
summary: `Set
|
|
4525
|
-
filesModified:
|
|
4773
|
+
summary: `Set accent to ${outcome.theme} on the ${outcome.baseColor} palette.`,
|
|
4774
|
+
filesModified: outcome.filesModified,
|
|
4526
4775
|
nextSteps: [
|
|
4527
|
-
"Run your dev server to preview the new
|
|
4776
|
+
"Run your dev server to preview the new accent.",
|
|
4777
|
+
"Run `vela ui base <color>` to change the palette underneath (this resets the accent).",
|
|
4528
4778
|
"Tweak individual CSS variables in src/app.css if you want to customize the theme further."
|
|
4529
4779
|
]
|
|
4530
4780
|
});
|
|
4531
|
-
}, "Failed to change
|
|
4781
|
+
}, "Failed to change accent.")
|
|
4532
4782
|
);
|
|
4533
4783
|
|
|
4534
4784
|
// src/commands/ui.ts
|
|
4535
|
-
var ui = new
|
|
4785
|
+
var ui = new Command46("ui").description("generate ui components").configureHelp(helpConfig).addCommand(add).addCommand(list).addCommand(style).addCommand(base).addCommand(theme);
|
|
4536
4786
|
|
|
4537
4787
|
// src/commands/legal.ts
|
|
4538
|
-
import { Command as
|
|
4788
|
+
import { Command as Command49 } from "commander";
|
|
4539
4789
|
|
|
4540
4790
|
// src/commands/legal/terms.ts
|
|
4541
|
-
import
|
|
4791
|
+
import fs23 from "node:fs";
|
|
4542
4792
|
import path21 from "node:path";
|
|
4543
|
-
import { Command as
|
|
4544
|
-
import * as
|
|
4793
|
+
import { Command as Command47 } from "commander";
|
|
4794
|
+
import * as p30 from "@clack/prompts";
|
|
4545
4795
|
|
|
4546
4796
|
// src/commands/legal/shared.ts
|
|
4547
4797
|
import process16 from "node:process";
|
|
4548
|
-
import * as
|
|
4798
|
+
import * as p29 from "@clack/prompts";
|
|
4549
4799
|
var sharedFields = {
|
|
4550
|
-
websiteUrl: () =>
|
|
4800
|
+
websiteUrl: () => p29.text({
|
|
4551
4801
|
message: "What is your website URL?",
|
|
4552
4802
|
placeholder: "http://www.mysite.com",
|
|
4553
4803
|
validate: (value) => {
|
|
@@ -4556,7 +4806,7 @@ var sharedFields = {
|
|
|
4556
4806
|
}
|
|
4557
4807
|
}
|
|
4558
4808
|
}),
|
|
4559
|
-
websiteName: () =>
|
|
4809
|
+
websiteName: () => p29.text({
|
|
4560
4810
|
message: "What is your website name?",
|
|
4561
4811
|
placeholder: "My Site",
|
|
4562
4812
|
validate: (value) => {
|
|
@@ -4565,7 +4815,7 @@ var sharedFields = {
|
|
|
4565
4815
|
}
|
|
4566
4816
|
}
|
|
4567
4817
|
}),
|
|
4568
|
-
entityType: () =>
|
|
4818
|
+
entityType: () => p29.select({
|
|
4569
4819
|
message: "Entity type",
|
|
4570
4820
|
options: [
|
|
4571
4821
|
{
|
|
@@ -4576,7 +4826,7 @@ var sharedFields = {
|
|
|
4576
4826
|
{ value: "individual", label: "I'm an Individual" }
|
|
4577
4827
|
]
|
|
4578
4828
|
}),
|
|
4579
|
-
businessName: ({ results }) => results?.entityType === "business" ?
|
|
4829
|
+
businessName: ({ results }) => results?.entityType === "business" ? p29.text({
|
|
4580
4830
|
message: "What is the name of the business?",
|
|
4581
4831
|
placeholder: "My Company LLC",
|
|
4582
4832
|
validate: (value) => {
|
|
@@ -4585,7 +4835,7 @@ var sharedFields = {
|
|
|
4585
4835
|
}
|
|
4586
4836
|
}
|
|
4587
4837
|
}) : void 0,
|
|
4588
|
-
businessAddress: ({ results }) => results?.entityType === "business" ?
|
|
4838
|
+
businessAddress: ({ results }) => results?.entityType === "business" ? p29.text({
|
|
4589
4839
|
message: "What is the address of the business?",
|
|
4590
4840
|
placeholder: "1 Cupertino, CA 95014",
|
|
4591
4841
|
validate: (value) => {
|
|
@@ -4594,7 +4844,7 @@ var sharedFields = {
|
|
|
4594
4844
|
}
|
|
4595
4845
|
}
|
|
4596
4846
|
}) : void 0,
|
|
4597
|
-
country: () =>
|
|
4847
|
+
country: () => p29.text({
|
|
4598
4848
|
message: "Enter the country",
|
|
4599
4849
|
validate: (value) => {
|
|
4600
4850
|
if (!value) {
|
|
@@ -4602,7 +4852,7 @@ var sharedFields = {
|
|
|
4602
4852
|
}
|
|
4603
4853
|
}
|
|
4604
4854
|
}),
|
|
4605
|
-
state: () =>
|
|
4855
|
+
state: () => p29.text({
|
|
4606
4856
|
message: "Enter the state",
|
|
4607
4857
|
validate: (value) => {
|
|
4608
4858
|
if (!value) {
|
|
@@ -4612,11 +4862,11 @@ var sharedFields = {
|
|
|
4612
4862
|
})
|
|
4613
4863
|
};
|
|
4614
4864
|
var onCancel = () => {
|
|
4615
|
-
|
|
4865
|
+
p29.cancel("Operation cancelled.");
|
|
4616
4866
|
process16.exit(0);
|
|
4617
4867
|
};
|
|
4618
4868
|
async function contactMethods(type) {
|
|
4619
|
-
const selection = await
|
|
4869
|
+
const selection = await p29.multiselect({
|
|
4620
4870
|
message: `How can users contact you for any questions regarding your ${type === "privacy" ? "Privacy Policy" : "Terms & Conditions"}? Check all that apply`,
|
|
4621
4871
|
options: [
|
|
4622
4872
|
{ value: "email", label: "By email" },
|
|
@@ -4625,11 +4875,11 @@ async function contactMethods(type) {
|
|
|
4625
4875
|
{ value: "mail", label: "By sending post mail" }
|
|
4626
4876
|
]
|
|
4627
4877
|
});
|
|
4628
|
-
if (
|
|
4878
|
+
if (p29.isCancel(selection)) onCancel();
|
|
4629
4879
|
const contact = selection;
|
|
4630
4880
|
const details = {};
|
|
4631
4881
|
if (contact.includes("email")) {
|
|
4632
|
-
const email3 = await
|
|
4882
|
+
const email3 = await p29.text({
|
|
4633
4883
|
message: "What's the email?",
|
|
4634
4884
|
placeholder: "office@mycompany.com",
|
|
4635
4885
|
validate: (value) => {
|
|
@@ -4638,11 +4888,11 @@ async function contactMethods(type) {
|
|
|
4638
4888
|
}
|
|
4639
4889
|
}
|
|
4640
4890
|
});
|
|
4641
|
-
if (
|
|
4891
|
+
if (p29.isCancel(email3)) onCancel();
|
|
4642
4892
|
details.email = email3;
|
|
4643
4893
|
}
|
|
4644
4894
|
if (contact.includes("page")) {
|
|
4645
|
-
const page = await
|
|
4895
|
+
const page = await p29.text({
|
|
4646
4896
|
message: "What's the link?",
|
|
4647
4897
|
placeholder: "http://www.mycompany.com/contact",
|
|
4648
4898
|
validate: (value) => {
|
|
@@ -4651,11 +4901,11 @@ async function contactMethods(type) {
|
|
|
4651
4901
|
}
|
|
4652
4902
|
}
|
|
4653
4903
|
});
|
|
4654
|
-
if (
|
|
4904
|
+
if (p29.isCancel(page)) onCancel();
|
|
4655
4905
|
details.page = page;
|
|
4656
4906
|
}
|
|
4657
4907
|
if (contact.includes("phone")) {
|
|
4658
|
-
const phone = await
|
|
4908
|
+
const phone = await p29.text({
|
|
4659
4909
|
message: "What's the phone number?",
|
|
4660
4910
|
placeholder: "408.996.1010",
|
|
4661
4911
|
validate: (value) => {
|
|
@@ -4664,11 +4914,11 @@ async function contactMethods(type) {
|
|
|
4664
4914
|
}
|
|
4665
4915
|
}
|
|
4666
4916
|
});
|
|
4667
|
-
if (
|
|
4917
|
+
if (p29.isCancel(phone)) onCancel();
|
|
4668
4918
|
details.phone = phone;
|
|
4669
4919
|
}
|
|
4670
4920
|
if (contact.includes("mail")) {
|
|
4671
|
-
const address = await
|
|
4921
|
+
const address = await p29.text({
|
|
4672
4922
|
message: "What's the address?",
|
|
4673
4923
|
placeholder: "767 Fifth Avenue New York, NY 10153, United States",
|
|
4674
4924
|
validate: (value) => {
|
|
@@ -4677,14 +4927,14 @@ async function contactMethods(type) {
|
|
|
4677
4927
|
}
|
|
4678
4928
|
}
|
|
4679
4929
|
});
|
|
4680
|
-
if (
|
|
4930
|
+
if (p29.isCancel(address)) onCancel();
|
|
4681
4931
|
details.address = address;
|
|
4682
4932
|
}
|
|
4683
4933
|
return { methods: contact, details };
|
|
4684
4934
|
}
|
|
4685
4935
|
var escapeHtml = (value) => String(value ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
4686
4936
|
var applyTypography = (html) => html.replaceAll("<p>", '<p class="text-base leading-7">').replaceAll("<ul>", '<ul class="list-disc pl-6 space-y-1 text-base leading-7">').replaceAll("<h3>", '<h3 class="text-lg font-semibold">').replaceAll("<h4>", '<h4 class="font-semibold">');
|
|
4687
|
-
var
|
|
4937
|
+
var list2 = (items) => items.length ? `<ul class="list-disc pl-6 space-y-1 text-base leading-7">${items.map((i) => `<li>${i}</li>`).join("")}</ul>` : "";
|
|
4688
4938
|
var titledSection = (title, body) => body ? `<section class="space-y-3"><h2 class="text-xl font-semibold">${escapeHtml(
|
|
4689
4939
|
title
|
|
4690
4940
|
)}</h2>${applyTypography(body)}</section>` : "";
|
|
@@ -4893,7 +5143,7 @@ var sectionSubscriptions = (a) => {
|
|
|
4893
5143
|
const autoRenewalNotice = `<p><strong>Auto-renewal disclosure (California, New York, and other states).</strong> In accordance with the California Automatic Renewal Law (Cal. Bus. & Prof. Code § 17600 et seq.), New York General Business Law § 527-a, and similar laws, you acknowledge that your subscription will continue until cancelled, that we will charge the payment method you provided on a recurring basis at the frequency described at the time of purchase, that your subscription will automatically renew unless you cancel, and that you may cancel at any time using the cancellation methods described above.</p>`;
|
|
4894
5144
|
return titledSection(
|
|
4895
5145
|
"Subscriptions and Automatic Renewal",
|
|
4896
|
-
`<p>Some parts of the Service may be billed on a subscription basis.</p>${
|
|
5146
|
+
`<p>Some parts of the Service may be billed on a subscription basis.</p>${list2(bullets)}${autoRenewalNotice}`
|
|
4897
5147
|
);
|
|
4898
5148
|
};
|
|
4899
5149
|
var sectionPromotions = () => titledSection(
|
|
@@ -4902,7 +5152,7 @@ var sectionPromotions = () => titledSection(
|
|
|
4902
5152
|
);
|
|
4903
5153
|
var sectionProhibited = () => titledSection(
|
|
4904
5154
|
"Prohibited Uses",
|
|
4905
|
-
`<p>You agree not to use the Service:</p>${
|
|
5155
|
+
`<p>You agree not to use the Service:</p>${list2([
|
|
4906
5156
|
"In any way that violates any applicable national, state, local, or international law or regulation (including, without limitation, any laws regarding the export of data or software to and from the United States or other countries).",
|
|
4907
5157
|
"For the purpose of exploiting, harming, or attempting to exploit or harm minors in any way by exposing them to inappropriate content, asking for personally identifiable information, or otherwise.",
|
|
4908
5158
|
'To transmit, or procure the sending of, any advertising or promotional material, including any "junk mail," "chain letter," "spam," or any other similar solicitation, without our prior written consent.',
|
|
@@ -5032,7 +5282,7 @@ var sectionContact = (a) => {
|
|
|
5032
5282
|
if (a.contact?.methods?.includes("mail") && a.contact.details.address) {
|
|
5033
5283
|
items.push(`By mail: ${escapeHtml(a.contact.details.address)}`);
|
|
5034
5284
|
}
|
|
5035
|
-
return `<section class="space-y-3"><h2 class="text-xl font-semibold">Contact Us</h2><p class="text-base leading-7">If you have any questions about these Terms, you can contact us:</p>${
|
|
5285
|
+
return `<section class="space-y-3"><h2 class="text-xl font-semibold">Contact Us</h2><p class="text-base leading-7">If you have any questions about these Terms, you can contact us:</p>${list2(items)}</section>`;
|
|
5036
5286
|
};
|
|
5037
5287
|
var generateTermsHtml = (answers) => {
|
|
5038
5288
|
const c = compute(answers);
|
|
@@ -5073,7 +5323,7 @@ var generateTermsHtml = (answers) => {
|
|
|
5073
5323
|
};
|
|
5074
5324
|
async function termsAction() {
|
|
5075
5325
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
5076
|
-
const core = await
|
|
5326
|
+
const core = await p30.group(
|
|
5077
5327
|
{
|
|
5078
5328
|
websiteUrl: sharedFields.websiteUrl,
|
|
5079
5329
|
websiteName: sharedFields.websiteName,
|
|
@@ -5085,25 +5335,25 @@ async function termsAction() {
|
|
|
5085
5335
|
},
|
|
5086
5336
|
{ onCancel }
|
|
5087
5337
|
);
|
|
5088
|
-
const accounts = await
|
|
5338
|
+
const accounts = await p30.select({
|
|
5089
5339
|
message: "Can users create accounts?",
|
|
5090
5340
|
options: [
|
|
5091
5341
|
{ value: "yes", label: "Yes, users can create accounts" },
|
|
5092
5342
|
{ value: "no", label: "No" }
|
|
5093
5343
|
]
|
|
5094
5344
|
});
|
|
5095
|
-
if (
|
|
5096
|
-
const userContent = await
|
|
5345
|
+
if (p30.isCancel(accounts)) onCancel();
|
|
5346
|
+
const userContent = await p30.select({
|
|
5097
5347
|
message: "Can users create and/or upload content (ie. text, images)?",
|
|
5098
5348
|
options: [
|
|
5099
5349
|
{ value: "yes", label: "Yes, users can create and/or upload content" },
|
|
5100
5350
|
{ value: "no", label: "No" }
|
|
5101
5351
|
]
|
|
5102
5352
|
});
|
|
5103
|
-
if (
|
|
5353
|
+
if (p30.isCancel(userContent)) onCancel();
|
|
5104
5354
|
let infringementEmail;
|
|
5105
5355
|
if (userContent === "yes") {
|
|
5106
|
-
const email3 = await
|
|
5356
|
+
const email3 = await p30.text({
|
|
5107
5357
|
message: "What's the email address where you will receive infringements notices?",
|
|
5108
5358
|
placeholder: "dmca@website.com",
|
|
5109
5359
|
validate: (value) => {
|
|
@@ -5112,10 +5362,10 @@ async function termsAction() {
|
|
|
5112
5362
|
}
|
|
5113
5363
|
}
|
|
5114
5364
|
});
|
|
5115
|
-
if (
|
|
5365
|
+
if (p30.isCancel(email3)) onCancel();
|
|
5116
5366
|
infringementEmail = email3;
|
|
5117
5367
|
}
|
|
5118
|
-
const canBuyGoods = await
|
|
5368
|
+
const canBuyGoods = await p30.select({
|
|
5119
5369
|
message: "Can users buy goods (products, items)?",
|
|
5120
5370
|
options: [
|
|
5121
5371
|
{
|
|
@@ -5125,28 +5375,28 @@ async function termsAction() {
|
|
|
5125
5375
|
{ value: "no", label: "No" }
|
|
5126
5376
|
]
|
|
5127
5377
|
});
|
|
5128
|
-
if (
|
|
5129
|
-
const subscriptions2 = await
|
|
5378
|
+
if (p30.isCancel(canBuyGoods)) onCancel();
|
|
5379
|
+
const subscriptions2 = await p30.select({
|
|
5130
5380
|
message: "Do you offer subscription plans?",
|
|
5131
5381
|
options: [
|
|
5132
5382
|
{ value: "yes", label: "Yes, we offer subscription plans" },
|
|
5133
5383
|
{ value: "no", label: "No" }
|
|
5134
5384
|
]
|
|
5135
5385
|
});
|
|
5136
|
-
if (
|
|
5386
|
+
if (p30.isCancel(subscriptions2)) onCancel();
|
|
5137
5387
|
let freeTrial;
|
|
5138
5388
|
if (subscriptions2 === "yes") {
|
|
5139
|
-
const ft = await
|
|
5389
|
+
const ft = await p30.select({
|
|
5140
5390
|
message: "Do you offer a free trial?",
|
|
5141
5391
|
options: [
|
|
5142
5392
|
{ value: "yes", label: "Yes" },
|
|
5143
5393
|
{ value: "no", label: "No" }
|
|
5144
5394
|
]
|
|
5145
5395
|
});
|
|
5146
|
-
if (
|
|
5396
|
+
if (p30.isCancel(ft)) onCancel();
|
|
5147
5397
|
freeTrial = ft;
|
|
5148
5398
|
}
|
|
5149
|
-
const exclusiveContent = await
|
|
5399
|
+
const exclusiveContent = await p30.select({
|
|
5150
5400
|
message: "Do you want to make it clear that your own content & trademarks are your exclusive property?",
|
|
5151
5401
|
options: [
|
|
5152
5402
|
{
|
|
@@ -5156,24 +5406,24 @@ async function termsAction() {
|
|
|
5156
5406
|
{ value: "no", label: "No" }
|
|
5157
5407
|
]
|
|
5158
5408
|
});
|
|
5159
|
-
if (
|
|
5160
|
-
const feedbackReuse = await
|
|
5409
|
+
if (p30.isCancel(exclusiveContent)) onCancel();
|
|
5410
|
+
const feedbackReuse = await p30.select({
|
|
5161
5411
|
message: "If users provide you feedback & suggestions, do you want to use this feedback without compensation or credits given?",
|
|
5162
5412
|
options: [
|
|
5163
5413
|
{ value: "yes", label: "Yes, we may implement any feedback or suggestions we receive" },
|
|
5164
5414
|
{ value: "no", label: "No" }
|
|
5165
5415
|
]
|
|
5166
5416
|
});
|
|
5167
|
-
if (
|
|
5168
|
-
const promotions = await
|
|
5417
|
+
if (p30.isCancel(feedbackReuse)) onCancel();
|
|
5418
|
+
const promotions = await p30.select({
|
|
5169
5419
|
message: "Do you plan to offer promotions, contests, sweepstakes?",
|
|
5170
5420
|
options: [
|
|
5171
5421
|
{ value: "yes", label: "Yes, we may offer promotions, contests, sweepstakes" },
|
|
5172
5422
|
{ value: "no", label: "No" }
|
|
5173
5423
|
]
|
|
5174
5424
|
});
|
|
5175
|
-
if (
|
|
5176
|
-
const mobileAppRaw = await
|
|
5425
|
+
if (p30.isCancel(promotions)) onCancel();
|
|
5426
|
+
const mobileAppRaw = await p30.multiselect({
|
|
5177
5427
|
message: "Is the Service distributed through any mobile app stores? Check all that apply",
|
|
5178
5428
|
options: [
|
|
5179
5429
|
{ value: "apple", label: "Apple App Store" },
|
|
@@ -5181,7 +5431,7 @@ async function termsAction() {
|
|
|
5181
5431
|
],
|
|
5182
5432
|
required: false
|
|
5183
5433
|
});
|
|
5184
|
-
if (
|
|
5434
|
+
if (p30.isCancel(mobileAppRaw)) onCancel();
|
|
5185
5435
|
const mobileApp = mobileAppRaw ?? [];
|
|
5186
5436
|
const contact = await contactMethods("terms");
|
|
5187
5437
|
const html = generateTermsHtml({
|
|
@@ -5206,9 +5456,9 @@ async function termsAction() {
|
|
|
5206
5456
|
"+page.svelte"
|
|
5207
5457
|
);
|
|
5208
5458
|
const termsPageTs = path21.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5459
|
+
fs23.mkdirSync(path21.dirname(termsPage), { recursive: true });
|
|
5460
|
+
fs23.writeFileSync(termsPage, html);
|
|
5461
|
+
fs23.writeFileSync(
|
|
5212
5462
|
termsPageTs,
|
|
5213
5463
|
pageMetaTagsLoader("Terms of Service", `Terms of Service for ${core.websiteName}`)
|
|
5214
5464
|
);
|
|
@@ -5224,13 +5474,13 @@ async function termsAction() {
|
|
|
5224
5474
|
]
|
|
5225
5475
|
});
|
|
5226
5476
|
}
|
|
5227
|
-
var terms = new
|
|
5477
|
+
var terms = new Command47("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
|
|
5228
5478
|
|
|
5229
5479
|
// src/commands/legal/privacy.ts
|
|
5230
|
-
import
|
|
5480
|
+
import fs24 from "node:fs";
|
|
5231
5481
|
import path22 from "node:path";
|
|
5232
|
-
import { Command as
|
|
5233
|
-
import * as
|
|
5482
|
+
import { Command as Command48 } from "commander";
|
|
5483
|
+
import * as p31 from "@clack/prompts";
|
|
5234
5484
|
var mapLabels = {
|
|
5235
5485
|
personalInfo: {
|
|
5236
5486
|
email: "Email address",
|
|
@@ -5436,7 +5686,7 @@ var sectionCategoriesCollected = (a, c) => {
|
|
|
5436
5686
|
geolocation: pi.includes("address"),
|
|
5437
5687
|
sensitive: false
|
|
5438
5688
|
});
|
|
5439
|
-
const personal = `<h4 class="font-semibold">Personal Data</h4><p class="text-base leading-7">While using our Service, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you. Personally identifiable information may include, but is not limited to:</p>${
|
|
5689
|
+
const personal = `<h4 class="font-semibold">Personal Data</h4><p class="text-base leading-7">While using our Service, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you. Personally identifiable information may include, but is not limited to:</p>${list2(
|
|
5440
5690
|
(c.piLabels.length ? c.piLabels : [
|
|
5441
5691
|
"Email address",
|
|
5442
5692
|
"First name and last name",
|
|
@@ -5483,12 +5733,12 @@ var sectionUse = (a, c) => {
|
|
|
5483
5733
|
"<strong>For security and fraud prevention:</strong> to protect the rights, property, or safety of the Company, our users, or others, including detecting, preventing, and responding to fraud, abuse, security risks, and technical issues.",
|
|
5484
5734
|
"<strong>To comply with legal obligations:</strong> to comply with applicable laws, lawful requests, court orders, and legal processes."
|
|
5485
5735
|
);
|
|
5486
|
-
let body = `<p class="text-base leading-7">The Company may use Personal Data for the following purposes:</p>${
|
|
5736
|
+
let body = `<p class="text-base leading-7">The Company may use Personal Data for the following purposes:</p>${list2(useBullets)}`;
|
|
5487
5737
|
if (a.showAds === "yes") {
|
|
5488
|
-
body += `<p class="text-base leading-7">We may display advertising on the Service${c.adsPlatforms.length ? " using the following platforms:" : "."}</p>${c.adsPlatforms.length ?
|
|
5738
|
+
body += `<p class="text-base leading-7">We may display advertising on the Service${c.adsPlatforms.length ? " using the following platforms:" : "."}</p>${c.adsPlatforms.length ? list2(c.adsPlatforms.map(escapeHtml)) : ""}`;
|
|
5489
5739
|
}
|
|
5490
5740
|
if (a.canPay === "yes" && c.paymentProcessors.length) {
|
|
5491
|
-
body += `<p class="text-base leading-7">If you make purchases, we may process payments via the following providers, who handle your payment information in accordance with their own privacy policies:</p>${
|
|
5741
|
+
body += `<p class="text-base leading-7">If you make purchases, we may process payments via the following providers, who handle your payment information in accordance with their own privacy policies:</p>${list2(
|
|
5492
5742
|
c.paymentProcessors.map(escapeHtml)
|
|
5493
5743
|
)}`;
|
|
5494
5744
|
}
|
|
@@ -5506,7 +5756,7 @@ var sectionShare = (a, c) => {
|
|
|
5506
5756
|
body += "<li><strong>With your consent:</strong> for any other purpose with your consent.</li>";
|
|
5507
5757
|
body += "</ul>";
|
|
5508
5758
|
if (c.providers.length) {
|
|
5509
|
-
body += `<p>We currently use the following service providers:</p>${
|
|
5759
|
+
body += `<p>We currently use the following service providers:</p>${list2(c.providers.map(escapeHtml))}`;
|
|
5510
5760
|
}
|
|
5511
5761
|
void a;
|
|
5512
5762
|
return titledSection("How We Share or Disclose Personal Information", body);
|
|
@@ -5517,7 +5767,7 @@ var sectionSaleSharing = (a, c) => {
|
|
|
5517
5767
|
let recipients = "";
|
|
5518
5768
|
if (sells) {
|
|
5519
5769
|
const partners = [...c.adsPlatforms, ...c.remarketingPlatforms];
|
|
5520
|
-
const list_ = partners.length ? `<p>The categories of third parties to which we may disclose personal information for these purposes include advertising networks, analytics providers, and marketing partners, including:</p>${
|
|
5770
|
+
const list_ = partners.length ? `<p>The categories of third parties to which we may disclose personal information for these purposes include advertising networks, analytics providers, and marketing partners, including:</p>${list2(
|
|
5521
5771
|
partners.map(escapeHtml)
|
|
5522
5772
|
)}` : "<p>The categories of third parties to which we may disclose personal information for these purposes include advertising networks, analytics providers, social media platforms, and marketing partners.</p>";
|
|
5523
5773
|
recipients = list_;
|
|
@@ -5531,20 +5781,20 @@ var sectionSaleSharing = (a, c) => {
|
|
|
5531
5781
|
var sectionCookies = (a, c) => {
|
|
5532
5782
|
let body = `<p>We use Cookies and similar tracking technologies (such as web beacons, pixels, tags, scripts, and software development kits) to track the activity on our Service and hold certain information.</p><p>Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on your personal computer or mobile device when you go offline, while Session Cookies are deleted as soon as you close your web browser.</p><h4>Categories of Cookies We Use</h4><ul><li><strong>Strictly Necessary Cookies.</strong> These are required for the operation of the Service and to provide functionalities you request, such as logging in or accessing secure areas. The Service cannot function properly without them.</li><li><strong>Performance / Analytics Cookies.</strong> These cookies allow us to count visits and traffic sources so we can measure and improve the performance of the Service.</li><li><strong>Functional Cookies.</strong> These cookies enable enhanced functionality and personalization, such as remembering your preferences.</li><li><strong>Targeting / Advertising Cookies.</strong> These cookies may be set through our Service by our advertising partners to build a profile of your interests and show you relevant advertisements on other sites.</li><li><strong>Cookies Policy / Notice Acceptance Cookies.</strong> These cookies identify whether users have accepted the use of cookies on the Service.</li></ul>`;
|
|
5533
5783
|
if (a.tracking === "yes" && c.trackingTools.length) {
|
|
5534
|
-
body += `<p>We currently use the following analytics and tracking tools:</p>${
|
|
5784
|
+
body += `<p>We currently use the following analytics and tracking tools:</p>${list2(c.trackingTools.map(escapeHtml))}`;
|
|
5535
5785
|
}
|
|
5536
5786
|
body += `<h4>Your Choices About Cookies</h4><p>You can instruct your browser to refuse all Cookies or to indicate when a Cookie is being sent. If you do not accept Cookies, you may not be able to use some parts of our Service. You can also manage your cookie preferences through any cookie banner or preference center we provide.</p><h4>Do Not Track and Global Privacy Control</h4><p>Some browsers transmit "Do Not Track" ("DNT") or Global Privacy Control ("GPC") signals. There is currently no industry standard for responding to DNT signals, but we honor GPC signals as an opt-out of the sale or sharing of personal information for the browser or device on which the signal is detected, as required by applicable law.</p>`;
|
|
5537
5787
|
return titledSection("Tracking Technologies and Cookies", body);
|
|
5538
5788
|
};
|
|
5539
5789
|
var sectionEmail = (a, c) => a.sendEmails === "yes" ? titledSection(
|
|
5540
5790
|
"Email Communications",
|
|
5541
|
-
c.emailPlatforms.length ? `<p>We may send transactional, account-related, and (where you have opted in) marketing emails using the following platforms, who process email information on our behalf as service providers:</p>${
|
|
5791
|
+
c.emailPlatforms.length ? `<p>We may send transactional, account-related, and (where you have opted in) marketing emails using the following platforms, who process email information on our behalf as service providers:</p>${list2(
|
|
5542
5792
|
c.emailPlatforms.map(escapeHtml)
|
|
5543
5793
|
)}<p>You may unsubscribe from marketing emails at any time using the unsubscribe link included in those emails. Even if you unsubscribe from marketing emails, we may still send you transactional or account-related emails (for example, to confirm a purchase or notify you of changes to the Service).</p>` : "<p>We may send you transactional, account-related, and (where you have opted in) marketing emails. You may unsubscribe from marketing emails at any time using the unsubscribe link included in those emails.</p>"
|
|
5544
5794
|
) : "";
|
|
5545
5795
|
var sectionRemarketing = (a, c) => a.remarketing === "yes" ? titledSection(
|
|
5546
5796
|
"Remarketing and Targeted Advertising",
|
|
5547
|
-
c.remarketingPlatforms.length ? `<p>We use remarketing services to advertise to visitors of our Service on third-party websites and applications after they have visited the Service. These services may use cookies and similar technologies to deliver advertisements based on your past visits. The remarketing services we use include:</p>${
|
|
5797
|
+
c.remarketingPlatforms.length ? `<p>We use remarketing services to advertise to visitors of our Service on third-party websites and applications after they have visited the Service. These services may use cookies and similar technologies to deliver advertisements based on your past visits. The remarketing services we use include:</p>${list2(
|
|
5548
5798
|
c.remarketingPlatforms.map(escapeHtml)
|
|
5549
5799
|
)}<p>You may opt out of personalized advertising by visiting the Network Advertising Initiative opt-out page (<a href="https://www.networkadvertising.org/choices/" rel="external nofollow noopener" target="_blank">https://www.networkadvertising.org/choices/</a>), the Digital Advertising Alliance opt-out page (<a href="https://www.aboutads.info/choices/" rel="external nofollow noopener" target="_blank">https://www.aboutads.info/choices/</a>), or the European Interactive Digital Advertising Alliance (<a href="https://www.youronlinechoices.eu" rel="external nofollow noopener" target="_blank">https://www.youronlinechoices.eu</a>).</p>` : "<p>We use remarketing services to advertise to visitors of our Service on third-party websites and applications after they have visited the Service.</p>"
|
|
5550
5800
|
) : "";
|
|
@@ -5619,7 +5869,7 @@ var sectionContact2 = (a) => {
|
|
|
5619
5869
|
if (a.contact?.methods?.includes("mail") && a.contact.details.address) {
|
|
5620
5870
|
items.push(`By mail: ${escapeHtml(a.contact.details.address)}`);
|
|
5621
5871
|
}
|
|
5622
|
-
return `<section class="space-y-3"><h2 class="text-xl font-semibold">Contact Us</h2><p class="text-base leading-7">If you have any questions about this Privacy Policy, you can contact us:</p>${
|
|
5872
|
+
return `<section class="space-y-3"><h2 class="text-xl font-semibold">Contact Us</h2><p class="text-base leading-7">If you have any questions about this Privacy Policy, you can contact us:</p>${list2(items)}</section>`;
|
|
5623
5873
|
};
|
|
5624
5874
|
var generatePrivacyHtml = (answers) => {
|
|
5625
5875
|
const c = compute2(answers);
|
|
@@ -5648,12 +5898,12 @@ var generatePrivacyHtml = (answers) => {
|
|
|
5648
5898
|
return `<section data-role="content">${sections.join("")}</section>`;
|
|
5649
5899
|
};
|
|
5650
5900
|
async function promptWithCustom(message, options, customMessage) {
|
|
5651
|
-
const selection = await
|
|
5652
|
-
if (
|
|
5901
|
+
const selection = await p31.multiselect({ message, options });
|
|
5902
|
+
if (p31.isCancel(selection)) onCancel();
|
|
5653
5903
|
const values = selection;
|
|
5654
5904
|
if (values.includes("custom")) {
|
|
5655
|
-
const custom = await
|
|
5656
|
-
if (
|
|
5905
|
+
const custom = await p31.text({ message: customMessage });
|
|
5906
|
+
if (p31.isCancel(custom)) onCancel();
|
|
5657
5907
|
const idx = values.indexOf("custom");
|
|
5658
5908
|
if (idx !== -1) values.splice(idx, 1);
|
|
5659
5909
|
if (custom) values.push(String(custom));
|
|
@@ -5662,7 +5912,7 @@ async function promptWithCustom(message, options, customMessage) {
|
|
|
5662
5912
|
}
|
|
5663
5913
|
async function privacyAction() {
|
|
5664
5914
|
const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
|
|
5665
|
-
const core = await
|
|
5915
|
+
const core = await p31.group(
|
|
5666
5916
|
{
|
|
5667
5917
|
websiteUrl: sharedFields.websiteUrl,
|
|
5668
5918
|
websiteName: sharedFields.websiteName,
|
|
@@ -5674,7 +5924,7 @@ async function privacyAction() {
|
|
|
5674
5924
|
},
|
|
5675
5925
|
{ onCancel }
|
|
5676
5926
|
);
|
|
5677
|
-
const personalInfo = await
|
|
5927
|
+
const personalInfo = await p31.multiselect({
|
|
5678
5928
|
message: "What kind of personal information do you collect from users? Check all that apply",
|
|
5679
5929
|
options: [
|
|
5680
5930
|
{ value: "email", label: "Email address" },
|
|
@@ -5689,16 +5939,16 @@ async function privacyAction() {
|
|
|
5689
5939
|
],
|
|
5690
5940
|
required: false
|
|
5691
5941
|
});
|
|
5692
|
-
if (
|
|
5942
|
+
if (p31.isCancel(personalInfo)) onCancel();
|
|
5693
5943
|
const contact = await contactMethods("privacy");
|
|
5694
|
-
const tracking = await
|
|
5944
|
+
const tracking = await p31.select({
|
|
5695
5945
|
message: "Do you use tracking and/or analytics tools, such as Google Analytics?",
|
|
5696
5946
|
options: [
|
|
5697
5947
|
{ value: "yes", label: "Yes, we use Google Analytics or other related tools" },
|
|
5698
5948
|
{ value: "no", label: "No" }
|
|
5699
5949
|
]
|
|
5700
5950
|
});
|
|
5701
|
-
if (
|
|
5951
|
+
if (p31.isCancel(tracking)) onCancel();
|
|
5702
5952
|
let trackingTools;
|
|
5703
5953
|
if (tracking === "yes") {
|
|
5704
5954
|
trackingTools = await promptWithCustom(
|
|
@@ -5717,7 +5967,7 @@ async function privacyAction() {
|
|
|
5717
5967
|
"Enter your custom tracking/analytics tool name"
|
|
5718
5968
|
);
|
|
5719
5969
|
}
|
|
5720
|
-
const sendEmails = await
|
|
5970
|
+
const sendEmails = await p31.select({
|
|
5721
5971
|
message: "Do you send emails to users?",
|
|
5722
5972
|
options: [
|
|
5723
5973
|
{
|
|
@@ -5727,7 +5977,7 @@ async function privacyAction() {
|
|
|
5727
5977
|
{ value: "no", label: "No" }
|
|
5728
5978
|
]
|
|
5729
5979
|
});
|
|
5730
|
-
if (
|
|
5980
|
+
if (p31.isCancel(sendEmails)) onCancel();
|
|
5731
5981
|
let emailPlatforms;
|
|
5732
5982
|
if (sendEmails === "yes") {
|
|
5733
5983
|
emailPlatforms = await promptWithCustom(
|
|
@@ -5742,14 +5992,14 @@ async function privacyAction() {
|
|
|
5742
5992
|
"Enter your custom email platform"
|
|
5743
5993
|
);
|
|
5744
5994
|
}
|
|
5745
|
-
const showAds = await
|
|
5995
|
+
const showAds = await p31.select({
|
|
5746
5996
|
message: "Do you show ads?",
|
|
5747
5997
|
options: [
|
|
5748
5998
|
{ value: "yes", label: "Yes, we show ads" },
|
|
5749
5999
|
{ value: "no", label: "No" }
|
|
5750
6000
|
]
|
|
5751
6001
|
});
|
|
5752
|
-
if (
|
|
6002
|
+
if (p31.isCancel(showAds)) onCancel();
|
|
5753
6003
|
let adsPlatforms;
|
|
5754
6004
|
if (showAds === "yes") {
|
|
5755
6005
|
adsPlatforms = await promptWithCustom(
|
|
@@ -5772,7 +6022,7 @@ async function privacyAction() {
|
|
|
5772
6022
|
"Enter your custom ads platform"
|
|
5773
6023
|
);
|
|
5774
6024
|
}
|
|
5775
|
-
const canPay = await
|
|
6025
|
+
const canPay = await p31.select({
|
|
5776
6026
|
message: "Can users pay for products or services?",
|
|
5777
6027
|
options: [
|
|
5778
6028
|
{ value: "yes", label: "Yes, users can pay for our products/services" },
|
|
@@ -5782,7 +6032,7 @@ async function privacyAction() {
|
|
|
5782
6032
|
}
|
|
5783
6033
|
]
|
|
5784
6034
|
});
|
|
5785
|
-
if (
|
|
6035
|
+
if (p31.isCancel(canPay)) onCancel();
|
|
5786
6036
|
let paymentProcessors;
|
|
5787
6037
|
if (canPay === "yes") {
|
|
5788
6038
|
paymentProcessors = await promptWithCustom(
|
|
@@ -5813,14 +6063,14 @@ async function privacyAction() {
|
|
|
5813
6063
|
"Enter your custom payment processor/method"
|
|
5814
6064
|
);
|
|
5815
6065
|
}
|
|
5816
|
-
const remarketing = await
|
|
6066
|
+
const remarketing = await p31.select({
|
|
5817
6067
|
message: "Do you use remarketing services for marketing & advertising purposes?",
|
|
5818
6068
|
options: [
|
|
5819
6069
|
{ value: "yes", label: "Yes, we use remarketing services to advertise our business" },
|
|
5820
6070
|
{ value: "no", label: "No" }
|
|
5821
6071
|
]
|
|
5822
6072
|
});
|
|
5823
|
-
if (
|
|
6073
|
+
if (p31.isCancel(remarketing)) onCancel();
|
|
5824
6074
|
let remarketingPlatforms;
|
|
5825
6075
|
if (remarketing === "yes") {
|
|
5826
6076
|
remarketingPlatforms = await promptWithCustom(
|
|
@@ -5839,7 +6089,7 @@ async function privacyAction() {
|
|
|
5839
6089
|
"Enter your custom remarketing platform"
|
|
5840
6090
|
);
|
|
5841
6091
|
}
|
|
5842
|
-
const providersRaw = await
|
|
6092
|
+
const providersRaw = await p31.multiselect({
|
|
5843
6093
|
message: "Select if you use any of the following providers",
|
|
5844
6094
|
options: [
|
|
5845
6095
|
{ value: "recaptcha", label: "Invisible reCAPTCHA" },
|
|
@@ -5850,16 +6100,16 @@ async function privacyAction() {
|
|
|
5850
6100
|
],
|
|
5851
6101
|
required: false
|
|
5852
6102
|
});
|
|
5853
|
-
if (
|
|
6103
|
+
if (p31.isCancel(providersRaw)) onCancel();
|
|
5854
6104
|
const providers = providersRaw;
|
|
5855
6105
|
if (providers.includes("custom")) {
|
|
5856
|
-
const custom = await
|
|
5857
|
-
if (
|
|
6106
|
+
const custom = await p31.text({ message: "Enter your custom provider" });
|
|
6107
|
+
if (p31.isCancel(custom)) onCancel();
|
|
5858
6108
|
const idx = providers.indexOf("custom");
|
|
5859
6109
|
if (idx !== -1) providers.splice(idx, 1);
|
|
5860
6110
|
if (custom) providers.push(String(custom));
|
|
5861
6111
|
}
|
|
5862
|
-
const usStates = await
|
|
6112
|
+
const usStates = await p31.select({
|
|
5863
6113
|
message: "Include U.S. state privacy rights (CCPA/CPRA, VCDPA, CPA, CTDPA, UCPA, TX, OR, etc.)?",
|
|
5864
6114
|
options: [
|
|
5865
6115
|
{
|
|
@@ -5870,55 +6120,55 @@ async function privacyAction() {
|
|
|
5870
6120
|
],
|
|
5871
6121
|
initialValue: "yes"
|
|
5872
6122
|
});
|
|
5873
|
-
if (
|
|
5874
|
-
const gdpr = await
|
|
6123
|
+
if (p31.isCancel(usStates)) onCancel();
|
|
6124
|
+
const gdpr = await p31.select({
|
|
5875
6125
|
message: "Do you want your Privacy Policy to include GDPR / UK GDPR wording?",
|
|
5876
6126
|
options: [
|
|
5877
6127
|
{ value: "yes", label: "Yes. Include GDPR rights for EEA, UK, and Swiss residents" },
|
|
5878
6128
|
{ value: "no", label: "No" }
|
|
5879
6129
|
]
|
|
5880
6130
|
});
|
|
5881
|
-
if (
|
|
6131
|
+
if (p31.isCancel(gdpr)) onCancel();
|
|
5882
6132
|
let facebookFanPage = "no";
|
|
5883
6133
|
const facebookDetails = { name: "", url: "" };
|
|
5884
6134
|
if (gdpr === "yes") {
|
|
5885
|
-
const fan = await
|
|
6135
|
+
const fan = await p31.select({
|
|
5886
6136
|
message: "Do you have a Facebook Fan Page?",
|
|
5887
6137
|
options: [
|
|
5888
6138
|
{ value: "yes", label: "Yes, we have a Facebook Fan Page" },
|
|
5889
6139
|
{ value: "no", label: "No" }
|
|
5890
6140
|
]
|
|
5891
6141
|
});
|
|
5892
|
-
if (
|
|
6142
|
+
if (p31.isCancel(fan)) onCancel();
|
|
5893
6143
|
facebookFanPage = fan;
|
|
5894
6144
|
if (facebookFanPage === "yes") {
|
|
5895
|
-
const name = await
|
|
6145
|
+
const name = await p31.text({
|
|
5896
6146
|
message: "What is the name of the Facebook Fan Page?",
|
|
5897
6147
|
placeholder: "My Facebook Page"
|
|
5898
6148
|
});
|
|
5899
|
-
if (
|
|
6149
|
+
if (p31.isCancel(name)) onCancel();
|
|
5900
6150
|
facebookDetails.name = name;
|
|
5901
|
-
const url = await
|
|
6151
|
+
const url = await p31.text({
|
|
5902
6152
|
message: "What is the URL of the Facebook Fan Page?",
|
|
5903
6153
|
placeholder: "https://facebook.com/my-facebook-page"
|
|
5904
6154
|
});
|
|
5905
|
-
if (
|
|
6155
|
+
if (p31.isCancel(url)) onCancel();
|
|
5906
6156
|
facebookDetails.url = url;
|
|
5907
6157
|
}
|
|
5908
6158
|
}
|
|
5909
|
-
const kids = await
|
|
6159
|
+
const kids = await p31.select({
|
|
5910
6160
|
message: "Do you collect information from kids under the age of 13?",
|
|
5911
6161
|
options: [
|
|
5912
6162
|
{ value: "yes", label: "Yes. We collect information from children under the age of 13" },
|
|
5913
6163
|
{ value: "no", label: "No" }
|
|
5914
6164
|
]
|
|
5915
6165
|
});
|
|
5916
|
-
if (
|
|
5917
|
-
const retention = await
|
|
6166
|
+
if (p31.isCancel(kids)) onCancel();
|
|
6167
|
+
const retention = await p31.text({
|
|
5918
6168
|
message: "How long do you retain personal information? (leave blank for default wording)",
|
|
5919
6169
|
placeholder: "e.g. 12 months after account closure"
|
|
5920
6170
|
});
|
|
5921
|
-
if (
|
|
6171
|
+
if (p31.isCancel(retention)) onCancel();
|
|
5922
6172
|
const html = generatePrivacyHtml({
|
|
5923
6173
|
core,
|
|
5924
6174
|
personalInfo: personalInfo ?? [],
|
|
@@ -5955,9 +6205,9 @@ async function privacyAction() {
|
|
|
5955
6205
|
"privacy",
|
|
5956
6206
|
"+page.ts"
|
|
5957
6207
|
);
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
6208
|
+
fs24.mkdirSync(path22.dirname(privacyPage), { recursive: true });
|
|
6209
|
+
fs24.writeFileSync(privacyPage, html);
|
|
6210
|
+
fs24.writeFileSync(
|
|
5961
6211
|
privacyPageTs,
|
|
5962
6212
|
pageMetaTagsLoader("Privacy Policy", `Privacy Policy for ${core.websiteName}`)
|
|
5963
6213
|
);
|
|
@@ -5973,19 +6223,19 @@ async function privacyAction() {
|
|
|
5973
6223
|
]
|
|
5974
6224
|
});
|
|
5975
6225
|
}
|
|
5976
|
-
var privacy = new
|
|
6226
|
+
var privacy = new Command48("privacy").description("generate placeholder privacy policy").configureHelp(helpConfig).action(() => runCommand(privacyAction, "Failed to generate privacy policy."));
|
|
5977
6227
|
|
|
5978
6228
|
// src/commands/legal.ts
|
|
5979
|
-
var legal = new
|
|
6229
|
+
var legal = new Command49("legal").description("generate placeholder legal documents").configureHelp(helpConfig).addCommand(terms).addCommand(privacy);
|
|
5980
6230
|
|
|
5981
6231
|
// src/commands/fixtures.ts
|
|
5982
|
-
import { Command as
|
|
6232
|
+
import { Command as Command55 } from "commander";
|
|
5983
6233
|
|
|
5984
6234
|
// src/commands/fixtures/load.ts
|
|
5985
|
-
import { Command as
|
|
6235
|
+
import { Command as Command50 } from "commander";
|
|
5986
6236
|
|
|
5987
6237
|
// src/lib/data.ts
|
|
5988
|
-
import
|
|
6238
|
+
import fs25 from "node:fs";
|
|
5989
6239
|
import path23 from "node:path";
|
|
5990
6240
|
import { ClientResponseError } from "pocketbase";
|
|
5991
6241
|
|
|
@@ -6027,8 +6277,8 @@ function dataDir(cwd, kind) {
|
|
|
6027
6277
|
}
|
|
6028
6278
|
function getDataFiles(cwd, kind) {
|
|
6029
6279
|
const dir = dataDir(cwd, kind);
|
|
6030
|
-
if (!
|
|
6031
|
-
return
|
|
6280
|
+
if (!fs25.existsSync(dir)) return [];
|
|
6281
|
+
return fs25.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
|
|
6032
6282
|
collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
|
|
6033
6283
|
filePath: path23.join(dir, file)
|
|
6034
6284
|
}));
|
|
@@ -6040,16 +6290,16 @@ function getFixtureFiles(cwd) {
|
|
|
6040
6290
|
return getDataFiles(cwd, "fixtures");
|
|
6041
6291
|
}
|
|
6042
6292
|
function readRecords(filePath) {
|
|
6043
|
-
return JSON.parse(
|
|
6293
|
+
return JSON.parse(fs25.readFileSync(filePath, "utf8"));
|
|
6044
6294
|
}
|
|
6045
6295
|
function readSeedIds(cwd) {
|
|
6046
6296
|
const ids = /* @__PURE__ */ new Map();
|
|
6047
6297
|
for (const { collectionName, filePath } of getSeedFiles(cwd)) {
|
|
6048
|
-
const
|
|
6298
|
+
const list3 = ids.get(collectionName) ?? [];
|
|
6049
6299
|
for (const record of readRecords(filePath)) {
|
|
6050
|
-
if (typeof record.id === "string" && record.id)
|
|
6300
|
+
if (typeof record.id === "string" && record.id) list3.push(record.id);
|
|
6051
6301
|
}
|
|
6052
|
-
ids.set(collectionName,
|
|
6302
|
+
ids.set(collectionName, list3);
|
|
6053
6303
|
}
|
|
6054
6304
|
return ids;
|
|
6055
6305
|
}
|
|
@@ -6172,7 +6422,7 @@ async function hasLoadedFixtures(pb) {
|
|
|
6172
6422
|
}
|
|
6173
6423
|
|
|
6174
6424
|
// src/commands/fixtures/load.ts
|
|
6175
|
-
var load = new
|
|
6425
|
+
var load = new Command50("load").description("load fixtures into the database").configureHelp(helpConfig).action(
|
|
6176
6426
|
() => runCommand(async () => {
|
|
6177
6427
|
const { workspaceRootDir } = await getWorkspace();
|
|
6178
6428
|
let loaded = [];
|
|
@@ -6198,8 +6448,8 @@ var load = new Command47("load").description("load fixtures into the database").
|
|
|
6198
6448
|
);
|
|
6199
6449
|
|
|
6200
6450
|
// src/commands/fixtures/clear.ts
|
|
6201
|
-
import { Command as
|
|
6202
|
-
var clear = new
|
|
6451
|
+
import { Command as Command51 } from "commander";
|
|
6452
|
+
var clear = new Command51("clear").description("clear loaded fixtures").configureHelp(helpConfig).action(
|
|
6203
6453
|
() => runCommand(async () => {
|
|
6204
6454
|
const { workspaceRootDir } = await getWorkspace();
|
|
6205
6455
|
let cleared = [];
|
|
@@ -6228,8 +6478,8 @@ var clear = new Command48("clear").description("clear loaded fixtures").configur
|
|
|
6228
6478
|
);
|
|
6229
6479
|
|
|
6230
6480
|
// src/commands/fixtures/reset.ts
|
|
6231
|
-
import { Command as
|
|
6232
|
-
var reset = new
|
|
6481
|
+
import { Command as Command52 } from "commander";
|
|
6482
|
+
var reset = new Command52("reset").description("clear and reload fixtures").configureHelp(helpConfig).action(
|
|
6233
6483
|
() => runCommand(async () => {
|
|
6234
6484
|
const { workspaceRootDir } = await getWorkspace();
|
|
6235
6485
|
let cleared = [];
|
|
@@ -6259,10 +6509,10 @@ var reset = new Command49("reset").description("clear and reload fixtures").conf
|
|
|
6259
6509
|
);
|
|
6260
6510
|
|
|
6261
6511
|
// src/commands/fixtures/generate.ts
|
|
6262
|
-
import
|
|
6512
|
+
import fs26 from "node:fs";
|
|
6263
6513
|
import path24 from "node:path";
|
|
6264
|
-
import { Command as
|
|
6265
|
-
import * as
|
|
6514
|
+
import { Command as Command53, InvalidArgumentError } from "commander";
|
|
6515
|
+
import * as p32 from "@clack/prompts";
|
|
6266
6516
|
import { annotate } from "annotate-json-schema";
|
|
6267
6517
|
import { createGenerator } from "json-schema-faker";
|
|
6268
6518
|
import { faker } from "@faker-js/faker";
|
|
@@ -6275,20 +6525,20 @@ function padZeros(num, length) {
|
|
|
6275
6525
|
function parseCount(value) {
|
|
6276
6526
|
const n = parseInt(value, 10);
|
|
6277
6527
|
if (!Number.isFinite(n) || n <= 0 || n > 999) {
|
|
6278
|
-
throw new
|
|
6528
|
+
throw new InvalidArgumentError("count must be between 1 and 999");
|
|
6279
6529
|
}
|
|
6280
6530
|
return n;
|
|
6281
6531
|
}
|
|
6282
6532
|
function parseSeed(value) {
|
|
6283
6533
|
const n = parseInt(value, 10);
|
|
6284
6534
|
if (!Number.isFinite(n)) {
|
|
6285
|
-
throw new
|
|
6535
|
+
throw new InvalidArgumentError("seed must be an integer");
|
|
6286
6536
|
}
|
|
6287
6537
|
return n;
|
|
6288
6538
|
}
|
|
6289
6539
|
async function loadCollections(pb) {
|
|
6290
|
-
const
|
|
6291
|
-
return
|
|
6540
|
+
const list3 = await pb.collections.getFullList();
|
|
6541
|
+
return list3.map((c) => ({
|
|
6292
6542
|
id: c.id,
|
|
6293
6543
|
name: c.name,
|
|
6294
6544
|
type: c.type,
|
|
@@ -6297,9 +6547,9 @@ async function loadCollections(pb) {
|
|
|
6297
6547
|
}
|
|
6298
6548
|
async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
6299
6549
|
const fixturesDir = dataDir(workspaceRootDir, "fixtures");
|
|
6300
|
-
|
|
6301
|
-
for (const file of
|
|
6302
|
-
if (file.endsWith(".json"))
|
|
6550
|
+
fs26.mkdirSync(fixturesDir, { recursive: true });
|
|
6551
|
+
for (const file of fs26.readdirSync(fixturesDir)) {
|
|
6552
|
+
if (file.endsWith(".json")) fs26.unlinkSync(path24.join(fixturesDir, file));
|
|
6303
6553
|
}
|
|
6304
6554
|
if (opts.seed !== void 0) faker.seed(opts.seed);
|
|
6305
6555
|
const generator = createGenerator({
|
|
@@ -6366,13 +6616,13 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
|
|
|
6366
6616
|
items.push(record);
|
|
6367
6617
|
}
|
|
6368
6618
|
const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
|
|
6369
|
-
|
|
6619
|
+
fs26.writeFileSync(path24.join(fixturesDir, filename), JSON.stringify(items, null, 2));
|
|
6370
6620
|
writtenFiles.push(`${path24.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
|
|
6371
6621
|
fileIndex++;
|
|
6372
6622
|
}
|
|
6373
6623
|
return { writtenFiles, warnings };
|
|
6374
6624
|
}
|
|
6375
|
-
var generate2 = new
|
|
6625
|
+
var generate2 = new Command53("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(
|
|
6376
6626
|
(opts) => runCommand(async () => {
|
|
6377
6627
|
const { workspaceRootDir } = await getWorkspace();
|
|
6378
6628
|
const existing = getFixtureFiles(workspaceRootDir);
|
|
@@ -6401,7 +6651,7 @@ var generate2 = new Command50("generate").description("generate fixture data").o
|
|
|
6401
6651
|
seed: opts.seed
|
|
6402
6652
|
});
|
|
6403
6653
|
});
|
|
6404
|
-
for (const warning of result.warnings)
|
|
6654
|
+
for (const warning of result.warnings) p32.log.warn(warning);
|
|
6405
6655
|
if (result.writtenFiles.length === 0) {
|
|
6406
6656
|
reportResult({
|
|
6407
6657
|
summary: "No eligible collections found to generate fixtures for.",
|
|
@@ -6425,23 +6675,23 @@ var generate2 = new Command50("generate").description("generate fixture data").o
|
|
|
6425
6675
|
);
|
|
6426
6676
|
|
|
6427
6677
|
// src/commands/fixtures/regen.ts
|
|
6428
|
-
import { Command as
|
|
6429
|
-
import * as
|
|
6678
|
+
import { Command as Command54, InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
6679
|
+
import * as p33 from "@clack/prompts";
|
|
6430
6680
|
function parseCount2(value) {
|
|
6431
6681
|
const n = parseInt(value, 10);
|
|
6432
6682
|
if (!Number.isFinite(n) || n <= 0 || n > 999) {
|
|
6433
|
-
throw new
|
|
6683
|
+
throw new InvalidArgumentError2("count must be between 1 and 999");
|
|
6434
6684
|
}
|
|
6435
6685
|
return n;
|
|
6436
6686
|
}
|
|
6437
6687
|
function parseSeed2(value) {
|
|
6438
6688
|
const n = parseInt(value, 10);
|
|
6439
6689
|
if (!Number.isFinite(n)) {
|
|
6440
|
-
throw new
|
|
6690
|
+
throw new InvalidArgumentError2("seed must be an integer");
|
|
6441
6691
|
}
|
|
6442
6692
|
return n;
|
|
6443
6693
|
}
|
|
6444
|
-
var regen = new
|
|
6694
|
+
var regen = new Command54("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(
|
|
6445
6695
|
(opts) => runCommand(async () => {
|
|
6446
6696
|
const { workspaceRootDir } = await getWorkspace();
|
|
6447
6697
|
let cleared = [];
|
|
@@ -6455,7 +6705,7 @@ var regen = new Command51("regen").description("clear the database, regenerate f
|
|
|
6455
6705
|
});
|
|
6456
6706
|
loaded = await loadFixtures(pb, workspaceRootDir);
|
|
6457
6707
|
});
|
|
6458
|
-
for (const warning of result.warnings)
|
|
6708
|
+
for (const warning of result.warnings) p33.log.warn(warning);
|
|
6459
6709
|
reportResult({
|
|
6460
6710
|
summary: `Regenerated fixtures (${loaded.length} collection(s) reloaded).`,
|
|
6461
6711
|
filesCreated: result.writtenFiles,
|
|
@@ -6470,14 +6720,14 @@ var regen = new Command51("regen").description("clear the database, regenerate f
|
|
|
6470
6720
|
);
|
|
6471
6721
|
|
|
6472
6722
|
// src/commands/fixtures.ts
|
|
6473
|
-
var fixtures = new
|
|
6723
|
+
var fixtures = new Command55("fixtures").description("manage fixture data").configureHelp(helpConfig).addCommand(generate2).addCommand(load).addCommand(clear).addCommand(reset).addCommand(regen);
|
|
6474
6724
|
|
|
6475
6725
|
// src/commands/seeds.ts
|
|
6476
|
-
import { Command as
|
|
6726
|
+
import { Command as Command59 } from "commander";
|
|
6477
6727
|
|
|
6478
6728
|
// src/commands/seeds/load.ts
|
|
6479
|
-
import { Command as
|
|
6480
|
-
var load2 = new
|
|
6729
|
+
import { Command as Command56 } from "commander";
|
|
6730
|
+
var load2 = new Command56("load").description("load seeds into the database").option("-f, --force", "load even if target collections already have records").configureHelp(helpConfig).action(
|
|
6481
6731
|
(opts) => runCommand(async () => {
|
|
6482
6732
|
const { workspaceRootDir } = await getWorkspace();
|
|
6483
6733
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -6514,9 +6764,9 @@ var load2 = new Command53("load").description("load seeds into the database").op
|
|
|
6514
6764
|
);
|
|
6515
6765
|
|
|
6516
6766
|
// src/commands/seeds/save.ts
|
|
6517
|
-
import
|
|
6767
|
+
import fs27 from "node:fs";
|
|
6518
6768
|
import path25 from "node:path";
|
|
6519
|
-
import { Command as
|
|
6769
|
+
import { Command as Command57 } from "commander";
|
|
6520
6770
|
var padZeros2 = (num, length) => num.toString().padStart(length, "0");
|
|
6521
6771
|
function filterSystemFields(record, systemFieldNames) {
|
|
6522
6772
|
const out = {};
|
|
@@ -6527,7 +6777,7 @@ function filterSystemFields(record, systemFieldNames) {
|
|
|
6527
6777
|
}
|
|
6528
6778
|
return out;
|
|
6529
6779
|
}
|
|
6530
|
-
var save = new
|
|
6780
|
+
var save = new Command57("save").description("save the current data as seeds").option("-f, --force", "overwrite existing seed files").configureHelp(helpConfig).action(
|
|
6531
6781
|
(opts) => runCommand(async () => {
|
|
6532
6782
|
const { workspaceRootDir } = await getWorkspace();
|
|
6533
6783
|
const seedsPath = dataDir(workspaceRootDir, "seeds");
|
|
@@ -6535,10 +6785,10 @@ var save = new Command54("save").description("save the current data as seeds").o
|
|
|
6535
6785
|
if (existing.length > 0 && !opts.force) {
|
|
6536
6786
|
throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
|
|
6537
6787
|
}
|
|
6538
|
-
|
|
6788
|
+
fs27.mkdirSync(seedsPath, { recursive: true });
|
|
6539
6789
|
if (opts.force) {
|
|
6540
|
-
for (const file of
|
|
6541
|
-
if (file.endsWith(".json"))
|
|
6790
|
+
for (const file of fs27.readdirSync(seedsPath)) {
|
|
6791
|
+
if (file.endsWith(".json")) fs27.unlinkSync(path25.join(seedsPath, file));
|
|
6542
6792
|
}
|
|
6543
6793
|
}
|
|
6544
6794
|
const saved = [];
|
|
@@ -6573,7 +6823,7 @@ var save = new Command54("save").description("save the current data as seeds").o
|
|
|
6573
6823
|
`${padZeros2(count, 2)}-${collectionName}.json`
|
|
6574
6824
|
);
|
|
6575
6825
|
const seedPath = path25.join(workspaceRootDir, relativeSeedPath);
|
|
6576
|
-
|
|
6826
|
+
fs27.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
|
|
6577
6827
|
saved.push(`${relativeSeedPath} (${filtered.length} records)`);
|
|
6578
6828
|
count++;
|
|
6579
6829
|
}
|
|
@@ -6599,8 +6849,8 @@ var save = new Command54("save").description("save the current data as seeds").o
|
|
|
6599
6849
|
);
|
|
6600
6850
|
|
|
6601
6851
|
// src/commands/seeds/clear.ts
|
|
6602
|
-
import { Command as
|
|
6603
|
-
var clear2 = new
|
|
6852
|
+
import { Command as Command58 } from "commander";
|
|
6853
|
+
var clear2 = new Command58("clear").description("clear seeded records").configureHelp(helpConfig).action(
|
|
6604
6854
|
() => runCommand(async () => {
|
|
6605
6855
|
const { workspaceRootDir } = await getWorkspace();
|
|
6606
6856
|
const seedFiles = getSeedFiles(workspaceRootDir);
|
|
@@ -6631,23 +6881,23 @@ var clear2 = new Command55("clear").description("clear seeded records").configur
|
|
|
6631
6881
|
);
|
|
6632
6882
|
|
|
6633
6883
|
// src/commands/seeds.ts
|
|
6634
|
-
var seeds = new
|
|
6884
|
+
var seeds = new Command59("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
|
|
6635
6885
|
|
|
6636
6886
|
// src/commands/signup.ts
|
|
6637
|
-
import { Command as
|
|
6638
|
-
import * as
|
|
6887
|
+
import { Command as Command61 } from "commander";
|
|
6888
|
+
import * as p35 from "@clack/prompts";
|
|
6639
6889
|
import makeFetchCookie2 from "fetch-cookie";
|
|
6640
6890
|
|
|
6641
6891
|
// src/commands/login.ts
|
|
6642
6892
|
import os3 from "node:os";
|
|
6643
|
-
import { Command as
|
|
6644
|
-
import * as
|
|
6893
|
+
import { Command as Command60 } from "commander";
|
|
6894
|
+
import * as p34 from "@clack/prompts";
|
|
6645
6895
|
import makeFetchCookie from "fetch-cookie";
|
|
6646
|
-
var login = new
|
|
6896
|
+
var login = new Command60("login").description("login to velastack.dev").configureHelp(helpConfig).action(
|
|
6647
6897
|
() => runCommand(async () => {
|
|
6648
|
-
const { email: email3, password: password11 } = await
|
|
6649
|
-
email: () =>
|
|
6650
|
-
password: () =>
|
|
6898
|
+
const { email: email3, password: password11 } = await p34.group({
|
|
6899
|
+
email: () => p34.text({ message: "Email" }),
|
|
6900
|
+
password: () => p34.password({ message: "Password" })
|
|
6651
6901
|
});
|
|
6652
6902
|
const fetchCookie = makeFetchCookie(fetch);
|
|
6653
6903
|
const loginRes = await fetchCookie(`${API_URL}/login`, {
|
|
@@ -6669,7 +6919,7 @@ var login = new Command57("login").description("login to velastack.dev").configu
|
|
|
6669
6919
|
}
|
|
6670
6920
|
const apiKey = await issueApiKey(fetchCookie);
|
|
6671
6921
|
writeConfig({ apiKey });
|
|
6672
|
-
|
|
6922
|
+
p34.log.success("Logged in to velastack.dev");
|
|
6673
6923
|
}, "Failed to login.")
|
|
6674
6924
|
);
|
|
6675
6925
|
async function issueApiKey(fetchCookie) {
|
|
@@ -6710,12 +6960,12 @@ function extractApiKey(cookie) {
|
|
|
6710
6960
|
}
|
|
6711
6961
|
|
|
6712
6962
|
// src/commands/signup.ts
|
|
6713
|
-
var signup = new
|
|
6963
|
+
var signup = new Command61("signup").description("signup to velastack.dev").configureHelp(helpConfig).action(
|
|
6714
6964
|
() => runCommand(async () => {
|
|
6715
|
-
const { email: email3, password: password11, passwordConfirm } = await
|
|
6716
|
-
email: () =>
|
|
6717
|
-
password: () =>
|
|
6718
|
-
passwordConfirm: () =>
|
|
6965
|
+
const { email: email3, password: password11, passwordConfirm } = await p35.group({
|
|
6966
|
+
email: () => p35.text({ message: "Email" }),
|
|
6967
|
+
password: () => p35.password({ message: "Password" }),
|
|
6968
|
+
passwordConfirm: () => p35.password({ message: "Confirm password" })
|
|
6719
6969
|
});
|
|
6720
6970
|
if (password11 !== passwordConfirm) {
|
|
6721
6971
|
throw new Error("Passwords do not match.");
|
|
@@ -6739,33 +6989,33 @@ var signup = new Command58("signup").description("signup to velastack.dev").conf
|
|
|
6739
6989
|
}
|
|
6740
6990
|
const apiKey = await issueApiKey(fetchCookie);
|
|
6741
6991
|
writeConfig({ apiKey });
|
|
6742
|
-
|
|
6743
|
-
|
|
6992
|
+
p35.log.success("Signed up to velastack.dev");
|
|
6993
|
+
p35.log.info("Check your email for a confirmation link.");
|
|
6744
6994
|
}, "Failed to signup.")
|
|
6745
6995
|
);
|
|
6746
6996
|
|
|
6747
6997
|
// src/commands/logout.ts
|
|
6748
|
-
import { Command as
|
|
6749
|
-
import * as
|
|
6750
|
-
var logout = new
|
|
6998
|
+
import { Command as Command62 } from "commander";
|
|
6999
|
+
import * as p36 from "@clack/prompts";
|
|
7000
|
+
var logout = new Command62("logout").alias("signout").description("logout from velastack.dev").configureHelp(helpConfig).action(
|
|
6751
7001
|
() => runCommand(() => {
|
|
6752
7002
|
if (!readConfig()) {
|
|
6753
|
-
|
|
7003
|
+
p36.log.info("Not logged in");
|
|
6754
7004
|
return;
|
|
6755
7005
|
}
|
|
6756
7006
|
clearConfig();
|
|
6757
|
-
|
|
7007
|
+
p36.log.success("Logged out of velastack.dev");
|
|
6758
7008
|
})
|
|
6759
7009
|
);
|
|
6760
7010
|
|
|
6761
7011
|
// src/commands/whoami.ts
|
|
6762
|
-
import { Command as
|
|
6763
|
-
import * as
|
|
6764
|
-
var whoami = new
|
|
7012
|
+
import { Command as Command63 } from "commander";
|
|
7013
|
+
import * as p37 from "@clack/prompts";
|
|
7014
|
+
var whoami = new Command63("whoami").description("show the current user").configureHelp(helpConfig).action(
|
|
6765
7015
|
() => runCommand(async () => {
|
|
6766
7016
|
const apiKey = readConfig()?.apiKey;
|
|
6767
7017
|
if (!apiKey) {
|
|
6768
|
-
|
|
7018
|
+
p37.log.info("Not logged in. Run `vela login` to login.");
|
|
6769
7019
|
return;
|
|
6770
7020
|
}
|
|
6771
7021
|
const res = await fetch(`${API_URL}/api/collections/users/records`, {
|
|
@@ -6773,15 +7023,15 @@ var whoami = new Command60("whoami").description("show the current user").config
|
|
|
6773
7023
|
});
|
|
6774
7024
|
const data = await res.json();
|
|
6775
7025
|
if (!data.items.length) throw new Error("No user found. Run `vela login` to login.");
|
|
6776
|
-
|
|
7026
|
+
p37.log.success(`Logged in as ${data.items[0].email}`);
|
|
6777
7027
|
})
|
|
6778
7028
|
);
|
|
6779
7029
|
|
|
6780
7030
|
// src/commands/migrate.ts
|
|
6781
|
-
import { Command as
|
|
7031
|
+
import { Command as Command69 } from "commander";
|
|
6782
7032
|
|
|
6783
7033
|
// src/commands/migrate/up.ts
|
|
6784
|
-
import { Command as
|
|
7034
|
+
import { Command as Command64 } from "commander";
|
|
6785
7035
|
|
|
6786
7036
|
// src/lib/migrate.ts
|
|
6787
7037
|
import path26 from "node:path";
|
|
@@ -6820,18 +7070,18 @@ async function runMigrateUp() {
|
|
|
6820
7070
|
]
|
|
6821
7071
|
});
|
|
6822
7072
|
}
|
|
6823
|
-
var up = new
|
|
7073
|
+
var up = new Command64("up").description("apply all pending migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations."));
|
|
6824
7074
|
|
|
6825
7075
|
// src/commands/migrate/down.ts
|
|
6826
|
-
import { Command as
|
|
7076
|
+
import { Command as Command65, InvalidArgumentError as InvalidArgumentError3 } from "commander";
|
|
6827
7077
|
function parseSteps(value) {
|
|
6828
7078
|
const n = parseInt(value, 10);
|
|
6829
7079
|
if (!Number.isFinite(n) || n <= 0) {
|
|
6830
|
-
throw new
|
|
7080
|
+
throw new InvalidArgumentError3("number must be a positive integer");
|
|
6831
7081
|
}
|
|
6832
7082
|
return n;
|
|
6833
7083
|
}
|
|
6834
|
-
var down = new
|
|
7084
|
+
var down = new Command65("down").alias("rollback").description("revert the last N applied migrations").argument("[number]", "how many migrations to revert", parseSteps, 1).configureHelp(helpConfig).action(
|
|
6835
7085
|
(n) => runCommand(async () => {
|
|
6836
7086
|
await runPocketbaseMigrate(["down", String(n)]);
|
|
6837
7087
|
reportResult({
|
|
@@ -6845,11 +7095,11 @@ var down = new Command62("down").alias("rollback").description("revert the last
|
|
|
6845
7095
|
);
|
|
6846
7096
|
|
|
6847
7097
|
// src/commands/migrate/create.ts
|
|
6848
|
-
import
|
|
7098
|
+
import fs28 from "node:fs";
|
|
6849
7099
|
import path27 from "node:path";
|
|
6850
7100
|
import process18 from "node:process";
|
|
6851
|
-
import { Command as
|
|
6852
|
-
var create2 = new
|
|
7101
|
+
import { Command as Command66 } from "commander";
|
|
7102
|
+
var create2 = new Command66("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
|
|
6853
7103
|
(name) => runCommand(async () => {
|
|
6854
7104
|
const cwd = process18.cwd();
|
|
6855
7105
|
const before = listMigrationFiles(cwd);
|
|
@@ -6868,16 +7118,16 @@ var create2 = new Command63("create").alias("new").description("create a new bla
|
|
|
6868
7118
|
);
|
|
6869
7119
|
function listMigrationFiles(cwd) {
|
|
6870
7120
|
const dir = path27.join(cwd, MIGRATIONS_DIR);
|
|
6871
|
-
if (!
|
|
6872
|
-
return new Set(
|
|
7121
|
+
if (!fs28.existsSync(dir)) return /* @__PURE__ */ new Set();
|
|
7122
|
+
return new Set(fs28.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
|
|
6873
7123
|
}
|
|
6874
7124
|
|
|
6875
7125
|
// src/commands/migrate/collections.ts
|
|
6876
|
-
import
|
|
7126
|
+
import fs29 from "node:fs";
|
|
6877
7127
|
import path28 from "node:path";
|
|
6878
7128
|
import process19 from "node:process";
|
|
6879
|
-
import { Command as
|
|
6880
|
-
var collections = new
|
|
7129
|
+
import { Command as Command67 } from "commander";
|
|
7130
|
+
var collections = new Command67("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
|
|
6881
7131
|
() => runCommand(async () => {
|
|
6882
7132
|
const cwd = process19.cwd();
|
|
6883
7133
|
const before = listMigrationFiles2(cwd);
|
|
@@ -6903,13 +7153,13 @@ var collections = new Command64("collections").alias("snapshot").description("sn
|
|
|
6903
7153
|
);
|
|
6904
7154
|
function listMigrationFiles2(cwd) {
|
|
6905
7155
|
const dir = path28.join(cwd, MIGRATIONS_DIR);
|
|
6906
|
-
if (!
|
|
6907
|
-
return new Set(
|
|
7156
|
+
if (!fs29.existsSync(dir)) return /* @__PURE__ */ new Set();
|
|
7157
|
+
return new Set(fs29.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
|
|
6908
7158
|
}
|
|
6909
7159
|
|
|
6910
7160
|
// src/commands/migrate/history-sync.ts
|
|
6911
|
-
import { Command as
|
|
6912
|
-
var historySync = new
|
|
7161
|
+
import { Command as Command68 } from "commander";
|
|
7162
|
+
var historySync = new Command68("history-sync").description("drop _migrations rows whose files no longer exist").configureHelp(helpConfig).action(
|
|
6913
7163
|
() => runCommand(async () => {
|
|
6914
7164
|
await runPocketbaseMigrate(["history-sync"]);
|
|
6915
7165
|
reportResult({
|
|
@@ -6920,14 +7170,14 @@ var historySync = new Command65("history-sync").description("drop _migrations ro
|
|
|
6920
7170
|
);
|
|
6921
7171
|
|
|
6922
7172
|
// src/commands/migrate.ts
|
|
6923
|
-
var migrate = new
|
|
7173
|
+
var migrate = new Command69("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
|
|
6924
7174
|
|
|
6925
7175
|
// src/commands/dev.ts
|
|
6926
|
-
import
|
|
7176
|
+
import fs30 from "node:fs";
|
|
6927
7177
|
import path30 from "node:path";
|
|
6928
7178
|
import process21 from "node:process";
|
|
6929
7179
|
import { performance } from "node:perf_hooks";
|
|
6930
|
-
import { Command as
|
|
7180
|
+
import { Command as Command70, InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
6931
7181
|
import pc13 from "picocolors";
|
|
6932
7182
|
import PocketBase4 from "pocketbase";
|
|
6933
7183
|
|
|
@@ -6972,11 +7222,11 @@ async function loadVite(cwd = process20.cwd()) {
|
|
|
6972
7222
|
function parsePort(value) {
|
|
6973
7223
|
const port = Number(value);
|
|
6974
7224
|
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
6975
|
-
throw new
|
|
7225
|
+
throw new InvalidArgumentError4("must be a whole number between 1 and 65535.");
|
|
6976
7226
|
}
|
|
6977
7227
|
return port;
|
|
6978
7228
|
}
|
|
6979
|
-
var dev = new
|
|
7229
|
+
var dev = new Command70("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) => {
|
|
6980
7230
|
const cwd = process21.cwd();
|
|
6981
7231
|
process21.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
6982
7232
|
const startTime = performance.now();
|
|
@@ -6988,7 +7238,7 @@ var dev = new Command67("dev").description("start the development server").optio
|
|
|
6988
7238
|
const needsStart = backend3 && !process21.env.POCKETBASE_URL;
|
|
6989
7239
|
const cleanup = () => {
|
|
6990
7240
|
if (pbProc?.pid) pbProc.kill();
|
|
6991
|
-
if (
|
|
7241
|
+
if (fs30.existsSync(viteMetadataFile)) fs30.rmSync(viteMetadataFile);
|
|
6992
7242
|
};
|
|
6993
7243
|
if (needsStart) {
|
|
6994
7244
|
const dataDir2 = path30.join(cwd, DATA_DIR);
|
|
@@ -7026,8 +7276,8 @@ var dev = new Command67("dev").description("start the development server").optio
|
|
|
7026
7276
|
if (!backend3) return;
|
|
7027
7277
|
const { address, port: vitePort } = server.httpServer.address();
|
|
7028
7278
|
const viteHost = address === "::1" ? "localhost" : address;
|
|
7029
|
-
await
|
|
7030
|
-
await
|
|
7279
|
+
await fs30.promises.mkdir(viteMetadataDir, { recursive: true });
|
|
7280
|
+
await fs30.promises.writeFile(
|
|
7031
7281
|
viteMetadataFile,
|
|
7032
7282
|
JSON.stringify({
|
|
7033
7283
|
pocketbaseUrl: process21.env.POCKETBASE_URL,
|
|
@@ -7068,9 +7318,9 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
7068
7318
|
void (async () => {
|
|
7069
7319
|
for (; ; ) {
|
|
7070
7320
|
try {
|
|
7071
|
-
await
|
|
7072
|
-
for await (const event of
|
|
7073
|
-
if (event.eventType === "rename" && event.filename === "$types.d.ts" && !
|
|
7321
|
+
await fs30.promises.mkdir(pocketbaseDir, { recursive: true });
|
|
7322
|
+
for await (const event of fs30.promises.watch(pocketbaseDir)) {
|
|
7323
|
+
if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs30.existsSync(pocketbaseTypes)) {
|
|
7074
7324
|
setTimeout(regenerate, 100);
|
|
7075
7325
|
}
|
|
7076
7326
|
}
|
|
@@ -7082,15 +7332,15 @@ async function startWatchingTypes(cwd, pb) {
|
|
|
7082
7332
|
}
|
|
7083
7333
|
|
|
7084
7334
|
// src/commands/build.ts
|
|
7085
|
-
import
|
|
7335
|
+
import fs31 from "node:fs";
|
|
7086
7336
|
import path31 from "node:path";
|
|
7087
7337
|
import process23 from "node:process";
|
|
7088
|
-
import { Command as
|
|
7089
|
-
import * as
|
|
7338
|
+
import { Command as Command71 } from "commander";
|
|
7339
|
+
import * as p38 from "@clack/prompts";
|
|
7090
7340
|
import pc14 from "picocolors";
|
|
7091
7341
|
import { x as x3 } from "tinyexec";
|
|
7092
|
-
import { detect as
|
|
7093
|
-
import { resolveCommand as
|
|
7342
|
+
import { detect as detect4 } from "package-manager-detector";
|
|
7343
|
+
import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
|
|
7094
7344
|
|
|
7095
7345
|
// src/lib/build-env.ts
|
|
7096
7346
|
function applyBuildEnv(cwd, env2 = process.env) {
|
|
@@ -7119,7 +7369,7 @@ function normalizeOrigin(value) {
|
|
|
7119
7369
|
|
|
7120
7370
|
// src/commands/build.ts
|
|
7121
7371
|
var PRERENDERED_DIR = path31.join(".svelte-kit", "output", "prerendered");
|
|
7122
|
-
var build = new
|
|
7372
|
+
var build = new Command71("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
|
|
7123
7373
|
const cwd = process23.cwd();
|
|
7124
7374
|
applyBuildEnv(cwd);
|
|
7125
7375
|
const origin = await originForBuild(cwd, options.target);
|
|
@@ -7147,8 +7397,8 @@ var build = new Command68("build").description("build the app").configureHelp(he
|
|
|
7147
7397
|
});
|
|
7148
7398
|
}
|
|
7149
7399
|
try {
|
|
7150
|
-
const pm = (await
|
|
7151
|
-
const resolved =
|
|
7400
|
+
const pm = (await detect4({ cwd }))?.name ?? "npm";
|
|
7401
|
+
const resolved = resolveCommand4(pm, "execute", ["vite", "build"]);
|
|
7152
7402
|
const args = resolved.args.slice();
|
|
7153
7403
|
if (pm === "npm") args.unshift("--yes");
|
|
7154
7404
|
await x3(resolved.command, args, {
|
|
@@ -7174,8 +7424,8 @@ async function originForBuild(cwd, target) {
|
|
|
7174
7424
|
}
|
|
7175
7425
|
function warnIfPrerendered(cwd) {
|
|
7176
7426
|
const dir = path31.join(cwd, PRERENDERED_DIR);
|
|
7177
|
-
if (!
|
|
7178
|
-
|
|
7427
|
+
if (!fs31.existsSync(dir) || fs31.readdirSync(dir).length === 0) return;
|
|
7428
|
+
p38.log.warn(
|
|
7179
7429
|
`Prerendered pages were built with no domain configured, so their canonical
|
|
7180
7430
|
links point at SvelteKit's placeholder host rather than at this site.
|
|
7181
7431
|
|
|
@@ -7186,11 +7436,11 @@ Set one with ${pc14.cyan("vela deploy --domain example.com")}, or pass ${pc14.cy
|
|
|
7186
7436
|
// src/commands/preview.ts
|
|
7187
7437
|
import path32 from "node:path";
|
|
7188
7438
|
import process24 from "node:process";
|
|
7189
|
-
import { Command as
|
|
7439
|
+
import { Command as Command72 } from "commander";
|
|
7190
7440
|
import { x as x4 } from "tinyexec";
|
|
7191
|
-
import { detect as
|
|
7192
|
-
import { resolveCommand as
|
|
7193
|
-
var preview = new
|
|
7441
|
+
import { detect as detect5 } from "package-manager-detector";
|
|
7442
|
+
import { resolveCommand as resolveCommand5 } from "package-manager-detector/commands";
|
|
7443
|
+
var preview = new Command72("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
|
|
7194
7444
|
const cwd = process24.cwd();
|
|
7195
7445
|
process24.env.VELA_DATA_DIR ??= localDataDir(cwd);
|
|
7196
7446
|
let pbProc;
|
|
@@ -7215,8 +7465,8 @@ var preview = new Command69("preview").description("preview the built app").conf
|
|
|
7215
7465
|
});
|
|
7216
7466
|
}
|
|
7217
7467
|
try {
|
|
7218
|
-
const pm = (await
|
|
7219
|
-
const resolved =
|
|
7468
|
+
const pm = (await detect5({ cwd }))?.name ?? "npm";
|
|
7469
|
+
const resolved = resolveCommand5(pm, "execute", ["vite", "preview"]);
|
|
7220
7470
|
const args = resolved.args.slice();
|
|
7221
7471
|
if (pm === "npm") args.unshift("--yes");
|
|
7222
7472
|
await x4(resolved.command, args, {
|
|
@@ -7230,8 +7480,8 @@ var preview = new Command69("preview").description("preview the built app").conf
|
|
|
7230
7480
|
|
|
7231
7481
|
// src/commands/sync.ts
|
|
7232
7482
|
import path33 from "node:path";
|
|
7233
|
-
import { Command as
|
|
7234
|
-
var sync = new
|
|
7483
|
+
import { Command as Command73 } from "commander";
|
|
7484
|
+
var sync = new Command73("sync").description("sync types from the database").configureHelp(helpConfig).action(
|
|
7235
7485
|
() => runCommand(async () => {
|
|
7236
7486
|
const { workspaceRootDir } = await getWorkspace();
|
|
7237
7487
|
const typesDir = path33.join(workspaceRootDir, ".svelte-kit", "types");
|
|
@@ -7244,8 +7494,8 @@ var sync = new Command70("sync").description("sync types from the database").con
|
|
|
7244
7494
|
);
|
|
7245
7495
|
|
|
7246
7496
|
// src/commands/provision.ts
|
|
7247
|
-
import { Command as
|
|
7248
|
-
import * as
|
|
7497
|
+
import { Command as Command74 } from "commander";
|
|
7498
|
+
import * as p39 from "@clack/prompts";
|
|
7249
7499
|
import pc15 from "picocolors";
|
|
7250
7500
|
import * as v6 from "valibot";
|
|
7251
7501
|
var OptionsSchema2 = v6.object({
|
|
@@ -7254,24 +7504,24 @@ var OptionsSchema2 = v6.object({
|
|
|
7254
7504
|
nodeMajor: v6.optional(v6.string())
|
|
7255
7505
|
});
|
|
7256
7506
|
var provision = addSshOptions(
|
|
7257
|
-
new
|
|
7507
|
+
new Command74("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
|
|
7258
7508
|
).option("--pb-version <version>", "PocketBase version to install").option("--node-major <version>", "Node.js major version to install", "22").action(
|
|
7259
7509
|
(target, raw) => runCommand(async () => {
|
|
7260
7510
|
const options = parseOptions(OptionsSchema2, raw);
|
|
7261
7511
|
const pbVersion = options.pbVersion ?? pocketbaseVersion();
|
|
7262
|
-
|
|
7263
|
-
|
|
7512
|
+
p39.intro(pc15.bgCyan(pc15.black(" vela provision ")));
|
|
7513
|
+
p39.log.info(`Target ${pc15.cyan(target)}`);
|
|
7264
7514
|
await withSsh(target, sshOptionsFrom(options), async (session) => {
|
|
7265
7515
|
await session.detectElevation();
|
|
7266
7516
|
const existing = await readServerInfo(session);
|
|
7267
7517
|
if (existing) {
|
|
7268
|
-
|
|
7518
|
+
p39.log.info(
|
|
7269
7519
|
`Already provisioned by vela ${existing.cliVersion} on ${existing.provisionedAt}. Bringing it up to date.`
|
|
7270
7520
|
);
|
|
7271
7521
|
}
|
|
7272
|
-
|
|
7522
|
+
p39.log.step("Uploading server scripts");
|
|
7273
7523
|
await syncServerScripts(session);
|
|
7274
|
-
|
|
7524
|
+
p39.log.step("Running provision");
|
|
7275
7525
|
const result = await runServerScript(session, "provision.sh", {
|
|
7276
7526
|
args: [
|
|
7277
7527
|
"--pb-version",
|
|
@@ -7283,7 +7533,7 @@ var provision = addSshOptions(
|
|
|
7283
7533
|
],
|
|
7284
7534
|
stream: true
|
|
7285
7535
|
});
|
|
7286
|
-
|
|
7536
|
+
p39.log.success(
|
|
7287
7537
|
`${target} is ready.
|
|
7288
7538
|
|
|
7289
7539
|
Node ${result?.node ?? "installed"}
|
|
@@ -7291,27 +7541,27 @@ var provision = addSshOptions(
|
|
|
7291
7541
|
PocketBase ${result?.pocketbase ?? pbVersion}`
|
|
7292
7542
|
);
|
|
7293
7543
|
});
|
|
7294
|
-
|
|
7544
|
+
p39.outro(`Deploy with ${pc15.cyan(`vela deploy --server ${target}`)}`);
|
|
7295
7545
|
}, "Failed to provision.")
|
|
7296
7546
|
);
|
|
7297
7547
|
|
|
7298
7548
|
// src/commands/deploy.ts
|
|
7299
7549
|
import path36 from "node:path";
|
|
7300
|
-
import
|
|
7301
|
-
import { Command as
|
|
7302
|
-
import * as
|
|
7550
|
+
import fs34 from "node:fs";
|
|
7551
|
+
import { Command as Command75, Option as Option2 } from "commander";
|
|
7552
|
+
import * as p40 from "@clack/prompts";
|
|
7303
7553
|
import pc16 from "picocolors";
|
|
7304
7554
|
import * as v7 from "valibot";
|
|
7305
7555
|
|
|
7306
7556
|
// src/lib/pocketbase-settings.ts
|
|
7307
|
-
import
|
|
7557
|
+
import fs32 from "node:fs";
|
|
7308
7558
|
import path34 from "node:path";
|
|
7309
7559
|
import process25 from "node:process";
|
|
7310
7560
|
import PocketBase5 from "pocketbase";
|
|
7311
7561
|
var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
|
|
7312
7562
|
async function readLocalMeta(cwd) {
|
|
7313
7563
|
const dataDir2 = path34.join(cwd, DATA_DIR);
|
|
7314
|
-
if (!
|
|
7564
|
+
if (!fs32.existsSync(dataDir2)) return null;
|
|
7315
7565
|
const email3 = process25.env.POCKETBASE_SUPERUSER_EMAIL;
|
|
7316
7566
|
const password11 = process25.env.POCKETBASE_SUPERUSER_PASSWORD;
|
|
7317
7567
|
if (!email3 || !password11) return null;
|
|
@@ -7362,10 +7612,10 @@ async function seedRemoteMeta(session, instance, local, appURL) {
|
|
|
7362
7612
|
}
|
|
7363
7613
|
|
|
7364
7614
|
// src/lib/artifact.ts
|
|
7365
|
-
import
|
|
7615
|
+
import fs33 from "node:fs";
|
|
7366
7616
|
import path35 from "node:path";
|
|
7367
|
-
import { detect as
|
|
7368
|
-
import { resolveCommand as
|
|
7617
|
+
import { detect as detect6 } from "package-manager-detector";
|
|
7618
|
+
import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
|
|
7369
7619
|
var DEFAULT_OUTPUT_DIR = "build";
|
|
7370
7620
|
var BuildError = class extends Error {
|
|
7371
7621
|
};
|
|
@@ -7381,8 +7631,8 @@ async function runBuild(cwd, buildCommand, env2) {
|
|
|
7381
7631
|
throw new BuildError(`\`${buildCommand}\` exited ${result2.exitCode}.`);
|
|
7382
7632
|
return;
|
|
7383
7633
|
}
|
|
7384
|
-
const pm = (await
|
|
7385
|
-
const resolved =
|
|
7634
|
+
const pm = (await detect6({ cwd }))?.name ?? "npm";
|
|
7635
|
+
const resolved = resolveCommand6(pm, "run", ["build"]);
|
|
7386
7636
|
if (!resolved) throw new BuildError(`Could not work out how to run a build with ${pm}.`);
|
|
7387
7637
|
const result = await spawnCapture(resolved.command, resolved.args, {
|
|
7388
7638
|
cwd,
|
|
@@ -7401,10 +7651,10 @@ function collectArtifact(cwd, config = {}) {
|
|
|
7401
7651
|
const entries = [];
|
|
7402
7652
|
const add2 = (rel, remoteDir = "") => {
|
|
7403
7653
|
const localPath = path35.join(cwd, rel);
|
|
7404
|
-
if (
|
|
7654
|
+
if (fs33.existsSync(localPath)) entries.push({ localPath, remoteDir });
|
|
7405
7655
|
};
|
|
7406
7656
|
const buildPath = path35.join(cwd, outputDir);
|
|
7407
|
-
if (!
|
|
7657
|
+
if (!fs33.existsSync(path35.join(buildPath, "index.js"))) {
|
|
7408
7658
|
throw new BuildError(
|
|
7409
7659
|
`No ${outputDir}/index.js after the build.
|
|
7410
7660
|
|
|
@@ -7418,7 +7668,7 @@ the adapter in your Vite or Svelte config, then build again.`
|
|
|
7418
7668
|
add2(".npmrc");
|
|
7419
7669
|
add2(MIGRATIONS_DIR);
|
|
7420
7670
|
const hooks = path35.join(cwd, DATA_DIR, "hooks");
|
|
7421
|
-
if (
|
|
7671
|
+
if (fs33.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
|
|
7422
7672
|
for (const extra of config.include ?? []) add2(extra);
|
|
7423
7673
|
return entries;
|
|
7424
7674
|
}
|
|
@@ -7440,7 +7690,7 @@ var OptionsSchema3 = v7.object({
|
|
|
7440
7690
|
build: v7.optional(v7.boolean())
|
|
7441
7691
|
});
|
|
7442
7692
|
var deploy = addTargetOptions(
|
|
7443
|
-
new
|
|
7693
|
+
new Command75("deploy").description("deploy the app").configureHelp(helpConfig),
|
|
7444
7694
|
"production"
|
|
7445
7695
|
).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(
|
|
7446
7696
|
new Option2(
|
|
@@ -7456,13 +7706,13 @@ var deploy = addTargetOptions(
|
|
|
7456
7706
|
const options = parseOptions(OptionsSchema3, raw);
|
|
7457
7707
|
const backend3 = hasBackend();
|
|
7458
7708
|
const release = releaseId();
|
|
7459
|
-
|
|
7709
|
+
p40.intro(pc16.bgCyan(pc16.black(" vela deploy ")));
|
|
7460
7710
|
await withTarget(
|
|
7461
7711
|
raw,
|
|
7462
7712
|
{
|
|
7463
7713
|
remote: async (ctx) => {
|
|
7464
7714
|
const { session, instance, workspaceRootDir, config } = ctx;
|
|
7465
|
-
|
|
7715
|
+
p40.log.info(
|
|
7466
7716
|
`${pc16.cyan(ctx.appName)} ${pc16.dim("\u2192")} ${pc16.cyan(ctx.targetName)} ${pc16.dim(`(${ctx.server})`)}`
|
|
7467
7717
|
);
|
|
7468
7718
|
const [existing] = await readInstanceStates(session, instance);
|
|
@@ -7478,7 +7728,7 @@ var deploy = addTargetOptions(
|
|
|
7478
7728
|
tunnel = await openDatabaseTunnel(session, instance, existing);
|
|
7479
7729
|
} catch (err) {
|
|
7480
7730
|
if (askedForRemoteDb) throw err;
|
|
7481
|
-
|
|
7731
|
+
p40.log.warn(
|
|
7482
7732
|
`Could not build against the ${pc16.cyan(ctx.targetName)} database, using a local one instead.
|
|
7483
7733
|
${pc16.dim(String(err))}`
|
|
7484
7734
|
);
|
|
@@ -7486,13 +7736,13 @@ ${pc16.dim(String(err))}`
|
|
|
7486
7736
|
}
|
|
7487
7737
|
if (tunnel) {
|
|
7488
7738
|
buildEnv = { ...buildEnv, ...tunnel.env };
|
|
7489
|
-
|
|
7739
|
+
p40.log.info(
|
|
7490
7740
|
`Building against the ${pc16.cyan(ctx.targetName)} database on ${ctx.server} ${pc16.dim(`(port ${tunnel.pbPort})`)}`
|
|
7491
7741
|
);
|
|
7492
7742
|
} else if (backend3) {
|
|
7493
7743
|
await ensureSuperuser(workspaceRootDir);
|
|
7494
7744
|
}
|
|
7495
|
-
|
|
7745
|
+
p40.log.step("Building");
|
|
7496
7746
|
try {
|
|
7497
7747
|
await runBuild(workspaceRootDir, config.deploy?.buildCommand, buildEnv);
|
|
7498
7748
|
} finally {
|
|
@@ -7501,9 +7751,9 @@ ${pc16.dim(String(err))}`
|
|
|
7501
7751
|
}
|
|
7502
7752
|
const entries = collectArtifact(workspaceRootDir, config.deploy ?? {});
|
|
7503
7753
|
const sha = await gitSha(workspaceRootDir);
|
|
7504
|
-
|
|
7754
|
+
p40.log.step(`Uploading release ${pc16.dim(release)}`);
|
|
7505
7755
|
await uploadRelease(session, instance, release, entries);
|
|
7506
|
-
|
|
7756
|
+
p40.log.step("Activating");
|
|
7507
7757
|
const result = await runServerScript(session, "apply.sh", {
|
|
7508
7758
|
args: [
|
|
7509
7759
|
instance,
|
|
@@ -7535,7 +7785,7 @@ ${pc16.dim(String(err))}`
|
|
|
7535
7785
|
});
|
|
7536
7786
|
if (!existing) await reportEmptyEnvironment(session, instance, workspaceRootDir);
|
|
7537
7787
|
const url = result?.url ?? "";
|
|
7538
|
-
|
|
7788
|
+
p40.log.success(
|
|
7539
7789
|
`Deployed ${pc16.cyan(ctx.appName)} ${pc16.dim(release)}
|
|
7540
7790
|
|
|
7541
7791
|
URL ${url}
|
|
@@ -7548,7 +7798,7 @@ ${pc16.dim(String(err))}`
|
|
|
7548
7798
|
workspaceRootDir,
|
|
7549
7799
|
domain ? result?.url ?? "" : ""
|
|
7550
7800
|
);
|
|
7551
|
-
|
|
7801
|
+
p40.log.info(
|
|
7552
7802
|
`Created the PocketBase superuser this app authenticates as.
|
|
7553
7803
|
|
|
7554
7804
|
Its credentials are stored in the environment on the server. To use
|
|
@@ -7559,7 +7809,7 @@ and deploy again.`
|
|
|
7559
7809
|
await reportAppURLDrift(session, instance, domain);
|
|
7560
7810
|
}
|
|
7561
7811
|
if (!domain) {
|
|
7562
|
-
|
|
7812
|
+
p40.log.warn(
|
|
7563
7813
|
`No domain configured, so nothing is proxied to this app yet.
|
|
7564
7814
|
Redeploy with ${pc16.cyan("--domain example.com")} once DNS points at ${ctx.server}.`
|
|
7565
7815
|
);
|
|
@@ -7568,7 +7818,7 @@ Redeploy with ${pc16.cyan("--domain example.com")} once DNS points at ${ctx.serv
|
|
|
7568
7818
|
},
|
|
7569
7819
|
{ project: options.project, askDomain: true, label: "deploy" }
|
|
7570
7820
|
);
|
|
7571
|
-
|
|
7821
|
+
p40.outro(`${pc16.cyan("vela status")} to see what is running`);
|
|
7572
7822
|
}, "Failed to deploy.")
|
|
7573
7823
|
);
|
|
7574
7824
|
async function reportAppURLDrift(session, instance, domain) {
|
|
@@ -7576,7 +7826,7 @@ async function reportAppURLDrift(session, instance, domain) {
|
|
|
7576
7826
|
if (!expected) return;
|
|
7577
7827
|
const current = await readRemoteAppURL(session, instance);
|
|
7578
7828
|
if (!current || normalizeOrigin(current) === expected) return;
|
|
7579
|
-
|
|
7829
|
+
p40.log.warn(
|
|
7580
7830
|
`This app's PocketBase ${pc16.cyan("appURL")} is ${pc16.dim(current)}, but it is served on ${pc16.dim(expected)}.
|
|
7581
7831
|
|
|
7582
7832
|
Emails and anything else PocketBase links to will use the former. Update it in
|
|
@@ -7591,15 +7841,15 @@ async function copyLocalBranding(session, instance, workspaceRootDir, appURL) {
|
|
|
7591
7841
|
if (copied.length === 0) return;
|
|
7592
7842
|
const outcome = await restartInstance(session, instance);
|
|
7593
7843
|
if (outcome.deployed && !outcome.restarted) {
|
|
7594
|
-
|
|
7844
|
+
p40.log.warn(
|
|
7595
7845
|
`Copied ${copied.join(", ")}, but the app did not restart to pick them up.
|
|
7596
7846
|
${pc16.dim(outcome.error ?? "")}`
|
|
7597
7847
|
);
|
|
7598
7848
|
return;
|
|
7599
7849
|
}
|
|
7600
|
-
|
|
7850
|
+
p40.log.success(`Copied ${copied.join(", ")} from this project's database`);
|
|
7601
7851
|
} catch (err) {
|
|
7602
|
-
|
|
7852
|
+
p40.log.warn(
|
|
7603
7853
|
`Could not copy this project's PocketBase settings across.
|
|
7604
7854
|
Set them in the admin panel instead. ${pc16.dim(String(err))}`
|
|
7605
7855
|
);
|
|
@@ -7683,7 +7933,7 @@ async function uploadRelease(session, instance, release, entries) {
|
|
|
7683
7933
|
}
|
|
7684
7934
|
function isDirectory(target) {
|
|
7685
7935
|
try {
|
|
7686
|
-
return
|
|
7936
|
+
return fs34.statSync(target).isDirectory();
|
|
7687
7937
|
} catch {
|
|
7688
7938
|
return false;
|
|
7689
7939
|
}
|
|
@@ -7691,8 +7941,8 @@ function isDirectory(target) {
|
|
|
7691
7941
|
async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
7692
7942
|
const remote = await readRemoteEnv(session, instance);
|
|
7693
7943
|
if (Object.keys(remote).length > 0) return;
|
|
7694
|
-
if (!
|
|
7695
|
-
|
|
7944
|
+
if (!fs34.existsSync(path36.join(workspaceRootDir, ".env"))) return;
|
|
7945
|
+
p40.log.warn(
|
|
7696
7946
|
`This app has no production environment variables yet.
|
|
7697
7947
|
|
|
7698
7948
|
Local ${pc16.cyan(".env")} values are not uploaded by a deploy. Set them with
|
|
@@ -7703,8 +7953,8 @@ ${pc16.cyan("vela env set KEY")}, or copy a file across with ${pc16.cyan("vela e
|
|
|
7703
7953
|
// src/commands/link.ts
|
|
7704
7954
|
import path37 from "node:path";
|
|
7705
7955
|
import process26 from "node:process";
|
|
7706
|
-
import { Command as
|
|
7707
|
-
import * as
|
|
7956
|
+
import { Command as Command76 } from "commander";
|
|
7957
|
+
import * as p41 from "@clack/prompts";
|
|
7708
7958
|
|
|
7709
7959
|
// src/lib/velastack-api.ts
|
|
7710
7960
|
async function apiFetch(apiKey, pathAndQuery, init) {
|
|
@@ -7755,12 +8005,12 @@ async function createProject2(apiKey, args) {
|
|
|
7755
8005
|
|
|
7756
8006
|
// src/commands/link.ts
|
|
7757
8007
|
var CREATE_NEW = "__new__";
|
|
7758
|
-
var link = new
|
|
8008
|
+
var link = new Command76("link").description("link this project to a velastack.dev project").configureHelp(helpConfig).action(() => runCommand(linkProject, "Failed to link the project."));
|
|
7759
8009
|
async function linkProject() {
|
|
7760
8010
|
const { workspaceRootDir } = await getWorkspace();
|
|
7761
8011
|
const existing = readProjectConfig(workspaceRootDir);
|
|
7762
8012
|
if (existing) {
|
|
7763
|
-
|
|
8013
|
+
p41.log.success(`Linked to ${existing.projectName}.`);
|
|
7764
8014
|
return;
|
|
7765
8015
|
}
|
|
7766
8016
|
const apiKey = requireApiKey();
|
|
@@ -7787,10 +8037,10 @@ async function linkProject() {
|
|
|
7787
8037
|
projectName = created.name;
|
|
7788
8038
|
}
|
|
7789
8039
|
writeProjectConfig(workspaceRootDir, { projectId, teamId, projectName });
|
|
7790
|
-
|
|
8040
|
+
p41.log.success(`Linked to ${projectName}.`);
|
|
7791
8041
|
}
|
|
7792
8042
|
async function pickExistingProject(projects) {
|
|
7793
|
-
const choice = await
|
|
8043
|
+
const choice = await p41.select({
|
|
7794
8044
|
message: "Select a project",
|
|
7795
8045
|
options: [
|
|
7796
8046
|
...projects.map((pr) => ({
|
|
@@ -7800,38 +8050,38 @@ async function pickExistingProject(projects) {
|
|
|
7800
8050
|
{ value: CREATE_NEW, label: "Create a new project" }
|
|
7801
8051
|
]
|
|
7802
8052
|
});
|
|
7803
|
-
if (
|
|
7804
|
-
|
|
8053
|
+
if (p41.isCancel(choice)) {
|
|
8054
|
+
p41.cancel("Operation cancelled.");
|
|
7805
8055
|
process26.exit(0);
|
|
7806
8056
|
}
|
|
7807
8057
|
return choice;
|
|
7808
8058
|
}
|
|
7809
8059
|
async function pickTeam(teams3) {
|
|
7810
8060
|
if (teams3.length === 1) return teams3[0];
|
|
7811
|
-
const choice = await
|
|
8061
|
+
const choice = await p41.select({
|
|
7812
8062
|
message: "Select a team",
|
|
7813
8063
|
options: teams3.map((team) => ({
|
|
7814
8064
|
value: team.id,
|
|
7815
8065
|
label: team.is_personal ? `${team.name} (personal)` : team.name
|
|
7816
8066
|
}))
|
|
7817
8067
|
});
|
|
7818
|
-
if (
|
|
7819
|
-
|
|
8068
|
+
if (p41.isCancel(choice)) {
|
|
8069
|
+
p41.cancel("Operation cancelled.");
|
|
7820
8070
|
process26.exit(0);
|
|
7821
8071
|
}
|
|
7822
8072
|
return teams3.find((team) => team.id === choice);
|
|
7823
8073
|
}
|
|
7824
8074
|
async function promptProjectName(workspaceRootDir) {
|
|
7825
8075
|
const defaultValue = defaultProjectName2(workspaceRootDir);
|
|
7826
|
-
const value = await
|
|
8076
|
+
const value = await p41.text({
|
|
7827
8077
|
message: "Project name",
|
|
7828
8078
|
defaultValue,
|
|
7829
8079
|
initialValue: defaultValue,
|
|
7830
8080
|
placeholder: defaultValue,
|
|
7831
8081
|
validate: (v9) => !v9?.trim() ? "Required" : void 0
|
|
7832
8082
|
});
|
|
7833
|
-
if (
|
|
7834
|
-
|
|
8083
|
+
if (p41.isCancel(value)) {
|
|
8084
|
+
p41.cancel("Operation cancelled.");
|
|
7835
8085
|
process26.exit(0);
|
|
7836
8086
|
}
|
|
7837
8087
|
return value.trim();
|
|
@@ -7847,14 +8097,14 @@ function defaultProjectName2(workspaceRootDir) {
|
|
|
7847
8097
|
}
|
|
7848
8098
|
|
|
7849
8099
|
// src/commands/env.ts
|
|
7850
|
-
import { Command as
|
|
8100
|
+
import { Command as Command81 } from "commander";
|
|
7851
8101
|
|
|
7852
8102
|
// src/commands/env/list.ts
|
|
7853
|
-
import { Command as
|
|
7854
|
-
import * as
|
|
8103
|
+
import { Command as Command77 } from "commander";
|
|
8104
|
+
import * as p42 from "@clack/prompts";
|
|
7855
8105
|
import pc17 from "picocolors";
|
|
7856
8106
|
var envList = addTargetOptions(
|
|
7857
|
-
new
|
|
8107
|
+
new Command77("list").description("list environment variable names").configureHelp(helpConfig),
|
|
7858
8108
|
"local"
|
|
7859
8109
|
).action(
|
|
7860
8110
|
(raw) => runCommand(
|
|
@@ -7876,10 +8126,10 @@ var envList = addTargetOptions(
|
|
|
7876
8126
|
);
|
|
7877
8127
|
function report(keys, where) {
|
|
7878
8128
|
if (keys.length === 0) {
|
|
7879
|
-
|
|
8129
|
+
p42.log.info(`No environment variables configured ${pc17.dim(`(${where})`)}.`);
|
|
7880
8130
|
return;
|
|
7881
8131
|
}
|
|
7882
|
-
|
|
8132
|
+
p42.log.info(
|
|
7883
8133
|
`Environment ${pc17.dim(`(${where})`)}
|
|
7884
8134
|
|
|
7885
8135
|
` + keys.sort().map((key) => ` ${key}`).join("\n")
|
|
@@ -7888,11 +8138,11 @@ function report(keys, where) {
|
|
|
7888
8138
|
|
|
7889
8139
|
// src/commands/env/set.ts
|
|
7890
8140
|
import process27 from "node:process";
|
|
7891
|
-
import { Command as
|
|
7892
|
-
import * as
|
|
8141
|
+
import { Command as Command78 } from "commander";
|
|
8142
|
+
import * as p43 from "@clack/prompts";
|
|
7893
8143
|
import pc18 from "picocolors";
|
|
7894
8144
|
var envSet = addTargetOptions(
|
|
7895
|
-
new
|
|
8145
|
+
new Command78("set").description("set an environment variable").argument("<key>", "variable name").argument("[value]", "value \u2014 prompted for, without echo, when omitted").configureHelp(helpConfig),
|
|
7896
8146
|
"local"
|
|
7897
8147
|
).action(
|
|
7898
8148
|
(key, value, raw) => runCommand(
|
|
@@ -7902,14 +8152,14 @@ var envSet = addTargetOptions(
|
|
|
7902
8152
|
local: async (ctx) => {
|
|
7903
8153
|
const resolved = await resolveValue(key, value);
|
|
7904
8154
|
setLocalEnv(ctx.envFile, key, resolved);
|
|
7905
|
-
|
|
8155
|
+
p43.log.success(`${key} updated ${pc18.dim("(local)")}`);
|
|
7906
8156
|
await applyLocalEnvChange(ctx, [key]);
|
|
7907
8157
|
},
|
|
7908
8158
|
remote: async (ctx) => {
|
|
7909
8159
|
const resolved = await resolveValue(key, value);
|
|
7910
8160
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
7911
8161
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...env2, [key]: resolved });
|
|
7912
|
-
|
|
8162
|
+
p43.log.success(`${key} updated ${pc18.dim(`(${ctx.targetName})`)}`);
|
|
7913
8163
|
await applyEnvRestart(ctx, [key]);
|
|
7914
8164
|
}
|
|
7915
8165
|
},
|
|
@@ -7923,23 +8173,23 @@ async function resolveValue(key, value) {
|
|
|
7923
8173
|
return value ?? await promptValue(key);
|
|
7924
8174
|
}
|
|
7925
8175
|
async function promptValue(key) {
|
|
7926
|
-
const value = await
|
|
8176
|
+
const value = await p43.password({
|
|
7927
8177
|
message: `Value for ${pc18.cyan(key)}`,
|
|
7928
8178
|
validate: (input) => !input?.length ? "Required" : void 0
|
|
7929
8179
|
});
|
|
7930
|
-
if (
|
|
7931
|
-
|
|
8180
|
+
if (p43.isCancel(value)) {
|
|
8181
|
+
p43.cancel("Operation cancelled.");
|
|
7932
8182
|
process27.exit(0);
|
|
7933
8183
|
}
|
|
7934
8184
|
return value;
|
|
7935
8185
|
}
|
|
7936
8186
|
|
|
7937
8187
|
// src/commands/env/unset.ts
|
|
7938
|
-
import { Command as
|
|
7939
|
-
import * as
|
|
8188
|
+
import { Command as Command79 } from "commander";
|
|
8189
|
+
import * as p44 from "@clack/prompts";
|
|
7940
8190
|
import pc19 from "picocolors";
|
|
7941
8191
|
var envUnset = addTargetOptions(
|
|
7942
|
-
new
|
|
8192
|
+
new Command79("unset").description("remove an environment variable").argument("<key>", "variable name").configureHelp(helpConfig),
|
|
7943
8193
|
"local"
|
|
7944
8194
|
).action(
|
|
7945
8195
|
(key, raw) => runCommand(
|
|
@@ -7948,22 +8198,22 @@ var envUnset = addTargetOptions(
|
|
|
7948
8198
|
{
|
|
7949
8199
|
local: async (ctx) => {
|
|
7950
8200
|
if (!(key in readLocalEnv(ctx.envFile))) {
|
|
7951
|
-
|
|
8201
|
+
p44.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
7952
8202
|
return;
|
|
7953
8203
|
}
|
|
7954
8204
|
unsetLocalEnv(ctx.envFile, key);
|
|
7955
|
-
|
|
8205
|
+
p44.log.success(`${key} removed ${pc19.dim("(local)")}`);
|
|
7956
8206
|
await applyLocalEnvChange(ctx, [key]);
|
|
7957
8207
|
},
|
|
7958
8208
|
remote: async (ctx) => {
|
|
7959
8209
|
const env2 = await readRemoteEnv(ctx.session, ctx.instance);
|
|
7960
8210
|
if (!(key in env2)) {
|
|
7961
|
-
|
|
8211
|
+
p44.log.info(`${key} is not set \u2014 nothing to remove.`);
|
|
7962
8212
|
return;
|
|
7963
8213
|
}
|
|
7964
8214
|
delete env2[key];
|
|
7965
8215
|
await writeRemoteEnv(ctx.session, ctx.instance, env2);
|
|
7966
|
-
|
|
8216
|
+
p44.log.success(`${key} removed ${pc19.dim(`(${ctx.targetName})`)}`);
|
|
7967
8217
|
await applyEnvRestart(ctx, [key]);
|
|
7968
8218
|
}
|
|
7969
8219
|
},
|
|
@@ -7974,14 +8224,14 @@ var envUnset = addTargetOptions(
|
|
|
7974
8224
|
);
|
|
7975
8225
|
|
|
7976
8226
|
// src/commands/env/import.ts
|
|
7977
|
-
import
|
|
8227
|
+
import fs35 from "node:fs";
|
|
7978
8228
|
import path38 from "node:path";
|
|
7979
8229
|
import process28 from "node:process";
|
|
7980
|
-
import { Command as
|
|
7981
|
-
import * as
|
|
8230
|
+
import { Command as Command80 } from "commander";
|
|
8231
|
+
import * as p45 from "@clack/prompts";
|
|
7982
8232
|
import pc20 from "picocolors";
|
|
7983
8233
|
var envImport = addTargetOptions(
|
|
7984
|
-
new
|
|
8234
|
+
new Command80("import").description("merge a dotenv file into the environment").argument("<file>", "dotenv file to read").configureHelp(helpConfig),
|
|
7985
8235
|
"local"
|
|
7986
8236
|
).action(
|
|
7987
8237
|
(file, raw) => runCommand(
|
|
@@ -7996,22 +8246,22 @@ var envImport = addTargetOptions(
|
|
|
7996
8246
|
const incoming = read(source, file);
|
|
7997
8247
|
const keys = Object.keys(incoming);
|
|
7998
8248
|
if (keys.length === 0) return;
|
|
7999
|
-
|
|
8249
|
+
p45.log.step(`Importing ${keys.length} variable(s) from ${pc20.cyan(file)}`);
|
|
8000
8250
|
editLocalEnv(
|
|
8001
8251
|
ctx.envFile,
|
|
8002
8252
|
(content) => keys.reduce((acc, key) => upsertEnvVar(acc, key, incoming[key]), content)
|
|
8003
8253
|
);
|
|
8004
|
-
|
|
8254
|
+
p45.log.success(`${keys.length} variable(s) updated ${pc20.dim("(local)")}`);
|
|
8005
8255
|
await applyLocalEnvChange(ctx, keys);
|
|
8006
8256
|
},
|
|
8007
8257
|
remote: async (ctx) => {
|
|
8008
8258
|
const incoming = read(resolve(file), file);
|
|
8009
8259
|
const keys = Object.keys(incoming);
|
|
8010
8260
|
if (keys.length === 0) return;
|
|
8011
|
-
|
|
8261
|
+
p45.log.step(`Importing ${keys.length} variable(s) from ${pc20.cyan(file)}`);
|
|
8012
8262
|
const existing = await readRemoteEnv(ctx.session, ctx.instance);
|
|
8013
8263
|
await writeRemoteEnv(ctx.session, ctx.instance, { ...existing, ...incoming });
|
|
8014
|
-
|
|
8264
|
+
p45.log.success(`${keys.length} variable(s) updated ${pc20.dim(`(${ctx.targetName})`)}`);
|
|
8015
8265
|
await applyEnvRestart(ctx, keys);
|
|
8016
8266
|
}
|
|
8017
8267
|
},
|
|
@@ -8024,21 +8274,21 @@ function resolve(file) {
|
|
|
8024
8274
|
return path38.resolve(process28.cwd(), file);
|
|
8025
8275
|
}
|
|
8026
8276
|
function read(resolved, shown) {
|
|
8027
|
-
if (!
|
|
8277
|
+
if (!fs35.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
8028
8278
|
const incoming = readLocalEnvFile(resolved);
|
|
8029
|
-
if (Object.keys(incoming).length === 0)
|
|
8279
|
+
if (Object.keys(incoming).length === 0) p45.log.info(`${shown} has no variables to import.`);
|
|
8030
8280
|
return incoming;
|
|
8031
8281
|
}
|
|
8032
8282
|
|
|
8033
8283
|
// src/commands/env.ts
|
|
8034
|
-
var env = new
|
|
8284
|
+
var env = new Command81("env").description("manage environment variables, locally or on a target").configureHelp(helpConfig).addCommand(envList).addCommand(envSet).addCommand(envUnset).addCommand(envImport);
|
|
8035
8285
|
|
|
8036
8286
|
// src/commands/status.ts
|
|
8037
|
-
import { Command as
|
|
8038
|
-
import * as
|
|
8287
|
+
import { Command as Command82 } from "commander";
|
|
8288
|
+
import * as p46 from "@clack/prompts";
|
|
8039
8289
|
import pc21 from "picocolors";
|
|
8040
8290
|
var status = addTargetOptions(
|
|
8041
|
-
new
|
|
8291
|
+
new Command82("status").description("show what is deployed").configureHelp(helpConfig),
|
|
8042
8292
|
"production"
|
|
8043
8293
|
).option("--all", "show every app on the server, not just this project").option("--json", "print raw JSON").action(
|
|
8044
8294
|
(raw) => runCommand(async () => {
|
|
@@ -8069,11 +8319,11 @@ function report2(states, json) {
|
|
|
8069
8319
|
return;
|
|
8070
8320
|
}
|
|
8071
8321
|
if (states.length === 0) {
|
|
8072
|
-
|
|
8322
|
+
p46.log.info("Nothing is deployed here yet.");
|
|
8073
8323
|
return;
|
|
8074
8324
|
}
|
|
8075
8325
|
for (const state of states) {
|
|
8076
|
-
|
|
8326
|
+
p46.log.info(describe(state));
|
|
8077
8327
|
}
|
|
8078
8328
|
}
|
|
8079
8329
|
function describe(state) {
|
|
@@ -8096,11 +8346,11 @@ function describe(state) {
|
|
|
8096
8346
|
}
|
|
8097
8347
|
|
|
8098
8348
|
// src/commands/rollback.ts
|
|
8099
|
-
import { Command as
|
|
8100
|
-
import * as
|
|
8349
|
+
import { Command as Command83 } from "commander";
|
|
8350
|
+
import * as p47 from "@clack/prompts";
|
|
8101
8351
|
import pc22 from "picocolors";
|
|
8102
8352
|
var rollback = addTargetOptions(
|
|
8103
|
-
new
|
|
8353
|
+
new Command83("rollback").description("put the previous release back").configureHelp(helpConfig),
|
|
8104
8354
|
"production"
|
|
8105
8355
|
).option("--to <release>", "roll back to a specific release instead of the previous one").action(
|
|
8106
8356
|
(raw) => runCommand(async () => {
|
|
@@ -8109,7 +8359,7 @@ var rollback = addTargetOptions(
|
|
|
8109
8359
|
raw,
|
|
8110
8360
|
{
|
|
8111
8361
|
remote: async (ctx) => {
|
|
8112
|
-
|
|
8362
|
+
p47.log.step(
|
|
8113
8363
|
`Rolling back ${pc22.cyan(ctx.appName)} ${pc22.dim(`(${ctx.targetName})`)} on ${ctx.server}`
|
|
8114
8364
|
);
|
|
8115
8365
|
const result = await runServerScript(
|
|
@@ -8120,7 +8370,7 @@ var rollback = addTargetOptions(
|
|
|
8120
8370
|
stream: true
|
|
8121
8371
|
}
|
|
8122
8372
|
);
|
|
8123
|
-
|
|
8373
|
+
p47.log.success(
|
|
8124
8374
|
`Rolled back to ${pc22.cyan(result?.release ?? "the previous release")}` + (result?.from ? ` ${pc22.dim(`(was ${result.from})`)}` : "")
|
|
8125
8375
|
);
|
|
8126
8376
|
}
|
|
@@ -8134,9 +8384,9 @@ var rollback = addTargetOptions(
|
|
|
8134
8384
|
);
|
|
8135
8385
|
|
|
8136
8386
|
// src/commands/logs.ts
|
|
8137
|
-
import { Command as
|
|
8387
|
+
import { Command as Command84 } from "commander";
|
|
8138
8388
|
var logs = addTargetOptions(
|
|
8139
|
-
new
|
|
8389
|
+
new Command84("logs").description("tail the logs of a deployed app").configureHelp(helpConfig),
|
|
8140
8390
|
"production"
|
|
8141
8391
|
).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(
|
|
8142
8392
|
(raw) => runCommand(async () => {
|
|
@@ -8170,16 +8420,16 @@ var logs = addTargetOptions(
|
|
|
8170
8420
|
);
|
|
8171
8421
|
|
|
8172
8422
|
// src/commands/admin.ts
|
|
8173
|
-
import { Command as
|
|
8423
|
+
import { Command as Command86 } from "commander";
|
|
8174
8424
|
|
|
8175
8425
|
// src/commands/admin/create.ts
|
|
8176
8426
|
import process29 from "node:process";
|
|
8177
|
-
import { Command as
|
|
8178
|
-
import * as
|
|
8427
|
+
import { Command as Command85 } from "commander";
|
|
8428
|
+
import * as p48 from "@clack/prompts";
|
|
8179
8429
|
import pc23 from "picocolors";
|
|
8180
8430
|
var MIN_PASSWORD = 10;
|
|
8181
8431
|
var adminCreate = addTargetOptions(
|
|
8182
|
-
new
|
|
8432
|
+
new Command85("create").description("create a login for the admin panel").argument("[email]", "email to sign in with \u2014 prompted for when omitted").configureHelp(helpConfig),
|
|
8183
8433
|
"local"
|
|
8184
8434
|
).action(
|
|
8185
8435
|
(email3, raw) => runCommand(
|
|
@@ -8207,7 +8457,7 @@ var adminCreate = addTargetOptions(
|
|
|
8207
8457
|
const metadata = getPocketbaseMetadata(ctx.workspaceRootDir);
|
|
8208
8458
|
if (metadata) signIn = `http://${metadata.viteHost}:${metadata.vitePort}`;
|
|
8209
8459
|
}
|
|
8210
|
-
|
|
8460
|
+
p48.log.info(
|
|
8211
8461
|
signIn ? `Sign in at ${pc23.cyan(`${signIn}/admin`)}` : `Sign in at ${pc23.cyan("/admin")} once ${pc23.cyan("vela dev")} is running.`
|
|
8212
8462
|
);
|
|
8213
8463
|
},
|
|
@@ -8221,7 +8471,7 @@ var adminCreate = addTargetOptions(
|
|
|
8221
8471
|
(pb) => upsertSuperuser(pb, address, password11)
|
|
8222
8472
|
);
|
|
8223
8473
|
const base2 = state?.domain ? `https://${state.domain.split(",")[0].trim()}` : "";
|
|
8224
|
-
|
|
8474
|
+
p48.log.info(
|
|
8225
8475
|
base2 ? `Sign in at ${pc23.cyan(`${base2}/admin`)}` : `Sign in at ${pc23.cyan("/admin")} once a domain is configured for this target.`
|
|
8226
8476
|
);
|
|
8227
8477
|
}
|
|
@@ -8234,20 +8484,20 @@ var adminCreate = addTargetOptions(
|
|
|
8234
8484
|
async function upsertSuperuser(pb, email3, password11) {
|
|
8235
8485
|
const existing = await findSuperuser(pb, email3);
|
|
8236
8486
|
if (existing) {
|
|
8237
|
-
const confirmed = await
|
|
8487
|
+
const confirmed = await p48.confirm({
|
|
8238
8488
|
message: `${email3} already has an account, update its password?`,
|
|
8239
8489
|
initialValue: false
|
|
8240
8490
|
});
|
|
8241
|
-
if (
|
|
8242
|
-
|
|
8491
|
+
if (p48.isCancel(confirmed) || !confirmed) {
|
|
8492
|
+
p48.cancel("Operation cancelled.");
|
|
8243
8493
|
process29.exit(0);
|
|
8244
8494
|
}
|
|
8245
8495
|
await pb.collection("_superusers").update(existing, { password: password11, passwordConfirm: password11 });
|
|
8246
|
-
|
|
8496
|
+
p48.log.success(`Password updated for ${pc23.cyan(email3)}, you can sign in now`);
|
|
8247
8497
|
return;
|
|
8248
8498
|
}
|
|
8249
8499
|
await pb.collection("_superusers").create({ email: email3, password: password11, passwordConfirm: password11 });
|
|
8250
|
-
|
|
8500
|
+
p48.log.success(`${pc23.cyan(email3)} can now sign in`);
|
|
8251
8501
|
}
|
|
8252
8502
|
async function findSuperuser(pb, email3) {
|
|
8253
8503
|
try {
|
|
@@ -8258,47 +8508,47 @@ async function findSuperuser(pb, email3) {
|
|
|
8258
8508
|
}
|
|
8259
8509
|
}
|
|
8260
8510
|
async function promptEmail() {
|
|
8261
|
-
const value = await
|
|
8511
|
+
const value = await p48.text({
|
|
8262
8512
|
message: "Email to sign in with",
|
|
8263
8513
|
validate: (input) => input?.includes("@") ? void 0 : "An email address is required"
|
|
8264
8514
|
});
|
|
8265
|
-
if (
|
|
8266
|
-
|
|
8515
|
+
if (p48.isCancel(value)) {
|
|
8516
|
+
p48.cancel("Operation cancelled.");
|
|
8267
8517
|
process29.exit(0);
|
|
8268
8518
|
}
|
|
8269
8519
|
return value.trim();
|
|
8270
8520
|
}
|
|
8271
8521
|
async function promptPassword2() {
|
|
8272
|
-
const value = await
|
|
8522
|
+
const value = await p48.password({
|
|
8273
8523
|
message: "Password",
|
|
8274
8524
|
validate: (input) => (input?.length ?? 0) >= MIN_PASSWORD ? void 0 : `At least ${MIN_PASSWORD} characters is required`
|
|
8275
8525
|
});
|
|
8276
|
-
if (
|
|
8277
|
-
|
|
8526
|
+
if (p48.isCancel(value)) {
|
|
8527
|
+
p48.cancel("Operation cancelled.");
|
|
8278
8528
|
process29.exit(0);
|
|
8279
8529
|
}
|
|
8280
|
-
const again = await
|
|
8530
|
+
const again = await p48.password({
|
|
8281
8531
|
message: "Password again",
|
|
8282
8532
|
validate: (input) => input === value ? void 0 : "The two do not match"
|
|
8283
8533
|
});
|
|
8284
|
-
if (
|
|
8285
|
-
|
|
8534
|
+
if (p48.isCancel(again)) {
|
|
8535
|
+
p48.cancel("Operation cancelled.");
|
|
8286
8536
|
process29.exit(0);
|
|
8287
8537
|
}
|
|
8288
8538
|
return value;
|
|
8289
8539
|
}
|
|
8290
8540
|
|
|
8291
8541
|
// src/commands/admin.ts
|
|
8292
|
-
var admin = new
|
|
8542
|
+
var admin = new Command86("admin").description("manage admin panel logins").configureHelp(helpConfig).addCommand(adminCreate);
|
|
8293
8543
|
|
|
8294
8544
|
// src/commands/backup.ts
|
|
8295
|
-
import { Command as
|
|
8545
|
+
import { Command as Command92 } from "commander";
|
|
8296
8546
|
|
|
8297
8547
|
// src/commands/backup/create.ts
|
|
8298
|
-
import
|
|
8548
|
+
import fs36 from "node:fs";
|
|
8299
8549
|
import path39 from "node:path";
|
|
8300
|
-
import { Command as
|
|
8301
|
-
import * as
|
|
8550
|
+
import { Command as Command87 } from "commander";
|
|
8551
|
+
import * as p49 from "@clack/prompts";
|
|
8302
8552
|
import pc24 from "picocolors";
|
|
8303
8553
|
|
|
8304
8554
|
// src/lib/backups.ts
|
|
@@ -8320,8 +8570,8 @@ async function readStorageSettings(pb) {
|
|
|
8320
8570
|
};
|
|
8321
8571
|
}
|
|
8322
8572
|
async function listBackups(pb) {
|
|
8323
|
-
const
|
|
8324
|
-
return [...
|
|
8573
|
+
const list3 = await pb.backups.getFullList();
|
|
8574
|
+
return [...list3].sort((a, b) => b.modified.localeCompare(a.modified));
|
|
8325
8575
|
}
|
|
8326
8576
|
function isClientTimeout(error) {
|
|
8327
8577
|
for (let e = error, depth = 0; e && depth < 5; depth++) {
|
|
@@ -8386,7 +8636,7 @@ async function writeSchedule(pb, cron, maxKeep) {
|
|
|
8386
8636
|
// src/commands/backup/create.ts
|
|
8387
8637
|
var DEFAULT_BACKUP_DIR = "backups";
|
|
8388
8638
|
var backupCreate = addTargetOptions(
|
|
8389
|
-
new
|
|
8639
|
+
new Command87("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),
|
|
8390
8640
|
"production"
|
|
8391
8641
|
).action(
|
|
8392
8642
|
(name, raw) => runCommand(() => {
|
|
@@ -8402,7 +8652,7 @@ Backup names are lowercase letters, digits, ${pc24.cyan("-")} and ${pc24.cyan("_
|
|
|
8402
8652
|
}
|
|
8403
8653
|
const storage = await readStorageSettings(ctx.pb);
|
|
8404
8654
|
if (storage.s3Enabled) {
|
|
8405
|
-
|
|
8655
|
+
p49.log.warn(
|
|
8406
8656
|
`Uploads are stored in S3, so this archive holds the database only.
|
|
8407
8657
|
|
|
8408
8658
|
PocketBase leaves ${pc24.cyan("storage/")} out of a backup whenever S3 is on.
|
|
@@ -8410,16 +8660,16 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
8410
8660
|
);
|
|
8411
8661
|
}
|
|
8412
8662
|
if (ctx.session) await checkpointAppDatabases(ctx.session, ctx.instance);
|
|
8413
|
-
const
|
|
8414
|
-
|
|
8663
|
+
const spinner7 = p49.spinner();
|
|
8664
|
+
spinner7.start(`Backing up ${ctx.targetName}`);
|
|
8415
8665
|
try {
|
|
8416
8666
|
await createBackup(ctx.pb, key);
|
|
8417
8667
|
} catch (error) {
|
|
8418
|
-
|
|
8668
|
+
spinner7.stop(`Backup of ${ctx.targetName} failed.`);
|
|
8419
8669
|
throw error;
|
|
8420
8670
|
}
|
|
8421
8671
|
const size = (await listBackups(ctx.pb)).find((b) => b.key === key)?.size ?? 0;
|
|
8422
|
-
|
|
8672
|
+
spinner7.stop(`Backed up ${ctx.targetName} \u2014 ${key} (${formatBytes(size)})`);
|
|
8423
8673
|
if (storage.backupsS3Enabled) {
|
|
8424
8674
|
reportResult({
|
|
8425
8675
|
summary: `Backed up ${ctx.targetName} to your backups bucket.`,
|
|
@@ -8451,37 +8701,37 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
8451
8701
|
);
|
|
8452
8702
|
async function download(ctx, key, outputDir) {
|
|
8453
8703
|
const dir = path39.resolve(ctx.workspaceRootDir, outputDir);
|
|
8454
|
-
|
|
8704
|
+
fs36.mkdirSync(dir, { recursive: true });
|
|
8455
8705
|
const destination = path39.join(dir, key);
|
|
8456
8706
|
if (!ctx.session) {
|
|
8457
|
-
|
|
8707
|
+
fs36.copyFileSync(path39.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
8458
8708
|
return path39.relative(ctx.workspaceRootDir, destination);
|
|
8459
8709
|
}
|
|
8460
|
-
const
|
|
8461
|
-
|
|
8710
|
+
const spinner7 = p49.spinner();
|
|
8711
|
+
spinner7.start(`Downloading ${key}`);
|
|
8462
8712
|
try {
|
|
8463
8713
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
8464
8714
|
} catch (error) {
|
|
8465
|
-
|
|
8715
|
+
spinner7.stop(`Could not download ${key}.`);
|
|
8466
8716
|
throw error;
|
|
8467
8717
|
}
|
|
8468
|
-
|
|
8718
|
+
spinner7.stop(`Downloaded ${key}`);
|
|
8469
8719
|
return path39.relative(ctx.workspaceRootDir, destination);
|
|
8470
8720
|
}
|
|
8471
8721
|
|
|
8472
8722
|
// src/commands/backup/list.ts
|
|
8473
|
-
import { Command as
|
|
8474
|
-
import * as
|
|
8723
|
+
import { Command as Command88 } from "commander";
|
|
8724
|
+
import * as p50 from "@clack/prompts";
|
|
8475
8725
|
import pc25 from "picocolors";
|
|
8476
8726
|
var backupList = addTargetOptions(
|
|
8477
|
-
new
|
|
8727
|
+
new Command88("list").description("list the backups on a target").configureHelp(helpConfig),
|
|
8478
8728
|
"production"
|
|
8479
8729
|
).action(
|
|
8480
8730
|
(raw) => runCommand(
|
|
8481
8731
|
() => withBackupTarget(raw, "backup list", async (ctx) => {
|
|
8482
8732
|
const backups = await listBackups(ctx.pb);
|
|
8483
8733
|
if (backups.length === 0) {
|
|
8484
|
-
|
|
8734
|
+
p50.log.info(
|
|
8485
8735
|
`${pc25.cyan(ctx.targetName)} has no backups yet.
|
|
8486
8736
|
|
|
8487
8737
|
Take one with ${pc25.cyan("vela backup create")}.`
|
|
@@ -8489,7 +8739,7 @@ Take one with ${pc25.cyan("vela backup create")}.`
|
|
|
8489
8739
|
return;
|
|
8490
8740
|
}
|
|
8491
8741
|
const width = Math.max(...backups.map((b) => b.key.length));
|
|
8492
|
-
|
|
8742
|
+
p50.log.message(
|
|
8493
8743
|
backups.map(
|
|
8494
8744
|
(b) => `${b.key.padEnd(width)} ${pc25.dim(formatBytes(b.size).padStart(8))} ${pc25.dim(b.modified)}`
|
|
8495
8745
|
).join("\n")
|
|
@@ -8500,13 +8750,13 @@ Take one with ${pc25.cyan("vela backup create")}.`
|
|
|
8500
8750
|
);
|
|
8501
8751
|
|
|
8502
8752
|
// src/commands/backup/download.ts
|
|
8503
|
-
import
|
|
8753
|
+
import fs37 from "node:fs";
|
|
8504
8754
|
import path40 from "node:path";
|
|
8505
|
-
import { Command as
|
|
8506
|
-
import * as
|
|
8755
|
+
import { Command as Command89 } from "commander";
|
|
8756
|
+
import * as p51 from "@clack/prompts";
|
|
8507
8757
|
import pc26 from "picocolors";
|
|
8508
8758
|
var backupDownload = addTargetOptions(
|
|
8509
|
-
new
|
|
8759
|
+
new Command89("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),
|
|
8510
8760
|
"production"
|
|
8511
8761
|
).action(
|
|
8512
8762
|
(key, raw) => runCommand(() => {
|
|
@@ -8529,20 +8779,20 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
8529
8779
|
);
|
|
8530
8780
|
}
|
|
8531
8781
|
const dir = path40.resolve(ctx.workspaceRootDir, options.output);
|
|
8532
|
-
|
|
8782
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
8533
8783
|
const destination = path40.join(dir, key);
|
|
8534
8784
|
if (!ctx.session) {
|
|
8535
|
-
|
|
8785
|
+
fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
8536
8786
|
} else {
|
|
8537
|
-
const
|
|
8538
|
-
|
|
8787
|
+
const spinner7 = p51.spinner();
|
|
8788
|
+
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
8539
8789
|
try {
|
|
8540
8790
|
await ctx.session.download(remotePaths.backup(ctx.instance, key), destination);
|
|
8541
8791
|
} catch (error) {
|
|
8542
|
-
|
|
8792
|
+
spinner7.stop(`Could not download ${key}.`);
|
|
8543
8793
|
throw error;
|
|
8544
8794
|
}
|
|
8545
|
-
|
|
8795
|
+
spinner7.stop(`Downloaded ${key}`);
|
|
8546
8796
|
}
|
|
8547
8797
|
reportResult({
|
|
8548
8798
|
summary: `Saved ${key} from ${ctx.targetName}.`,
|
|
@@ -8554,11 +8804,11 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
8554
8804
|
|
|
8555
8805
|
// src/commands/backup/delete.ts
|
|
8556
8806
|
import process30 from "node:process";
|
|
8557
|
-
import { Command as
|
|
8558
|
-
import * as
|
|
8807
|
+
import { Command as Command90 } from "commander";
|
|
8808
|
+
import * as p52 from "@clack/prompts";
|
|
8559
8809
|
import pc27 from "picocolors";
|
|
8560
8810
|
var backupDelete = addTargetOptions(
|
|
8561
|
-
new
|
|
8811
|
+
new Command90("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),
|
|
8562
8812
|
"production"
|
|
8563
8813
|
).action(
|
|
8564
8814
|
(key, raw) => runCommand(() => {
|
|
@@ -8573,12 +8823,12 @@ Run ${pc27.cyan("vela backup list")} to see what it does have.`
|
|
|
8573
8823
|
);
|
|
8574
8824
|
}
|
|
8575
8825
|
if (!options.yes) {
|
|
8576
|
-
const confirmed = await
|
|
8826
|
+
const confirmed = await p52.confirm({
|
|
8577
8827
|
message: `Delete ${key} (${formatBytes(found.size)}) from ${ctx.targetName}?`,
|
|
8578
8828
|
initialValue: false
|
|
8579
8829
|
});
|
|
8580
|
-
if (
|
|
8581
|
-
|
|
8830
|
+
if (p52.isCancel(confirmed) || !confirmed) {
|
|
8831
|
+
p52.cancel("Operation cancelled.");
|
|
8582
8832
|
process30.exit(0);
|
|
8583
8833
|
}
|
|
8584
8834
|
}
|
|
@@ -8589,12 +8839,12 @@ Run ${pc27.cyan("vela backup list")} to see what it does have.`
|
|
|
8589
8839
|
);
|
|
8590
8840
|
|
|
8591
8841
|
// src/commands/backup/schedule.ts
|
|
8592
|
-
import { Command as
|
|
8593
|
-
import * as
|
|
8842
|
+
import { Command as Command91 } from "commander";
|
|
8843
|
+
import * as p53 from "@clack/prompts";
|
|
8594
8844
|
import pc28 from "picocolors";
|
|
8595
8845
|
var DEFAULT_KEEP = 7;
|
|
8596
8846
|
var backupSchedule = addTargetOptions(
|
|
8597
|
-
new
|
|
8847
|
+
new Command91("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),
|
|
8598
8848
|
"production"
|
|
8599
8849
|
).action(
|
|
8600
8850
|
(cron, raw) => runCommand(() => {
|
|
@@ -8607,7 +8857,7 @@ var backupSchedule = addTargetOptions(
|
|
|
8607
8857
|
}
|
|
8608
8858
|
if (!cron) {
|
|
8609
8859
|
const current = await readSchedule(ctx.pb);
|
|
8610
|
-
|
|
8860
|
+
p53.log.info(
|
|
8611
8861
|
current.cron ? `${ctx.targetName} backs up on ${pc28.cyan(current.cron)}, keeping ${current.maxKeep}.` : `${ctx.targetName} has no backup schedule.
|
|
8612
8862
|
|
|
8613
8863
|
Set one with ${pc28.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
@@ -8638,17 +8888,17 @@ Set one with ${pc28.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
|
8638
8888
|
);
|
|
8639
8889
|
|
|
8640
8890
|
// src/commands/backup.ts
|
|
8641
|
-
var backup = new
|
|
8891
|
+
var backup = new Command92("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);
|
|
8642
8892
|
|
|
8643
8893
|
// src/commands/restore.ts
|
|
8644
|
-
import
|
|
8894
|
+
import fs38 from "node:fs";
|
|
8645
8895
|
import path41 from "node:path";
|
|
8646
8896
|
import process31 from "node:process";
|
|
8647
|
-
import { Command as
|
|
8648
|
-
import * as
|
|
8897
|
+
import { Command as Command93 } from "commander";
|
|
8898
|
+
import * as p54 from "@clack/prompts";
|
|
8649
8899
|
import pc29 from "picocolors";
|
|
8650
8900
|
var restore = addTargetOptions(
|
|
8651
|
-
new
|
|
8901
|
+
new Command93("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),
|
|
8652
8902
|
"production"
|
|
8653
8903
|
).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(
|
|
8654
8904
|
(source, raw) => runCommand(async () => {
|
|
@@ -8663,10 +8913,10 @@ var restore = addTargetOptions(
|
|
|
8663
8913
|
`${ctx.targetName} was deployed without a database, so there is nothing to restore.`
|
|
8664
8914
|
);
|
|
8665
8915
|
}
|
|
8666
|
-
const local = source &&
|
|
8916
|
+
const local = source && fs38.existsSync(source) ? source : void 0;
|
|
8667
8917
|
const key = local ? void 0 : await resolveKey(ctx, source);
|
|
8668
8918
|
if (!options.yes) {
|
|
8669
|
-
await
|
|
8919
|
+
await confirm12(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
|
|
8670
8920
|
}
|
|
8671
8921
|
const archive = local ? await stage(ctx, local) : remotePaths.backup(ctx.instance, key);
|
|
8672
8922
|
const result = await runServerScript(ctx.session, "restore.sh", {
|
|
@@ -8683,18 +8933,18 @@ var restore = addTargetOptions(
|
|
|
8683
8933
|
],
|
|
8684
8934
|
stream: true
|
|
8685
8935
|
});
|
|
8686
|
-
|
|
8936
|
+
p54.log.success(
|
|
8687
8937
|
`Restored ${pc29.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc29.cyan(
|
|
8688
8938
|
local ? path41.basename(local) : key
|
|
8689
8939
|
)}.`
|
|
8690
8940
|
);
|
|
8691
8941
|
if (result?.storageCarriedOver) {
|
|
8692
|
-
|
|
8942
|
+
p54.log.info(
|
|
8693
8943
|
"The archive held no uploads, so the files already on the server were kept."
|
|
8694
8944
|
);
|
|
8695
8945
|
}
|
|
8696
8946
|
if (result?.previousDataDir) {
|
|
8697
|
-
|
|
8947
|
+
p54.log.info(
|
|
8698
8948
|
`The database this replaced is at ${pc29.cyan(result.previousDataDir)}.
|
|
8699
8949
|
|
|
8700
8950
|
It is the only way back. Remove it once you are satisfied with the restore.`
|
|
@@ -8735,7 +8985,7 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
|
|
|
8735
8985
|
Take one with ${pc29.cyan("vela backup create")}, or pass the path to an archive on this machine.`
|
|
8736
8986
|
);
|
|
8737
8987
|
}
|
|
8738
|
-
const chosen = await
|
|
8988
|
+
const chosen = await p54.select({
|
|
8739
8989
|
message: `Which backup should ${ctx.targetName} be restored from?`,
|
|
8740
8990
|
options: backups.map((b) => ({
|
|
8741
8991
|
value: b.key,
|
|
@@ -8743,8 +8993,8 @@ Take one with ${pc29.cyan("vela backup create")}, or pass the path to an archive
|
|
|
8743
8993
|
hint: `${formatBytes(b.size)}, ${b.modified}`
|
|
8744
8994
|
}))
|
|
8745
8995
|
});
|
|
8746
|
-
if (
|
|
8747
|
-
|
|
8996
|
+
if (p54.isCancel(chosen)) {
|
|
8997
|
+
p54.cancel("Operation cancelled.");
|
|
8748
8998
|
process31.exit(0);
|
|
8749
8999
|
}
|
|
8750
9000
|
return chosen;
|
|
@@ -8752,44 +9002,44 @@ Take one with ${pc29.cyan("vela backup create")}, or pass the path to an archive
|
|
|
8752
9002
|
async function stage(ctx, file) {
|
|
8753
9003
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
8754
9004
|
const remote = `${dir}/${path41.basename(file)}`;
|
|
8755
|
-
const
|
|
8756
|
-
|
|
9005
|
+
const spinner7 = p54.spinner();
|
|
9006
|
+
spinner7.start(`Uploading ${path41.basename(file)}`);
|
|
8757
9007
|
try {
|
|
8758
9008
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
8759
9009
|
await ctx.session.upload([file], dir);
|
|
8760
9010
|
} catch (error) {
|
|
8761
|
-
|
|
9011
|
+
spinner7.stop(`Could not upload ${path41.basename(file)}.`);
|
|
8762
9012
|
throw error;
|
|
8763
9013
|
}
|
|
8764
|
-
|
|
9014
|
+
spinner7.stop(`Uploaded ${path41.basename(file)}`);
|
|
8765
9015
|
return remote;
|
|
8766
9016
|
}
|
|
8767
|
-
async function
|
|
9017
|
+
async function confirm12(appName, targetName, envTag, from) {
|
|
8768
9018
|
const what = `${pc29.cyan(`${appName} (${targetName})`)} from ${pc29.cyan(path41.basename(from))}`;
|
|
8769
9019
|
if (isProd(envTag)) {
|
|
8770
|
-
const answer = await
|
|
9020
|
+
const answer = await p54.text({
|
|
8771
9021
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
8772
9022
|
validate: (value) => value === appName ? void 0 : `Type ${appName} to confirm`
|
|
8773
9023
|
});
|
|
8774
|
-
if (
|
|
8775
|
-
|
|
9024
|
+
if (p54.isCancel(answer)) {
|
|
9025
|
+
p54.cancel("Operation cancelled.");
|
|
8776
9026
|
process31.exit(0);
|
|
8777
9027
|
}
|
|
8778
9028
|
return;
|
|
8779
9029
|
}
|
|
8780
|
-
const ok = await
|
|
9030
|
+
const ok = await p54.confirm({
|
|
8781
9031
|
message: `Replace the database and uploads of ${what}?`,
|
|
8782
9032
|
initialValue: false
|
|
8783
9033
|
});
|
|
8784
|
-
if (
|
|
8785
|
-
|
|
9034
|
+
if (p54.isCancel(ok) || !ok) {
|
|
9035
|
+
p54.cancel("Operation cancelled.");
|
|
8786
9036
|
process31.exit(0);
|
|
8787
9037
|
}
|
|
8788
9038
|
}
|
|
8789
9039
|
|
|
8790
9040
|
// src/commands/targets.ts
|
|
8791
|
-
import { Command as
|
|
8792
|
-
import * as
|
|
9041
|
+
import { Command as Command94 } from "commander";
|
|
9042
|
+
import * as p55 from "@clack/prompts";
|
|
8793
9043
|
import pc30 from "picocolors";
|
|
8794
9044
|
import * as v8 from "valibot";
|
|
8795
9045
|
var OptionsSchema4 = v8.object({
|
|
@@ -8798,7 +9048,7 @@ var OptionsSchema4 = v8.object({
|
|
|
8798
9048
|
offline: v8.optional(v8.boolean())
|
|
8799
9049
|
});
|
|
8800
9050
|
var targets = addSshOptions(
|
|
8801
|
-
new
|
|
9051
|
+
new Command94("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
|
|
8802
9052
|
).option("--json", "print raw JSON").option("--offline", "skip connecting to servers").action(
|
|
8803
9053
|
(raw) => runCommand(async () => {
|
|
8804
9054
|
const options = parseOptions(OptionsSchema4, raw);
|
|
@@ -8864,11 +9114,11 @@ function report3(rows, offline) {
|
|
|
8864
9114
|
const lines = rows.map(
|
|
8865
9115
|
(row) => `${row.kind === "local" ? pc30.dim(row.target.padEnd(target)) : pc30.cyan(row.target.padEnd(target))} ${row.server.padEnd(server)} ${row.domain.padEnd(domain)} ${row.release}`
|
|
8866
9116
|
);
|
|
8867
|
-
|
|
9117
|
+
p55.log.info(`${pc30.dim(header)}
|
|
8868
9118
|
${lines.join("\n")}`);
|
|
8869
9119
|
const unreachable = rows.filter((row) => row.kind === "remote" && !row.reachable);
|
|
8870
9120
|
if (!offline && unreachable.length > 0) {
|
|
8871
|
-
|
|
9121
|
+
p55.log.warn(
|
|
8872
9122
|
`Could not reach ${unreachable.map((row) => row.server).join(", ")}.
|
|
8873
9123
|
Release and domain are shown from what this project recorded.`
|
|
8874
9124
|
);
|
|
@@ -8878,19 +9128,19 @@ Release and domain are shown from what this project recorded.`
|
|
|
8878
9128
|
// src/commands/test.ts
|
|
8879
9129
|
import path42 from "node:path";
|
|
8880
9130
|
import process32 from "node:process";
|
|
8881
|
-
import { Command as
|
|
9131
|
+
import { Command as Command95 } from "commander";
|
|
8882
9132
|
import PocketBase6 from "pocketbase";
|
|
8883
9133
|
import pc31 from "picocolors";
|
|
8884
9134
|
import { x as x5 } from "tinyexec";
|
|
8885
|
-
import { detect as
|
|
8886
|
-
import { resolveCommand as
|
|
8887
|
-
import
|
|
8888
|
-
var testServer = new
|
|
9135
|
+
import { detect as detect7 } from "package-manager-detector";
|
|
9136
|
+
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
9137
|
+
import fs39 from "node:fs";
|
|
9138
|
+
var testServer = new Command95("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
8889
9139
|
const cwd = process32.cwd();
|
|
8890
9140
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
8891
9141
|
const password11 = "password";
|
|
8892
9142
|
const testDataDir = path42.join(cwd, "test-data");
|
|
8893
|
-
|
|
9143
|
+
fs39.rmSync(testDataDir, { recursive: true, force: true });
|
|
8894
9144
|
const { stop, url } = await launchPocketbase(cwd, {
|
|
8895
9145
|
dir: testDataDir,
|
|
8896
9146
|
migrationsDir: path42.join(cwd, MIGRATIONS_DIR),
|
|
@@ -8913,7 +9163,7 @@ var testServer = new Command92("test:server").description("run server tests").al
|
|
|
8913
9163
|
if (cleanedUp) return;
|
|
8914
9164
|
cleanedUp = true;
|
|
8915
9165
|
stop();
|
|
8916
|
-
|
|
9166
|
+
fs39.rmSync(testDataDir, { recursive: true, force: true });
|
|
8917
9167
|
};
|
|
8918
9168
|
const cleanup = async () => {
|
|
8919
9169
|
if (cleanedUp) return;
|
|
@@ -8965,8 +9215,8 @@ var testServer = new Command92("test:server").description("run server tests").al
|
|
|
8965
9215
|
const passthrough = filter ? extraArgs.filter((a) => a !== filter) : extraArgs;
|
|
8966
9216
|
if (!filter) filter = "server";
|
|
8967
9217
|
try {
|
|
8968
|
-
const pm = (await
|
|
8969
|
-
const resolved =
|
|
9218
|
+
const pm = (await detect7({ cwd }))?.name ?? "npm";
|
|
9219
|
+
const resolved = resolveCommand7(pm, "execute", [
|
|
8970
9220
|
"vitest",
|
|
8971
9221
|
"run",
|
|
8972
9222
|
filter,
|
|
@@ -9012,9 +9262,9 @@ function stubPagesPlugin() {
|
|
|
9012
9262
|
}
|
|
9013
9263
|
|
|
9014
9264
|
// src/commands/routes.ts
|
|
9015
|
-
import
|
|
9265
|
+
import fs40 from "node:fs";
|
|
9016
9266
|
import path43 from "node:path";
|
|
9017
|
-
import { Command as
|
|
9267
|
+
import { Command as Command96 } from "commander";
|
|
9018
9268
|
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
9019
9269
|
"GET",
|
|
9020
9270
|
"POST",
|
|
@@ -9025,7 +9275,7 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
9025
9275
|
"HEAD",
|
|
9026
9276
|
"fallback"
|
|
9027
9277
|
]);
|
|
9028
|
-
var routes = new
|
|
9278
|
+
var routes = new Command96("routes").description("list routes").configureHelp(helpConfig).action(async () => {
|
|
9029
9279
|
const { workspaceRootDir, routesDir } = await getWorkspace();
|
|
9030
9280
|
const routesRoot = path43.join(workspaceRootDir, routesDir);
|
|
9031
9281
|
const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
|
|
@@ -9033,7 +9283,7 @@ var routes = new Command93("routes").description("list routes").configureHelp(he
|
|
|
9033
9283
|
printTable(found);
|
|
9034
9284
|
});
|
|
9035
9285
|
function walk(root, dir) {
|
|
9036
|
-
const entries =
|
|
9286
|
+
const entries = fs40.readdirSync(dir, { withFileTypes: true });
|
|
9037
9287
|
const routes2 = [];
|
|
9038
9288
|
const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
|
|
9039
9289
|
if (hasLeaf) {
|
|
@@ -9059,7 +9309,7 @@ function isRouteFile(name) {
|
|
|
9059
9309
|
}
|
|
9060
9310
|
function extractMethods(file) {
|
|
9061
9311
|
try {
|
|
9062
|
-
const content =
|
|
9312
|
+
const content = fs40.readFileSync(file, "utf8");
|
|
9063
9313
|
const methods = [];
|
|
9064
9314
|
const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
|
|
9065
9315
|
let match;
|
|
@@ -9101,14 +9351,14 @@ function printTable(routes2) {
|
|
|
9101
9351
|
|
|
9102
9352
|
// src/commands/i18n.ts
|
|
9103
9353
|
import process33 from "node:process";
|
|
9104
|
-
import { Command as
|
|
9354
|
+
import { Command as Command97 } from "commander";
|
|
9105
9355
|
import { x as x6 } from "tinyexec";
|
|
9106
|
-
import { detect as
|
|
9107
|
-
import { resolveCommand as
|
|
9356
|
+
import { detect as detect8 } from "package-manager-detector";
|
|
9357
|
+
import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
|
|
9108
9358
|
async function runWuchale(extraArgs) {
|
|
9109
9359
|
const cwd = process33.cwd();
|
|
9110
|
-
const pm = (await
|
|
9111
|
-
const resolved =
|
|
9360
|
+
const pm = (await detect8({ cwd }))?.name ?? "npm";
|
|
9361
|
+
const resolved = resolveCommand8(pm, "execute", ["wuchale", ...extraArgs]);
|
|
9112
9362
|
const args = resolved.args.slice();
|
|
9113
9363
|
if (pm === "npm") args.unshift("--yes");
|
|
9114
9364
|
await x6(resolved.command, args, {
|
|
@@ -9116,11 +9366,11 @@ async function runWuchale(extraArgs) {
|
|
|
9116
9366
|
throwOnError: true
|
|
9117
9367
|
});
|
|
9118
9368
|
}
|
|
9119
|
-
var extract = new
|
|
9120
|
-
var watch = new
|
|
9121
|
-
var status2 = new
|
|
9122
|
-
var clean = new
|
|
9123
|
-
var i18n3 = new
|
|
9369
|
+
var extract = new Command97("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
|
|
9370
|
+
var watch = new Command97("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
|
|
9371
|
+
var status2 = new Command97("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
|
|
9372
|
+
var clean = new Command97("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--clean"]));
|
|
9373
|
+
var i18n3 = new Command97("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
|
|
9124
9374
|
|
|
9125
9375
|
// src/commands/oauth.ts
|
|
9126
9376
|
var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
@@ -9129,15 +9379,15 @@ var oauth = stubCommand("oauth", "configure OAuth providers");
|
|
|
9129
9379
|
var schemas = stubCommand("schemas", "manage database schemas");
|
|
9130
9380
|
|
|
9131
9381
|
// src/commands/cms.ts
|
|
9132
|
-
import { Command as
|
|
9382
|
+
import { Command as Command102 } from "commander";
|
|
9133
9383
|
|
|
9134
9384
|
// src/commands/cms/editor.ts
|
|
9135
|
-
import { Command as
|
|
9385
|
+
import { Command as Command101 } from "commander";
|
|
9136
9386
|
|
|
9137
9387
|
// src/commands/cms/editor/add.ts
|
|
9138
9388
|
import { randomBytes } from "node:crypto";
|
|
9139
|
-
import { Command as
|
|
9140
|
-
import * as
|
|
9389
|
+
import { Command as Command98 } from "commander";
|
|
9390
|
+
import * as p56 from "@clack/prompts";
|
|
9141
9391
|
import pc33 from "picocolors";
|
|
9142
9392
|
|
|
9143
9393
|
// src/lib/cms-backend.ts
|
|
@@ -9179,7 +9429,7 @@ async function withCmsBackend(fn, cwd = process34.cwd()) {
|
|
|
9179
9429
|
}
|
|
9180
9430
|
|
|
9181
9431
|
// src/commands/cms/editor/add.ts
|
|
9182
|
-
var editorAdd = new
|
|
9432
|
+
var editorAdd = new Command98("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(
|
|
9183
9433
|
(email3, options) => runCommand(async () => {
|
|
9184
9434
|
const generated = options.password === void 0;
|
|
9185
9435
|
const password11 = options.password ?? randomBytes(12).toString("base64url");
|
|
@@ -9190,31 +9440,31 @@ var editorAdd = new Command95("add").description("create an editor who can sign
|
|
|
9190
9440
|
if (generated) {
|
|
9191
9441
|
lines.push("", `Password: ${pc33.bold(password11)}`, "", "It is shown once; copy it now.");
|
|
9192
9442
|
}
|
|
9193
|
-
|
|
9194
|
-
|
|
9443
|
+
p56.log.success(lines.join("\n"));
|
|
9444
|
+
p56.log.info(
|
|
9195
9445
|
`Run ${pc33.cyan("vela dev")}, open any page with ${pc33.cyan("?edit")} on the URL (or press ${pc33.cyan("Ctrl+E")}), and sign in.`
|
|
9196
9446
|
);
|
|
9197
9447
|
}, "Failed to add the editor.")
|
|
9198
9448
|
);
|
|
9199
9449
|
|
|
9200
9450
|
// src/commands/cms/editor/password.ts
|
|
9201
|
-
import { Command as
|
|
9202
|
-
import * as
|
|
9451
|
+
import { Command as Command99 } from "commander";
|
|
9452
|
+
import * as p57 from "@clack/prompts";
|
|
9203
9453
|
import pc34 from "picocolors";
|
|
9204
|
-
var editorPassword = new
|
|
9454
|
+
var editorPassword = new Command99("password").description("set an editor's password").argument("<email>", "email of the editor").argument("<password>", "new password").configureHelp(helpConfig).action(
|
|
9205
9455
|
(email3, password11) => runCommand(async () => {
|
|
9206
9456
|
await withCmsBackend((cms3) => cms3.editors.setPassword(email3, password11));
|
|
9207
|
-
|
|
9457
|
+
p57.log.success(
|
|
9208
9458
|
`Updated the password for ${pc34.cyan(email3)}. Existing sessions were signed out.`
|
|
9209
9459
|
);
|
|
9210
9460
|
}, "Failed to set the password.")
|
|
9211
9461
|
);
|
|
9212
9462
|
|
|
9213
9463
|
// src/commands/cms/editor/list.ts
|
|
9214
|
-
import { Command as
|
|
9215
|
-
import * as
|
|
9464
|
+
import { Command as Command100 } from "commander";
|
|
9465
|
+
import * as p58 from "@clack/prompts";
|
|
9216
9466
|
import pc35 from "picocolors";
|
|
9217
|
-
var editorList = new
|
|
9467
|
+
var editorList = new Command100("list").description("list editors and the projects they may edit").configureHelp(helpConfig).action(
|
|
9218
9468
|
() => runCommand(async () => {
|
|
9219
9469
|
const rows = await withCmsBackend(
|
|
9220
9470
|
async (cms3) => cms3.editors.list().map((editor2) => ({
|
|
@@ -9223,11 +9473,11 @@ var editorList = new Command97("list").description("list editors and the project
|
|
|
9223
9473
|
}))
|
|
9224
9474
|
);
|
|
9225
9475
|
if (rows.length === 0) {
|
|
9226
|
-
|
|
9476
|
+
p58.log.info(`No editors yet. Add one with ${pc35.cyan("vela cms editor add <email>")}.`);
|
|
9227
9477
|
return;
|
|
9228
9478
|
}
|
|
9229
9479
|
const width = Math.max(...rows.map((row) => row.email.length));
|
|
9230
|
-
|
|
9480
|
+
p58.log.info(
|
|
9231
9481
|
`Editors
|
|
9232
9482
|
|
|
9233
9483
|
` + rows.map(
|
|
@@ -9238,10 +9488,10 @@ var editorList = new Command97("list").description("list editors and the project
|
|
|
9238
9488
|
);
|
|
9239
9489
|
|
|
9240
9490
|
// src/commands/cms/editor.ts
|
|
9241
|
-
var editor = new
|
|
9491
|
+
var editor = new Command101("editor").description("manage who can sign in to the admin bar").configureHelp(helpConfig).addCommand(editorAdd).addCommand(editorPassword).addCommand(editorList);
|
|
9242
9492
|
|
|
9243
9493
|
// src/commands/cms.ts
|
|
9244
|
-
var cms2 = new
|
|
9494
|
+
var cms2 = new Command102("cms").description("manage the CMS").configureHelp(helpConfig).addCommand(editor);
|
|
9245
9495
|
|
|
9246
9496
|
// src/program.ts
|
|
9247
9497
|
var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -9276,7 +9526,7 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
|
9276
9526
|
]);
|
|
9277
9527
|
var BACKEND_OPTIONAL_COMMANDS = /* @__PURE__ */ new Set(["dev", "build", "preview", "deploy"]);
|
|
9278
9528
|
var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
|
|
9279
|
-
var program = new
|
|
9529
|
+
var program = new Command103().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
|
|
9280
9530
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
9281
9531
|
if (isStub(actionCommand)) return;
|
|
9282
9532
|
const envRoot = findWorkspaceRoot() ?? process35.cwd();
|
|
@@ -9287,20 +9537,20 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
|
9287
9537
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
9288
9538
|
if (!hasBackend()) {
|
|
9289
9539
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
9290
|
-
|
|
9540
|
+
p59.log.error(
|
|
9291
9541
|
`${pc36.cyan(`vela ${path45}`)} needs a backend, and this project does not have one.
|
|
9292
9542
|
|
|
9293
9543
|
Static projects have no database to talk to.
|
|
9294
9544
|
|
|
9295
9545
|
To add a backend to this project, run ${pc36.cyan("vela bless")}.`
|
|
9296
9546
|
);
|
|
9297
|
-
|
|
9298
|
-
|
|
9547
|
+
p59.log.message();
|
|
9548
|
+
p59.cancel("Operation failed.");
|
|
9299
9549
|
process35.exit(1);
|
|
9300
9550
|
}
|
|
9301
9551
|
if (SELF_CREDENTIALED_COMMANDS.has(path45)) return;
|
|
9302
9552
|
if (!process35.env.POCKETBASE_SUPERUSER_EMAIL || !process35.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
9303
|
-
|
|
9553
|
+
p59.log.error(
|
|
9304
9554
|
`PocketBase superuser credentials are required.
|
|
9305
9555
|
|
|
9306
9556
|
Set ${pc36.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc36.cyan("POCKETBASE_SUPERUSER_PASSWORD")} in your .env file.
|
|
@@ -9308,8 +9558,8 @@ Set ${pc36.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc36.cyan("POCKETBASE_SUPER
|
|
|
9308
9558
|
To set up a new project, run ${pc36.cyan("vela create")}.
|
|
9309
9559
|
To set up an existing project, run ${pc36.cyan("vela bless")}.`
|
|
9310
9560
|
);
|
|
9311
|
-
|
|
9312
|
-
|
|
9561
|
+
p59.log.message();
|
|
9562
|
+
p59.cancel("Operation failed.");
|
|
9313
9563
|
process35.exit(1);
|
|
9314
9564
|
}
|
|
9315
9565
|
});
|