vela 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/bin.ts
4
- import process55 from "node:process";
4
+ import process56 from "node:process";
5
5
 
6
6
  // src/lib/argv.ts
7
7
  function normalizeArgv(argv) {
@@ -11,7 +11,7 @@ function normalizeArgv(argv) {
11
11
  }
12
12
 
13
13
  // src/program.ts
14
- import process54 from "node:process";
14
+ import process55 from "node:process";
15
15
  import * as p75 from "@clack/prompts";
16
16
  import { Command as Command122 } from "commander";
17
17
  import nodePath from "node:path";
@@ -20,7 +20,7 @@ import dotenv2 from "dotenv";
20
20
  // package.json
21
21
  var package_default = {
22
22
  name: "vela",
23
- version: "0.22.0",
23
+ version: "0.24.0",
24
24
  type: "module",
25
25
  description: "A CLI for creating and updating SvelteKit projects",
26
26
  license: "MIT",
@@ -36,12 +36,19 @@ var package_default = {
36
36
  vela: "./dist/bin.js",
37
37
  velastack: "./dist/bin.js"
38
38
  },
39
+ exports: {
40
+ "./testing": {
41
+ types: "./dist/testing.d.ts",
42
+ default: "./dist/testing.js"
43
+ },
44
+ "./package.json": "./package.json"
45
+ },
39
46
  files: [
40
47
  "dist",
41
48
  "templates"
42
49
  ],
43
50
  scripts: {
44
- build: "node --experimental-strip-types scripts/build.ts",
51
+ build: "node --experimental-strip-types scripts/build.ts && tsc -p tsconfig.testing.json",
45
52
  dev: "node --experimental-strip-types scripts/build.ts --watch",
46
53
  clean: "rm -rf dist",
47
54
  lint: "npm run lint:ts && npm run lint:format && npm run lint:sh",
@@ -57,7 +64,7 @@ var package_default = {
57
64
  dependencies: {
58
65
  "@clack/prompts": "^1.7.0",
59
66
  "@faker-js/faker": "^10.6.0",
60
- "@velastack/patterns": "^0.10.1",
67
+ "@velastack/patterns": "^0.11.0",
61
68
  "@velastack/pocketbase-codegen": "^0.1.0",
62
69
  "@velastack/schema": "^0.3.0",
63
70
  "@velastack/schema-ui": "^0.3.1",
@@ -301,8 +308,8 @@ function dropTemplateAdapters(user, template) {
301
308
  }
302
309
  return copy;
303
310
  }
304
- function readPackageJson(path68) {
305
- return JSON.parse(fs2.readFileSync(path68, "utf8"));
311
+ function readPackageJson(path69) {
312
+ return JSON.parse(fs2.readFileSync(path69, "utf8"));
306
313
  }
307
314
  var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
308
315
  var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
@@ -331,12 +338,12 @@ function jsString(value) {
331
338
  const quote2 = count("'") > count('"') ? '"' : "'";
332
339
  return `${quote2}${escapeFor(quote2, value)}${quote2}`;
333
340
  }
334
- function readTemplatePackageJson(path68, values) {
335
- const raw = fillTemplatePlaceholders(fs2.readFileSync(path68, "utf8"), values);
341
+ function readTemplatePackageJson(path69, values) {
342
+ const raw = fillTemplatePlaceholders(fs2.readFileSync(path69, "utf8"), values);
336
343
  return JSON.parse(raw);
337
344
  }
338
- function writePackageJson(path68, pkg) {
339
- fs2.writeFileSync(path68, JSON.stringify(pkg, null, " ") + "\n");
345
+ function writePackageJson(path69, pkg) {
346
+ fs2.writeFileSync(path69, JSON.stringify(pkg, null, " ") + "\n");
340
347
  }
341
348
  function toValidPackageName(name) {
342
349
  return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
@@ -505,16 +512,16 @@ function compareVersions(a, b) {
505
512
  return b.prerelease.length - a.prerelease.length;
506
513
  }
507
514
  for (let i = 0; i < Math.max(a.prerelease.length, b.prerelease.length); i++) {
508
- const x8 = a.prerelease[i];
515
+ const x9 = a.prerelease[i];
509
516
  const y = b.prerelease[i];
510
- if (x8 === void 0) return -1;
517
+ if (x9 === void 0) return -1;
511
518
  if (y === void 0) return 1;
512
- if (x8 === y) continue;
513
- const xn = /^\d+$/.test(x8);
519
+ if (x9 === y) continue;
520
+ const xn = /^\d+$/.test(x9);
514
521
  const yn = /^\d+$/.test(y);
515
- if (xn && yn) return Number(x8) - Number(y);
522
+ if (xn && yn) return Number(x9) - Number(y);
516
523
  if (xn !== yn) return xn ? -1 : 1;
517
- return x8 < y ? -1 : 1;
524
+ return x9 < y ? -1 : 1;
518
525
  }
519
526
  return 0;
520
527
  }
@@ -887,7 +894,7 @@ var entrySchema = v2.object({
887
894
  ),
888
895
  /** The schema.org type its JSON-LD describes (`ProfessionalService`, `Restaurant`, …). */
889
896
  schemaType: v2.optional(v2.string()),
890
- /** Tarball location, relative to the index URL. */
897
+ /** Tarball location, relative to the index URL; a paid entry's names velastack.dev's download, which `resolveDownloadUrl` derives itself. */
891
898
  file: v2.string(),
892
899
  sha256: v2.pipe(v2.string(), v2.regex(/^[0-9a-f]{64}$/)),
893
900
  size: v2.optional(v2.number()),
@@ -950,10 +957,11 @@ async function readBytes(url, options) {
950
957
  signal: AbortSignal.timeout(options.timeoutMs)
951
958
  });
952
959
  if (!res.ok) {
953
- throw new Error(`${res.status} ${res.statusText}`.trim());
960
+ throw new DownloadRefused(res.status, res.statusText, await res.text().catch(() => ""));
954
961
  }
955
962
  return new Uint8Array(await res.arrayBuffer());
956
963
  }
964
+ var headersObject = (headers) => headers ? Object.fromEntries(new Headers(headers)) : {};
957
965
  async function fetchTemplateIndex(url, options = {}) {
958
966
  const now = options.now ?? Date.now();
959
967
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -974,9 +982,47 @@ async function fetchTemplateIndex(url, options = {}) {
974
982
  return { index: null, stale: false, reason };
975
983
  }
976
984
  }
977
- function resolveDownloadUrl(entry, indexUrl) {
985
+ var isPaidEntry = (entry) => (entry.price ?? 0) > 0;
986
+ function resolveDownloadUrl(entry, indexUrl, apiUrl = API_URL) {
987
+ if (isPaidEntry(entry)) return `${apiUrl}/v1/templates/${entry.name}/download`;
978
988
  return new URL(entry.file, indexUrl).href;
979
989
  }
990
+ var DownloadRefused = class extends Error {
991
+ status;
992
+ body;
993
+ constructor(status3, statusText, body) {
994
+ super(`${status3} ${statusText}`.trim());
995
+ this.status = status3;
996
+ this.body = body;
997
+ }
998
+ };
999
+ var TemplateNotPurchased = class extends Error {
1000
+ constructor(entry, url) {
1001
+ super(
1002
+ `${entry.title ?? entry.name} is a paid template (US$${entry.price}). Buy it for your team at ${url}, then run this again.`
1003
+ );
1004
+ this.entry = entry;
1005
+ this.url = url;
1006
+ }
1007
+ entry;
1008
+ url;
1009
+ name = "TemplateNotPurchased";
1010
+ };
1011
+ function paidDownloadError(entry, error) {
1012
+ if (error.status === 402) {
1013
+ let url = `https://velabase.dev/templates/${entry.name}`;
1014
+ try {
1015
+ const parsed = JSON.parse(error.body);
1016
+ if (typeof parsed.url === "string") url = parsed.url;
1017
+ } catch {
1018
+ }
1019
+ return new TemplateNotPurchased(entry, url);
1020
+ }
1021
+ if (error.status === 401) {
1022
+ return new Error(`velastack.dev did not accept your login. Run \`vela login\` and try again.`);
1023
+ }
1024
+ return new Error(`Could not download template ${entry.name}: ${error.message}`);
1025
+ }
980
1026
  function sha256(bytes) {
981
1027
  return createHash("sha256").update(bytes).digest("hex");
982
1028
  }
@@ -996,11 +1042,19 @@ async function downloadTemplate(entry, indexUrl, options = {}) {
996
1042
  haveTarball = sha256(cached2) === entry.sha256;
997
1043
  }
998
1044
  if (!haveTarball) {
999
- const url = resolveDownloadUrl(entry, indexUrl);
1045
+ const paid = isPaidEntry(entry);
1046
+ if (paid && !options.apiKey) {
1047
+ throw new Error(
1048
+ `${entry.title ?? entry.name} is a paid template. Run \`vela login\` (or set VELA_API_KEY) so velastack.dev can check it was bought for you.`
1049
+ );
1050
+ }
1051
+ const url = resolveDownloadUrl(entry, indexUrl, options.apiUrl);
1052
+ const headers = paid ? { ...headersObject(options.headers), Authorization: `Bearer ${options.apiKey}` } : options.headers;
1000
1053
  let fetched;
1001
1054
  try {
1002
- fetched = await readBytes(url, { timeoutMs, headers: options.headers });
1055
+ fetched = await readBytes(url, { timeoutMs, headers });
1003
1056
  } catch (e) {
1057
+ if (paid && e instanceof DownloadRefused) throw paidDownloadError(entry, e);
1004
1058
  throw new Error(`Could not download template ${entry.name}: ${e.message}`);
1005
1059
  }
1006
1060
  const digest = sha256(fetched);
@@ -1108,13 +1162,13 @@ function templateChoicesMessage(templates) {
1108
1162
  }
1109
1163
  return [...groups].map(([category, names]) => `${category}: ${names.join(", ")}`).join("; ");
1110
1164
  }
1111
- async function resolveTemplate(template) {
1165
+ async function resolveTemplate(template, options = {}) {
1112
1166
  if (!("entry" in template)) {
1113
1167
  return { ...template, cleanup() {
1114
1168
  } };
1115
1169
  }
1116
1170
  const { entry, indexUrl, ...info } = template;
1117
- const dir = await downloadTemplate(entry, indexUrl);
1171
+ const dir = await downloadTemplate(entry, indexUrl, { apiKey: options.apiKey });
1118
1172
  return {
1119
1173
  ...info,
1120
1174
  dir,
@@ -2799,7 +2853,7 @@ var VELA_ONLY_FILES = [
2799
2853
  { path: ".ignore", adds: "search ignores for generated files" },
2800
2854
  {
2801
2855
  path: "vitest.config.ts",
2802
- adds: "the server test project `vela test:server` runs \u2014 without it test/setup.ts never loads"
2856
+ adds: "the server test project, with the `vela/testing` global setup that starts its servers \u2014 without it test/setup.ts never loads"
2803
2857
  }
2804
2858
  ];
2805
2859
  var VELA_ONLY_DIRS = ["src/lib/components", "src/lib/workflows", "data", "test", "static"];
@@ -3738,6 +3792,12 @@ async function createProject(apiKey, args) {
3738
3792
  })
3739
3793
  });
3740
3794
  }
3795
+ async function purchaseTemplate(apiKey, slug2, teamId) {
3796
+ return apiFetch(apiKey, `/v1/templates/${slug2}/purchase`, {
3797
+ method: "POST",
3798
+ body: JSON.stringify({ team: teamId })
3799
+ });
3800
+ }
3741
3801
  async function registerServer(apiKey, input) {
3742
3802
  return apiFetch(apiKey, "/v1/servers", {
3743
3803
  method: "POST",
@@ -3900,8 +3960,8 @@ function cancelled() {
3900
3960
  p9.cancel("Operation cancelled.");
3901
3961
  process14.exit(0);
3902
3962
  }
3903
- async function postForm(fetchCookie, path68, fields) {
3904
- const res = await fetchCookie(`${API_URL}${path68}`, {
3963
+ async function postForm(fetchCookie, path69, fields) {
3964
+ const res = await fetchCookie(`${API_URL}${path69}`, {
3905
3965
  method: "POST",
3906
3966
  headers: {
3907
3967
  "Content-Type": "application/x-www-form-urlencoded",
@@ -6407,7 +6467,7 @@ async function createProject2(cwdArg, options, listing) {
6407
6467
  const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
6408
6468
  checkFlagsForTemplate(template, options);
6409
6469
  const gallerySchema = options.schema ? findGallerySchema(options.schema) : void 0;
6410
- const resolved = await resolveCreatableTemplate(template);
6470
+ const resolved = await resolveCreatableTemplate(template, options);
6411
6471
  const onCancel2 = () => {
6412
6472
  resolved.cleanup();
6413
6473
  p12.cancel("Operation cancelled.");
@@ -6469,9 +6529,28 @@ async function createProject2(cwdArg, options, listing) {
6469
6529
  }
6470
6530
  return { directory: projectPath, packageManager: packageManager2, installed: installed2, migrated, name, template, link: link2 };
6471
6531
  }
6472
- async function resolveCreatableTemplate(template) {
6532
+ async function resolveCreatableTemplate(template, options = {}) {
6533
+ let apiKey = readApiKey();
6534
+ if ((template.price ?? 0) > 0 && !apiKey) {
6535
+ if (!isInteractive()) {
6536
+ throw new Error(
6537
+ `${template.name} is a paid template. Run \`vela login\` or set VELA_API_KEY, then run this again.`
6538
+ );
6539
+ }
6540
+ p12.log.info(
6541
+ `${template.name} is a paid template (US$${template.price}). Log in to velastack.dev to download it.`
6542
+ );
6543
+ apiKey = await loginInteractively();
6544
+ }
6473
6545
  if (template.source === "remote") p12.log.step(`Downloading template ${template.name}...`);
6474
- const resolved = await resolveTemplate(template);
6546
+ let resolved;
6547
+ try {
6548
+ resolved = await resolveTemplate(template, { apiKey });
6549
+ } catch (error) {
6550
+ if (!(error instanceof TemplateNotPurchased) || !apiKey || !isInteractive()) throw error;
6551
+ await buyTemplate(error, apiKey, options);
6552
+ resolved = await resolveTemplate(template, { apiKey });
6553
+ }
6475
6554
  const blocker = findKit3Blocker(resolved.dir);
6476
6555
  if (blocker) {
6477
6556
  resolved.cleanup();
@@ -6479,6 +6558,31 @@ async function resolveCreatableTemplate(template) {
6479
6558
  }
6480
6559
  return resolved;
6481
6560
  }
6561
+ async function buyTemplate(refusal, apiKey, options) {
6562
+ const { entry } = refusal;
6563
+ const title = entry.title ?? entry.name;
6564
+ p12.log.warn(`${title} is a paid template (US$${entry.price}).`);
6565
+ const team = await resolveTeam(await listTeams(apiKey), {
6566
+ teamId: options.team,
6567
+ interactive: true
6568
+ });
6569
+ const confirmed = await p12.confirm({
6570
+ message: `Buy ${title} for US$${entry.price} for ${team.name}? The card on file at velastack.dev is charged.`
6571
+ });
6572
+ if (p12.isCancel(confirmed) || !confirmed) throw refusal;
6573
+ if (options.link === void 0 || options.link === "new") options.team = team.id;
6574
+ const outcome = await purchaseTemplate(apiKey, entry.name, team.id);
6575
+ if (outcome.status === "purchased") {
6576
+ const card = outcome.last4 ? ` on the card ending ${outcome.last4}` : "";
6577
+ p12.log.success(`Bought ${title} for ${team.name}${card}. It is yours to deploy again any time.`);
6578
+ return;
6579
+ }
6580
+ p12.log.info(`${outcome.message}
6581
+ Buy it in the browser, then come back here:
6582
+ ${outcome.url}`);
6583
+ const done = await p12.confirm({ message: "Bought it? The download is tried again." });
6584
+ if (p12.isCancel(done) || !done) throw refusal;
6585
+ }
6482
6586
  async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
6483
6587
  const interactive = isInteractive();
6484
6588
  let directory;
@@ -7682,8 +7786,13 @@ var apiKeys = new Command16("api-keys").description("enable API key management")
7682
7786
  );
7683
7787
 
7684
7788
  // src/commands/enable/backend.ts
7789
+ import fs34 from "node:fs";
7790
+ import path34 from "node:path";
7685
7791
  import process18 from "node:process";
7686
7792
  import * as v6 from "valibot";
7793
+ import { x as x3 } from "tinyexec";
7794
+ import { detect as detect6 } from "package-manager-detector";
7795
+ import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
7687
7796
  import { Command as Command17 } from "commander";
7688
7797
  import * as p21 from "@clack/prompts";
7689
7798
  import pc7 from "picocolors";
@@ -7711,7 +7820,10 @@ var backend = new Command17("backend").description("enable the PocketBase backen
7711
7820
  },
7712
7821
  // The pattern installs `pocketbase-server` before this runs, and
7713
7822
  // scaffolds the `data/` directory the database lives in.
7714
- () => initPocketbase(workspaceRootDir, credentials)
7823
+ async () => {
7824
+ await ensureVelaDependency(workspaceRootDir);
7825
+ await initPocketbase(workspaceRootDir, credentials);
7826
+ }
7715
7827
  );
7716
7828
  }, "Failed to enable backend.")
7717
7829
  );
@@ -7731,6 +7843,22 @@ function backendNextSteps(ui2) {
7731
7843
  "`vela enable auth` needs shadcn-svelte: `npx sv add tailwindcss`, then `npx shadcn-svelte@latest init`."
7732
7844
  ];
7733
7845
  }
7846
+ async function ensureVelaDependency(root) {
7847
+ const file = path34.join(root, "package.json");
7848
+ if (!fs34.existsSync(file)) return;
7849
+ const manifest = JSON.parse(fs34.readFileSync(file, "utf8"));
7850
+ if (manifest.dependencies?.vela || manifest.devDependencies?.vela) return;
7851
+ p21.log.step("Adding vela to devDependencies...");
7852
+ const pm = (await detect6({ cwd: root }))?.name ?? "npm";
7853
+ const resolved = resolveCommand4(pm, "add", [`vela@^${package_default.version}`, "-D"]);
7854
+ const result = await x3(resolved.command, resolved.args, {
7855
+ nodeOptions: { cwd: root, stdio: "pipe" }
7856
+ });
7857
+ if (result.exitCode !== 0) {
7858
+ throw new Error(`Failed to add vela to devDependencies:
7859
+ ${result.stderr || result.stdout}`);
7860
+ }
7861
+ }
7734
7862
  async function initPocketbase(root, { email: email2, password: password8 }) {
7735
7863
  p21.log.step("Initializing PocketBase...");
7736
7864
  await upsertSuperuser(root, email2, password8);
@@ -7814,22 +7942,22 @@ var teams = new Command19("teams").description("enable team / multi-tenant suppo
7814
7942
  );
7815
7943
 
7816
7944
  // src/commands/enable/payments.ts
7817
- import fs35 from "node:fs";
7818
- import path35 from "node:path";
7945
+ import fs36 from "node:fs";
7946
+ import path36 from "node:path";
7819
7947
  import process19 from "node:process";
7820
7948
  import { Command as Command20 } from "commander";
7821
7949
  import * as p22 from "@clack/prompts";
7822
7950
 
7823
7951
  // src/lib/order-form.ts
7824
- import fs34 from "node:fs";
7825
- import path34 from "node:path";
7952
+ import fs35 from "node:fs";
7953
+ import path35 from "node:path";
7826
7954
  var ORDER_FORM_KEY = "order";
7827
7955
  var ORDER_FORM_NAME = "Orders";
7828
7956
  var HOSTED_CMS = /^(https?:\/\/[^/]+)\/v1\/projects\/([^/?#]+)\/cms\/?$/;
7829
7957
  function hostedCmsProject(root) {
7830
7958
  let source;
7831
7959
  try {
7832
- source = fs34.readFileSync(path34.join(root, "src", "lib", "cms.ts"), "utf8");
7960
+ source = fs35.readFileSync(path35.join(root, "src", "lib", "cms.ts"), "utf8");
7833
7961
  } catch {
7834
7962
  return null;
7835
7963
  }
@@ -7948,9 +8076,9 @@ function isCountry(code2) {
7948
8076
  }
7949
8077
  function declaredBusiness() {
7950
8078
  const root = findWorkspaceRoot();
7951
- const site = root ? path35.join(root, "src", "lib", "site.ts") : null;
7952
- if (!site || !fs35.existsSync(site)) return {};
7953
- const source = fs35.readFileSync(site, "utf8");
8079
+ const site = root ? path36.join(root, "src", "lib", "site.ts") : null;
8080
+ if (!site || !fs36.existsSync(site)) return {};
8081
+ const source = fs36.readFileSync(site, "utf8");
7954
8082
  return {
7955
8083
  currency: /^\s*currency\s*:\s*['"]([A-Za-z]{3})['"]/m.exec(source)?.[1],
7956
8084
  country: /^\s*country\s*:\s*['"]([A-Za-z]{2})['"]/m.exec(source)?.[1],
@@ -8912,25 +9040,25 @@ import * as p26 from "@clack/prompts";
8912
9040
  import pc9 from "picocolors";
8913
9041
 
8914
9042
  // src/lib/deploy-config.ts
8915
- import fs36 from "node:fs";
8916
- import path36 from "node:path";
9043
+ import fs37 from "node:fs";
9044
+ import path37 from "node:path";
8917
9045
  import crypto2 from "node:crypto";
8918
9046
  function projectFilePath(workspaceRootDir) {
8919
- return path36.join(workspaceRootDir, ".vela", "project.json");
9047
+ return path37.join(workspaceRootDir, ".vela", "project.json");
8920
9048
  }
8921
9049
  function readProjectFile(workspaceRootDir) {
8922
9050
  const file = projectFilePath(workspaceRootDir);
8923
- if (!fs36.existsSync(file)) return {};
9051
+ if (!fs37.existsSync(file)) return {};
8924
9052
  try {
8925
- return JSON.parse(fs36.readFileSync(file, "utf8"));
9053
+ return JSON.parse(fs37.readFileSync(file, "utf8"));
8926
9054
  } catch {
8927
9055
  return {};
8928
9056
  }
8929
9057
  }
8930
9058
  function writeProjectFile(workspaceRootDir, data) {
8931
9059
  const file = projectFilePath(workspaceRootDir);
8932
- fs36.mkdirSync(path36.dirname(file), { recursive: true });
8933
- fs36.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
9060
+ fs37.mkdirSync(path37.dirname(file), { recursive: true });
9061
+ fs37.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
8934
9062
  }
8935
9063
  function resolveAppIdentity(workspaceRootDir, projectName) {
8936
9064
  const project = readProjectFile(workspaceRootDir);
@@ -8955,11 +9083,11 @@ function readAppIdentity(workspaceRootDir, projectName) {
8955
9083
  }
8956
9084
  function defaultProjectName(workspaceRootDir) {
8957
9085
  try {
8958
- const pkg = readPackageJson(path36.join(workspaceRootDir, "package.json"));
9086
+ const pkg = readPackageJson(path37.join(workspaceRootDir, "package.json"));
8959
9087
  if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
8960
9088
  } catch {
8961
9089
  }
8962
- return path36.basename(workspaceRootDir);
9090
+ return path37.basename(workspaceRootDir);
8963
9091
  }
8964
9092
  function slug(value) {
8965
9093
  return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
@@ -9030,15 +9158,15 @@ function randomSuffix() {
9030
9158
  }
9031
9159
 
9032
9160
  // src/lib/artifact.ts
9033
- import fs38 from "node:fs";
9034
- import path38 from "node:path";
9035
- import { detect as detect6 } from "package-manager-detector";
9036
- import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
9161
+ import fs39 from "node:fs";
9162
+ import path39 from "node:path";
9163
+ import { detect as detect7 } from "package-manager-detector";
9164
+ import { resolveCommand as resolveCommand5 } from "package-manager-detector/commands";
9037
9165
 
9038
9166
  // src/lib/ssh.ts
9039
- import fs37 from "node:fs";
9167
+ import fs38 from "node:fs";
9040
9168
  import os5 from "node:os";
9041
- import path37 from "node:path";
9169
+ import path38 from "node:path";
9042
9170
  import crypto4 from "node:crypto";
9043
9171
  import process24 from "node:process";
9044
9172
  import { spawn as spawn4 } from "node:child_process";
@@ -9081,9 +9209,9 @@ var SshSession = class {
9081
9209
  }
9082
9210
  async open() {
9083
9211
  if (this.controlPath) return;
9084
- const dir = path37.join(os5.tmpdir(), "vela-ssh");
9085
- fs37.mkdirSync(dir, { recursive: true, mode: 448 });
9086
- const socket = path37.join(dir, `${crypto4.randomBytes(6).toString("hex")}.sock`);
9212
+ const dir = path38.join(os5.tmpdir(), "vela-ssh");
9213
+ fs38.mkdirSync(dir, { recursive: true, mode: 448 });
9214
+ const socket = path38.join(dir, `${crypto4.randomBytes(6).toString("hex")}.sock`);
9087
9215
  this.controlPath = socket;
9088
9216
  const args = [
9089
9217
  ...this.sshArgs(),
@@ -9354,8 +9482,8 @@ async function runBuild(cwd, buildCommand, env2) {
9354
9482
  throw new BuildError(`\`${buildCommand}\` exited ${result2.exitCode}.`);
9355
9483
  return;
9356
9484
  }
9357
- const pm = (await detect6({ cwd }))?.name ?? "npm";
9358
- const resolved = resolveCommand4(pm, "run", ["build"]);
9485
+ const pm = (await detect7({ cwd }))?.name ?? "npm";
9486
+ const resolved = resolveCommand5(pm, "run", ["build"]);
9359
9487
  if (!resolved) throw new BuildError(`Could not work out how to run a build with ${pm}.`);
9360
9488
  const result = await spawnCapture(resolved.command, resolved.args, {
9361
9489
  cwd,
@@ -9373,11 +9501,11 @@ function collectArtifact(cwd) {
9373
9501
  const outputDir = DEFAULT_OUTPUT_DIR;
9374
9502
  const entries = [];
9375
9503
  const add2 = (rel, remoteDir = "") => {
9376
- const localPath = path38.join(cwd, rel);
9377
- if (fs38.existsSync(localPath)) entries.push({ localPath, remoteDir });
9504
+ const localPath = path39.join(cwd, rel);
9505
+ if (fs39.existsSync(localPath)) entries.push({ localPath, remoteDir });
9378
9506
  };
9379
- const buildPath = path38.join(cwd, outputDir);
9380
- if (!fs38.existsSync(path38.join(buildPath, "index.js"))) {
9507
+ const buildPath = path39.join(cwd, outputDir);
9508
+ if (!fs39.existsSync(path39.join(buildPath, "index.js"))) {
9381
9509
  throw new BuildError(
9382
9510
  `No ${outputDir}/index.js to deploy.
9383
9511
 
@@ -9390,18 +9518,18 @@ build ran with it as the adapter, then deploy again.`
9390
9518
  for (const lockfile of [NPM_LOCKFILE, ...FOREIGN_LOCKFILES]) add2(lockfile);
9391
9519
  add2(".npmrc");
9392
9520
  add2(MIGRATIONS_DIR);
9393
- const hooks = path38.join(cwd, DATA_DIR, "hooks");
9394
- if (fs38.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
9521
+ const hooks = path39.join(cwd, DATA_DIR, "hooks");
9522
+ if (fs39.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
9395
9523
  return entries;
9396
9524
  }
9397
9525
  var NPM_LOCKFILE = "package-lock.json";
9398
9526
  var FOREIGN_LOCKFILES = ["pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"];
9399
9527
  function hasLockfile(cwd) {
9400
- return fs38.existsSync(path38.join(cwd, NPM_LOCKFILE));
9528
+ return fs39.existsSync(path39.join(cwd, NPM_LOCKFILE));
9401
9529
  }
9402
9530
  function foreignLockfile(cwd) {
9403
9531
  if (hasLockfile(cwd)) return void 0;
9404
- return FOREIGN_LOCKFILES.find((name) => fs38.existsSync(path38.join(cwd, name)));
9532
+ return FOREIGN_LOCKFILES.find((name) => fs39.existsSync(path39.join(cwd, name)));
9405
9533
  }
9406
9534
  async function gitSha(cwd) {
9407
9535
  const result = await spawnCapture("git", ["rev-parse", "HEAD"], { cwd });
@@ -9440,8 +9568,8 @@ function sshOptionsFrom(options) {
9440
9568
 
9441
9569
  // src/lib/remote.ts
9442
9570
  import crypto5 from "node:crypto";
9443
- import fs39 from "node:fs";
9444
- import path39 from "node:path";
9571
+ import fs40 from "node:fs";
9572
+ import path40 from "node:path";
9445
9573
  import process25 from "node:process";
9446
9574
  var VELA_ROOT = "/var/lib/vela";
9447
9575
  var VELA_ETC = "/etc/vela";
@@ -9454,19 +9582,19 @@ function instanceHasBackend(state) {
9454
9582
  return state.backend ?? Boolean(state.pbPort);
9455
9583
  }
9456
9584
  function serverTemplatesDir() {
9457
- return path39.join(templatesDir(), "server");
9585
+ return path40.join(templatesDir(), "server");
9458
9586
  }
9459
9587
  var DIGEST_LENGTH = 12;
9460
9588
  function serverScriptsDigest(dir = serverTemplatesDir()) {
9461
9589
  const hash = crypto5.createHash("sha256");
9462
9590
  for (const file of listFiles(dir).sort()) {
9463
- hash.update(file).update("\0").update(fs39.readFileSync(path39.join(dir, file))).update("\0");
9591
+ hash.update(file).update("\0").update(fs40.readFileSync(path40.join(dir, file))).update("\0");
9464
9592
  }
9465
9593
  return hash.digest("hex").slice(0, DIGEST_LENGTH);
9466
9594
  }
9467
9595
  function listFiles(root, prefix = "") {
9468
9596
  const files = [];
9469
- for (const entry of fs39.readdirSync(path39.join(root, prefix), { withFileTypes: true })) {
9597
+ for (const entry of fs40.readdirSync(path40.join(root, prefix), { withFileTypes: true })) {
9470
9598
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
9471
9599
  if (entry.isDirectory()) files.push(...listFiles(root, rel));
9472
9600
  else if (entry.isFile()) files.push(rel);
@@ -9593,7 +9721,7 @@ var remotePaths = {
9593
9721
  };
9594
9722
 
9595
9723
  // src/lib/remote-env.ts
9596
- import fs40 from "node:fs";
9724
+ import fs41 from "node:fs";
9597
9725
  import dotenv from "dotenv";
9598
9726
  var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
9599
9727
  function isValidKey(key) {
@@ -9641,7 +9769,7 @@ function quote(value) {
9641
9769
  return `"${escaped}"`;
9642
9770
  }
9643
9771
  function readLocalEnvFile(file) {
9644
- const parsed = dotenv.parse(fs40.readFileSync(file));
9772
+ const parsed = dotenv.parse(fs41.readFileSync(file));
9645
9773
  const result = {};
9646
9774
  for (const [key, value] of Object.entries(parsed)) {
9647
9775
  if (isValidKey(key)) result[key] = value;
@@ -10524,14 +10652,14 @@ var ui = new Command59("ui").description("generate ui components").configureHelp
10524
10652
  import { Command as Command62 } from "commander";
10525
10653
 
10526
10654
  // src/commands/legal/terms.ts
10527
- import path41 from "node:path";
10655
+ import path42 from "node:path";
10528
10656
  import { Command as Command60 } from "commander";
10529
10657
  import * as p37 from "@clack/prompts";
10530
10658
 
10531
10659
  // src/commands/legal/shared.ts
10532
10660
  import process29 from "node:process";
10533
- import fs41 from "node:fs";
10534
- import path40 from "node:path";
10661
+ import fs42 from "node:fs";
10662
+ import path41 from "node:path";
10535
10663
  import * as p36 from "@clack/prompts";
10536
10664
  function siteFields(site) {
10537
10665
  const url = site?.url && !isLocalUrl(site.url) ? site.url : void 0;
@@ -10813,16 +10941,16 @@ function writeLegalPage(root, dir, page) {
10813
10941
 
10814
10942
  ${html}`;
10815
10943
  }
10816
- const pagePath = path40.join(root, dir, "+page.svelte");
10817
- fs41.mkdirSync(path40.dirname(pagePath), { recursive: true });
10818
- fs41.writeFileSync(pagePath, html);
10944
+ const pagePath = path41.join(root, dir, "+page.svelte");
10945
+ fs42.mkdirSync(path41.dirname(pagePath), { recursive: true });
10946
+ fs42.writeFileSync(pagePath, html);
10819
10947
  const written = [pagePath];
10820
10948
  if (metaTags) {
10821
- const loaderPath = path40.join(root, dir, "+page.ts");
10822
- fs41.writeFileSync(loaderPath, pageMetaTagsLoader(page.title, page.description));
10949
+ const loaderPath = path41.join(root, dir, "+page.ts");
10950
+ fs42.writeFileSync(loaderPath, pageMetaTagsLoader(page.title, page.description));
10823
10951
  written.push(loaderPath);
10824
10952
  }
10825
- return written.map((file) => path40.relative(root, file));
10953
+ return written.map((file) => path41.relative(root, file));
10826
10954
  }
10827
10955
 
10828
10956
  // src/commands/legal/terms.ts
@@ -11219,7 +11347,7 @@ async function termsAction() {
11219
11347
  });
11220
11348
  const [relativeTermsPage, ...rest] = writeLegalPage(
11221
11349
  workspaceRootDir,
11222
- path41.join(publicRoutesDir, LEGAL_DIR, "terms"),
11350
+ path42.join(publicRoutesDir, LEGAL_DIR, "terms"),
11223
11351
  {
11224
11352
  html,
11225
11353
  title: "Terms of Service",
@@ -11239,7 +11367,7 @@ async function termsAction() {
11239
11367
  var terms = new Command60("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
11240
11368
 
11241
11369
  // src/commands/legal/privacy.ts
11242
- import path42 from "node:path";
11370
+ import path43 from "node:path";
11243
11371
  import { Command as Command61 } from "commander";
11244
11372
  import * as p38 from "@clack/prompts";
11245
11373
  var mapLabels = {
@@ -11955,7 +12083,7 @@ async function privacyAction() {
11955
12083
  });
11956
12084
  const [relativePrivacyPage, ...rest] = writeLegalPage(
11957
12085
  workspaceRootDir,
11958
- path42.join(publicRoutesDir, LEGAL_DIR, "privacy"),
12086
+ path43.join(publicRoutesDir, LEGAL_DIR, "privacy"),
11959
12087
  {
11960
12088
  html,
11961
12089
  title: "Privacy Policy",
@@ -11984,8 +12112,8 @@ import { Command as Command68 } from "commander";
11984
12112
  import { Command as Command63 } from "commander";
11985
12113
 
11986
12114
  // src/lib/data.ts
11987
- import fs42 from "node:fs";
11988
- import path43 from "node:path";
12115
+ import fs43 from "node:fs";
12116
+ import path44 from "node:path";
11989
12117
  import { ClientResponseError } from "pocketbase";
11990
12118
 
11991
12119
  // src/lib/collections.ts
@@ -12022,14 +12150,14 @@ function dependencyOrder(collections2, startingCollectionId) {
12022
12150
 
12023
12151
  // src/lib/data.ts
12024
12152
  function dataDir(cwd, kind) {
12025
- return path43.join(cwd, DATA_DIR, kind);
12153
+ return path44.join(cwd, DATA_DIR, kind);
12026
12154
  }
12027
12155
  function getDataFiles(cwd, kind) {
12028
12156
  const dir = dataDir(cwd, kind);
12029
- if (!fs42.existsSync(dir)) return [];
12030
- return fs42.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
12157
+ if (!fs43.existsSync(dir)) return [];
12158
+ return fs43.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
12031
12159
  collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
12032
- filePath: path43.join(dir, file)
12160
+ filePath: path44.join(dir, file)
12033
12161
  }));
12034
12162
  }
12035
12163
  function getSeedFiles(cwd) {
@@ -12039,7 +12167,7 @@ function getFixtureFiles(cwd) {
12039
12167
  return getDataFiles(cwd, "fixtures");
12040
12168
  }
12041
12169
  function readRecords(filePath) {
12042
- return JSON.parse(fs42.readFileSync(filePath, "utf8"));
12170
+ return JSON.parse(fs43.readFileSync(filePath, "utf8"));
12043
12171
  }
12044
12172
  function readSeedIds(cwd) {
12045
12173
  const ids = /* @__PURE__ */ new Map();
@@ -12076,7 +12204,7 @@ function describeError(e) {
12076
12204
  return e instanceof Error ? e.message : String(e);
12077
12205
  }
12078
12206
  function label(cwd, filePath, count) {
12079
- return `${path43.relative(cwd, filePath)} (${count} records)`;
12207
+ return `${path44.relative(cwd, filePath)} (${count} records)`;
12080
12208
  }
12081
12209
  async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
12082
12210
  const records = readRecords(filePath);
@@ -12084,7 +12212,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
12084
12212
  try {
12085
12213
  await pb.collection(collectionName).create(record);
12086
12214
  } catch (e) {
12087
- throw new DataLoadError(kind, path43.relative(cwd, filePath), index, e);
12215
+ throw new DataLoadError(kind, path44.relative(cwd, filePath), index, e);
12088
12216
  }
12089
12217
  }
12090
12218
  return records.length;
@@ -12258,8 +12386,8 @@ var reset = new Command65("reset").description("clear and reload fixtures").conf
12258
12386
  );
12259
12387
 
12260
12388
  // src/commands/fixtures/generate.ts
12261
- import fs43 from "node:fs";
12262
- import path44 from "node:path";
12389
+ import fs44 from "node:fs";
12390
+ import path45 from "node:path";
12263
12391
  import { Command as Command66, InvalidArgumentError } from "commander";
12264
12392
  import * as p39 from "@clack/prompts";
12265
12393
  import { annotate } from "annotate-json-schema";
@@ -12296,9 +12424,9 @@ async function loadCollections(pb) {
12296
12424
  }
12297
12425
  async function generateFixtureFiles(pb, workspaceRootDir, opts) {
12298
12426
  const fixturesDir = dataDir(workspaceRootDir, "fixtures");
12299
- fs43.mkdirSync(fixturesDir, { recursive: true });
12300
- for (const file of fs43.readdirSync(fixturesDir)) {
12301
- if (file.endsWith(".json")) fs43.unlinkSync(path44.join(fixturesDir, file));
12427
+ fs44.mkdirSync(fixturesDir, { recursive: true });
12428
+ for (const file of fs44.readdirSync(fixturesDir)) {
12429
+ if (file.endsWith(".json")) fs44.unlinkSync(path45.join(fixturesDir, file));
12302
12430
  }
12303
12431
  if (opts.seed !== void 0) faker.seed(opts.seed);
12304
12432
  const generator = createGenerator({
@@ -12365,8 +12493,8 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
12365
12493
  items.push(record);
12366
12494
  }
12367
12495
  const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
12368
- fs43.writeFileSync(path44.join(fixturesDir, filename), JSON.stringify(items, null, 2));
12369
- writtenFiles.push(`${path44.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
12496
+ fs44.writeFileSync(path45.join(fixturesDir, filename), JSON.stringify(items, null, 2));
12497
+ writtenFiles.push(`${path45.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
12370
12498
  fileIndex++;
12371
12499
  }
12372
12500
  return { writtenFiles, warnings };
@@ -12513,8 +12641,8 @@ var load2 = new Command69("load").description("load seeds into the database").op
12513
12641
  );
12514
12642
 
12515
12643
  // src/commands/seeds/save.ts
12516
- import fs44 from "node:fs";
12517
- import path45 from "node:path";
12644
+ import fs45 from "node:fs";
12645
+ import path46 from "node:path";
12518
12646
  import { Command as Command70 } from "commander";
12519
12647
  var padZeros2 = (num, length) => num.toString().padStart(length, "0");
12520
12648
  function filterSystemFields(record, systemFieldNames) {
@@ -12534,10 +12662,10 @@ var save = new Command70("save").description("save the current data as seeds").o
12534
12662
  if (existing.length > 0 && !opts.force) {
12535
12663
  throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
12536
12664
  }
12537
- fs44.mkdirSync(seedsPath, { recursive: true });
12665
+ fs45.mkdirSync(seedsPath, { recursive: true });
12538
12666
  if (opts.force) {
12539
- for (const file of fs44.readdirSync(seedsPath)) {
12540
- if (file.endsWith(".json")) fs44.unlinkSync(path45.join(seedsPath, file));
12667
+ for (const file of fs45.readdirSync(seedsPath)) {
12668
+ if (file.endsWith(".json")) fs45.unlinkSync(path46.join(seedsPath, file));
12541
12669
  }
12542
12670
  }
12543
12671
  const saved = [];
@@ -12566,13 +12694,13 @@ var save = new Command70("save").description("save the current data as seeds").o
12566
12694
  const filtered = records.map(
12567
12695
  (r) => filterSystemFields(r, systemFieldNames)
12568
12696
  );
12569
- const relativeSeedPath = path45.join(
12697
+ const relativeSeedPath = path46.join(
12570
12698
  DATA_DIR,
12571
12699
  "seeds",
12572
12700
  `${padZeros2(count, 2)}-${collectionName}.json`
12573
12701
  );
12574
- const seedPath = path45.join(workspaceRootDir, relativeSeedPath);
12575
- fs44.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
12702
+ const seedPath = path46.join(workspaceRootDir, relativeSeedPath);
12703
+ fs45.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
12576
12704
  saved.push(`${relativeSeedPath} (${filtered.length} records)`);
12577
12705
  count++;
12578
12706
  }
@@ -12719,9 +12847,9 @@ import { Command as Command82 } from "commander";
12719
12847
  import { Command as Command76 } from "commander";
12720
12848
 
12721
12849
  // src/lib/migrate.ts
12722
- import path46 from "node:path";
12850
+ import path47 from "node:path";
12723
12851
  import process30 from "node:process";
12724
- import { x as x3 } from "tinyexec";
12852
+ import { x as x4 } from "tinyexec";
12725
12853
  function migrateRoot() {
12726
12854
  return findWorkspaceRoot() ?? process30.cwd();
12727
12855
  }
@@ -12729,13 +12857,13 @@ async function runPocketbaseMigrate(args) {
12729
12857
  const cwd = migrateRoot();
12730
12858
  const { getBinaryPath } = await import("pocketbase-server");
12731
12859
  const binaryPath = getBinaryPath();
12732
- await x3(
12860
+ await x4(
12733
12861
  binaryPath,
12734
12862
  [
12735
12863
  "--dir",
12736
- path46.join(cwd, DATA_DIR),
12864
+ path47.join(cwd, DATA_DIR),
12737
12865
  "--migrationsDir",
12738
- path46.join(cwd, MIGRATIONS_DIR),
12866
+ path47.join(cwd, MIGRATIONS_DIR),
12739
12867
  "migrate",
12740
12868
  ...args
12741
12869
  ],
@@ -12783,8 +12911,8 @@ var down = new Command77("down").alias("rollback").description("revert the last
12783
12911
  );
12784
12912
 
12785
12913
  // src/commands/migrate/create.ts
12786
- import fs45 from "node:fs";
12787
- import path47 from "node:path";
12914
+ import fs46 from "node:fs";
12915
+ import path48 from "node:path";
12788
12916
  import { Command as Command78 } from "commander";
12789
12917
  var create2 = new Command78("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
12790
12918
  (name) => runCommand(async () => {
@@ -12795,7 +12923,7 @@ var create2 = new Command78("create").alias("new").description("create a new bla
12795
12923
  const added = [...after].filter((f) => !before.has(f));
12796
12924
  reportResult({
12797
12925
  summary: `Created blank migration ${name}.`,
12798
- filesCreated: added.map((f) => path47.join(MIGRATIONS_DIR, f)),
12926
+ filesCreated: added.map((f) => path48.join(MIGRATIONS_DIR, f)),
12799
12927
  nextSteps: [
12800
12928
  `Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
12801
12929
  "Run `vela migrate up` to apply the migration once the handlers are written."
@@ -12804,14 +12932,14 @@ var create2 = new Command78("create").alias("new").description("create a new bla
12804
12932
  }, "Failed to create migration.")
12805
12933
  );
12806
12934
  function listMigrationFiles(cwd) {
12807
- const dir = path47.join(cwd, MIGRATIONS_DIR);
12808
- if (!fs45.existsSync(dir)) return /* @__PURE__ */ new Set();
12809
- return new Set(fs45.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
12935
+ const dir = path48.join(cwd, MIGRATIONS_DIR);
12936
+ if (!fs46.existsSync(dir)) return /* @__PURE__ */ new Set();
12937
+ return new Set(fs46.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
12810
12938
  }
12811
12939
 
12812
12940
  // src/commands/migrate/collections.ts
12813
- import fs46 from "node:fs";
12814
- import path48 from "node:path";
12941
+ import fs47 from "node:fs";
12942
+ import path49 from "node:path";
12815
12943
  import { Command as Command79 } from "commander";
12816
12944
  var collections = new Command79("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
12817
12945
  () => runCommand(async () => {
@@ -12828,7 +12956,7 @@ var collections = new Command79("collections").alias("snapshot").description("sn
12828
12956
  }
12829
12957
  reportResult({
12830
12958
  summary: "Snapshotted local collections into a new migration.",
12831
- filesCreated: added.map((f) => path48.join(MIGRATIONS_DIR, f)),
12959
+ filesCreated: added.map((f) => path49.join(MIGRATIONS_DIR, f)),
12832
12960
  nextSteps: [
12833
12961
  `Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
12834
12962
  "Commit the snapshot so teammates pick up the new schema.",
@@ -12838,9 +12966,9 @@ var collections = new Command79("collections").alias("snapshot").description("sn
12838
12966
  }, "Failed to snapshot collections.")
12839
12967
  );
12840
12968
  function listMigrationFiles2(cwd) {
12841
- const dir = path48.join(cwd, MIGRATIONS_DIR);
12842
- if (!fs46.existsSync(dir)) return /* @__PURE__ */ new Set();
12843
- return new Set(fs46.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
12969
+ const dir = path49.join(cwd, MIGRATIONS_DIR);
12970
+ if (!fs47.existsSync(dir)) return /* @__PURE__ */ new Set();
12971
+ return new Set(fs47.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
12844
12972
  }
12845
12973
 
12846
12974
  // src/commands/migrate/history-sync.ts
@@ -12856,14 +12984,14 @@ var historySync = new Command80("history-sync").description("drop _migrations ro
12856
12984
  );
12857
12985
 
12858
12986
  // src/commands/migrate/sveltekit-3.ts
12859
- import path49 from "node:path";
12987
+ import path50 from "node:path";
12860
12988
  import process31 from "node:process";
12861
12989
  import { Command as Command81 } from "commander";
12862
12990
  import * as p44 from "@clack/prompts";
12863
12991
  import pc13 from "picocolors";
12864
12992
  var sveltekit3 = new Command81("sveltekit-3").description("upgrade a SvelteKit 2 project to SvelteKit 3 (sv migrate, then the vela steps)").option("--cwd <path>", "the project to migrate (default: the current project)").option("--no-install", "skip installing dependencies").option("--force", "run even when the git working tree has uncommitted changes").option("--skip-sv", "only run the vela steps (sv has already been run)").configureHelp(helpConfig).action(
12865
12993
  (options) => runCommand(async () => {
12866
- const root = options.cwd ? path49.resolve(options.cwd) : findWorkspaceRoot() ?? process31.cwd();
12994
+ const root = options.cwd ? path50.resolve(options.cwd) : findWorkspaceRoot() ?? process31.cwd();
12867
12995
  p44.intro(pc13.bgCyan(pc13.black(" vela migrate sveltekit-3 ")));
12868
12996
  const result = await runKit3Migration(root, {
12869
12997
  install: options.install,
@@ -12880,7 +13008,7 @@ function printReport(root, result) {
12880
13008
  sections.push({ label: "Build output removed first", items: result.sv.cleared });
12881
13009
  }
12882
13010
  for (const fixup2 of changed) sections.push({ label: fixup2.name, items: fixup2.details });
12883
- const summary = result.mode === "repair" ? changed.length > 0 ? "Already on SvelteKit 3; brought the vela setup up to date." : "Already on SvelteKit 3; nothing left to change." : `Migrated ${path49.basename(root)} to SvelteKit 3.`;
13011
+ const summary = result.mode === "repair" ? changed.length > 0 ? "Already on SvelteKit 3; brought the vela setup up to date." : "Already on SvelteKit 3; nothing left to change." : `Migrated ${path50.basename(root)} to SvelteKit 3.`;
12884
13012
  reportResult({ summary, sections });
12885
13013
  const tasks = result.tasks;
12886
13014
  if (tasks && (tasks.sections.length > 0 || tasks.markerComments > 0)) {
@@ -12938,8 +13066,8 @@ function nextStepsFor(result) {
12938
13066
  var migrate = new Command82("migrate").description("manage database migrations (and `migrate sveltekit-3` to upgrade SvelteKit)").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync).addCommand(sveltekit3);
12939
13067
 
12940
13068
  // src/commands/dev.ts
12941
- import fs47 from "node:fs";
12942
- import path51 from "node:path";
13069
+ import fs48 from "node:fs";
13070
+ import path52 from "node:path";
12943
13071
  import process33 from "node:process";
12944
13072
  import { performance } from "node:perf_hooks";
12945
13073
  import { Command as Command83, InvalidArgumentError as InvalidArgumentError4 } from "commander";
@@ -12971,7 +13099,7 @@ function createPocketbaseLogFilter() {
12971
13099
  }
12972
13100
 
12973
13101
  // src/lib/vite.ts
12974
- import path50 from "node:path";
13102
+ import path51 from "node:path";
12975
13103
  import process32 from "node:process";
12976
13104
  import { createRequire as createRequire4 } from "node:module";
12977
13105
  import { pathToFileURL } from "node:url";
@@ -12991,7 +13119,7 @@ function viteVersionError(version) {
12991
13119
  }
12992
13120
  function resolveProjectVite(cwd) {
12993
13121
  try {
12994
- return createRequire4(path50.join(cwd, "package.json")).resolve("vite");
13122
+ return createRequire4(path51.join(cwd, "package.json")).resolve("vite");
12995
13123
  } catch {
12996
13124
  return null;
12997
13125
  }
@@ -13021,8 +13149,8 @@ var dev = new Command83("dev").description("start the development server").optio
13021
13149
  process33.env.VELA_DATA_DIR ??= localDataDir(cwd);
13022
13150
  const startTime = performance.now();
13023
13151
  const { createServer, resolveConfig, version } = await loadVite(cwd);
13024
- const viteMetadataDir = path51.join(cwd, "node_modules", ".vite");
13025
- const viteMetadataFile = path51.join(viteMetadataDir, "_pocketbase_metadata.json");
13152
+ const viteMetadataDir = path52.join(cwd, "node_modules", ".vite");
13153
+ const viteMetadataFile = path52.join(viteMetadataDir, "_pocketbase_metadata.json");
13026
13154
  const serverOptions = {};
13027
13155
  if (options.open !== void 0) serverOptions.open = options.open;
13028
13156
  if (options.host !== void 0) serverOptions.host = options.host;
@@ -13038,7 +13166,7 @@ var dev = new Command83("dev").description("start the development server").optio
13038
13166
  const needsStart = backend3 && !process33.env.POCKETBASE_URL;
13039
13167
  const cleanup = () => {
13040
13168
  if (pbProc?.pid) pbProc.kill();
13041
- if (fs47.existsSync(viteMetadataFile)) fs47.rmSync(viteMetadataFile);
13169
+ if (fs48.existsSync(viteMetadataFile)) fs48.rmSync(viteMetadataFile);
13042
13170
  };
13043
13171
  if (needsStart) {
13044
13172
  const resolved = await resolveConfig(inlineConfig, "serve");
@@ -13056,11 +13184,11 @@ var dev = new Command83("dev").description("start the development server").optio
13056
13184
  )
13057
13185
  );
13058
13186
  }
13059
- const dataDir2 = path51.join(cwd, DATA_DIR);
13187
+ const dataDir2 = path52.join(cwd, DATA_DIR);
13060
13188
  const started = await startPocketbaseServe({
13061
13189
  dataDir: dataDir2,
13062
13190
  migrationsDir: MIGRATIONS_DIR,
13063
- hooksDir: path51.join(dataDir2, "hooks"),
13191
+ hooksDir: path52.join(dataDir2, "hooks"),
13064
13192
  dev: true,
13065
13193
  stdio: "pipe",
13066
13194
  env: {
@@ -13082,8 +13210,8 @@ var dev = new Command83("dev").description("start the development server").optio
13082
13210
  if (!backend3) return;
13083
13211
  const { address, port: vitePort } = server.httpServer.address();
13084
13212
  const viteHost = address === "::1" ? "localhost" : address;
13085
- await fs47.promises.mkdir(viteMetadataDir, { recursive: true });
13086
- await fs47.promises.writeFile(
13213
+ await fs48.promises.mkdir(viteMetadataDir, { recursive: true });
13214
+ await fs48.promises.writeFile(
13087
13215
  viteMetadataFile,
13088
13216
  JSON.stringify({
13089
13217
  pocketbaseUrl: process33.env.POCKETBASE_URL,
@@ -13114,18 +13242,18 @@ var dev = new Command83("dev").description("start the development server").optio
13114
13242
  });
13115
13243
  async function startWatchingTypes(cwd, pb) {
13116
13244
  const { processTypes } = await import("@velastack/pocketbase-codegen");
13117
- const typesDir = path51.resolve(cwd, ".svelte-kit", "types");
13118
- const pocketbaseDir = path51.join(typesDir, "pocketbase");
13119
- const pocketbaseTypes = path51.join(pocketbaseDir, "$types.d.ts");
13245
+ const typesDir = path52.resolve(cwd, ".svelte-kit", "types");
13246
+ const pocketbaseDir = path52.join(typesDir, "pocketbase");
13247
+ const pocketbaseTypes = path52.join(pocketbaseDir, "$types.d.ts");
13120
13248
  const regenerate = () => processTypes(pb, typesDir).catch(() => {
13121
13249
  });
13122
13250
  await regenerate();
13123
13251
  void (async () => {
13124
13252
  for (; ; ) {
13125
13253
  try {
13126
- await fs47.promises.mkdir(pocketbaseDir, { recursive: true });
13127
- for await (const event of fs47.promises.watch(pocketbaseDir)) {
13128
- if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs47.existsSync(pocketbaseTypes)) {
13254
+ await fs48.promises.mkdir(pocketbaseDir, { recursive: true });
13255
+ for await (const event of fs48.promises.watch(pocketbaseDir)) {
13256
+ if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs48.existsSync(pocketbaseTypes)) {
13129
13257
  setTimeout(regenerate, 100);
13130
13258
  }
13131
13259
  }
@@ -13137,15 +13265,15 @@ async function startWatchingTypes(cwd, pb) {
13137
13265
  }
13138
13266
 
13139
13267
  // src/commands/build.ts
13140
- import fs48 from "node:fs";
13141
- import path52 from "node:path";
13268
+ import fs49 from "node:fs";
13269
+ import path53 from "node:path";
13142
13270
  import process35 from "node:process";
13143
13271
  import { Command as Command84 } from "commander";
13144
13272
  import * as p45 from "@clack/prompts";
13145
13273
  import pc16 from "picocolors";
13146
- import { x as x4 } from "tinyexec";
13147
- import { detect as detect7 } from "package-manager-detector";
13148
- import { resolveCommand as resolveCommand5 } from "package-manager-detector/commands";
13274
+ import { x as x5 } from "tinyexec";
13275
+ import { detect as detect8 } from "package-manager-detector";
13276
+ import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
13149
13277
 
13150
13278
  // src/lib/build-env.ts
13151
13279
  function applyBuildEnv(cwd, env2 = process.env) {
@@ -13180,7 +13308,7 @@ function splitHosts(value) {
13180
13308
  }
13181
13309
 
13182
13310
  // src/commands/build.ts
13183
- var PRERENDERED_DIR = path52.join(".svelte-kit", "output", "prerendered");
13311
+ var PRERENDERED_DIR = path53.join(".svelte-kit", "output", "prerendered");
13184
13312
  var build = new Command84("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
13185
13313
  const cwd = process35.cwd();
13186
13314
  warnIfKit2(findWorkspaceRoot(cwd) ?? cwd, (m) => p45.log.warn(m));
@@ -13198,22 +13326,22 @@ var build = new Command84("build").description("build the app").configureHelp(he
13198
13326
  onTerminate(cleanup);
13199
13327
  if (needsStart) {
13200
13328
  await ensureSuperuser(cwd);
13201
- const dataDir2 = path52.join(cwd, DATA_DIR);
13329
+ const dataDir2 = path53.join(cwd, DATA_DIR);
13202
13330
  const started = await startPocketbaseServe({
13203
13331
  dataDir: dataDir2,
13204
13332
  migrationsDir: MIGRATIONS_DIR,
13205
- hooksDir: path52.join(dataDir2, "hooks"),
13333
+ hooksDir: path53.join(dataDir2, "hooks"),
13206
13334
  dev: true
13207
13335
  });
13208
13336
  pbProc = started.proc;
13209
13337
  process35.env.POCKETBASE_URL = started.url;
13210
13338
  }
13211
13339
  try {
13212
- const pm = (await detect7({ cwd }))?.name ?? "npm";
13213
- const resolved = resolveCommand5(pm, "execute", ["vite", "build"]);
13340
+ const pm = (await detect8({ cwd }))?.name ?? "npm";
13341
+ const resolved = resolveCommand6(pm, "execute", ["vite", "build"]);
13214
13342
  const args = resolved.args.slice();
13215
13343
  if (pm === "npm") args.unshift("--yes");
13216
- const vite = x4(resolved.command, args, {
13344
+ const vite = x5(resolved.command, args, {
13217
13345
  nodeOptions: { cwd, stdio: "inherit" },
13218
13346
  throwOnError: true
13219
13347
  });
@@ -13249,8 +13377,8 @@ async function originForBuild(cwd, target) {
13249
13377
  }
13250
13378
  }
13251
13379
  function warnIfPrerendered(cwd) {
13252
- const dir = path52.join(cwd, PRERENDERED_DIR);
13253
- if (!fs48.existsSync(dir) || fs48.readdirSync(dir).length === 0) return;
13380
+ const dir = path53.join(cwd, PRERENDERED_DIR);
13381
+ if (!fs49.existsSync(dir) || fs49.readdirSync(dir).length === 0) return;
13254
13382
  if (process35.env.VELA_ORIGIN === "") {
13255
13383
  p45.log.warn(
13256
13384
  `Prerendered pages were built with no origin, on purpose: this app is served on
@@ -13273,16 +13401,16 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
13273
13401
  }
13274
13402
 
13275
13403
  // src/commands/preview.ts
13276
- import fs49 from "node:fs";
13277
- import path53 from "node:path";
13404
+ import fs50 from "node:fs";
13405
+ import path54 from "node:path";
13278
13406
  import process36 from "node:process";
13279
13407
  import { Command as Command85 } from "commander";
13280
13408
  import * as p46 from "@clack/prompts";
13281
13409
  import pc17 from "picocolors";
13282
- import { x as x5 } from "tinyexec";
13283
- import { detect as detect8 } from "package-manager-detector";
13284
- import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
13285
- var ADAPTER_NODE_MODULE = path53.join("build", "adapter-node.js");
13410
+ import { x as x6 } from "tinyexec";
13411
+ import { detect as detect9 } from "package-manager-detector";
13412
+ import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
13413
+ var ADAPTER_NODE_MODULE = path54.join("build", "adapter-node.js");
13286
13414
  var preview = new Command85("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
13287
13415
  const cwd = process36.cwd();
13288
13416
  process36.env.VELA_DATA_DIR ??= localDataDir(cwd);
@@ -13297,22 +13425,22 @@ var preview = new Command85("preview").description("preview the built app").conf
13297
13425
  };
13298
13426
  onTerminate(cleanup);
13299
13427
  if (needsStart) {
13300
- const dataDir2 = path53.join(cwd, DATA_DIR);
13428
+ const dataDir2 = path54.join(cwd, DATA_DIR);
13301
13429
  const started = await startPocketbaseServe({
13302
13430
  dataDir: dataDir2,
13303
13431
  migrationsDir: MIGRATIONS_DIR,
13304
- hooksDir: path53.join(dataDir2, "hooks"),
13432
+ hooksDir: path54.join(dataDir2, "hooks"),
13305
13433
  dev: true
13306
13434
  });
13307
13435
  pbProc = started.proc;
13308
13436
  process36.env.POCKETBASE_URL = started.url;
13309
13437
  }
13310
13438
  try {
13311
- const pm = (await detect8({ cwd }))?.name ?? "npm";
13312
- const resolved = resolveCommand6(pm, "execute", ["vite", "preview"]);
13439
+ const pm = (await detect9({ cwd }))?.name ?? "npm";
13440
+ const resolved = resolveCommand7(pm, "execute", ["vite", "preview"]);
13313
13441
  const args = resolved.args.slice();
13314
13442
  if (pm === "npm") args.unshift("--yes");
13315
- const vite = x5(resolved.command, args, {
13443
+ const vite = x6(resolved.command, args, {
13316
13444
  nodeOptions: { cwd, stdio: "inherit" },
13317
13445
  throwOnError: true
13318
13446
  });
@@ -13335,7 +13463,7 @@ function bakedOrigin(source) {
13335
13463
  function warnIfOriginBaked(cwd) {
13336
13464
  let source;
13337
13465
  try {
13338
- source = fs49.readFileSync(path53.join(cwd, ADAPTER_NODE_MODULE), "utf8");
13466
+ source = fs50.readFileSync(path54.join(cwd, ADAPTER_NODE_MODULE), "utf8");
13339
13467
  } catch {
13340
13468
  return;
13341
13469
  }
@@ -13351,12 +13479,12 @@ set empty so no domain is baked in.`
13351
13479
  }
13352
13480
 
13353
13481
  // src/commands/sync.ts
13354
- import path54 from "node:path";
13482
+ import path55 from "node:path";
13355
13483
  import { Command as Command86 } from "commander";
13356
13484
  var sync = new Command86("sync").description("sync types from the database").configureHelp(helpConfig).action(
13357
13485
  () => runCommand(async () => {
13358
13486
  const { workspaceRootDir } = await getWorkspace();
13359
- const typesDir = path54.join(workspaceRootDir, ".svelte-kit", "types");
13487
+ const typesDir = path55.join(workspaceRootDir, ".svelte-kit", "types");
13360
13488
  const { processTypes } = await import("@velastack/pocketbase-codegen");
13361
13489
  await withPocketbase(workspaceRootDir, async (pb) => {
13362
13490
  await processTypes(pb, typesDir);
@@ -13427,8 +13555,8 @@ var provision = addSshOptions(
13427
13555
  );
13428
13556
 
13429
13557
  // src/commands/deploy.ts
13430
- import path58 from "node:path";
13431
- import fs53 from "node:fs";
13558
+ import path59 from "node:path";
13559
+ import fs54 from "node:fs";
13432
13560
  import process38 from "node:process";
13433
13561
  import { Command as Command88, Option as Option2 } from "commander";
13434
13562
  import * as p49 from "@clack/prompts";
@@ -13546,12 +13674,12 @@ function reachedInstances(states, appId, layer) {
13546
13674
  }
13547
13675
 
13548
13676
  // src/lib/build-stack.ts
13549
- import fs51 from "node:fs";
13550
- import path56 from "node:path";
13677
+ import fs52 from "node:fs";
13678
+ import path57 from "node:path";
13551
13679
 
13552
13680
  // src/lib/static-env.ts
13553
- import fs50 from "node:fs";
13554
- import path55 from "node:path";
13681
+ import fs51 from "node:fs";
13682
+ import path56 from "node:path";
13555
13683
  import { ENV_DECL_CANDIDATES } from "@velastack/patterns";
13556
13684
  import { Node as Node5, Project as Project5, QuoteKind as QuoteKind3 } from "ts-morph";
13557
13685
  function staticEnv(root) {
@@ -13565,7 +13693,7 @@ function staticEnv(root) {
13565
13693
  };
13566
13694
  }
13567
13695
  const file = findEnvDecl(root);
13568
- const rel = file ? path55.relative(root, file).split(path55.sep).join("/") : ENV_DECL_CANDIDATES[0];
13696
+ const rel = file ? path56.relative(root, file).split(path56.sep).join("/") : ENV_DECL_CANDIDATES[0];
13569
13697
  return {
13570
13698
  names: file ? staticEnvDeclarations(file) : /* @__PURE__ */ new Set(),
13571
13699
  rule: "declarations",
@@ -13575,8 +13703,8 @@ function staticEnv(root) {
13575
13703
  }
13576
13704
  function findEnvDecl(root) {
13577
13705
  for (const rel of ENV_DECL_CANDIDATES) {
13578
- const abs = path55.join(root, rel);
13579
- if (fs50.existsSync(abs)) return abs;
13706
+ const abs = path56.join(root, rel);
13707
+ if (fs51.existsSync(abs)) return abs;
13580
13708
  }
13581
13709
  return null;
13582
13710
  }
@@ -13648,10 +13776,10 @@ var SOURCE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".js", ".mts", ".mjs",
13648
13776
  var STATIC_IMPORT = /import\s*(?:type\s*)?\{([^}]*)\}\s*from\s*['"]\$env\/static\/(?:private|public)['"]/g;
13649
13777
  function staticEnvImports(root) {
13650
13778
  const names = /* @__PURE__ */ new Set();
13651
- const src = path55.join(root, "src");
13652
- if (!fs50.existsSync(src)) return names;
13779
+ const src = path56.join(root, "src");
13780
+ if (!fs51.existsSync(src)) return names;
13653
13781
  for (const file of sourceFiles2(src)) {
13654
- const content = fs50.readFileSync(file, "utf8");
13782
+ const content = fs51.readFileSync(file, "utf8");
13655
13783
  if (!content.includes("$env/static/")) continue;
13656
13784
  for (const match of content.matchAll(STATIC_IMPORT)) {
13657
13785
  for (const spec of match[1].split(",")) {
@@ -13663,11 +13791,11 @@ function staticEnvImports(root) {
13663
13791
  return names;
13664
13792
  }
13665
13793
  function* sourceFiles2(dir) {
13666
- for (const entry of fs50.readdirSync(dir, { withFileTypes: true })) {
13794
+ for (const entry of fs51.readdirSync(dir, { withFileTypes: true })) {
13667
13795
  if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
13668
- const full = path55.join(dir, entry.name);
13796
+ const full = path56.join(dir, entry.name);
13669
13797
  if (entry.isDirectory()) yield* sourceFiles2(full);
13670
- else if (SOURCE_EXTENSIONS2.has(path55.extname(entry.name))) yield full;
13798
+ else if (SOURCE_EXTENSIONS2.has(path56.extname(entry.name))) yield full;
13671
13799
  }
13672
13800
  }
13673
13801
 
@@ -13678,8 +13806,8 @@ var DevOnlyEnvError = class extends Error {
13678
13806
  function buildStack(root, input) {
13679
13807
  const env2 = { ...input.stack, ...input.derived };
13680
13808
  const blanked = [];
13681
- const file = path56.join(root, ".env");
13682
- const local = fs51.existsSync(file) ? readLocalEnvFile(file) : {};
13809
+ const file = path57.join(root, ".env");
13810
+ const local = fs52.existsSync(file) ? readLocalEnvFile(file) : {};
13683
13811
  for (const key of Object.keys(local)) {
13684
13812
  if (key in env2) continue;
13685
13813
  if (!input.tunnel && LOCAL_BUILD_KEYS.test(key)) continue;
@@ -13700,16 +13828,16 @@ The build would bake in your development value. Set ${baked.length === 1 ? "it"
13700
13828
  }
13701
13829
 
13702
13830
  // src/lib/env-nudge.ts
13703
- import fs52 from "node:fs";
13704
- import path57 from "node:path";
13831
+ import fs53 from "node:fs";
13832
+ import path58 from "node:path";
13705
13833
  import process37 from "node:process";
13706
13834
  import * as p48 from "@clack/prompts";
13707
13835
  import pc19 from "picocolors";
13708
13836
  var ENV_EXAMPLE = ".env.example";
13709
13837
  var SUPPLIED = /^(NODE_ENV|HOST|PORT|ORIGIN|PROTOCOL_HEADER|HOST_HEADER|ADDRESS_HEADER|XFF_DEPTH|PB_PORT|POCKETBASE_URL|POCKETBASE_SUPERUSER_EMAIL|POCKETBASE_SUPERUSER_PASSWORD|APP_NAME|VELA_)/;
13710
13838
  function missingFromExample(root, present) {
13711
- const file = path57.join(root, ENV_EXAMPLE);
13712
- if (!fs52.existsSync(file)) return [];
13839
+ const file = path58.join(root, ENV_EXAMPLE);
13840
+ if (!fs53.existsSync(file)) return [];
13713
13841
  const have = new Set(present);
13714
13842
  return Object.keys(readLocalEnvFile(file)).filter((key) => !have.has(key) && !SUPPLIED.test(key)).sort();
13715
13843
  }
@@ -14058,12 +14186,12 @@ ${pc20.cyan(err.snippet)}` : err.message);
14058
14186
  current = detectAdapter(workspaceRootDir);
14059
14187
  } catch {
14060
14188
  }
14061
- const editable = current !== void 0 && !/^svelte\.config\./.test(path58.basename(current.file));
14189
+ const editable = current !== void 0 && !/^svelte\.config\./.test(path59.basename(current.file));
14062
14190
  if (current && editable && (current.kind === "auto" || current.kind === "none") && isInteractive()) {
14063
14191
  const has = current.kind === "auto" ? `is on ${ADAPTER_AUTO}` : "has no SvelteKit adapter configured";
14064
14192
  const confirmed = await p49.confirm({
14065
14193
  message: `This project ${has}, and vela deploy runs the app as a Node server.
14066
- Switch it to ${ADAPTER_NODE}? This edits ${path58.basename(current.file)} and package.json.`
14194
+ Switch it to ${ADAPTER_NODE}? This edits ${path59.basename(current.file)} and package.json.`
14067
14195
  });
14068
14196
  if (p49.isCancel(confirmed) || !confirmed) {
14069
14197
  p49.cancel("Nothing was changed, and nothing was deployed.");
@@ -14187,7 +14315,7 @@ async function uploadRelease(session, instance, release, entries) {
14187
14315
  }
14188
14316
  function isDirectory(target) {
14189
14317
  try {
14190
- return fs53.statSync(target).isDirectory();
14318
+ return fs54.statSync(target).isDirectory();
14191
14319
  } catch {
14192
14320
  return false;
14193
14321
  }
@@ -14228,7 +14356,7 @@ async function serverTimeOrLocal(session) {
14228
14356
  }
14229
14357
 
14230
14358
  // src/commands/link.ts
14231
- import path59 from "node:path";
14359
+ import path60 from "node:path";
14232
14360
  import process39 from "node:process";
14233
14361
  import { Command as Command89 } from "commander";
14234
14362
  import * as p50 from "@clack/prompts";
@@ -14291,12 +14419,12 @@ async function promptProjectName(workspaceRootDir) {
14291
14419
  }
14292
14420
  function defaultProjectName2(workspaceRootDir) {
14293
14421
  try {
14294
- const pkg = readPackageJson(path59.join(workspaceRootDir, "package.json"));
14422
+ const pkg = readPackageJson(path60.join(workspaceRootDir, "package.json"));
14295
14423
  const name = pkg.name;
14296
14424
  if (typeof name === "string" && name.trim()) return name.trim();
14297
14425
  } catch {
14298
14426
  }
14299
- return path59.basename(workspaceRootDir);
14427
+ return path60.basename(workspaceRootDir);
14300
14428
  }
14301
14429
 
14302
14430
  // src/commands/env.ts
@@ -14309,17 +14437,17 @@ import * as p53 from "@clack/prompts";
14309
14437
  import pc23 from "picocolors";
14310
14438
 
14311
14439
  // src/lib/local-env.ts
14312
- import fs54 from "node:fs";
14440
+ import fs55 from "node:fs";
14313
14441
  import * as p51 from "@clack/prompts";
14314
14442
  import pc21 from "picocolors";
14315
14443
  function readLocalEnv(envFile) {
14316
- if (!fs54.existsSync(envFile)) return {};
14444
+ if (!fs55.existsSync(envFile)) return {};
14317
14445
  return readLocalEnvFile(envFile);
14318
14446
  }
14319
14447
  function editLocalEnv(envFile, edit) {
14320
- const before = fs54.existsSync(envFile) ? fs54.readFileSync(envFile, "utf8") : "";
14448
+ const before = fs55.existsSync(envFile) ? fs55.readFileSync(envFile, "utf8") : "";
14321
14449
  const after = edit(before);
14322
- if (after !== before) fs54.writeFileSync(envFile, after);
14450
+ if (after !== before) fs55.writeFileSync(envFile, after);
14323
14451
  }
14324
14452
  function setLocalEnv(envFile, key, value) {
14325
14453
  editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
@@ -14848,8 +14976,8 @@ var envUnset = addEnvTargetOptions(
14848
14976
  );
14849
14977
 
14850
14978
  // src/commands/env/import.ts
14851
- import fs55 from "node:fs";
14852
- import path60 from "node:path";
14979
+ import fs56 from "node:fs";
14980
+ import path61 from "node:path";
14853
14981
  import process42 from "node:process";
14854
14982
  import { Command as Command93 } from "commander";
14855
14983
  import * as p56 from "@clack/prompts";
@@ -14920,10 +15048,10 @@ function report2(outcome, where) {
14920
15048
  p56.log.success(`${parts.join(", ")} variable(s) updated ${pc26.dim(`(${where})`)}`);
14921
15049
  }
14922
15050
  function resolve(file) {
14923
- return path60.resolve(process42.cwd(), file);
15051
+ return path61.resolve(process42.cwd(), file);
14924
15052
  }
14925
15053
  function read(resolved, shown) {
14926
- if (!fs55.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
15054
+ if (!fs56.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
14927
15055
  const incoming = readLocalEnvFile(resolved);
14928
15056
  if (Object.keys(incoming).length === 0) p56.log.info(`${shown} has no variables to import.`);
14929
15057
  return incoming;
@@ -15312,8 +15440,8 @@ var admin = new Command100("admin").description("manage admin panel logins").con
15312
15440
  import { Command as Command106 } from "commander";
15313
15441
 
15314
15442
  // src/commands/backup/create.ts
15315
- import fs56 from "node:fs";
15316
- import path61 from "node:path";
15443
+ import fs57 from "node:fs";
15444
+ import path62 from "node:path";
15317
15445
  import { Command as Command101 } from "commander";
15318
15446
  import * as p61 from "@clack/prompts";
15319
15447
  import pc32 from "picocolors";
@@ -15527,12 +15655,12 @@ Your bucket's own versioning is what protects the uploaded files.`
15527
15655
  }, "Failed to create the backup.")
15528
15656
  );
15529
15657
  async function download(ctx, key, outputDir) {
15530
- const dir = path61.resolve(ctx.workspaceRootDir, outputDir);
15531
- fs56.mkdirSync(dir, { recursive: true });
15532
- const destination = path61.join(dir, key);
15658
+ const dir = path62.resolve(ctx.workspaceRootDir, outputDir);
15659
+ fs57.mkdirSync(dir, { recursive: true });
15660
+ const destination = path62.join(dir, key);
15533
15661
  if (!ctx.session) {
15534
- fs56.copyFileSync(path61.join(ctx.workspaceRootDir, "data", "backups", key), destination);
15535
- return path61.relative(ctx.workspaceRootDir, destination);
15662
+ fs57.copyFileSync(path62.join(ctx.workspaceRootDir, "data", "backups", key), destination);
15663
+ return path62.relative(ctx.workspaceRootDir, destination);
15536
15664
  }
15537
15665
  const spinner9 = p61.spinner();
15538
15666
  spinner9.start(`Downloading ${key}`);
@@ -15543,7 +15671,7 @@ async function download(ctx, key, outputDir) {
15543
15671
  throw error;
15544
15672
  }
15545
15673
  spinner9.stop(`Downloaded ${key}`);
15546
- return path61.relative(ctx.workspaceRootDir, destination);
15674
+ return path62.relative(ctx.workspaceRootDir, destination);
15547
15675
  }
15548
15676
 
15549
15677
  // src/commands/backup/list.ts
@@ -15577,8 +15705,8 @@ Take one with ${pc33.cyan("vela backup create")}.`
15577
15705
  );
15578
15706
 
15579
15707
  // src/commands/backup/download.ts
15580
- import fs57 from "node:fs";
15581
- import path62 from "node:path";
15708
+ import fs58 from "node:fs";
15709
+ import path63 from "node:path";
15582
15710
  import { Command as Command103 } from "commander";
15583
15711
  import * as p63 from "@clack/prompts";
15584
15712
  import pc34 from "picocolors";
@@ -15605,11 +15733,11 @@ Run ${pc34.cyan("vela backup list")} to see what it does have.`
15605
15733
  Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
15606
15734
  );
15607
15735
  }
15608
- const dir = path62.resolve(ctx.workspaceRootDir, options.output);
15609
- fs57.mkdirSync(dir, { recursive: true });
15610
- const destination = path62.join(dir, key);
15736
+ const dir = path63.resolve(ctx.workspaceRootDir, options.output);
15737
+ fs58.mkdirSync(dir, { recursive: true });
15738
+ const destination = path63.join(dir, key);
15611
15739
  if (!ctx.session) {
15612
- fs57.copyFileSync(path62.join(ctx.workspaceRootDir, "data", "backups", key), destination);
15740
+ fs58.copyFileSync(path63.join(ctx.workspaceRootDir, "data", "backups", key), destination);
15613
15741
  } else {
15614
15742
  const spinner9 = p63.spinner();
15615
15743
  spinner9.start(`Downloading ${key} (${formatBytes(found.size)})`);
@@ -15623,7 +15751,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
15623
15751
  }
15624
15752
  reportResult({
15625
15753
  summary: `Saved ${key} from ${ctx.targetName}.`,
15626
- filesCreated: [path62.relative(ctx.workspaceRootDir, destination)]
15754
+ filesCreated: [path63.relative(ctx.workspaceRootDir, destination)]
15627
15755
  });
15628
15756
  });
15629
15757
  }, "Failed to download the backup.")
@@ -15718,8 +15846,8 @@ Set one with ${pc36.cyan('vela backup schedule "0 3 * * *"')}.`
15718
15846
  var backup = new Command106("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);
15719
15847
 
15720
15848
  // src/commands/restore.ts
15721
- import fs58 from "node:fs";
15722
- import path63 from "node:path";
15849
+ import fs59 from "node:fs";
15850
+ import path64 from "node:path";
15723
15851
  import process46 from "node:process";
15724
15852
  import { Command as Command107 } from "commander";
15725
15853
  import * as p66 from "@clack/prompts";
@@ -15749,7 +15877,7 @@ Run \`vela deploy\` first, then restore.`
15749
15877
  `${ctx.targetName} was deployed without a database, so there is nothing to restore.`
15750
15878
  );
15751
15879
  }
15752
- const local = source && fs58.existsSync(source) ? source : void 0;
15880
+ const local = source && fs59.existsSync(source) ? source : void 0;
15753
15881
  const key = local ? void 0 : await resolveKey(ctx, source);
15754
15882
  if (!options.yes) {
15755
15883
  await confirm14(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
@@ -15772,7 +15900,7 @@ Run \`vela deploy\` first, then restore.`
15772
15900
  });
15773
15901
  p66.log.success(
15774
15902
  `Restored ${pc37.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc37.cyan(
15775
- local ? path63.basename(local) : key
15903
+ local ? path64.basename(local) : key
15776
15904
  )}.`
15777
15905
  );
15778
15906
  if (result?.storageCarriedOver) {
@@ -15838,21 +15966,21 @@ Take one with ${pc37.cyan("vela backup create")}, or pass the path to an archive
15838
15966
  }
15839
15967
  async function stage(ctx, file) {
15840
15968
  const dir = remotePaths.restoreStage(ctx.instance);
15841
- const remote = `${dir}/${path63.basename(file)}`;
15969
+ const remote = `${dir}/${path64.basename(file)}`;
15842
15970
  const spinner9 = p66.spinner();
15843
- spinner9.start(`Uploading ${path63.basename(file)}`);
15971
+ spinner9.start(`Uploading ${path64.basename(file)}`);
15844
15972
  try {
15845
15973
  await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
15846
15974
  await ctx.session.upload([file], dir);
15847
15975
  } catch (error) {
15848
- spinner9.stop(`Could not upload ${path63.basename(file)}.`);
15976
+ spinner9.stop(`Could not upload ${path64.basename(file)}.`);
15849
15977
  throw error;
15850
15978
  }
15851
- spinner9.stop(`Uploaded ${path63.basename(file)}`);
15979
+ spinner9.stop(`Uploaded ${path64.basename(file)}`);
15852
15980
  return remote;
15853
15981
  }
15854
15982
  async function confirm14(appName, targetName, envTag, from) {
15855
- const what = `${pc37.cyan(`${appName} (${targetName})`)} from ${pc37.cyan(path63.basename(from))}`;
15983
+ const what = `${pc37.cyan(`${appName} (${targetName})`)} from ${pc37.cyan(path64.basename(from))}`;
15856
15984
  if (isProd(envTag)) {
15857
15985
  const answer = await p66.text({
15858
15986
  message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
@@ -15962,70 +16090,72 @@ Release and domain are shown from what this project recorded.`
15962
16090
  }
15963
16091
 
15964
16092
  // src/commands/test.ts
15965
- import path64 from "node:path";
15966
- import process47 from "node:process";
16093
+ import process48 from "node:process";
15967
16094
  import { Command as Command109 } from "commander";
15968
- import PocketBase7 from "pocketbase";
15969
16095
  import pc39 from "picocolors";
15970
- import { x as x6 } from "tinyexec";
15971
- import { detect as detect9 } from "package-manager-detector";
15972
- import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
15973
- import fs59 from "node:fs";
15974
- var testServer = new Command109("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
15975
- const cwd = process47.cwd();
15976
- warnIfKit2(cwd, (m) => console.warn(pc39.yellow(`\u25B2 ${m}`)));
16096
+ import { x as x7 } from "tinyexec";
16097
+ import { detect as detect10 } from "package-manager-detector";
16098
+ import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
16099
+
16100
+ // src/lib/test-harness.ts
16101
+ import fs60 from "node:fs";
16102
+ import path65 from "node:path";
16103
+ import process47 from "node:process";
16104
+ import PocketBase7 from "pocketbase";
16105
+ var TEST_DATA_DIR = "test-data";
16106
+ var HarnessError = class extends Error {
16107
+ };
16108
+ async function startTestHarness(cwd, { log: log58 = () => {
16109
+ } } = {}) {
15977
16110
  const email2 = `test-${Math.random().toString(36).slice(2)}@example.com`;
15978
16111
  const password8 = "password";
15979
- const testDataDir = path64.join(cwd, "test-data");
15980
- fs59.rmSync(testDataDir, { recursive: true, force: true });
15981
- const { stop, url } = await launchPocketbase(cwd, {
15982
- dir: testDataDir,
15983
- migrationsDir: path64.join(cwd, MIGRATIONS_DIR),
16112
+ const root = path65.join(cwd, TEST_DATA_DIR);
16113
+ pruneStaleRuns(root);
16114
+ const dataDir2 = path65.join(root, String(process47.pid));
16115
+ fs60.rmSync(dataDir2, { recursive: true, force: true });
16116
+ const { stop: stopPocketbase, url: pocketbaseUrl } = await launchPocketbase(cwd, {
16117
+ dir: dataDir2,
16118
+ migrationsDir: path65.join(cwd, MIGRATIONS_DIR),
15984
16119
  // The app's PocketBase hooks (slug generation, personal teams, …) are part
15985
16120
  // of its behaviour; the suite runs against the same server dev and build
15986
16121
  // start, so it loads them from the same place.
15987
- hooksDir: path64.join(cwd, DATA_DIR, "hooks"),
16122
+ hooksDir: path65.join(cwd, DATA_DIR, "hooks"),
15988
16123
  email: email2,
15989
16124
  password: password8
15990
16125
  });
15991
- process47.env.POCKETBASE_URL = url;
15992
- process47.env.POCKETBASE_SUPERUSER_EMAIL = email2;
15993
- process47.env.POCKETBASE_SUPERUSER_PASSWORD = password8;
15994
- process47.env.VELA_DATA_DIR = testDataDir;
15995
- process47.env.TEST = "true";
15996
- console.log(`${pc39.greenBright("\u2713")} Created test database`);
15997
16126
  let vite;
15998
- let cleanedUp = false;
15999
- const cleanupSync = () => {
16000
- if (cleanedUp) return;
16001
- cleanedUp = true;
16002
- stop();
16003
- fs59.rmSync(testDataDir, { recursive: true, force: true });
16127
+ let stopped = false;
16128
+ const stopSync = () => {
16129
+ if (stopped) return;
16130
+ stopped = true;
16131
+ stopPocketbase();
16132
+ fs60.rmSync(dataDir2, { recursive: true, force: true });
16004
16133
  };
16005
- const cleanup = async () => {
16006
- if (cleanedUp) return;
16134
+ const stop = async () => {
16135
+ if (stopped) return;
16007
16136
  process47.emit("sveltekit:shutdown", 0);
16008
16137
  await vite?.close().catch(() => {
16009
16138
  });
16010
- cleanupSync();
16139
+ stopSync();
16011
16140
  };
16012
16141
  const fail = async (message) => {
16013
- console.error(`${pc39.redBright("\u2717")} ${message}`);
16014
- await cleanup();
16015
- process47.exit(1);
16142
+ await stop();
16143
+ throw new HarnessError(message);
16016
16144
  };
16017
- process47.on("exit", cleanupSync);
16018
- for (const [signal, code2] of [
16019
- ["SIGINT", 130],
16020
- ["SIGTERM", 143],
16021
- ["SIGHUP", 129]
16022
- ]) {
16023
- process47.on(signal, () => {
16024
- cleanupSync();
16025
- process47.exit(code2);
16026
- });
16027
- }
16028
- const pb = new PocketBase7(url);
16145
+ const env2 = {
16146
+ POCKETBASE_URL: pocketbaseUrl,
16147
+ POCKETBASE_SUPERUSER_EMAIL: email2,
16148
+ POCKETBASE_SUPERUSER_PASSWORD: password8,
16149
+ // The app's data directory is PocketBase's, here as everywhere else. It
16150
+ // points at the throwaway one so that a database or an uploaded file the
16151
+ // suite creates is removed with it, rather than accumulating in the
16152
+ // directory the developer actually works against.
16153
+ VELA_DATA_DIR: dataDir2,
16154
+ TEST: "true"
16155
+ };
16156
+ Object.assign(process47.env, env2);
16157
+ log58("Created test database");
16158
+ const pb = new PocketBase7(pocketbaseUrl);
16029
16159
  try {
16030
16160
  await authWithRetries(pb, email2, password8);
16031
16161
  } catch (e) {
@@ -16033,60 +16163,61 @@ var testServer = new Command109("test:server").description("run server tests").a
16033
16163
  }
16034
16164
  try {
16035
16165
  const seeds2 = await loadSeeds(pb, cwd);
16036
- if (seeds2.length > 0) {
16037
- console.log(`${pc39.greenBright("\u2713")} Loaded ${seeds2.length} seed file(s)`);
16038
- }
16166
+ if (seeds2.length > 0) log58(`Loaded ${seeds2.length} seed file(s)`);
16039
16167
  const fixtures2 = await loadFixtures(pb, cwd);
16040
- if (fixtures2.length > 0) {
16041
- console.log(`${pc39.greenBright("\u2713")} Loaded ${fixtures2.length} fixture file(s)`);
16042
- }
16168
+ if (fixtures2.length > 0) log58(`Loaded ${fixtures2.length} fixture file(s)`);
16043
16169
  } catch (e) {
16044
16170
  await fail(describeLoadFailure(e));
16045
16171
  }
16046
- const { createServer } = await loadVite(cwd);
16047
- vite = await createServer({
16048
- mode: "test",
16049
- plugins: [stubPagesPlugin()],
16050
- optimizeDeps: { noDiscovery: true },
16051
- // This config differs from `vela dev`'s, so sharing node_modules/.vite
16052
- // would make Vite re-optimize dependencies under a running dev server,
16053
- // which then loads two copies of Svelte and fails reading `page`.
16054
- cacheDir: "node_modules/.vite-test"
16055
- });
16056
- const vitePort = await findFreePort();
16057
- await vite.listen(vitePort);
16058
- process47.env.VITE_TEST_URL = `http://localhost:${vitePort}`;
16059
- console.log(`${pc39.greenBright("\u2713")} Started Vite: http://localhost:${vitePort}`);
16060
- console.log(`${pc39.greenBright("\u2713")} Started PocketBase: ${url}`);
16061
- const extraArgs = (cmd.parent?.args ?? []).slice(1);
16062
- let filter = extraArgs.find((arg) => !arg.startsWith("-"));
16063
- const passthrough = filter ? extraArgs.filter((a) => a !== filter) : extraArgs;
16064
- const defaulted = !filter;
16065
- if (!filter) filter = "server";
16066
16172
  try {
16067
- const pm = (await detect9({ cwd }))?.name ?? "npm";
16068
- const resolved = resolveCommand7(pm, "execute", [
16069
- "vitest",
16070
- "run",
16071
- filter,
16072
- "--reporter=dot",
16073
- ...defaulted ? ["--passWithNoTests"] : [],
16074
- ...passthrough
16075
- ]);
16076
- const resolvedArgs = resolved.args.slice();
16077
- if (pm === "npm") resolvedArgs.unshift("--yes");
16078
- const result = await x6(resolved.command, resolvedArgs, {
16079
- nodeOptions: { cwd, stdio: "inherit", env: { ...process47.env, CI: "1" } }
16173
+ const { createServer } = await loadVite(cwd);
16174
+ vite = await createServer({
16175
+ mode: "test",
16176
+ plugins: [stubPagesPlugin()],
16177
+ optimizeDeps: { noDiscovery: true },
16178
+ // This config differs from `vela dev`'s, so sharing node_modules/.vite
16179
+ // would make Vite re-optimize dependencies under a running dev server,
16180
+ // which then loads two copies of Svelte and fails reading `page`.
16181
+ cacheDir: "node_modules/.vite-test"
16080
16182
  });
16081
- process47.exitCode = result.exitCode ?? 1;
16183
+ const port = await findFreePort();
16184
+ await vite.listen(port);
16082
16185
  } catch (e) {
16083
- console.error(`${pc39.redBright("\u2717")} ${e.message}`);
16084
- process47.exitCode = 1;
16085
- } finally {
16086
- await cleanup();
16087
- process47.exit(process47.exitCode ?? 0);
16186
+ await fail(`Failed to start Vite: ${e.message}`);
16088
16187
  }
16089
- });
16188
+ const appUrl = `http://localhost:${vite.config.server.port}`;
16189
+ env2.VITE_TEST_URL = appUrl;
16190
+ process47.env.VITE_TEST_URL = appUrl;
16191
+ log58(`Started Vite: ${appUrl}`);
16192
+ log58(`Started PocketBase: ${pocketbaseUrl}`);
16193
+ return {
16194
+ pocketbaseUrl,
16195
+ appUrl,
16196
+ superuser: { email: email2, password: password8 },
16197
+ dataDir: dataDir2,
16198
+ env: env2,
16199
+ stop,
16200
+ stopSync
16201
+ };
16202
+ }
16203
+ function pruneStaleRuns(root) {
16204
+ if (!fs60.existsSync(root)) return;
16205
+ for (const entry of fs60.readdirSync(root, { withFileTypes: true })) {
16206
+ if (!entry.isDirectory()) continue;
16207
+ const pid = Number(entry.name);
16208
+ if (!Number.isInteger(pid) || pid === process47.pid) continue;
16209
+ if (isAlive(pid)) continue;
16210
+ fs60.rmSync(path65.join(root, entry.name), { recursive: true, force: true });
16211
+ }
16212
+ }
16213
+ function isAlive(pid) {
16214
+ try {
16215
+ process47.kill(pid, 0);
16216
+ return true;
16217
+ } catch (e) {
16218
+ return e.code === "EPERM";
16219
+ }
16220
+ }
16090
16221
  function describeLoadFailure(e) {
16091
16222
  if (e instanceof DataLoadError) {
16092
16223
  const hint = e.kind === "fixtures" ? "Run `vela fixtures regen` to regenerate fixtures from the current schema." : `Check ${e.file} against the current schema.`;
@@ -16112,9 +16243,83 @@ function stubPagesPlugin() {
16112
16243
  };
16113
16244
  }
16114
16245
 
16246
+ // src/commands/test.ts
16247
+ var testServer = new Command109("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
16248
+ const cwd = process48.cwd();
16249
+ warnIfKit2(cwd, (m) => console.warn(pc39.yellow(`\u25B2 ${m}`)));
16250
+ const extraArgs = (cmd.parent?.args ?? []).slice(1);
16251
+ const filtered = extraArgs.some((arg) => !arg.startsWith("-"));
16252
+ try {
16253
+ const pm = (await detect10({ cwd }))?.name ?? "npm";
16254
+ const resolved = resolveCommand8(pm, "execute", [
16255
+ "vitest",
16256
+ "run",
16257
+ "--project",
16258
+ "server",
16259
+ "--reporter=dot",
16260
+ ...filtered ? [] : ["--passWithNoTests"],
16261
+ ...extraArgs
16262
+ ]);
16263
+ const resolvedArgs = resolved.args.slice();
16264
+ if (pm === "npm") resolvedArgs.unshift("--yes");
16265
+ const result = await x7(resolved.command, resolvedArgs, {
16266
+ nodeOptions: { cwd, stdio: "inherit", env: { ...process48.env, CI: "1" } }
16267
+ });
16268
+ process48.exitCode = result.exitCode ?? 1;
16269
+ } catch (e) {
16270
+ console.error(`${pc39.redBright("\u2717")} ${e.message}`);
16271
+ process48.exitCode = 1;
16272
+ }
16273
+ });
16274
+ var testHarness = new Command109("test:harness").description("start the servers for server tests and wait (used by vela/testing)").configureHelp(helpConfig).action(async () => {
16275
+ const cwd = process48.cwd();
16276
+ if (!process48.send) {
16277
+ console.error(
16278
+ `${pc39.redBright("\u2717")} vela test:harness is started by vitest through \`vela/testing\`. Run \`vela test:server\` instead.`
16279
+ );
16280
+ process48.exit(1);
16281
+ }
16282
+ let harness;
16283
+ let exiting = false;
16284
+ const exit = async (code2) => {
16285
+ if (exiting) return;
16286
+ exiting = true;
16287
+ await harness?.stop();
16288
+ process48.exit(code2);
16289
+ };
16290
+ process48.on("exit", () => harness?.stopSync());
16291
+ for (const [signal, code2] of [
16292
+ ["SIGINT", 130],
16293
+ ["SIGTERM", 143],
16294
+ ["SIGHUP", 129]
16295
+ ]) {
16296
+ process48.on(signal, () => void exit(code2));
16297
+ }
16298
+ process48.on("disconnect", () => void exit(0));
16299
+ process48.on("message", (message) => {
16300
+ if (message === "stop") void exit(0);
16301
+ });
16302
+ try {
16303
+ harness = await startTestHarness(cwd, {
16304
+ log: (message) => console.log(`${pc39.greenBright("\u2713")} ${message}`)
16305
+ });
16306
+ } catch (e) {
16307
+ const message = e instanceof HarnessError ? e.message : `Failed to start the test servers: ${e.message}`;
16308
+ console.error(`${pc39.redBright("\u2717")} ${message}`);
16309
+ process48.send({ type: "error", message });
16310
+ process48.exit(1);
16311
+ }
16312
+ const { pocketbaseUrl, appUrl, superuser, dataDir: dataDir2, env: env2 } = harness;
16313
+ process48.send({
16314
+ type: "ready",
16315
+ servers: { pocketbaseUrl, appUrl, superuser, dataDir: dataDir2 },
16316
+ env: env2
16317
+ });
16318
+ });
16319
+
16115
16320
  // src/commands/routes.ts
16116
- import fs60 from "node:fs";
16117
- import path65 from "node:path";
16321
+ import fs61 from "node:fs";
16322
+ import path66 from "node:path";
16118
16323
  import { Command as Command110 } from "commander";
16119
16324
  var HTTP_METHODS = /* @__PURE__ */ new Set([
16120
16325
  "GET",
@@ -16128,30 +16333,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
16128
16333
  ]);
16129
16334
  var routes = new Command110("routes").description("list routes").configureHelp(helpConfig).action(async () => {
16130
16335
  const { workspaceRootDir, routesDir } = await getWorkspace();
16131
- const routesRoot = path65.join(workspaceRootDir, routesDir);
16336
+ const routesRoot = path66.join(workspaceRootDir, routesDir);
16132
16337
  const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
16133
16338
  found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
16134
16339
  printTable(found);
16135
16340
  });
16136
16341
  function walk(root, dir) {
16137
- const entries = fs60.readdirSync(dir, { withFileTypes: true });
16342
+ const entries = fs61.readdirSync(dir, { withFileTypes: true });
16138
16343
  const routes2 = [];
16139
16344
  const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
16140
16345
  if (hasLeaf) {
16141
- const id = "/" + path65.relative(root, dir).split(path65.sep).filter(Boolean).join("/");
16346
+ const id = "/" + path66.relative(root, dir).split(path66.sep).filter(Boolean).join("/");
16142
16347
  const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
16143
16348
  const methods = /* @__PURE__ */ new Set();
16144
16349
  for (const entry of entries) {
16145
16350
  if (!entry.isFile()) continue;
16146
16351
  if (entry.name.endsWith("+page.svelte")) methods.add("GET");
16147
16352
  if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
16148
- extractMethods(path65.join(dir, entry.name)).forEach((m) => methods.add(m));
16353
+ extractMethods(path66.join(dir, entry.name)).forEach((m) => methods.add(m));
16149
16354
  }
16150
16355
  }
16151
16356
  routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
16152
16357
  }
16153
16358
  for (const entry of entries) {
16154
- if (entry.isDirectory()) routes2.push(...walk(root, path65.join(dir, entry.name)));
16359
+ if (entry.isDirectory()) routes2.push(...walk(root, path66.join(dir, entry.name)));
16155
16360
  }
16156
16361
  return routes2;
16157
16362
  }
@@ -16160,7 +16365,7 @@ function isRouteFile(name) {
16160
16365
  }
16161
16366
  function extractMethods(file) {
16162
16367
  try {
16163
- const content = fs60.readFileSync(file, "utf8");
16368
+ const content = fs61.readFileSync(file, "utf8");
16164
16369
  const methods = [];
16165
16370
  const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
16166
16371
  let match;
@@ -16201,24 +16406,24 @@ function printTable(routes2) {
16201
16406
  }
16202
16407
 
16203
16408
  // src/commands/i18n.ts
16204
- import fs61 from "node:fs";
16205
- import path66 from "node:path";
16206
- import process48 from "node:process";
16409
+ import fs62 from "node:fs";
16410
+ import path67 from "node:path";
16411
+ import process49 from "node:process";
16207
16412
  import { Command as Command111 } from "commander";
16208
- import { x as x7 } from "tinyexec";
16209
- import { detect as detect10 } from "package-manager-detector";
16210
- import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
16413
+ import { x as x8 } from "tinyexec";
16414
+ import { detect as detect11 } from "package-manager-detector";
16415
+ import { resolveCommand as resolveCommand9 } from "package-manager-detector/commands";
16211
16416
  var WUCHALE_CONFIG_NAMES = ["js", "mjs", "ts", "mts"].map((ext) => `wuchale.config.${ext}`);
16212
16417
  async function runWuchale(extraArgs) {
16213
- const cwd = findWorkspaceRoot() ?? process48.cwd();
16214
- if (!WUCHALE_CONFIG_NAMES.some((name) => fs61.existsSync(path66.join(cwd, name)))) {
16418
+ const cwd = findWorkspaceRoot() ?? process49.cwd();
16419
+ if (!WUCHALE_CONFIG_NAMES.some((name) => fs62.existsSync(path67.join(cwd, name)))) {
16215
16420
  throw new Error("No wuchale config found. Run `vela enable i18n` to set up i18n.");
16216
16421
  }
16217
- const pm = (await detect10({ cwd }))?.name ?? "npm";
16218
- const resolved = resolveCommand8(pm, "execute", ["wuchale", ...extraArgs]);
16422
+ const pm = (await detect11({ cwd }))?.name ?? "npm";
16423
+ const resolved = resolveCommand9(pm, "execute", ["wuchale", ...extraArgs]);
16219
16424
  const args = resolved.args.slice();
16220
16425
  if (pm === "npm") args.unshift("--yes");
16221
- await x7(resolved.command, args, {
16426
+ await x8(resolved.command, args, {
16222
16427
  nodeOptions: { cwd, stdio: "inherit" },
16223
16428
  throwOnError: true
16224
16429
  });
@@ -16233,7 +16438,7 @@ var i18n3 = new Command111("i18n").description("i18n utilities").configureHelp(h
16233
16438
  import { Command as Command117 } from "commander";
16234
16439
 
16235
16440
  // src/commands/cms/deploy.ts
16236
- import process49 from "node:process";
16441
+ import process50 from "node:process";
16237
16442
  import { Command as Command112 } from "commander";
16238
16443
  import * as p68 from "@clack/prompts";
16239
16444
  import pc40 from "picocolors";
@@ -16299,7 +16504,7 @@ function resolveProjectId(explicit) {
16299
16504
  }
16300
16505
  return explicit;
16301
16506
  }
16302
- const root = findWorkspaceRoot(process49.cwd());
16507
+ const root = findWorkspaceRoot(process50.cwd());
16303
16508
  const link2 = root ? readProjectConfig(root) : null;
16304
16509
  if (!link2) {
16305
16510
  throw new Error(
@@ -16339,15 +16544,15 @@ import pc42 from "picocolors";
16339
16544
 
16340
16545
  // src/lib/cms-backend.ts
16341
16546
  import { createRequire as createRequire5 } from "node:module";
16342
- import path67 from "node:path";
16343
- import process50 from "node:process";
16547
+ import path68 from "node:path";
16548
+ import process51 from "node:process";
16344
16549
  import { pathToFileURL as pathToFileURL2 } from "node:url";
16345
16550
  import pc41 from "picocolors";
16346
16551
  var DEFAULT_PROJECT = "default";
16347
16552
  async function loadBackendModule(root) {
16348
16553
  let entry;
16349
16554
  try {
16350
- entry = createRequire5(path67.join(root, "package.json")).resolve("@velastack/cms/backend");
16555
+ entry = createRequire5(path68.join(root, "package.json")).resolve("@velastack/cms/backend");
16351
16556
  } catch {
16352
16557
  throw new Error(
16353
16558
  `@velastack/cms is not installed in this project.
@@ -16357,7 +16562,7 @@ Run ${pc41.cyan("vela enable cms")} first.`
16357
16562
  }
16358
16563
  return await import(pathToFileURL2(entry).href);
16359
16564
  }
16360
- async function withCmsBackend(fn, cwd = process50.cwd()) {
16565
+ async function withCmsBackend(fn, cwd = process51.cwd()) {
16361
16566
  const root = findWorkspaceRoot(cwd);
16362
16567
  if (!root) {
16363
16568
  throw new Error("Could not find workspace root (no package.json found)");
@@ -16365,8 +16570,8 @@ async function withCmsBackend(fn, cwd = process50.cwd()) {
16365
16570
  const { createCmsBackend } = await loadBackendModule(root);
16366
16571
  const dataDir2 = localDataDir(root);
16367
16572
  const backend3 = createCmsBackend({
16368
- dbPath: path67.join(dataDir2, "cms.sqlite"),
16369
- uploadDir: path67.join(dataDir2, "uploads")
16573
+ dbPath: path68.join(dataDir2, "cms.sqlite"),
16574
+ uploadDir: path68.join(dataDir2, "uploads")
16370
16575
  });
16371
16576
  try {
16372
16577
  return await fn(backend3);
@@ -16444,7 +16649,7 @@ var cms2 = new Command117("cms").description("manage the CMS").configureHelp(hel
16444
16649
  import { Command as Command121 } from "commander";
16445
16650
 
16446
16651
  // src/commands/workflows/list.ts
16447
- import process51 from "node:process";
16652
+ import process52 from "node:process";
16448
16653
  import { Command as Command118, InvalidArgumentError as InvalidArgumentError5 } from "commander";
16449
16654
  import * as p72 from "@clack/prompts";
16450
16655
  import pc45 from "picocolors";
@@ -16522,7 +16727,7 @@ function formatRun(run, nameWidth) {
16522
16727
  }
16523
16728
  var workflowsList = new Command118("list").description("list recent workflow runs").option("--status <status>", `only runs in this state (${STATUSES.join(", ")})`, parseStatus).option("--name <workflow>", "only runs of this workflow").option("--limit <n>", "how many to show", parseLimit, 50).configureHelp(helpConfig).action(
16524
16729
  (options) => runCommand(async () => {
16525
- await withPocketbase(process51.cwd(), async (pb) => {
16730
+ await withPocketbase(process52.cwd(), async (pb) => {
16526
16731
  const runs = await listRuns(pb, {
16527
16732
  status: options.status,
16528
16733
  workflowName: options.name,
@@ -16543,7 +16748,7 @@ Start one from server code with ${pc45.cyan("<workflow>.run(input)")}, or with $
16543
16748
  );
16544
16749
 
16545
16750
  // src/commands/workflows/run.ts
16546
- import process52 from "node:process";
16751
+ import process53 from "node:process";
16547
16752
  import { Command as Command119, InvalidArgumentError as InvalidArgumentError6 } from "commander";
16548
16753
  import * as p73 from "@clack/prompts";
16549
16754
  import pc46 from "picocolors";
@@ -16556,7 +16761,7 @@ function parseInput(value) {
16556
16761
  }
16557
16762
  var workflowsRun = new Command119("run").description("start a run of a workflow; the running app picks it up").argument("<name>", "the workflow name, as in its defineWorkflow spec").argument("[input]", "the run input as JSON", parseInput).configureHelp(helpConfig).action(
16558
16763
  (name, input) => runCommand(async () => {
16559
- await withPocketbase(process52.cwd(), async (pb) => {
16764
+ await withPocketbase(process53.cwd(), async (pb) => {
16560
16765
  const run = await createRun(pb, name, input);
16561
16766
  p73.log.success(
16562
16767
  `Queued ${pc46.cyan(name)} as run ${pc46.bold(run.id)}.
@@ -16568,13 +16773,13 @@ It runs once the app is up (${pc46.cyan("vela dev")}); ${pc46.cyan("vela workflo
16568
16773
  );
16569
16774
 
16570
16775
  // src/commands/workflows/cancel.ts
16571
- import process53 from "node:process";
16776
+ import process54 from "node:process";
16572
16777
  import { Command as Command120 } from "commander";
16573
16778
  import * as p74 from "@clack/prompts";
16574
16779
  import pc47 from "picocolors";
16575
16780
  var workflowsCancel = new Command120("cancel").description("cancel a pending or running workflow run").argument("<run-id>", "the run id from `vela workflows list`").configureHelp(helpConfig).action(
16576
16781
  (id) => runCommand(async () => {
16577
- await withPocketbase(process53.cwd(), async (pb) => {
16782
+ await withPocketbase(process54.cwd(), async (pb) => {
16578
16783
  const run = await cancelRun(pb, id);
16579
16784
  p74.log.success(`Canceled run ${pc47.bold(run.id)} of ${pc47.cyan(run.workflowName)}.`);
16580
16785
  });
@@ -16654,30 +16859,30 @@ var PROVIDER_GATED_COMMANDS = /* @__PURE__ */ new Set([
16654
16859
  "destroy shop"
16655
16860
  ]);
16656
16861
  var BACKEND_OPTIONAL_COMMANDS = /* @__PURE__ */ new Set(["dev", "build", "preview", "deploy"]);
16657
- var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
16862
+ var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server", "test:harness"]);
16658
16863
  var program = new Command122().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
16659
16864
  program.hook("preAction", (_thisCommand, actionCommand) => {
16660
- const envRoot = findWorkspaceRoot() ?? process54.cwd();
16865
+ const envRoot = findWorkspaceRoot() ?? process55.cwd();
16661
16866
  dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
16662
- const path68 = getCommandPath(actionCommand);
16663
- if (NO_BACKEND_COMMMANDS.has(path68)) return;
16664
- if (PROVIDER_GATED_COMMANDS.has(path68)) return;
16665
- const top = path68.split(" ", 1)[0];
16867
+ const path69 = getCommandPath(actionCommand);
16868
+ if (NO_BACKEND_COMMMANDS.has(path69)) return;
16869
+ if (PROVIDER_GATED_COMMANDS.has(path69)) return;
16870
+ const top = path69.split(" ", 1)[0];
16666
16871
  if (NO_BACKEND_COMMMANDS.has(top)) return;
16667
16872
  if (!hasBackend()) {
16668
16873
  if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
16669
- p75.log.error(missingBackendMessage(`vela ${path68}`));
16874
+ p75.log.error(missingBackendMessage(`vela ${path69}`));
16670
16875
  p75.log.message();
16671
16876
  p75.cancel("Operation failed.");
16672
- process54.exit(1);
16877
+ process55.exit(1);
16673
16878
  }
16674
- if (SELF_CREDENTIALED_COMMANDS.has(path68)) return;
16675
- if (path68 === "generate migration" && actionCommand.opts().ai) return;
16879
+ if (SELF_CREDENTIALED_COMMANDS.has(path69)) return;
16880
+ if (path69 === "generate migration" && actionCommand.opts().ai) return;
16676
16881
  if (!hasSuperuserCredentials()) {
16677
16882
  p75.log.error(missingCredentialsMessage());
16678
16883
  p75.log.message();
16679
16884
  p75.cancel("Operation failed.");
16680
- process54.exit(1);
16885
+ process55.exit(1);
16681
16886
  }
16682
16887
  });
16683
16888
  function getCommandPath(cmd) {
@@ -16728,7 +16933,8 @@ for (const command of [
16728
16933
  ]) {
16729
16934
  program.addCommand(command);
16730
16935
  }
16936
+ program.addCommand(testHarness, { hidden: true });
16731
16937
 
16732
16938
  // src/bin.ts
16733
- program.parse(normalizeArgv(process55.argv.slice(2)), { from: "user" });
16939
+ program.parse(normalizeArgv(process56.argv.slice(2)), { from: "user" });
16734
16940
  //# sourceMappingURL=bin.js.map