vela 0.11.4 → 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/bin.js +454 -102
- package/dist/bin.js.map +4 -4
- package/package.json +16 -4
- package/templates/minimal/package.template.json +1 -1
- package/templates/minimal/vite.config.ts +1 -1
- package/templates/server/apply.sh +71 -30
- package/templates/server/lib.sh +16 -5
- package/templates/server/rollback.sh +2 -2
package/dist/bin.js
CHANGED
|
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "vela",
|
|
24
|
-
version: "0.11.
|
|
24
|
+
version: "0.11.5",
|
|
25
25
|
type: "module",
|
|
26
26
|
description: "A CLI for creating and updating SvelteKit projects",
|
|
27
27
|
license: "MIT",
|
|
@@ -57,7 +57,7 @@ var package_default = {
|
|
|
57
57
|
dependencies: {
|
|
58
58
|
"@clack/prompts": "^1.7.0",
|
|
59
59
|
"@faker-js/faker": "^10.6.0",
|
|
60
|
-
"@velastack/patterns": "^0.2.
|
|
60
|
+
"@velastack/patterns": "^0.2.4",
|
|
61
61
|
"@velastack/pocketbase-codegen": "^0.1.0",
|
|
62
62
|
"annotate-json-schema": "^0.1.0",
|
|
63
63
|
commander: "^13.1.0",
|
|
@@ -83,10 +83,10 @@ var package_default = {
|
|
|
83
83
|
"@types/node": "^22.0.0",
|
|
84
84
|
esbuild: "^0.28.2",
|
|
85
85
|
prettier: "^3.9.6",
|
|
86
|
+
shellcheck: "^4.1.0",
|
|
86
87
|
typescript: "^5.6.0",
|
|
87
88
|
vite: "^8.2.2",
|
|
88
|
-
vitest: "^4.1.11"
|
|
89
|
-
shellcheck: "^4.1.0"
|
|
89
|
+
vitest: "^4.1.11"
|
|
90
90
|
},
|
|
91
91
|
peerDependencies: {
|
|
92
92
|
"@sveltejs/kit": "^2.57.1",
|
|
@@ -100,6 +100,18 @@ var package_default = {
|
|
|
100
100
|
optional: true
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
+
overrides: {
|
|
104
|
+
"global-agent": "^4.1.3",
|
|
105
|
+
"@xhmikosr/decompress-unzip": {
|
|
106
|
+
"file-type": "^21.3.1"
|
|
107
|
+
},
|
|
108
|
+
"@xhmikosr/decompress-tar": {
|
|
109
|
+
"file-type": "^21.3.1"
|
|
110
|
+
},
|
|
111
|
+
"@felipecrs/decompress-tarxz": {
|
|
112
|
+
"file-type": "^21.3.1"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
103
115
|
keywords: [
|
|
104
116
|
"svelte",
|
|
105
117
|
"sveltekit",
|
|
@@ -291,8 +303,20 @@ function mergePackageJson(user, template) {
|
|
|
291
303
|
}
|
|
292
304
|
return { merged, added, conflicts, replaced };
|
|
293
305
|
}
|
|
294
|
-
function
|
|
295
|
-
|
|
306
|
+
function dropTemplateAdapters(user, template) {
|
|
307
|
+
const isAdapter = (name) => name.startsWith("@sveltejs/adapter-");
|
|
308
|
+
const userHasOne = DEP_KINDS.some((kind) => Object.keys(user[kind] ?? {}).some(isAdapter));
|
|
309
|
+
if (!userHasOne) return template;
|
|
310
|
+
const copy = { ...template };
|
|
311
|
+
for (const kind of DEP_KINDS) {
|
|
312
|
+
const deps = template[kind];
|
|
313
|
+
if (!deps) continue;
|
|
314
|
+
copy[kind] = Object.fromEntries(Object.entries(deps).filter(([name]) => !isAdapter(name)));
|
|
315
|
+
}
|
|
316
|
+
return copy;
|
|
317
|
+
}
|
|
318
|
+
function readPackageJson(path47) {
|
|
319
|
+
return JSON.parse(fs.readFileSync(path47, "utf8"));
|
|
296
320
|
}
|
|
297
321
|
var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
|
|
298
322
|
var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
|
|
@@ -305,12 +329,12 @@ function fillTemplatePlaceholders(raw, values) {
|
|
|
305
329
|
function escapeSingleQuoted(value) {
|
|
306
330
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
307
331
|
}
|
|
308
|
-
function readTemplatePackageJson(
|
|
309
|
-
const raw = fillTemplatePlaceholders(fs.readFileSync(
|
|
332
|
+
function readTemplatePackageJson(path47, values) {
|
|
333
|
+
const raw = fillTemplatePlaceholders(fs.readFileSync(path47, "utf8"), values);
|
|
310
334
|
return JSON.parse(raw);
|
|
311
335
|
}
|
|
312
|
-
function writePackageJson(
|
|
313
|
-
fs.writeFileSync(
|
|
336
|
+
function writePackageJson(path47, pkg) {
|
|
337
|
+
fs.writeFileSync(path47, JSON.stringify(pkg, null, " ") + "\n");
|
|
314
338
|
}
|
|
315
339
|
function toValidPackageName(name) {
|
|
316
340
|
return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
|
|
@@ -866,7 +890,7 @@ async function packageManagerPrompt(cwd) {
|
|
|
866
890
|
}
|
|
867
891
|
return pm;
|
|
868
892
|
}
|
|
869
|
-
async function installDependencies(agent, cwd) {
|
|
893
|
+
async function installDependencies(agent, cwd, { exitOnFailure = true } = {}) {
|
|
870
894
|
const task = p2.taskLog({
|
|
871
895
|
title: `Installing dependencies with ${agent}...`,
|
|
872
896
|
limit: Math.ceil(process5.stdout.rows / 2),
|
|
@@ -883,14 +907,16 @@ async function installDependencies(agent, cwd) {
|
|
|
883
907
|
proc.process?.stderr?.on("data", (data) => task.message(data.toString(), { raw: true }));
|
|
884
908
|
await proc;
|
|
885
909
|
task.success("Successfully installed dependencies");
|
|
910
|
+
return true;
|
|
886
911
|
} catch {
|
|
887
912
|
task.error("Failed to install dependencies");
|
|
913
|
+
if (!exitOnFailure) return false;
|
|
888
914
|
p2.cancel("Operation failed.");
|
|
889
915
|
process5.exit(2);
|
|
890
916
|
}
|
|
891
917
|
}
|
|
892
|
-
function addPnpmBuildDependencies(cwd,
|
|
893
|
-
if (!
|
|
918
|
+
function addPnpmBuildDependencies(cwd, packageManager2, allowedPackages) {
|
|
919
|
+
if (!packageManager2 || packageManager2 !== "pnpm") return;
|
|
894
920
|
const pkgPath = path6.join(cwd, "package.json");
|
|
895
921
|
if (!fs7.existsSync(pkgPath)) return;
|
|
896
922
|
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
@@ -1027,11 +1053,11 @@ function getPocketbaseMetadata(cwd) {
|
|
|
1027
1053
|
return null;
|
|
1028
1054
|
}
|
|
1029
1055
|
async function execPackageBin(cwd, args, stdio = "pipe") {
|
|
1030
|
-
const
|
|
1031
|
-
const resolved = resolveCommand(
|
|
1032
|
-
if (!resolved) throw new Error(`Could not resolve command for ${
|
|
1056
|
+
const packageManager2 = (await detect2({ cwd }))?.name ?? "npm";
|
|
1057
|
+
const resolved = resolveCommand(packageManager2, "execute", args);
|
|
1058
|
+
if (!resolved) throw new Error(`Could not resolve command for ${packageManager2}`);
|
|
1033
1059
|
const { command, args: resolvedArgs } = resolved;
|
|
1034
|
-
if (
|
|
1060
|
+
if (packageManager2 === "npm") resolvedArgs.unshift("--yes");
|
|
1035
1061
|
return x(command, resolvedArgs, { nodeOptions: { cwd, stdio }, throwOnError: true });
|
|
1036
1062
|
}
|
|
1037
1063
|
async function withPocketbase(cwd, fn, creds) {
|
|
@@ -1479,7 +1505,14 @@ var GITIGNORE_ENTRIES = [
|
|
|
1479
1505
|
"!.env.example",
|
|
1480
1506
|
"!.env.test",
|
|
1481
1507
|
"vite.config.js.timestamp-*",
|
|
1482
|
-
"vite.config.ts.timestamp-*"
|
|
1508
|
+
"vite.config.ts.timestamp-*",
|
|
1509
|
+
// The local database, minus the parts that are source. Same block as the
|
|
1510
|
+
// template's _gitignore; without it a blessed project commits its SQLite.
|
|
1511
|
+
"/data/*",
|
|
1512
|
+
"!/data/fixtures",
|
|
1513
|
+
"!/data/seeds",
|
|
1514
|
+
"!/data/hooks",
|
|
1515
|
+
"/backups"
|
|
1483
1516
|
];
|
|
1484
1517
|
function mergeGitignore(filePath) {
|
|
1485
1518
|
const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf8") : "";
|
|
@@ -1647,13 +1680,13 @@ async function blessProject(cwdArg, options) {
|
|
|
1647
1680
|
mergeAppDts(templateDir, projectPath);
|
|
1648
1681
|
maybeReplaceRoutes(projectPath, templateDir, options);
|
|
1649
1682
|
p4.log.success("Vela files in place");
|
|
1650
|
-
let
|
|
1683
|
+
let packageManager2;
|
|
1651
1684
|
if (options.install !== false) {
|
|
1652
1685
|
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
1653
1686
|
if (pm) {
|
|
1654
1687
|
addPnpmBuildDependencies(projectPath, pm, ["esbuild", "pocketbase-server"]);
|
|
1655
1688
|
await installDependencies(pm, projectPath);
|
|
1656
|
-
|
|
1689
|
+
packageManager2 = pm;
|
|
1657
1690
|
}
|
|
1658
1691
|
}
|
|
1659
1692
|
p4.log.step("Initializing PocketBase...");
|
|
@@ -1667,7 +1700,7 @@ async function blessProject(cwdArg, options) {
|
|
|
1667
1700
|
["PocketBase superuser credentials \u2014 used by `vela` commands"]
|
|
1668
1701
|
);
|
|
1669
1702
|
p4.log.success("PocketBase initialized");
|
|
1670
|
-
printNextSteps(projectPath,
|
|
1703
|
+
printNextSteps(projectPath, packageManager2);
|
|
1671
1704
|
}
|
|
1672
1705
|
function ensureShadcnCss(projectPath) {
|
|
1673
1706
|
if (ensureShadcnImport(path13.join(projectPath, "src", "app.css"))) {
|
|
@@ -1713,7 +1746,10 @@ function mergeDependencies(projectPath, templateDir) {
|
|
|
1713
1746
|
appName,
|
|
1714
1747
|
cliVersion: package_default.version
|
|
1715
1748
|
});
|
|
1716
|
-
const { merged, added, conflicts, replaced } = mergePackageJson(
|
|
1749
|
+
const { merged, added, conflicts, replaced } = mergePackageJson(
|
|
1750
|
+
userPkg,
|
|
1751
|
+
dropTemplateAdapters(userPkg, templatePkg)
|
|
1752
|
+
);
|
|
1717
1753
|
writePackageJson(userPkgPath, merged);
|
|
1718
1754
|
if (added.length > 0) {
|
|
1719
1755
|
p4.log.info(
|
|
@@ -1851,9 +1887,9 @@ function summarize(names) {
|
|
|
1851
1887
|
if (names.length <= 4) return names.join(", ");
|
|
1852
1888
|
return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
|
|
1853
1889
|
}
|
|
1854
|
-
function printNextSteps(projectPath,
|
|
1890
|
+
function printNextSteps(projectPath, packageManager2) {
|
|
1855
1891
|
const relative = path13.relative(process7.cwd(), projectPath);
|
|
1856
|
-
const pm =
|
|
1892
|
+
const pm = packageManager2 ?? getUserAgent() ?? "npm";
|
|
1857
1893
|
const nextSteps = [];
|
|
1858
1894
|
if (relative !== "") {
|
|
1859
1895
|
const hasSpaces = relative.includes(" ");
|
|
@@ -1901,19 +1937,19 @@ var create = new Command3("create").description("scaffold a new velastack projec
|
|
|
1901
1937
|
return runCommand(async () => {
|
|
1902
1938
|
const listing = await listAllTemplates();
|
|
1903
1939
|
const options = parseOptions(optionsSchema2(listing), rawOpts);
|
|
1904
|
-
const { directory, packageManager, name, template } = await createProject(
|
|
1940
|
+
const { directory, packageManager: packageManager2, name, template } = await createProject(
|
|
1905
1941
|
projectPath,
|
|
1906
1942
|
options,
|
|
1907
1943
|
listing
|
|
1908
1944
|
);
|
|
1909
1945
|
const relative = path14.relative(process8.cwd(), directory);
|
|
1910
|
-
const pm =
|
|
1946
|
+
const pm = packageManager2 ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
|
|
1911
1947
|
const nextSteps = [];
|
|
1912
1948
|
if (relative !== "") {
|
|
1913
1949
|
const hasSpaces = relative.includes(" ");
|
|
1914
1950
|
nextSteps.push(`\`cd ${hasSpaces ? `"${relative}"` : relative}\``);
|
|
1915
1951
|
}
|
|
1916
|
-
if (!
|
|
1952
|
+
if (!packageManager2) {
|
|
1917
1953
|
const resolved = resolveCommand3(pm, "install", []);
|
|
1918
1954
|
if (resolved) {
|
|
1919
1955
|
nextSteps.push(
|
|
@@ -2002,14 +2038,14 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2002
2038
|
throw new Error(`Template ${template.name} is missing package.template.json`);
|
|
2003
2039
|
}
|
|
2004
2040
|
p5.log.success("Project created");
|
|
2005
|
-
let
|
|
2041
|
+
let packageManager2;
|
|
2006
2042
|
if (options.install !== false) {
|
|
2007
2043
|
const pm = typeof options.install === "string" ? options.install : await packageManagerPrompt(projectPath);
|
|
2008
2044
|
if (pm) {
|
|
2009
2045
|
const builds = template.backend ? ["esbuild", "pocketbase-server"] : ["esbuild"];
|
|
2010
2046
|
addPnpmBuildDependencies(projectPath, pm, builds);
|
|
2011
2047
|
await installDependencies(pm, projectPath);
|
|
2012
|
-
|
|
2048
|
+
packageManager2 = pm;
|
|
2013
2049
|
}
|
|
2014
2050
|
}
|
|
2015
2051
|
if (credentials) {
|
|
@@ -2035,7 +2071,7 @@ async function createProject(cwdArg, options, listing) {
|
|
|
2035
2071
|
);
|
|
2036
2072
|
p5.log.success("PocketBase initialized");
|
|
2037
2073
|
}
|
|
2038
|
-
return { directory: projectPath, packageManager, name, template };
|
|
2074
|
+
return { directory: projectPath, packageManager: packageManager2, name, template };
|
|
2039
2075
|
}
|
|
2040
2076
|
function promptCredentials(options, onCancel2) {
|
|
2041
2077
|
return p5.group(
|
|
@@ -3523,10 +3559,11 @@ function collectArtifact(cwd, config = {}) {
|
|
|
3523
3559
|
const buildPath = path20.join(cwd, outputDir);
|
|
3524
3560
|
if (!fs21.existsSync(path20.join(buildPath, "index.js"))) {
|
|
3525
3561
|
throw new BuildError(
|
|
3526
|
-
`No ${outputDir}/index.js
|
|
3562
|
+
`No ${outputDir}/index.js to deploy.
|
|
3527
3563
|
|
|
3528
|
-
Deploying to a server needs @sveltejs/adapter-node.
|
|
3529
|
-
|
|
3564
|
+
Deploying to a server needs the output of @sveltejs/adapter-node. Check that the
|
|
3565
|
+
build ran with it as the adapter (and that \`outputDir\` in velastack.config
|
|
3566
|
+
matches where it writes), then deploy again.`
|
|
3530
3567
|
);
|
|
3531
3568
|
}
|
|
3532
3569
|
entries.push({ localPath: buildPath, remoteDir: "" });
|
|
@@ -3585,6 +3622,10 @@ var VELA_USER = "vela";
|
|
|
3585
3622
|
var SCRIPT_VERSIONS_DIR = `${VELA_ROOT}/script-versions`;
|
|
3586
3623
|
var PROVISIONED_MARKER = `${VELA_ETC}/provisioned`;
|
|
3587
3624
|
var ORIGIN_FILE = `${VELA_ETC}/origin.json`;
|
|
3625
|
+
function instanceHasBackend(state) {
|
|
3626
|
+
if (!state) return false;
|
|
3627
|
+
return state.backend ?? Boolean(state.pbPort);
|
|
3628
|
+
}
|
|
3588
3629
|
function serverTemplatesDir() {
|
|
3589
3630
|
return path21.join(templatesDir(), "server");
|
|
3590
3631
|
}
|
|
@@ -4138,12 +4179,13 @@ Set both ${pc6.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc6.cyan("POCKETBASE_SU
|
|
|
4138
4179
|
import PocketBase2 from "pocketbase";
|
|
4139
4180
|
async function openRemoteDatabase(session, instance) {
|
|
4140
4181
|
const [state] = await readInstanceStates(session, instance);
|
|
4141
|
-
const pbPort = state?.pbPort;
|
|
4182
|
+
const pbPort = instanceHasBackend(state) ? state?.pbPort : void 0;
|
|
4142
4183
|
if (!pbPort) {
|
|
4143
4184
|
throw new Error(
|
|
4144
4185
|
`${instance} has no deployed database yet.
|
|
4145
4186
|
|
|
4146
|
-
Run \`vela deploy\` first \u2014 the database is created by the first deploy
|
|
4187
|
+
Run \`vela deploy\` first \u2014 the database is created by the first deploy of a
|
|
4188
|
+
project with a backend (\`vela bless\` adds one).`
|
|
4147
4189
|
);
|
|
4148
4190
|
}
|
|
4149
4191
|
const env2 = await readRemoteEnv(session, instance);
|
|
@@ -8306,8 +8348,8 @@ var provision = addSshOptions(
|
|
|
8306
8348
|
);
|
|
8307
8349
|
|
|
8308
8350
|
// src/commands/deploy.ts
|
|
8309
|
-
import
|
|
8310
|
-
import
|
|
8351
|
+
import path38 from "node:path";
|
|
8352
|
+
import fs37 from "node:fs";
|
|
8311
8353
|
import { Command as Command76, Option as Option2 } from "commander";
|
|
8312
8354
|
import * as p42 from "@clack/prompts";
|
|
8313
8355
|
import pc18 from "picocolors";
|
|
@@ -8371,6 +8413,272 @@ async function seedRemoteMeta(session, instance, local, appURL) {
|
|
|
8371
8413
|
return Object.keys(patch);
|
|
8372
8414
|
}
|
|
8373
8415
|
|
|
8416
|
+
// src/lib/adapter.ts
|
|
8417
|
+
import fs36 from "node:fs";
|
|
8418
|
+
import path37 from "node:path";
|
|
8419
|
+
import {
|
|
8420
|
+
Project as Project2,
|
|
8421
|
+
QuoteKind as QuoteKind2,
|
|
8422
|
+
SyntaxKind as SyntaxKind2
|
|
8423
|
+
} from "ts-morph";
|
|
8424
|
+
import { detect as detect7 } from "package-manager-detector";
|
|
8425
|
+
var ADAPTER_NODE = "@sveltejs/adapter-node";
|
|
8426
|
+
var ADAPTER_AUTO = "@sveltejs/adapter-auto";
|
|
8427
|
+
var ADAPTER_STATIC = "@sveltejs/adapter-static";
|
|
8428
|
+
var ADAPTER_NODE_RANGE = "^5.5.7";
|
|
8429
|
+
var ADAPTER_SNIPPET = `import adapter from '${ADAPTER_NODE}';
|
|
8430
|
+
|
|
8431
|
+
// ...
|
|
8432
|
+
adapter: adapter()`;
|
|
8433
|
+
var AdapterError = class extends Error {
|
|
8434
|
+
constructor(message, snippet = ADAPTER_SNIPPET) {
|
|
8435
|
+
super(message);
|
|
8436
|
+
this.snippet = snippet;
|
|
8437
|
+
this.name = "AdapterError";
|
|
8438
|
+
}
|
|
8439
|
+
snippet;
|
|
8440
|
+
};
|
|
8441
|
+
function newProject() {
|
|
8442
|
+
return new Project2({
|
|
8443
|
+
compilerOptions: { allowJs: true },
|
|
8444
|
+
manipulationSettings: { quoteKind: QuoteKind2.Single }
|
|
8445
|
+
});
|
|
8446
|
+
}
|
|
8447
|
+
function getDefaultExportObject(sourceFile) {
|
|
8448
|
+
const exported = sourceFile.getExportAssignment((ea) => !ea.isExportEquals())?.getExpression();
|
|
8449
|
+
if (exported?.getKind() === SyntaxKind2.ObjectLiteralExpression) {
|
|
8450
|
+
return exported;
|
|
8451
|
+
}
|
|
8452
|
+
if (exported?.getKind() === SyntaxKind2.Identifier) {
|
|
8453
|
+
const init = sourceFile.getVariableDeclaration(exported.getText())?.getInitializer();
|
|
8454
|
+
if (init?.getKind() === SyntaxKind2.ObjectLiteralExpression) {
|
|
8455
|
+
return init;
|
|
8456
|
+
}
|
|
8457
|
+
}
|
|
8458
|
+
return null;
|
|
8459
|
+
}
|
|
8460
|
+
function resolveKitTarget(root) {
|
|
8461
|
+
const vite = inspectViteSveltekit(root);
|
|
8462
|
+
if (vite?.inlineArg) {
|
|
8463
|
+
return {
|
|
8464
|
+
sourceFile: vite.sourceFile,
|
|
8465
|
+
filePath: vite.filePath,
|
|
8466
|
+
container: "vite-inline",
|
|
8467
|
+
kit: vite.inlineArg,
|
|
8468
|
+
created: false,
|
|
8469
|
+
originalText: vite.sourceFile.getFullText()
|
|
8470
|
+
};
|
|
8471
|
+
}
|
|
8472
|
+
const sveltePath = probeFirstExisting(root, SVELTE_CONFIG_CANDIDATES);
|
|
8473
|
+
if (sveltePath) {
|
|
8474
|
+
const name = path37.basename(sveltePath);
|
|
8475
|
+
if (sveltePath.endsWith(".cjs")) {
|
|
8476
|
+
throw new AdapterError(`${name} is CommonJS, which vela does not edit.`);
|
|
8477
|
+
}
|
|
8478
|
+
const sourceFile = newProject().addSourceFileAtPath(sveltePath);
|
|
8479
|
+
const config = getDefaultExportObject(sourceFile);
|
|
8480
|
+
const kit = config && getOrCreateObjectLiteralProperty(config, "kit", "{}");
|
|
8481
|
+
if (!kit) {
|
|
8482
|
+
throw new AdapterError(`${name} has a shape vela does not understand.`);
|
|
8483
|
+
}
|
|
8484
|
+
return {
|
|
8485
|
+
sourceFile,
|
|
8486
|
+
filePath: sveltePath,
|
|
8487
|
+
container: "svelte-config",
|
|
8488
|
+
kit,
|
|
8489
|
+
created: false,
|
|
8490
|
+
originalText: sourceFile.getFullText()
|
|
8491
|
+
};
|
|
8492
|
+
}
|
|
8493
|
+
if (vite?.sveltekitCall) {
|
|
8494
|
+
const name = path37.basename(vite.filePath);
|
|
8495
|
+
if (vite.nonObjectArg) {
|
|
8496
|
+
throw new AdapterError(`${name} passes sveltekit() something other than an object literal.`);
|
|
8497
|
+
}
|
|
8498
|
+
const originalText = vite.sourceFile.getFullText();
|
|
8499
|
+
const kit = createSveltekitArg(vite);
|
|
8500
|
+
if (!kit)
|
|
8501
|
+
throw new AdapterError(`${name} has a sveltekit() call vela cannot add an argument to.`);
|
|
8502
|
+
return {
|
|
8503
|
+
sourceFile: vite.sourceFile,
|
|
8504
|
+
filePath: vite.filePath,
|
|
8505
|
+
container: "vite-inline",
|
|
8506
|
+
kit,
|
|
8507
|
+
created: true,
|
|
8508
|
+
originalText
|
|
8509
|
+
};
|
|
8510
|
+
}
|
|
8511
|
+
throw new AdapterError(
|
|
8512
|
+
`No svelte.config or vite.config with a sveltekit() plugin found in ${root}.`
|
|
8513
|
+
);
|
|
8514
|
+
}
|
|
8515
|
+
function classify(specifier) {
|
|
8516
|
+
if (specifier === ADAPTER_NODE) return "node";
|
|
8517
|
+
if (specifier === ADAPTER_AUTO) return "auto";
|
|
8518
|
+
if (specifier === ADAPTER_STATIC) return "static";
|
|
8519
|
+
return "other";
|
|
8520
|
+
}
|
|
8521
|
+
function importOf(sourceFile, identifier) {
|
|
8522
|
+
return sourceFile.getImportDeclarations().find((decl) => decl.getDefaultImport()?.getText() === identifier);
|
|
8523
|
+
}
|
|
8524
|
+
function inspectAdapter(target) {
|
|
8525
|
+
const base2 = { file: target.filePath, container: target.container };
|
|
8526
|
+
const prop = target.kit.getProperty("adapter");
|
|
8527
|
+
if (!prop) return { info: { ...base2, kind: "none" } };
|
|
8528
|
+
if (prop.getKind() !== SyntaxKind2.PropertyAssignment) {
|
|
8529
|
+
return { info: { ...base2, kind: "other" } };
|
|
8530
|
+
}
|
|
8531
|
+
const init = prop.asKindOrThrow(SyntaxKind2.PropertyAssignment).getInitializer();
|
|
8532
|
+
if (!init || init.getKind() !== SyntaxKind2.CallExpression) {
|
|
8533
|
+
return { info: { ...base2, kind: "other" } };
|
|
8534
|
+
}
|
|
8535
|
+
const callee = init.asKindOrThrow(SyntaxKind2.CallExpression).getExpression();
|
|
8536
|
+
if (callee.getKind() !== SyntaxKind2.Identifier) {
|
|
8537
|
+
return { info: { ...base2, kind: "other" } };
|
|
8538
|
+
}
|
|
8539
|
+
const importDecl = importOf(target.sourceFile, callee.getText());
|
|
8540
|
+
if (!importDecl) return { info: { ...base2, kind: "other" } };
|
|
8541
|
+
const specifier = importDecl.getModuleSpecifierValue();
|
|
8542
|
+
return { info: { ...base2, kind: classify(specifier), specifier }, importDecl };
|
|
8543
|
+
}
|
|
8544
|
+
async function ensureNodeAdapter(root, { install = true } = {}) {
|
|
8545
|
+
const target = resolveKitTarget(root);
|
|
8546
|
+
const { info, importDecl } = inspectAdapter(target);
|
|
8547
|
+
const name = path37.basename(target.filePath);
|
|
8548
|
+
const outcome = {
|
|
8549
|
+
previous: info.kind,
|
|
8550
|
+
removedDeps: [],
|
|
8551
|
+
packageJsonChanged: false
|
|
8552
|
+
};
|
|
8553
|
+
switch (info.kind) {
|
|
8554
|
+
case "node":
|
|
8555
|
+
break;
|
|
8556
|
+
case "static":
|
|
8557
|
+
throw new AdapterError(
|
|
8558
|
+
`This project builds a static site with ${ADAPTER_STATIC} (${name}).
|
|
8559
|
+
|
|
8560
|
+
vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}. Switch
|
|
8561
|
+
the adapter to deploy it here, or host the static output elsewhere.`
|
|
8562
|
+
);
|
|
8563
|
+
case "other":
|
|
8564
|
+
throw new AdapterError(
|
|
8565
|
+
`This project's adapter${info.specifier ? ` (${info.specifier})` : ""} in ${name} is not one
|
|
8566
|
+
vela will change for you.
|
|
8567
|
+
|
|
8568
|
+
vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}:`
|
|
8569
|
+
);
|
|
8570
|
+
case "auto":
|
|
8571
|
+
switchImport(target, importDecl);
|
|
8572
|
+
outcome.configFile = name;
|
|
8573
|
+
break;
|
|
8574
|
+
case "none":
|
|
8575
|
+
addAdapter(target);
|
|
8576
|
+
outcome.configFile = name;
|
|
8577
|
+
break;
|
|
8578
|
+
}
|
|
8579
|
+
if (outcome.configFile) saveTarget(target);
|
|
8580
|
+
const pkgPath = path37.join(root, "package.json");
|
|
8581
|
+
if (fs36.existsSync(pkgPath)) {
|
|
8582
|
+
const pkg = readPackageJson(pkgPath);
|
|
8583
|
+
const { changed, removed } = adoptNodeAdapter(pkg);
|
|
8584
|
+
if (changed) {
|
|
8585
|
+
writePackageJson(pkgPath, pkg);
|
|
8586
|
+
outcome.packageJsonChanged = true;
|
|
8587
|
+
outcome.removedDeps = removed;
|
|
8588
|
+
}
|
|
8589
|
+
}
|
|
8590
|
+
if (outcome.packageJsonChanged && install) {
|
|
8591
|
+
outcome.installedWith = await installAdapterDependencies(root);
|
|
8592
|
+
}
|
|
8593
|
+
return outcome;
|
|
8594
|
+
}
|
|
8595
|
+
async function installAdapterDependencies(root) {
|
|
8596
|
+
const agent = await packageManager(root);
|
|
8597
|
+
const ok = await installDependencies(agent, root, { exitOnFailure: false });
|
|
8598
|
+
if (!ok) {
|
|
8599
|
+
throw new AdapterError(
|
|
8600
|
+
`Installing ${ADAPTER_NODE} with ${agent} failed.
|
|
8601
|
+
|
|
8602
|
+
The config and package.json are already updated: run \`${agent} install\`, then deploy again.`,
|
|
8603
|
+
""
|
|
8604
|
+
);
|
|
8605
|
+
}
|
|
8606
|
+
return agent;
|
|
8607
|
+
}
|
|
8608
|
+
function switchImport(target, importDecl) {
|
|
8609
|
+
importDecl.setModuleSpecifier(ADAPTER_NODE);
|
|
8610
|
+
const prop = target.kit.getPropertyOrThrow("adapter").asKindOrThrow(SyntaxKind2.PropertyAssignment);
|
|
8611
|
+
const call = prop.getInitializerIfKindOrThrow(SyntaxKind2.CallExpression);
|
|
8612
|
+
for (let i = call.getArguments().length - 1; i >= 0; i--) call.removeArgument(i);
|
|
8613
|
+
dropAdapterAutoComments(target);
|
|
8614
|
+
}
|
|
8615
|
+
var ADAPTER_AUTO_COMMENT = /adapter-auto|svelte\.dev\/docs\/kit\/adapters|switch out the adapter/;
|
|
8616
|
+
function dropAdapterAutoComments(target) {
|
|
8617
|
+
const prop = target.kit.getPropertyOrThrow("adapter");
|
|
8618
|
+
const ranges = prop.getLeadingCommentRanges();
|
|
8619
|
+
if (ranges.length === 0 || !ranges.every((r) => ADAPTER_AUTO_COMMENT.test(r.getText()))) return;
|
|
8620
|
+
const fullStart = prop.getFullStart();
|
|
8621
|
+
const start = prop.getStart();
|
|
8622
|
+
const trivia = target.sourceFile.getFullText().slice(fullStart, start);
|
|
8623
|
+
const lastNewline = trivia.lastIndexOf("\n");
|
|
8624
|
+
if (lastNewline === -1) return;
|
|
8625
|
+
const indent = trivia.slice(lastNewline + 1);
|
|
8626
|
+
target.sourceFile.replaceText([fullStart, start], `
|
|
8627
|
+
${indent}`);
|
|
8628
|
+
}
|
|
8629
|
+
function addAdapter(target) {
|
|
8630
|
+
const taken = importOf(target.sourceFile, "adapter") ?? target.sourceFile.getVariableDeclaration("adapter");
|
|
8631
|
+
if (taken) {
|
|
8632
|
+
throw new AdapterError(
|
|
8633
|
+
`${path37.basename(target.filePath)} already binds the name \`adapter\` to something that is not the SvelteKit adapter.`
|
|
8634
|
+
);
|
|
8635
|
+
}
|
|
8636
|
+
target.sourceFile.addImportDeclaration({
|
|
8637
|
+
defaultImport: "adapter",
|
|
8638
|
+
moduleSpecifier: ADAPTER_NODE
|
|
8639
|
+
});
|
|
8640
|
+
target.kit.addPropertyAssignment({ name: "adapter", initializer: "adapter()" });
|
|
8641
|
+
}
|
|
8642
|
+
function saveTarget(target) {
|
|
8643
|
+
if (target.created) target.sourceFile.formatText();
|
|
8644
|
+
if (target.sourceFile.getFullText() === target.originalText) return;
|
|
8645
|
+
target.sourceFile.saveSync();
|
|
8646
|
+
}
|
|
8647
|
+
function adoptNodeAdapter(pkg) {
|
|
8648
|
+
const removed = [];
|
|
8649
|
+
let changed = false;
|
|
8650
|
+
for (const kind of ["dependencies", "devDependencies"]) {
|
|
8651
|
+
const deps = pkg[kind];
|
|
8652
|
+
if (deps && ADAPTER_AUTO in deps) {
|
|
8653
|
+
delete deps[ADAPTER_AUTO];
|
|
8654
|
+
removed.push(ADAPTER_AUTO);
|
|
8655
|
+
changed = true;
|
|
8656
|
+
}
|
|
8657
|
+
}
|
|
8658
|
+
if (!pkg.dependencies?.[ADAPTER_NODE] && !pkg.devDependencies?.[ADAPTER_NODE]) {
|
|
8659
|
+
pkg.devDependencies = sortKeys({ ...pkg.devDependencies, [ADAPTER_NODE]: ADAPTER_NODE_RANGE });
|
|
8660
|
+
changed = true;
|
|
8661
|
+
}
|
|
8662
|
+
return { changed, removed: [...new Set(removed)] };
|
|
8663
|
+
}
|
|
8664
|
+
function lockfileFor(agent) {
|
|
8665
|
+
switch (agent) {
|
|
8666
|
+
case "pnpm":
|
|
8667
|
+
return "pnpm-lock.yaml";
|
|
8668
|
+
case "yarn":
|
|
8669
|
+
return "yarn.lock";
|
|
8670
|
+
case "bun":
|
|
8671
|
+
return "bun.lock";
|
|
8672
|
+
case "deno":
|
|
8673
|
+
return "deno.lock";
|
|
8674
|
+
default:
|
|
8675
|
+
return "package-lock.json";
|
|
8676
|
+
}
|
|
8677
|
+
}
|
|
8678
|
+
async function packageManager(root) {
|
|
8679
|
+
return (await detect7({ cwd: root }))?.name ?? getUserAgent() ?? "npm";
|
|
8680
|
+
}
|
|
8681
|
+
|
|
8374
8682
|
// src/commands/deploy.ts
|
|
8375
8683
|
var OptionsSchema3 = v8.object({
|
|
8376
8684
|
...SSH_OPTION_SCHEMA,
|
|
@@ -8403,6 +8711,10 @@ var deploy = addLockWaitOption(
|
|
|
8403
8711
|
const options = parseOptions(OptionsSchema3, raw);
|
|
8404
8712
|
const backend3 = hasBackend();
|
|
8405
8713
|
p42.intro(pc18.bgCyan(pc18.black(" vela deploy ")));
|
|
8714
|
+
if (options.build !== false) {
|
|
8715
|
+
const { workspaceRootDir } = await getWorkspace();
|
|
8716
|
+
await prepareAdapter(workspaceRootDir);
|
|
8717
|
+
}
|
|
8406
8718
|
await withTarget(
|
|
8407
8719
|
raw,
|
|
8408
8720
|
{
|
|
@@ -8416,7 +8728,12 @@ var deploy = addLockWaitOption(
|
|
|
8416
8728
|
const isPreview2 = ctx.target.kind === "preview";
|
|
8417
8729
|
const configured = options.domain ?? (isPreview2 ? existing?.domain : ctx.binding.domain ?? config.deploy?.domain ?? existing?.domain) ?? "";
|
|
8418
8730
|
const askedForRemoteDb = options.remoteDb ?? config.deploy?.buildAgainstRemote;
|
|
8419
|
-
const remoteDb = askedForRemoteDb ??
|
|
8731
|
+
const remoteDb = askedForRemoteDb ?? instanceHasBackend(existing);
|
|
8732
|
+
if (existing && instanceHasBackend(existing) !== backend3) {
|
|
8733
|
+
p42.log.info(
|
|
8734
|
+
backend3 ? `${pc18.cyan(ctx.targetName)} was deployed without a backend before. This deploy adds PocketBase.` : `${pc18.cyan(ctx.targetName)} was deployed with a backend before. This deploy removes PocketBase; its database stays on the server.`
|
|
8735
|
+
);
|
|
8736
|
+
}
|
|
8420
8737
|
const sha = await gitSha(workspaceRootDir);
|
|
8421
8738
|
const reporter = createDeployReporter(workspaceRootDir);
|
|
8422
8739
|
const server = await reporter.identifyServer(session);
|
|
@@ -8572,6 +8889,38 @@ or ${pc18.cyan("vela link")} it to get a free velastack.app hostname.`) + `.`
|
|
|
8572
8889
|
p42.outro(`${pc18.cyan("vela status")} to see what is running`);
|
|
8573
8890
|
}, "Failed to deploy.")
|
|
8574
8891
|
);
|
|
8892
|
+
async function prepareAdapter(workspaceRootDir) {
|
|
8893
|
+
const rethrow = (err) => {
|
|
8894
|
+
if (err instanceof AdapterError) {
|
|
8895
|
+
throw new Error(err.snippet ? `${err.message}
|
|
8896
|
+
|
|
8897
|
+
${pc18.cyan(err.snippet)}` : err.message);
|
|
8898
|
+
}
|
|
8899
|
+
throw err;
|
|
8900
|
+
};
|
|
8901
|
+
const outcome = await ensureNodeAdapter(workspaceRootDir, { install: false }).catch(rethrow);
|
|
8902
|
+
if (!outcome.configFile && !outcome.packageJsonChanged) return;
|
|
8903
|
+
const changed = [
|
|
8904
|
+
outcome.configFile,
|
|
8905
|
+
outcome.packageJsonChanged ? "package.json" : void 0
|
|
8906
|
+
].filter((f) => Boolean(f));
|
|
8907
|
+
const why = outcome.previous === "auto" ? `${ADAPTER_AUTO} builds nothing for a server of your own` : outcome.previous === "none" ? "No adapter was configured" : `${ADAPTER_NODE} was configured but not in package.json`;
|
|
8908
|
+
p42.log.step(`Switching the adapter to ${pc18.cyan(ADAPTER_NODE)}`);
|
|
8909
|
+
p42.log.info(
|
|
8910
|
+
`${why}, and vela deploy runs the app as a Node server.
|
|
8911
|
+
|
|
8912
|
+
Changed ${changed.join(", ")}` + (outcome.removedDeps.length ? `
|
|
8913
|
+
Removed ${outcome.removedDeps.join(", ")}` : "")
|
|
8914
|
+
);
|
|
8915
|
+
if (outcome.packageJsonChanged) {
|
|
8916
|
+
try {
|
|
8917
|
+
changed.push(lockfileFor(await installAdapterDependencies(workspaceRootDir)));
|
|
8918
|
+
} catch (err) {
|
|
8919
|
+
rethrow(err);
|
|
8920
|
+
}
|
|
8921
|
+
}
|
|
8922
|
+
p42.log.warn(`Commit ${changed.join(", ")} so every deploy builds the same way.`);
|
|
8923
|
+
}
|
|
8575
8924
|
async function reportAppURLDrift(session, instance, domain) {
|
|
8576
8925
|
const expected = normalizeOrigin(domain);
|
|
8577
8926
|
if (!expected) return;
|
|
@@ -8607,10 +8956,10 @@ Set them in the admin panel instead. ${pc18.dim(String(err))}`
|
|
|
8607
8956
|
}
|
|
8608
8957
|
}
|
|
8609
8958
|
async function openDatabaseTunnel(session, instance, state) {
|
|
8610
|
-
const pbPort = state?.pbPort;
|
|
8959
|
+
const pbPort = instanceHasBackend(state) ? state?.pbPort : void 0;
|
|
8611
8960
|
if (!pbPort) {
|
|
8612
8961
|
throw new Error(
|
|
8613
|
-
`--remote-db needs
|
|
8962
|
+
`--remote-db needs a deployed database to build against, and ${instance} ${state ? "has no backend" : "has not been deployed yet"}.
|
|
8614
8963
|
|
|
8615
8964
|
Deploy once without it, then turn it on.`
|
|
8616
8965
|
);
|
|
@@ -8684,7 +9033,7 @@ async function uploadRelease(session, instance, release, entries) {
|
|
|
8684
9033
|
}
|
|
8685
9034
|
function isDirectory(target) {
|
|
8686
9035
|
try {
|
|
8687
|
-
return
|
|
9036
|
+
return fs37.statSync(target).isDirectory();
|
|
8688
9037
|
} catch {
|
|
8689
9038
|
return false;
|
|
8690
9039
|
}
|
|
@@ -8692,7 +9041,7 @@ function isDirectory(target) {
|
|
|
8692
9041
|
async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
|
|
8693
9042
|
const remote = await readRemoteEnv(session, instance);
|
|
8694
9043
|
if (Object.keys(remote).length > 0) return;
|
|
8695
|
-
if (!
|
|
9044
|
+
if (!fs37.existsSync(path38.join(workspaceRootDir, ".env"))) return;
|
|
8696
9045
|
p42.log.warn(
|
|
8697
9046
|
`This app has no production environment variables yet.
|
|
8698
9047
|
|
|
@@ -8710,7 +9059,7 @@ async function serverTimeOrLocal(session) {
|
|
|
8710
9059
|
}
|
|
8711
9060
|
|
|
8712
9061
|
// src/commands/link.ts
|
|
8713
|
-
import
|
|
9062
|
+
import path39 from "node:path";
|
|
8714
9063
|
import process29 from "node:process";
|
|
8715
9064
|
import { Command as Command77 } from "commander";
|
|
8716
9065
|
import * as p43 from "@clack/prompts";
|
|
@@ -8798,12 +9147,12 @@ async function promptProjectName(workspaceRootDir) {
|
|
|
8798
9147
|
}
|
|
8799
9148
|
function defaultProjectName2(workspaceRootDir) {
|
|
8800
9149
|
try {
|
|
8801
|
-
const pkg = readPackageJson(
|
|
9150
|
+
const pkg = readPackageJson(path39.join(workspaceRootDir, "package.json"));
|
|
8802
9151
|
const name = pkg.name;
|
|
8803
9152
|
if (typeof name === "string" && name.trim()) return name.trim();
|
|
8804
9153
|
} catch {
|
|
8805
9154
|
}
|
|
8806
|
-
return
|
|
9155
|
+
return path39.basename(workspaceRootDir);
|
|
8807
9156
|
}
|
|
8808
9157
|
|
|
8809
9158
|
// src/commands/env.ts
|
|
@@ -8934,8 +9283,8 @@ var envUnset = addTargetOptions(
|
|
|
8934
9283
|
);
|
|
8935
9284
|
|
|
8936
9285
|
// src/commands/env/import.ts
|
|
8937
|
-
import
|
|
8938
|
-
import
|
|
9286
|
+
import fs38 from "node:fs";
|
|
9287
|
+
import path40 from "node:path";
|
|
8939
9288
|
import process31 from "node:process";
|
|
8940
9289
|
import { Command as Command81 } from "commander";
|
|
8941
9290
|
import * as p47 from "@clack/prompts";
|
|
@@ -8981,10 +9330,10 @@ var envImport = addTargetOptions(
|
|
|
8981
9330
|
)
|
|
8982
9331
|
);
|
|
8983
9332
|
function resolve(file) {
|
|
8984
|
-
return
|
|
9333
|
+
return path40.resolve(process31.cwd(), file);
|
|
8985
9334
|
}
|
|
8986
9335
|
function read(resolved, shown) {
|
|
8987
|
-
if (!
|
|
9336
|
+
if (!fs38.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
|
|
8988
9337
|
const incoming = readLocalEnvFile(resolved);
|
|
8989
9338
|
if (Object.keys(incoming).length === 0) p47.log.info(`${shown} has no variables to import.`);
|
|
8990
9339
|
return incoming;
|
|
@@ -9262,8 +9611,8 @@ var admin = new Command87("admin").description("manage admin panel logins").conf
|
|
|
9262
9611
|
import { Command as Command93 } from "commander";
|
|
9263
9612
|
|
|
9264
9613
|
// src/commands/backup/create.ts
|
|
9265
|
-
import
|
|
9266
|
-
import
|
|
9614
|
+
import fs39 from "node:fs";
|
|
9615
|
+
import path41 from "node:path";
|
|
9267
9616
|
import { Command as Command88 } from "commander";
|
|
9268
9617
|
import * as p51 from "@clack/prompts";
|
|
9269
9618
|
import pc26 from "picocolors";
|
|
@@ -9417,12 +9766,12 @@ Your bucket's own versioning is what protects the uploaded files.`
|
|
|
9417
9766
|
}, "Failed to create the backup.")
|
|
9418
9767
|
);
|
|
9419
9768
|
async function download(ctx, key, outputDir) {
|
|
9420
|
-
const dir =
|
|
9421
|
-
|
|
9422
|
-
const destination =
|
|
9769
|
+
const dir = path41.resolve(ctx.workspaceRootDir, outputDir);
|
|
9770
|
+
fs39.mkdirSync(dir, { recursive: true });
|
|
9771
|
+
const destination = path41.join(dir, key);
|
|
9423
9772
|
if (!ctx.session) {
|
|
9424
|
-
|
|
9425
|
-
return
|
|
9773
|
+
fs39.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9774
|
+
return path41.relative(ctx.workspaceRootDir, destination);
|
|
9426
9775
|
}
|
|
9427
9776
|
const spinner7 = p51.spinner();
|
|
9428
9777
|
spinner7.start(`Downloading ${key}`);
|
|
@@ -9433,7 +9782,7 @@ async function download(ctx, key, outputDir) {
|
|
|
9433
9782
|
throw error;
|
|
9434
9783
|
}
|
|
9435
9784
|
spinner7.stop(`Downloaded ${key}`);
|
|
9436
|
-
return
|
|
9785
|
+
return path41.relative(ctx.workspaceRootDir, destination);
|
|
9437
9786
|
}
|
|
9438
9787
|
|
|
9439
9788
|
// src/commands/backup/list.ts
|
|
@@ -9467,8 +9816,8 @@ Take one with ${pc27.cyan("vela backup create")}.`
|
|
|
9467
9816
|
);
|
|
9468
9817
|
|
|
9469
9818
|
// src/commands/backup/download.ts
|
|
9470
|
-
import
|
|
9471
|
-
import
|
|
9819
|
+
import fs40 from "node:fs";
|
|
9820
|
+
import path42 from "node:path";
|
|
9472
9821
|
import { Command as Command90 } from "commander";
|
|
9473
9822
|
import * as p53 from "@clack/prompts";
|
|
9474
9823
|
import pc28 from "picocolors";
|
|
@@ -9495,11 +9844,11 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
|
|
|
9495
9844
|
Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
9496
9845
|
);
|
|
9497
9846
|
}
|
|
9498
|
-
const dir =
|
|
9499
|
-
|
|
9500
|
-
const destination =
|
|
9847
|
+
const dir = path42.resolve(ctx.workspaceRootDir, options.output);
|
|
9848
|
+
fs40.mkdirSync(dir, { recursive: true });
|
|
9849
|
+
const destination = path42.join(dir, key);
|
|
9501
9850
|
if (!ctx.session) {
|
|
9502
|
-
|
|
9851
|
+
fs40.copyFileSync(path42.join(ctx.workspaceRootDir, "data", "backups", key), destination);
|
|
9503
9852
|
} else {
|
|
9504
9853
|
const spinner7 = p53.spinner();
|
|
9505
9854
|
spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
|
|
@@ -9513,7 +9862,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
|
|
|
9513
9862
|
}
|
|
9514
9863
|
reportResult({
|
|
9515
9864
|
summary: `Saved ${key} from ${ctx.targetName}.`,
|
|
9516
|
-
filesCreated: [
|
|
9865
|
+
filesCreated: [path42.relative(ctx.workspaceRootDir, destination)]
|
|
9517
9866
|
});
|
|
9518
9867
|
});
|
|
9519
9868
|
}, "Failed to download the backup.")
|
|
@@ -9608,8 +9957,8 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
|
|
|
9608
9957
|
var backup = new Command93("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
|
|
9609
9958
|
|
|
9610
9959
|
// src/commands/restore.ts
|
|
9611
|
-
import
|
|
9612
|
-
import
|
|
9960
|
+
import fs41 from "node:fs";
|
|
9961
|
+
import path43 from "node:path";
|
|
9613
9962
|
import process34 from "node:process";
|
|
9614
9963
|
import { Command as Command94 } from "commander";
|
|
9615
9964
|
import * as p56 from "@clack/prompts";
|
|
@@ -9632,7 +9981,7 @@ var restore = addLockWaitOption(
|
|
|
9632
9981
|
`${ctx.targetName} was deployed without a database, so there is nothing to restore.`
|
|
9633
9982
|
);
|
|
9634
9983
|
}
|
|
9635
|
-
const local = source &&
|
|
9984
|
+
const local = source && fs41.existsSync(source) ? source : void 0;
|
|
9636
9985
|
const key = local ? void 0 : await resolveKey(ctx, source);
|
|
9637
9986
|
if (!options.yes) {
|
|
9638
9987
|
await confirm13(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
|
|
@@ -9655,7 +10004,7 @@ var restore = addLockWaitOption(
|
|
|
9655
10004
|
});
|
|
9656
10005
|
p56.log.success(
|
|
9657
10006
|
`Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
|
|
9658
|
-
local ?
|
|
10007
|
+
local ? path43.basename(local) : key
|
|
9659
10008
|
)}.`
|
|
9660
10009
|
);
|
|
9661
10010
|
if (result?.storageCarriedOver) {
|
|
@@ -9721,21 +10070,21 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
|
|
|
9721
10070
|
}
|
|
9722
10071
|
async function stage(ctx, file) {
|
|
9723
10072
|
const dir = remotePaths.restoreStage(ctx.instance);
|
|
9724
|
-
const remote = `${dir}/${
|
|
10073
|
+
const remote = `${dir}/${path43.basename(file)}`;
|
|
9725
10074
|
const spinner7 = p56.spinner();
|
|
9726
|
-
spinner7.start(`Uploading ${
|
|
10075
|
+
spinner7.start(`Uploading ${path43.basename(file)}`);
|
|
9727
10076
|
try {
|
|
9728
10077
|
await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
|
|
9729
10078
|
await ctx.session.upload([file], dir);
|
|
9730
10079
|
} catch (error) {
|
|
9731
|
-
spinner7.stop(`Could not upload ${
|
|
10080
|
+
spinner7.stop(`Could not upload ${path43.basename(file)}.`);
|
|
9732
10081
|
throw error;
|
|
9733
10082
|
}
|
|
9734
|
-
spinner7.stop(`Uploaded ${
|
|
10083
|
+
spinner7.stop(`Uploaded ${path43.basename(file)}`);
|
|
9735
10084
|
return remote;
|
|
9736
10085
|
}
|
|
9737
10086
|
async function confirm13(appName, targetName, envTag, from) {
|
|
9738
|
-
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(
|
|
10087
|
+
const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path43.basename(from))}`;
|
|
9739
10088
|
if (isProd(envTag)) {
|
|
9740
10089
|
const answer = await p56.text({
|
|
9741
10090
|
message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
|
|
@@ -9846,28 +10195,28 @@ Release and domain are shown from what this project recorded.`
|
|
|
9846
10195
|
}
|
|
9847
10196
|
|
|
9848
10197
|
// src/commands/test.ts
|
|
9849
|
-
import
|
|
10198
|
+
import path44 from "node:path";
|
|
9850
10199
|
import process35 from "node:process";
|
|
9851
10200
|
import { Command as Command96 } from "commander";
|
|
9852
10201
|
import PocketBase6 from "pocketbase";
|
|
9853
10202
|
import pc33 from "picocolors";
|
|
9854
10203
|
import { x as x5 } from "tinyexec";
|
|
9855
|
-
import { detect as
|
|
10204
|
+
import { detect as detect8 } from "package-manager-detector";
|
|
9856
10205
|
import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
|
|
9857
|
-
import
|
|
10206
|
+
import fs42 from "node:fs";
|
|
9858
10207
|
var testServer = new Command96("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
|
|
9859
10208
|
const cwd = process35.cwd();
|
|
9860
10209
|
const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
|
|
9861
10210
|
const password11 = "password";
|
|
9862
|
-
const testDataDir =
|
|
9863
|
-
|
|
10211
|
+
const testDataDir = path44.join(cwd, "test-data");
|
|
10212
|
+
fs42.rmSync(testDataDir, { recursive: true, force: true });
|
|
9864
10213
|
const { stop, url } = await launchPocketbase(cwd, {
|
|
9865
10214
|
dir: testDataDir,
|
|
9866
|
-
migrationsDir:
|
|
10215
|
+
migrationsDir: path44.join(cwd, MIGRATIONS_DIR),
|
|
9867
10216
|
// The app's PocketBase hooks (slug generation, personal teams, …) are part
|
|
9868
10217
|
// of its behaviour; the suite runs against the same server dev and build
|
|
9869
10218
|
// start, so it loads them from the same place.
|
|
9870
|
-
hooksDir:
|
|
10219
|
+
hooksDir: path44.join(cwd, DATA_DIR, "hooks"),
|
|
9871
10220
|
email: email3,
|
|
9872
10221
|
password: password11
|
|
9873
10222
|
});
|
|
@@ -9883,7 +10232,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9883
10232
|
if (cleanedUp) return;
|
|
9884
10233
|
cleanedUp = true;
|
|
9885
10234
|
stop();
|
|
9886
|
-
|
|
10235
|
+
fs42.rmSync(testDataDir, { recursive: true, force: true });
|
|
9887
10236
|
};
|
|
9888
10237
|
const cleanup = async () => {
|
|
9889
10238
|
if (cleanedUp) return;
|
|
@@ -9935,7 +10284,7 @@ var testServer = new Command96("test:server").description("run server tests").al
|
|
|
9935
10284
|
const passthrough = filter ? extraArgs.filter((a) => a !== filter) : extraArgs;
|
|
9936
10285
|
if (!filter) filter = "server";
|
|
9937
10286
|
try {
|
|
9938
|
-
const pm = (await
|
|
10287
|
+
const pm = (await detect8({ cwd }))?.name ?? "npm";
|
|
9939
10288
|
const resolved = resolveCommand7(pm, "execute", [
|
|
9940
10289
|
"vitest",
|
|
9941
10290
|
"run",
|
|
@@ -9982,8 +10331,8 @@ function stubPagesPlugin() {
|
|
|
9982
10331
|
}
|
|
9983
10332
|
|
|
9984
10333
|
// src/commands/routes.ts
|
|
9985
|
-
import
|
|
9986
|
-
import
|
|
10334
|
+
import fs43 from "node:fs";
|
|
10335
|
+
import path45 from "node:path";
|
|
9987
10336
|
import { Command as Command97 } from "commander";
|
|
9988
10337
|
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
9989
10338
|
"GET",
|
|
@@ -9997,30 +10346,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
9997
10346
|
]);
|
|
9998
10347
|
var routes = new Command97("routes").description("list routes").configureHelp(helpConfig).action(async () => {
|
|
9999
10348
|
const { workspaceRootDir, routesDir } = await getWorkspace();
|
|
10000
|
-
const routesRoot =
|
|
10349
|
+
const routesRoot = path45.join(workspaceRootDir, routesDir);
|
|
10001
10350
|
const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
|
|
10002
10351
|
found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
|
|
10003
10352
|
printTable(found);
|
|
10004
10353
|
});
|
|
10005
10354
|
function walk(root, dir) {
|
|
10006
|
-
const entries =
|
|
10355
|
+
const entries = fs43.readdirSync(dir, { withFileTypes: true });
|
|
10007
10356
|
const routes2 = [];
|
|
10008
10357
|
const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
|
|
10009
10358
|
if (hasLeaf) {
|
|
10010
|
-
const id = "/" +
|
|
10359
|
+
const id = "/" + path45.relative(root, dir).split(path45.sep).filter(Boolean).join("/");
|
|
10011
10360
|
const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
|
|
10012
10361
|
const methods = /* @__PURE__ */ new Set();
|
|
10013
10362
|
for (const entry of entries) {
|
|
10014
10363
|
if (!entry.isFile()) continue;
|
|
10015
10364
|
if (entry.name.endsWith("+page.svelte")) methods.add("GET");
|
|
10016
10365
|
if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
|
|
10017
|
-
extractMethods(
|
|
10366
|
+
extractMethods(path45.join(dir, entry.name)).forEach((m) => methods.add(m));
|
|
10018
10367
|
}
|
|
10019
10368
|
}
|
|
10020
10369
|
routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
|
|
10021
10370
|
}
|
|
10022
10371
|
for (const entry of entries) {
|
|
10023
|
-
if (entry.isDirectory()) routes2.push(...walk(root,
|
|
10372
|
+
if (entry.isDirectory()) routes2.push(...walk(root, path45.join(dir, entry.name)));
|
|
10024
10373
|
}
|
|
10025
10374
|
return routes2;
|
|
10026
10375
|
}
|
|
@@ -10029,7 +10378,7 @@ function isRouteFile(name) {
|
|
|
10029
10378
|
}
|
|
10030
10379
|
function extractMethods(file) {
|
|
10031
10380
|
try {
|
|
10032
|
-
const content =
|
|
10381
|
+
const content = fs43.readFileSync(file, "utf8");
|
|
10033
10382
|
const methods = [];
|
|
10034
10383
|
const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
|
|
10035
10384
|
let match;
|
|
@@ -10073,11 +10422,11 @@ function printTable(routes2) {
|
|
|
10073
10422
|
import process36 from "node:process";
|
|
10074
10423
|
import { Command as Command98 } from "commander";
|
|
10075
10424
|
import { x as x6 } from "tinyexec";
|
|
10076
|
-
import { detect as
|
|
10425
|
+
import { detect as detect9 } from "package-manager-detector";
|
|
10077
10426
|
import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
|
|
10078
10427
|
async function runWuchale(extraArgs) {
|
|
10079
10428
|
const cwd = process36.cwd();
|
|
10080
|
-
const pm = (await
|
|
10429
|
+
const pm = (await detect9({ cwd }))?.name ?? "npm";
|
|
10081
10430
|
const resolved = resolveCommand8(pm, "execute", ["wuchale", ...extraArgs]);
|
|
10082
10431
|
const args = resolved.args.slice();
|
|
10083
10432
|
if (pm === "npm") args.unshift("--yes");
|
|
@@ -10112,7 +10461,7 @@ import pc35 from "picocolors";
|
|
|
10112
10461
|
|
|
10113
10462
|
// src/lib/cms-backend.ts
|
|
10114
10463
|
import { createRequire as createRequire3 } from "node:module";
|
|
10115
|
-
import
|
|
10464
|
+
import path46 from "node:path";
|
|
10116
10465
|
import process37 from "node:process";
|
|
10117
10466
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
10118
10467
|
import pc34 from "picocolors";
|
|
@@ -10120,7 +10469,7 @@ var DEFAULT_PROJECT = "default";
|
|
|
10120
10469
|
async function loadBackendModule(root) {
|
|
10121
10470
|
let entry;
|
|
10122
10471
|
try {
|
|
10123
|
-
entry = createRequire3(
|
|
10472
|
+
entry = createRequire3(path46.join(root, "package.json")).resolve("@velastack/cms/backend");
|
|
10124
10473
|
} catch {
|
|
10125
10474
|
throw new Error(
|
|
10126
10475
|
`@velastack/cms is not installed in this project.
|
|
@@ -10138,8 +10487,8 @@ async function withCmsBackend(fn, cwd = process37.cwd()) {
|
|
|
10138
10487
|
const { createCmsBackend } = await loadBackendModule(root);
|
|
10139
10488
|
const dataDir2 = localDataDir(root);
|
|
10140
10489
|
const backend3 = createCmsBackend({
|
|
10141
|
-
dbPath:
|
|
10142
|
-
uploadDir:
|
|
10490
|
+
dbPath: path46.join(dataDir2, "cms.sqlite"),
|
|
10491
|
+
uploadDir: path46.join(dataDir2, "uploads")
|
|
10143
10492
|
});
|
|
10144
10493
|
try {
|
|
10145
10494
|
return await fn(backend3);
|
|
@@ -10242,7 +10591,10 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
|
|
|
10242
10591
|
// Acts on whichever target `-t` names; the local path reads the project's
|
|
10243
10592
|
// own credentials rather than requiring them in this process.
|
|
10244
10593
|
"backup",
|
|
10245
|
-
"restore"
|
|
10594
|
+
"restore",
|
|
10595
|
+
// Removes a copy from its server; the other `destroy` subcommands edit the
|
|
10596
|
+
// local schema and stay gated.
|
|
10597
|
+
"destroy deployment"
|
|
10246
10598
|
]);
|
|
10247
10599
|
var BACKEND_OPTIONAL_COMMANDS = /* @__PURE__ */ new Set(["dev", "build", "preview", "deploy"]);
|
|
10248
10600
|
var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
|
|
@@ -10251,14 +10603,14 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
|
10251
10603
|
if (isStub(actionCommand)) return;
|
|
10252
10604
|
const envRoot = findWorkspaceRoot() ?? process38.cwd();
|
|
10253
10605
|
dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
|
|
10254
|
-
const
|
|
10255
|
-
if (NO_BACKEND_COMMMANDS.has(
|
|
10256
|
-
const top =
|
|
10606
|
+
const path47 = getCommandPath(actionCommand);
|
|
10607
|
+
if (NO_BACKEND_COMMMANDS.has(path47)) return;
|
|
10608
|
+
const top = path47.split(" ", 1)[0];
|
|
10257
10609
|
if (NO_BACKEND_COMMMANDS.has(top)) return;
|
|
10258
10610
|
if (!hasBackend()) {
|
|
10259
10611
|
if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
|
|
10260
10612
|
p61.log.error(
|
|
10261
|
-
`${pc38.cyan(`vela ${
|
|
10613
|
+
`${pc38.cyan(`vela ${path47}`)} needs a backend, and this project does not have one.
|
|
10262
10614
|
|
|
10263
10615
|
Static projects have no database to talk to.
|
|
10264
10616
|
|
|
@@ -10268,7 +10620,7 @@ To add a backend to this project, run ${pc38.cyan("vela bless")}.`
|
|
|
10268
10620
|
p61.cancel("Operation failed.");
|
|
10269
10621
|
process38.exit(1);
|
|
10270
10622
|
}
|
|
10271
|
-
if (SELF_CREDENTIALED_COMMANDS.has(
|
|
10623
|
+
if (SELF_CREDENTIALED_COMMANDS.has(path47)) return;
|
|
10272
10624
|
if (!process38.env.POCKETBASE_SUPERUSER_EMAIL || !process38.env.POCKETBASE_SUPERUSER_PASSWORD) {
|
|
10273
10625
|
p61.log.error(
|
|
10274
10626
|
`PocketBase superuser credentials are required.
|