vela 0.13.5 → 0.14.1

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
@@ -13,7 +13,7 @@ function normalizeArgv(argv) {
13
13
  // src/program.ts
14
14
  import process45 from "node:process";
15
15
  import * as p67 from "@clack/prompts";
16
- import { Command as Command114 } from "commander";
16
+ import { Command as Command117 } from "commander";
17
17
  import nodePath from "node:path";
18
18
  import dotenv2 from "dotenv";
19
19
  import pc42 from "picocolors";
@@ -21,7 +21,7 @@ import pc42 from "picocolors";
21
21
  // package.json
22
22
  var package_default = {
23
23
  name: "vela",
24
- version: "0.13.5",
24
+ version: "0.14.1",
25
25
  type: "module",
26
26
  description: "A CLI for creating and updating SvelteKit projects",
27
27
  license: "MIT",
@@ -57,7 +57,7 @@ var package_default = {
57
57
  dependencies: {
58
58
  "@clack/prompts": "^1.7.0",
59
59
  "@faker-js/faker": "^10.6.0",
60
- "@velastack/patterns": "^0.2.12",
60
+ "@velastack/patterns": "^0.3.1",
61
61
  "@velastack/pocketbase-codegen": "^0.1.0",
62
62
  "annotate-json-schema": "^0.1.0",
63
63
  commander: "^13.1.0",
@@ -70,7 +70,7 @@ var package_default = {
70
70
  "package-manager-detector": "^1.8.0",
71
71
  picocolors: "^1.1.1",
72
72
  pocketbase: "^0.28.0",
73
- "pocketbase-server": "^0.40.5-beta.1",
73
+ "pocketbase-server": "^0.40.5-beta.2",
74
74
  stripe: "^19.3.0",
75
75
  svelte: "^5.56.10",
76
76
  tar: "^7.5.22",
@@ -343,8 +343,8 @@ function dropTemplateAdapters(user, template) {
343
343
  }
344
344
  return copy;
345
345
  }
346
- function readPackageJson(path49) {
347
- return JSON.parse(fs2.readFileSync(path49, "utf8"));
346
+ function readPackageJson(path50) {
347
+ return JSON.parse(fs2.readFileSync(path50, "utf8"));
348
348
  }
349
349
  var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
350
350
  var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
@@ -362,12 +362,12 @@ function fillTemplatePlaceholders(raw, values) {
362
362
  function escapeSingleQuoted(value) {
363
363
  return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
364
364
  }
365
- function readTemplatePackageJson(path49, values) {
366
- const raw = fillTemplatePlaceholders(fs2.readFileSync(path49, "utf8"), values);
365
+ function readTemplatePackageJson(path50, values) {
366
+ const raw = fillTemplatePlaceholders(fs2.readFileSync(path50, "utf8"), values);
367
367
  return JSON.parse(raw);
368
368
  }
369
- function writePackageJson(path49, pkg) {
370
- fs2.writeFileSync(path49, JSON.stringify(pkg, null, " ") + "\n");
369
+ function writePackageJson(path50, pkg) {
370
+ fs2.writeFileSync(path50, JSON.stringify(pkg, null, " ") + "\n");
371
371
  }
372
372
  function toValidPackageName(name) {
373
373
  return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
@@ -459,8 +459,8 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
459
459
  }
460
460
 
461
461
  // src/commands/bless.ts
462
- import fs15 from "node:fs";
463
- import path13 from "node:path";
462
+ import fs16 from "node:fs";
463
+ import path14 from "node:path";
464
464
  import process7 from "node:process";
465
465
  import * as v3 from "valibot";
466
466
  import { Command as Command2 } from "commander";
@@ -1083,10 +1083,10 @@ async function startPocketbaseServe(opts) {
1083
1083
  }
1084
1084
  throw lastErr instanceof Error ? lastErr : new Error("Failed to start PocketBase");
1085
1085
  }
1086
- async function authWithRetries(pb, email3, password11, attempts = 3) {
1086
+ async function authWithRetries(pb, email3, password12, attempts = 3) {
1087
1087
  for (let attempt = 1; attempt <= attempts; attempt++) {
1088
1088
  try {
1089
- await pb.collection("_superusers").authWithPassword(email3, password11);
1089
+ await pb.collection("_superusers").authWithPassword(email3, password12);
1090
1090
  return;
1091
1091
  } catch (e) {
1092
1092
  if (attempt === attempts) {
@@ -1118,14 +1118,14 @@ async function withPocketbase(cwd, fn, creds) {
1118
1118
  const migrationsDir = path8.join(cwd, MIGRATIONS_DIR);
1119
1119
  const host = "localhost";
1120
1120
  const email3 = creds?.email ?? process6.env.POCKETBASE_SUPERUSER_EMAIL;
1121
- const password11 = creds?.password ?? process6.env.POCKETBASE_SUPERUSER_PASSWORD;
1121
+ const password12 = creds?.password ?? process6.env.POCKETBASE_SUPERUSER_PASSWORD;
1122
1122
  if (!fs9.existsSync(dir)) {
1123
1123
  throw new Error("PocketBase data directory does not exist");
1124
1124
  }
1125
1125
  const metadata = getPocketbaseMetadata(cwd);
1126
1126
  if (metadata?.pocketbaseUrl) {
1127
1127
  const pb = new PocketBase(metadata.pocketbaseUrl);
1128
- await authWithRetries(pb, email3, password11);
1128
+ await authWithRetries(pb, email3, password12);
1129
1129
  await fn(pb);
1130
1130
  return;
1131
1131
  }
@@ -1137,13 +1137,13 @@ async function withPocketbase(cwd, fn, creds) {
1137
1137
  });
1138
1138
  try {
1139
1139
  const pb = new PocketBase(url);
1140
- await authWithRetries(pb, email3, password11);
1140
+ await authWithRetries(pb, email3, password12);
1141
1141
  await fn(pb);
1142
1142
  } finally {
1143
1143
  proc.kill();
1144
1144
  }
1145
1145
  }
1146
- async function createSuperuser(cwd, email3, password11) {
1146
+ async function createSuperuser(cwd, email3, password12) {
1147
1147
  const dir = path8.join(cwd, DATA_DIR);
1148
1148
  const migrationsDir = path8.join(cwd, MIGRATIONS_DIR);
1149
1149
  fs9.mkdirSync(dir, { recursive: true });
@@ -1159,7 +1159,7 @@ async function createSuperuser(cwd, email3, password11) {
1159
1159
  "superuser",
1160
1160
  "create",
1161
1161
  email3,
1162
- password11
1162
+ password12
1163
1163
  ],
1164
1164
  "pipe"
1165
1165
  );
@@ -1169,7 +1169,7 @@ async function launchPocketbase(cwd, {
1169
1169
  migrationsDir,
1170
1170
  hooksDir,
1171
1171
  email: email3,
1172
- password: password11
1172
+ password: password12
1173
1173
  }) {
1174
1174
  const host = "localhost";
1175
1175
  fs9.mkdirSync(dir, { recursive: true });
@@ -1185,7 +1185,7 @@ async function launchPocketbase(cwd, {
1185
1185
  "superuser",
1186
1186
  "create",
1187
1187
  email3,
1188
- password11
1188
+ password12
1189
1189
  ],
1190
1190
  "pipe"
1191
1191
  );
@@ -1213,8 +1213,8 @@ function pocketbaseVersion() {
1213
1213
  }
1214
1214
  async function ensureSuperuser(cwd) {
1215
1215
  const email3 = process6.env.POCKETBASE_SUPERUSER_EMAIL;
1216
- const password11 = process6.env.POCKETBASE_SUPERUSER_PASSWORD;
1217
- if (!email3 || !password11) return;
1216
+ const password12 = process6.env.POCKETBASE_SUPERUSER_PASSWORD;
1217
+ if (!email3 || !password12) return;
1218
1218
  const dir = path8.join(cwd, DATA_DIR);
1219
1219
  if (!fs9.existsSync(dir)) return;
1220
1220
  const { getBinaryPath } = await import("pocketbase-server");
@@ -1228,7 +1228,7 @@ async function ensureSuperuser(cwd) {
1228
1228
  "superuser",
1229
1229
  "upsert",
1230
1230
  email3,
1231
- password11
1231
+ password12
1232
1232
  ],
1233
1233
  { nodeOptions: { cwd, stdio: "ignore" } }
1234
1234
  );
@@ -1321,13 +1321,49 @@ function ensureShadcnImport(appCssPath) {
1321
1321
  return true;
1322
1322
  }
1323
1323
 
1324
+ // src/lib/site.ts
1325
+ import fs12 from "node:fs";
1326
+ import path10 from "node:path";
1327
+ var SITE_FILE = path10.join("src", "lib", "site.ts");
1328
+ async function readSite(root) {
1329
+ const file = path10.join(root, SITE_FILE);
1330
+ if (!fs12.existsSync(file)) return null;
1331
+ const { Project: Project3, Node } = await import("ts-morph");
1332
+ const project = new Project3({ useInMemoryFileSystem: true });
1333
+ const source = project.createSourceFile("site.ts", fs12.readFileSync(file, "utf8"));
1334
+ let object6 = source.getVariableDeclaration("site")?.getInitializer();
1335
+ while (object6 && (Node.isAsExpression(object6) || Node.isSatisfiesExpression(object6))) {
1336
+ object6 = object6.getExpression();
1337
+ }
1338
+ if (!object6 || !Node.isObjectLiteralExpression(object6)) return null;
1339
+ const info = {};
1340
+ for (const key of ["name", "url"]) {
1341
+ const property = object6.getProperty(key);
1342
+ if (!property || !Node.isPropertyAssignment(property)) continue;
1343
+ const value = property.getInitializer();
1344
+ if (Node.isStringLiteral(value) || Node.isNoSubstitutionTemplateLiteral(value)) {
1345
+ const text19 = value.getLiteralValue().trim();
1346
+ if (text19) info[key] = text19;
1347
+ }
1348
+ }
1349
+ return info;
1350
+ }
1351
+ function isLocalUrl(url) {
1352
+ try {
1353
+ const { hostname } = new URL(url);
1354
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
1355
+ } catch {
1356
+ return false;
1357
+ }
1358
+ }
1359
+
1324
1360
  // src/lib/config-merge.ts
1325
- import fs13 from "node:fs";
1326
- import path11 from "node:path";
1361
+ import fs14 from "node:fs";
1362
+ import path12 from "node:path";
1327
1363
 
1328
1364
  // src/lib/config-target.ts
1329
- import fs12 from "node:fs";
1330
- import path10 from "node:path";
1365
+ import fs13 from "node:fs";
1366
+ import path11 from "node:path";
1331
1367
  import {
1332
1368
  Project,
1333
1369
  QuoteKind,
@@ -1347,8 +1383,8 @@ var SVELTE_CONFIG_CANDIDATES = [
1347
1383
  ];
1348
1384
  function probeFirstExisting(root, candidates) {
1349
1385
  for (const rel of candidates) {
1350
- const abs = path10.join(root, rel);
1351
- if (fs12.existsSync(abs)) return abs;
1386
+ const abs = path11.join(root, rel);
1387
+ if (fs13.existsSync(abs)) return abs;
1352
1388
  }
1353
1389
  return null;
1354
1390
  }
@@ -1424,7 +1460,7 @@ function mergeSvelteConfig(projectRoot) {
1424
1460
  };
1425
1461
  }
1426
1462
  function mergeRunesIntoViteArg(vite, arg) {
1427
- const file = path11.basename(vite.filePath);
1463
+ const file = path12.basename(vite.filePath);
1428
1464
  const compilerOptions = getOrCreateObjectLiteralProperty(arg, "compilerOptions", "{}");
1429
1465
  if (!compilerOptions) {
1430
1466
  return {
@@ -1443,8 +1479,8 @@ function mergeRunesIntoViteArg(vite, arg) {
1443
1479
  return { applied: true, reason: "added runes compilerOption", file };
1444
1480
  }
1445
1481
  function mergeRunesIntoSvelteConfig(filePath) {
1446
- const file = path11.basename(filePath);
1447
- const original = fs13.readFileSync(filePath, "utf8");
1482
+ const file = path12.basename(filePath);
1483
+ const original = fs14.readFileSync(filePath, "utf8");
1448
1484
  if (/runes\s*:/m.test(original)) {
1449
1485
  return { applied: false, reason: "runes already configured", file };
1450
1486
  }
@@ -1467,11 +1503,11 @@ function mergeRunesIntoSvelteConfig(filePath) {
1467
1503
  }
1468
1504
  const insertAt = anchor.index + anchor[0].length;
1469
1505
  const updated = original.slice(0, insertAt) + RUNES_SNIPPET + original.slice(insertAt);
1470
- fs13.writeFileSync(filePath, updated);
1506
+ fs14.writeFileSync(filePath, updated);
1471
1507
  return { applied: true, reason: "added runes compilerOption", file };
1472
1508
  }
1473
1509
  function mergeViteConfig(filePath) {
1474
- if (!fs13.existsSync(filePath)) {
1510
+ if (!fs14.existsSync(filePath)) {
1475
1511
  return {
1476
1512
  applied: false,
1477
1513
  reason: "vite.config.ts not found",
@@ -1479,7 +1515,7 @@ function mergeViteConfig(filePath) {
1479
1515
  // then add tailwindcss() to the plugins array`
1480
1516
  };
1481
1517
  }
1482
- const original = fs13.readFileSync(filePath, "utf8");
1518
+ const original = fs14.readFileSync(filePath, "utf8");
1483
1519
  if (original.includes("@tailwindcss/vite")) {
1484
1520
  return { applied: false, reason: "tailwindcss plugin already present" };
1485
1521
  }
@@ -1498,14 +1534,14 @@ function mergeViteConfig(filePath) {
1498
1534
  const trailing = withImport.slice(insertAt);
1499
1535
  const prefix = /^\s*\]/.test(trailing) ? "tailwindcss()" : "tailwindcss(), ";
1500
1536
  const updated = withImport.slice(0, insertAt) + prefix + withImport.slice(insertAt);
1501
- fs13.writeFileSync(filePath, updated);
1537
+ fs14.writeFileSync(filePath, updated);
1502
1538
  return { applied: true, reason: "added @tailwindcss/vite plugin" };
1503
1539
  }
1504
1540
  function mergeTsconfig(filePath) {
1505
- if (!fs13.existsSync(filePath)) {
1541
+ if (!fs14.existsSync(filePath)) {
1506
1542
  return { applied: false, reason: "tsconfig.json not found" };
1507
1543
  }
1508
- const original = fs13.readFileSync(filePath, "utf8");
1544
+ const original = fs14.readFileSync(filePath, "utf8");
1509
1545
  if (/rewriteRelativeImportExtensions/.test(original)) {
1510
1546
  return { applied: false, reason: "rewriteRelativeImportExtensions already set" };
1511
1547
  }
@@ -1521,7 +1557,7 @@ function mergeTsconfig(filePath) {
1521
1557
  const indent = detectIndent(original, insertAt);
1522
1558
  const updated = original.slice(0, insertAt) + `
1523
1559
  ${indent}"rewriteRelativeImportExtensions": true,` + original.slice(insertAt);
1524
- fs13.writeFileSync(filePath, updated);
1560
+ fs14.writeFileSync(filePath, updated);
1525
1561
  return { applied: true, reason: "added rewriteRelativeImportExtensions" };
1526
1562
  }
1527
1563
  var GITIGNORE_ENTRIES = [
@@ -1540,7 +1576,7 @@ var GITIGNORE_ENTRIES = [
1540
1576
  "/backups"
1541
1577
  ];
1542
1578
  function mergeGitignore(filePath) {
1543
- const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf8") : "";
1579
+ const existing = fs14.existsSync(filePath) ? fs14.readFileSync(filePath, "utf8") : "";
1544
1580
  const lines = existing.split("\n").map((l) => l.trim());
1545
1581
  const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.includes(entry));
1546
1582
  if (missing.length === 0) {
@@ -1549,7 +1585,7 @@ function mergeGitignore(filePath) {
1549
1585
  const needsNewline = existing.length > 0 && !existing.endsWith("\n");
1550
1586
  const appended = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
1551
1587
  `;
1552
- fs13.writeFileSync(filePath, appended);
1588
+ fs14.writeFileSync(filePath, appended);
1553
1589
  return { applied: true, reason: `added ${missing.length} gitignore entries` };
1554
1590
  }
1555
1591
  function addImport(source, importLine) {
@@ -1574,14 +1610,14 @@ function detectIndent(source, atOffset) {
1574
1610
  }
1575
1611
 
1576
1612
  // src/lib/scaffold-detect.ts
1577
- import fs14 from "node:fs";
1578
- import path12 from "node:path";
1613
+ import fs15 from "node:fs";
1614
+ import path13 from "node:path";
1579
1615
  var VANILLA_MARKER = "Welcome to SvelteKit";
1580
- var PAGE_REL = path12.join("src", "routes", "+page.svelte");
1616
+ var PAGE_REL = path13.join("src", "routes", "+page.svelte");
1581
1617
  function isVanillaRoutes(cwd) {
1582
- const pagePath = path12.join(cwd, PAGE_REL);
1583
- if (!fs14.existsSync(pagePath)) return false;
1584
- return fs14.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
1618
+ const pagePath = path13.join(cwd, PAGE_REL);
1619
+ if (!fs15.existsSync(pagePath)) return false;
1620
+ return fs15.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
1585
1621
  }
1586
1622
 
1587
1623
  // src/lib/result-report.ts
@@ -1676,7 +1712,7 @@ async function blessProject(cwdArg, options) {
1676
1712
  const projectPath = cwdArg ? resolveProjectPath(cwdArg) : (await getWorkspace()).workspaceRootDir;
1677
1713
  assertNotAlreadyBlessed(projectPath);
1678
1714
  const templateDir = findProjectTemplate(options.template ?? DEFAULT_TEMPLATE).dir;
1679
- const { email: email3, password: password11 } = await p4.group(
1715
+ const { email: email3, password: password12 } = await p4.group(
1680
1716
  {
1681
1717
  email: () => {
1682
1718
  if (options.email) return Promise.resolve(options.email);
@@ -1703,6 +1739,7 @@ async function blessProject(cwdArg, options) {
1703
1739
  );
1704
1740
  mergeDependencies(projectPath, templateDir);
1705
1741
  copyVelaOnlyFiles(templateDir, projectPath);
1742
+ writeSiteFile(templateDir, projectPath);
1706
1743
  ensureShadcnCss(projectPath);
1707
1744
  hintComponentsJson(projectPath);
1708
1745
  mergeConfigFiles(projectPath);
@@ -1719,12 +1756,12 @@ async function blessProject(cwdArg, options) {
1719
1756
  }
1720
1757
  }
1721
1758
  p4.log.step("Initializing PocketBase...");
1722
- await createSuperuser(projectPath, email3, password11);
1759
+ await createSuperuser(projectPath, email3, password12);
1723
1760
  writeEnvFile(
1724
1761
  projectPath,
1725
1762
  {
1726
1763
  POCKETBASE_SUPERUSER_EMAIL: email3,
1727
- POCKETBASE_SUPERUSER_PASSWORD: password11
1764
+ POCKETBASE_SUPERUSER_PASSWORD: password12
1728
1765
  },
1729
1766
  ["PocketBase superuser credentials \u2014 used by `vela` commands"]
1730
1767
  );
@@ -1732,7 +1769,7 @@ async function blessProject(cwdArg, options) {
1732
1769
  printNextSteps(projectPath, packageManager2);
1733
1770
  }
1734
1771
  function ensureShadcnCss(projectPath) {
1735
- if (ensureShadcnImport(path13.join(projectPath, "src", "app.css"))) {
1772
+ if (ensureShadcnImport(path14.join(projectPath, "src", "app.css"))) {
1736
1773
  p4.log.info(
1737
1774
  "src/app.css: added the shadcn-svelte/tailwind.css import its registry components rely on."
1738
1775
  );
@@ -1744,22 +1781,22 @@ function hintComponentsJson(projectPath) {
1744
1781
  for (const hint of componentsJsonHints(config)) p4.log.warn(hint);
1745
1782
  }
1746
1783
  function resolveProjectPath(cwdArg) {
1747
- const projectPath = path13.resolve(cwdArg);
1748
- if (!fs15.existsSync(projectPath)) {
1784
+ const projectPath = path14.resolve(cwdArg);
1785
+ if (!fs16.existsSync(projectPath)) {
1749
1786
  throw new Error(`Path does not exist: ${projectPath}`);
1750
1787
  }
1751
- if (!fs15.existsSync(path13.join(projectPath, "package.json"))) {
1788
+ if (!fs16.existsSync(path14.join(projectPath, "package.json"))) {
1752
1789
  throw new Error(`No package.json found at ${projectPath}`);
1753
1790
  }
1754
- if (!fs15.existsSync(path13.join(projectPath, "src", "routes"))) {
1791
+ if (!fs16.existsSync(path14.join(projectPath, "src", "routes"))) {
1755
1792
  throw new Error(`No src/routes directory found at ${projectPath}`);
1756
1793
  }
1757
1794
  return projectPath;
1758
1795
  }
1759
1796
  function assertNotAlreadyBlessed(projectPath) {
1760
- const hooksPath = path13.join(projectPath, "src", "hooks.server.ts");
1761
- if (!fs15.existsSync(hooksPath)) return;
1762
- const content = fs15.readFileSync(hooksPath, "utf8");
1797
+ const hooksPath = path14.join(projectPath, "src", "hooks.server.ts");
1798
+ if (!fs16.existsSync(hooksPath)) return;
1799
+ const content = fs16.readFileSync(hooksPath, "utf8");
1763
1800
  if (content.includes("@velastack/pocketbase")) {
1764
1801
  throw new Error(
1765
1802
  "This project already looks blessed (src/hooks.server.ts imports @velastack/pocketbase). Run `vela sync` instead."
@@ -1767,8 +1804,8 @@ function assertNotAlreadyBlessed(projectPath) {
1767
1804
  }
1768
1805
  }
1769
1806
  function mergeDependencies(projectPath, templateDir) {
1770
- const userPkgPath = path13.join(projectPath, "package.json");
1771
- const templatePkgPath = path13.join(templateDir, "package.template.json");
1807
+ const userPkgPath = path14.join(projectPath, "package.json");
1808
+ const templatePkgPath = path14.join(templateDir, "package.template.json");
1772
1809
  const userPkg = readPackageJson(userPkgPath);
1773
1810
  const appName = typeof userPkg.name === "string" ? userPkg.name : "sveltekit";
1774
1811
  const templatePkg = readTemplatePackageJson(templatePkgPath, {
@@ -1803,24 +1840,46 @@ ${lines.join("\n")}`);
1803
1840
  function copyVelaOnlyFiles(templateDir, projectPath) {
1804
1841
  const kept = [];
1805
1842
  for (const file of VELA_ONLY_FILES) {
1806
- const src = path13.join(templateDir, templateName(file.path));
1807
- const dest = path13.join(projectPath, file.path);
1808
- if (!fs15.existsSync(src)) continue;
1809
- if (fs15.existsSync(dest)) {
1843
+ const src = path14.join(templateDir, templateName(file.path));
1844
+ const dest = path14.join(projectPath, file.path);
1845
+ if (!fs16.existsSync(src)) continue;
1846
+ if (fs16.existsSync(dest)) {
1810
1847
  kept.push(file);
1811
1848
  continue;
1812
1849
  }
1813
- fs15.mkdirSync(path13.dirname(dest), { recursive: true });
1814
- fs15.copyFileSync(src, dest);
1850
+ fs16.mkdirSync(path14.dirname(dest), { recursive: true });
1851
+ fs16.copyFileSync(src, dest);
1815
1852
  }
1816
1853
  reportKeptFiles(kept);
1817
1854
  for (const rel of VELA_ONLY_DIRS) {
1818
- const src = path13.join(templateDir, rel);
1819
- const dest = path13.join(projectPath, rel);
1820
- if (!fs15.existsSync(src)) continue;
1855
+ const src = path14.join(templateDir, rel);
1856
+ const dest = path14.join(projectPath, rel);
1857
+ if (!fs16.existsSync(src)) continue;
1821
1858
  copyDirShallow(src, dest);
1822
1859
  }
1823
1860
  }
1861
+ function writeSiteFile(templateDir, projectPath) {
1862
+ const source = path14.join(templateDir, SITE_FILE.replace(/\.ts$/, ".template.ts"));
1863
+ const dest = path14.join(projectPath, SITE_FILE);
1864
+ if (!fs16.existsSync(source)) return;
1865
+ if (fs16.existsSync(dest)) {
1866
+ p4.log.info(
1867
+ `Kept your ${pc3.bold(SITE_FILE)}. Vela's layouts read ${pc3.cyan("name")} and ${pc3.cyan("url")} from its ${pc3.cyan("site")} export.`
1868
+ );
1869
+ return;
1870
+ }
1871
+ const userPkg = readPackageJson(path14.join(projectPath, "package.json"));
1872
+ const appName = typeof userPkg.name === "string" && userPkg.name ? userPkg.name : "SvelteKit";
1873
+ fs16.mkdirSync(path14.dirname(dest), { recursive: true });
1874
+ fs16.writeFileSync(
1875
+ dest,
1876
+ fillTemplatePlaceholders(fs16.readFileSync(source, "utf8"), {
1877
+ appName,
1878
+ cliVersion: package_default.version
1879
+ })
1880
+ );
1881
+ p4.log.info(`Wrote ${pc3.bold(SITE_FILE)}, naming the app ${pc3.cyan(appName)}. Edit it to rename.`);
1882
+ }
1824
1883
  function reportKeptFiles(kept) {
1825
1884
  if (kept.length === 0) return;
1826
1885
  const padding = Math.max(...kept.map((f) => f.path.length));
@@ -1831,15 +1890,15 @@ ${lines.join("\n")}`
1831
1890
  );
1832
1891
  }
1833
1892
  function copyDirShallow(src, dest) {
1834
- fs15.mkdirSync(dest, { recursive: true });
1835
- for (const entry of fs15.readdirSync(src, { withFileTypes: true })) {
1893
+ fs16.mkdirSync(dest, { recursive: true });
1894
+ for (const entry of fs16.readdirSync(src, { withFileTypes: true })) {
1836
1895
  if (entry.name === ".DS_Store") continue;
1837
- const srcChild = path13.join(src, entry.name);
1838
- const destChild = path13.join(dest, entry.name);
1896
+ const srcChild = path14.join(src, entry.name);
1897
+ const destChild = path14.join(dest, entry.name);
1839
1898
  if (entry.isDirectory()) {
1840
1899
  copyDirShallow(srcChild, destChild);
1841
- } else if (entry.isFile() && !fs15.existsSync(destChild)) {
1842
- fs15.copyFileSync(srcChild, destChild);
1900
+ } else if (entry.isFile() && !fs16.existsSync(destChild)) {
1901
+ fs16.copyFileSync(srcChild, destChild);
1843
1902
  }
1844
1903
  }
1845
1904
  }
@@ -1847,9 +1906,9 @@ function mergeConfigFiles(projectPath) {
1847
1906
  const runes = mergeSvelteConfig(projectPath);
1848
1907
  const outcomes = [
1849
1908
  [runes.file ?? "svelte.config", runes],
1850
- ["vite.config.ts", mergeViteConfig(path13.join(projectPath, "vite.config.ts"))],
1851
- ["tsconfig.json", mergeTsconfig(path13.join(projectPath, "tsconfig.json"))],
1852
- [".gitignore", mergeGitignore(path13.join(projectPath, ".gitignore"))]
1909
+ ["vite.config.ts", mergeViteConfig(path14.join(projectPath, "vite.config.ts"))],
1910
+ ["tsconfig.json", mergeTsconfig(path14.join(projectPath, "tsconfig.json"))],
1911
+ [".gitignore", mergeGitignore(path14.join(projectPath, ".gitignore"))]
1853
1912
  ];
1854
1913
  for (const [name, outcome] of outcomes) {
1855
1914
  if (outcome.applied) {
@@ -1866,14 +1925,14 @@ ${pc3.cyan(outcome.snippet)}`
1866
1925
  }
1867
1926
  }
1868
1927
  function mergeAppDts(templateDir, projectPath) {
1869
- const dest = path13.join(projectPath, "src", "app.d.ts");
1870
- const templateFile = path13.join(templateDir, "src", "app.d.ts");
1871
- if (!fs15.existsSync(dest)) {
1872
- if (!fs15.existsSync(templateFile)) return;
1873
- fs15.copyFileSync(templateFile, dest);
1928
+ const dest = path14.join(projectPath, "src", "app.d.ts");
1929
+ const templateFile = path14.join(templateDir, "src", "app.d.ts");
1930
+ if (!fs16.existsSync(dest)) {
1931
+ if (!fs16.existsSync(templateFile)) return;
1932
+ fs16.copyFileSync(templateFile, dest);
1874
1933
  return;
1875
1934
  }
1876
- const current = fs15.readFileSync(dest, "utf8");
1935
+ const current = fs16.readFileSync(dest, "utf8");
1877
1936
  if (current.includes("namespace Superforms")) return;
1878
1937
  const block = ` namespace Superforms {
1879
1938
  type Message = {
@@ -1892,7 +1951,7 @@ ${pc3.cyan(block)}`
1892
1951
  }
1893
1952
  const insertAt = match.index + match[0].length;
1894
1953
  const updated = current.slice(0, insertAt) + block + current.slice(insertAt);
1895
- fs15.writeFileSync(dest, updated);
1954
+ fs16.writeFileSync(dest, updated);
1896
1955
  }
1897
1956
  function maybeReplaceRoutes(projectPath, templateDir, options) {
1898
1957
  if (options.skipRoutes) {
@@ -1903,12 +1962,12 @@ function maybeReplaceRoutes(projectPath, templateDir, options) {
1903
1962
  p4.log.info("Leaving src/routes alone (looks customized).");
1904
1963
  return;
1905
1964
  }
1906
- const target = path13.join(projectPath, "src", "routes");
1907
- fs15.rmSync(target, { recursive: true, force: true });
1908
- const src = path13.join(templateDir, "src", "routes");
1909
- fs15.cpSync(src, target, {
1965
+ const target = path14.join(projectPath, "src", "routes");
1966
+ fs16.rmSync(target, { recursive: true, force: true });
1967
+ const src = path14.join(templateDir, "src", "routes");
1968
+ fs16.cpSync(src, target, {
1910
1969
  recursive: true,
1911
- filter: (s) => path13.basename(s) !== ".DS_Store"
1970
+ filter: (s) => path14.basename(s) !== ".DS_Store"
1912
1971
  });
1913
1972
  p4.log.success("Replaced src/routes with the vela template.");
1914
1973
  }
@@ -1917,7 +1976,7 @@ function summarize(names) {
1917
1976
  return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
1918
1977
  }
1919
1978
  function printNextSteps(projectPath, packageManager2) {
1920
- const relative = path13.relative(process7.cwd(), projectPath);
1979
+ const relative = path14.relative(process7.cwd(), projectPath);
1921
1980
  const pm = packageManager2 ?? getUserAgent() ?? "npm";
1922
1981
  const nextSteps = [];
1923
1982
  if (relative !== "") {
@@ -1941,8 +2000,8 @@ function printNextSteps(projectPath, packageManager2) {
1941
2000
  }
1942
2001
 
1943
2002
  // src/commands/create.ts
1944
- import fs17 from "node:fs";
1945
- import path15 from "node:path";
2003
+ import fs18 from "node:fs";
2004
+ import path16 from "node:path";
1946
2005
  import process11 from "node:process";
1947
2006
  import * as v4 from "valibot";
1948
2007
  import { Command as Command4 } from "commander";
@@ -2041,7 +2100,9 @@ async function collectProviderEnv(provider) {
2041
2100
  values[variable.key] = variable.default ?? "";
2042
2101
  continue;
2043
2102
  }
2044
- const value = await p5.text({
2103
+ const value = variable.secret ? await p5.password({
2104
+ message: variable.placeholder ? `${variable.label} (${variable.placeholder})` : variable.label
2105
+ }) : await p5.text({
2045
2106
  message: variable.label,
2046
2107
  placeholder: variable.placeholder,
2047
2108
  initialValue: variable.default
@@ -2262,16 +2323,16 @@ function toLinked(project, team) {
2262
2323
  }
2263
2324
 
2264
2325
  // src/lib/project-config.ts
2265
- import fs16 from "node:fs";
2266
- import path14 from "node:path";
2326
+ import fs17 from "node:fs";
2327
+ import path15 from "node:path";
2267
2328
  function projectConfigPath(workspaceRootDir) {
2268
- return path14.join(workspaceRootDir, ".vela", "project.json");
2329
+ return path15.join(workspaceRootDir, ".vela", "project.json");
2269
2330
  }
2270
2331
  function readProjectConfig(workspaceRootDir) {
2271
2332
  const file = projectConfigPath(workspaceRootDir);
2272
- if (!fs16.existsSync(file)) return null;
2333
+ if (!fs17.existsSync(file)) return null;
2273
2334
  try {
2274
- const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
2335
+ const parsed = JSON.parse(fs17.readFileSync(file, "utf8"));
2275
2336
  if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
2276
2337
  return null;
2277
2338
  }
@@ -2286,15 +2347,15 @@ function readProjectConfig(workspaceRootDir) {
2286
2347
  }
2287
2348
  function writeProjectConfig(workspaceRootDir, config) {
2288
2349
  const file = projectConfigPath(workspaceRootDir);
2289
- fs16.mkdirSync(path14.dirname(file), { recursive: true });
2350
+ fs17.mkdirSync(path15.dirname(file), { recursive: true });
2290
2351
  let existing = {};
2291
- if (fs16.existsSync(file)) {
2352
+ if (fs17.existsSync(file)) {
2292
2353
  try {
2293
- existing = JSON.parse(fs16.readFileSync(file, "utf8"));
2354
+ existing = JSON.parse(fs17.readFileSync(file, "utf8"));
2294
2355
  } catch {
2295
2356
  }
2296
2357
  }
2297
- fs16.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
2358
+ fs17.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
2298
2359
  }
2299
2360
 
2300
2361
  // src/commands/login.ts
@@ -2310,7 +2371,7 @@ var login = new Command3("login").description("login to velastack.dev").configur
2310
2371
  }, "Failed to login.")
2311
2372
  );
2312
2373
  async function loginInteractively() {
2313
- const { email: email3, password: password11 } = await p7.group(
2374
+ const { email: email3, password: password12 } = await p7.group(
2314
2375
  {
2315
2376
  email: () => p7.text({ message: "Email" }),
2316
2377
  password: () => p7.password({ message: "Password" })
@@ -2329,7 +2390,7 @@ async function loginInteractively() {
2329
2390
  "Content-Type": "application/x-www-form-urlencoded",
2330
2391
  Origin: API_URL
2331
2392
  },
2332
- body: new URLSearchParams({ type: "password", email: email3, password: password11 }).toString()
2393
+ body: new URLSearchParams({ type: "password", email: email3, password: password12 }).toString()
2333
2394
  });
2334
2395
  if (!loginRes.headers.get("Set-Cookie")) {
2335
2396
  throw new Error(
@@ -2420,7 +2481,7 @@ function checkFlagsForTemplate(template, options) {
2420
2481
  throw new Error("--team only applies together with --link new.");
2421
2482
  }
2422
2483
  }
2423
- var create = new Command4("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold (built-in or from the registry)", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").option(
2484
+ var create = new Command4("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold (built-in or from the registry)", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name, written to src/lib/site.ts").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").option(
2424
2485
  "--link <new|none|project-id>",
2425
2486
  "link to a velastack.dev project: create one, skip, or use an existing project id (default: create when logged in at a terminal)"
2426
2487
  ).option("--team <id>", "velastack.dev team for `--link new` (default: your personal team)").option(
@@ -2435,7 +2496,7 @@ var create = new Command4("create").description("scaffold a new velastack projec
2435
2496
  options,
2436
2497
  listing
2437
2498
  );
2438
- const relative = path15.relative(process11.cwd(), directory);
2499
+ const relative = path16.relative(process11.cwd(), directory);
2439
2500
  const pm = packageManager2 ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
2440
2501
  const nextSteps = [];
2441
2502
  if (relative !== "") {
@@ -2460,6 +2521,7 @@ var create = new Command4("create").description("scaffold a new velastack projec
2460
2521
  nextSteps.push(...template.nextSteps);
2461
2522
  } else if (template.backend) {
2462
2523
  nextSteps.push("Run `vela generate scaffold <model>` to generate your first CRUD pages.");
2524
+ nextSteps.push("Set your deployed URL in `src/lib/site.ts` before deploying.");
2463
2525
  } else {
2464
2526
  nextSteps.push(
2465
2527
  "Set your deployed URL in `src/lib/site.ts` before building for production."
@@ -2483,7 +2545,7 @@ async function createProject2(cwdArg, options, listing) {
2483
2545
  checkFlagsForTemplate(template, options);
2484
2546
  let directory;
2485
2547
  if (cwdArg) {
2486
- directory = path15.resolve(cwdArg);
2548
+ directory = path16.resolve(cwdArg);
2487
2549
  } else {
2488
2550
  const answer = await p8.text({
2489
2551
  message: "Where would you like your project to be created?",
@@ -2491,22 +2553,22 @@ async function createProject2(cwdArg, options, listing) {
2491
2553
  defaultValue: "./"
2492
2554
  });
2493
2555
  if (p8.isCancel(answer)) onCancel2();
2494
- directory = path15.resolve(answer);
2556
+ directory = path16.resolve(answer);
2495
2557
  }
2496
- if (fs17.existsSync(directory) && fs17.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
2558
+ if (fs18.existsSync(directory) && fs18.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
2497
2559
  const force = await p8.confirm({
2498
2560
  message: "Directory not empty. Continue?",
2499
2561
  initialValue: false
2500
2562
  });
2501
2563
  if (p8.isCancel(force) || !force) onCancel2();
2502
2564
  }
2503
- const dirName = path15.basename(directory);
2565
+ const dirName = path16.basename(directory);
2504
2566
  const { name } = await p8.group(
2505
2567
  {
2506
2568
  name: () => {
2507
2569
  if (options.name) return Promise.resolve(options.name);
2508
2570
  return p8.text({
2509
- message: "App name (used for emails, etc)",
2571
+ message: "App name (written to src/lib/site.ts)",
2510
2572
  initialValue: dirName || "SvelteKit",
2511
2573
  validate: (value) => value?.trim() ? void 0 : "App name is required"
2512
2574
  });
@@ -2529,7 +2591,7 @@ async function createProject2(cwdArg, options, listing) {
2529
2591
  } finally {
2530
2592
  resolved.cleanup();
2531
2593
  }
2532
- if (!fs17.existsSync(path15.join(projectPath, "package.json"))) {
2594
+ if (!fs18.existsSync(path16.join(projectPath, "package.json"))) {
2533
2595
  throw new Error(`Template ${template.name} is missing package.template.json`);
2534
2596
  }
2535
2597
  if (link2.linked) {
@@ -2548,9 +2610,9 @@ async function createProject2(cwdArg, options, listing) {
2548
2610
  }
2549
2611
  }
2550
2612
  if (credentials) {
2551
- const { email: email3, password: password11 } = credentials;
2613
+ const { email: email3, password: password12 } = credentials;
2552
2614
  p8.log.step("Initializing PocketBase...");
2553
- await createSuperuser(projectPath, email3, password11);
2615
+ await createSuperuser(projectPath, email3, password12);
2554
2616
  await withPocketbase(
2555
2617
  projectPath,
2556
2618
  async (pb) => {
@@ -2558,13 +2620,13 @@ async function createProject2(cwdArg, options, listing) {
2558
2620
  meta: { appName: name, appURL: "http://localhost:5173" }
2559
2621
  });
2560
2622
  },
2561
- { email: email3, password: password11 }
2623
+ { email: email3, password: password12 }
2562
2624
  );
2563
2625
  writeEnvFile(
2564
2626
  projectPath,
2565
2627
  {
2566
2628
  POCKETBASE_SUPERUSER_EMAIL: email3,
2567
- POCKETBASE_SUPERUSER_PASSWORD: password11
2629
+ POCKETBASE_SUPERUSER_PASSWORD: password12
2568
2630
  },
2569
2631
  ["PocketBase superuser credentials \u2014 used by `vela` commands"]
2570
2632
  );
@@ -2686,11 +2748,11 @@ import { Command as Command5 } from "commander";
2686
2748
  import * as p14 from "@clack/prompts";
2687
2749
 
2688
2750
  // src/lib/pattern-runner.ts
2689
- import path16 from "node:path";
2751
+ import path17 from "node:path";
2690
2752
  import * as p9 from "@clack/prompts";
2691
2753
  import { bySlug as bySlug2 } from "@velastack/patterns";
2692
2754
  function toRelative(root, filePath) {
2693
- return path16.isAbsolute(filePath) ? path16.relative(root, filePath) : filePath;
2755
+ return path17.isAbsolute(filePath) ? path17.relative(root, filePath) : filePath;
2694
2756
  }
2695
2757
  var isSuccess = (f) => (f.status ?? "success") === "success";
2696
2758
  async function runPattern(slug2, argv, input, report4) {
@@ -2759,10 +2821,10 @@ async function runPattern(slug2, argv, input, report4) {
2759
2821
  }
2760
2822
 
2761
2823
  // src/lib/form-ui.ts
2762
- import path17 from "node:path";
2824
+ import path18 from "node:path";
2763
2825
  var UIS = ["shadcn", "plain"];
2764
2826
  function detectFormInput(root) {
2765
- const pkg = readPackageJson(path17.join(root, "package.json"));
2827
+ const pkg = readPackageJson(path18.join(root, "package.json"));
2766
2828
  const hasDep = (name) => Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
2767
2829
  return {
2768
2830
  flash: hasDep("sveltekit-flash-message"),
@@ -2784,8 +2846,8 @@ function resolveFormInput(root, detectedUi, requested) {
2784
2846
  }
2785
2847
 
2786
2848
  // src/lib/ai-flow.ts
2787
- import fs18 from "node:fs";
2788
- import path18 from "node:path";
2849
+ import fs19 from "node:fs";
2850
+ import path19 from "node:path";
2789
2851
  import * as p13 from "@clack/prompts";
2790
2852
  import pc4 from "picocolors";
2791
2853
 
@@ -3060,15 +3122,15 @@ function specToArgv(spec) {
3060
3122
  return collectionSpecToArgv(spec);
3061
3123
  }
3062
3124
  function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
3063
- const dir = path18.join(workspaceRootDir, "data", "ai-form-layouts");
3064
- fs18.mkdirSync(dir, { recursive: true });
3065
- const file = path18.join(dir, `${modelName}.json`);
3066
- fs18.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
3067
- return path18.relative(workspaceRootDir, file);
3125
+ const dir = path19.join(workspaceRootDir, "data", "ai-form-layouts");
3126
+ fs19.mkdirSync(dir, { recursive: true });
3127
+ const file = path19.join(dir, `${modelName}.json`);
3128
+ fs19.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
3129
+ return path19.relative(workspaceRootDir, file);
3068
3130
  }
3069
3131
 
3070
3132
  // src/commands/generate/form.ts
3071
- var form = new Command5("form").description("generate a form from a model").argument("[model]", 'model name (e.g. "contact")').argument("[fields...]", 'field definitions (e.g. "name:text", "email:email")').option("--remote", "generate a form backed by a remote PocketBase collection").option(
3133
+ var form = new Command5("form").description("generate a form from a model").argument("[model]", 'model name (e.g. "contact")').argument("[fields...]", 'field definitions (e.g. "name:text", "email:email")').option("--remote", "generate the form with SvelteKit remote functions instead of superforms").option(
3072
3134
  "--route <route>",
3073
3135
  'place the form at a custom route (e.g. "(app)/[team_id]/projects/new"). Defaults to the model name under the (app) or (public) group, or src/routes when it has neither.'
3074
3136
  ).option(
@@ -3212,7 +3274,7 @@ var resource = new Command7("resource").description("generate a resource (model
3212
3274
  // src/commands/generate/scaffold.ts
3213
3275
  import { Command as Command8 } from "commander";
3214
3276
  import * as p16 from "@clack/prompts";
3215
- var scaffold = new Command8("scaffold").description("generate a full CRUD scaffold (model, forms, list, detail)").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--remote", "generate a scaffold backed by a remote PocketBase collection").option(
3277
+ var scaffold = new Command8("scaffold").description("generate a full CRUD scaffold (model, forms, list, detail)").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--remote", "generate create/update forms with SvelteKit remote functions").option(
3216
3278
  "--route <route>",
3217
3279
  'place the scaffold at a custom route (e.g. "(app)/[team_id]/projects"). Defaults to the pluralized model name under the (app) or (public) group, or src/routes when it has neither.'
3218
3280
  ).option(
@@ -3330,11 +3392,44 @@ var workflow = new Command10("workflow").description("generate a background work
3330
3392
  var generate = new Command11("generate").description("generate scaffolding for database models and forms").configureHelp(helpConfig).addCommand(form).addCommand(schema).addCommand(resource).addCommand(scaffold).addCommand(migration).addCommand(workflow);
3331
3393
 
3332
3394
  // src/commands/enable.ts
3333
- import { Command as Command28 } from "commander";
3395
+ import { Command as Command29 } from "commander";
3334
3396
 
3335
- // src/commands/enable/analytics.ts
3397
+ // src/commands/enable/ai.ts
3336
3398
  import { Command as Command12 } from "commander";
3337
- var analytics = new Command12("analytics").description("enable web analytics (Plausible, Google Analytics or PostHog)").option("--provider <provider>", "analytics provider: plausible, google or posthog").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3399
+ var ai = new Command12("ai").description("enable AI chat with the Vercel AI SDK (Vercel AI Gateway, OpenAI or Anthropic)").option("--provider <provider>", "AI provider: gateway, openai or anthropic").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3400
+ (opts, cmd) => runCommand(async () => {
3401
+ const provider = await resolveProvider("enable-ai", opts.provider);
3402
+ const providerEnv = await collectProviderEnv(provider);
3403
+ const blank = missingEnvKeys(provider, providerEnv);
3404
+ const keys = (provider.env ?? []).map((variable) => variable.key);
3405
+ const { workspaceRootDir, features } = await getWorkspace();
3406
+ const { serverTests } = detectFormInput(workspaceRootDir);
3407
+ await runPattern(
3408
+ "enable-ai",
3409
+ cmd.args,
3410
+ { provider: provider.id, providerEnv, serverTests },
3411
+ {
3412
+ summary: `Enabled AI with ${provider.label}.`,
3413
+ nextSteps: [
3414
+ ...blank.map((key) => `Set ${key} in .env; /api/chat answers 503 until it is set.`),
3415
+ "Run `vela dev` and open /ai to chat.",
3416
+ features.auth ? "Only signed-in users can call /api/chat, and the /ai page sits behind sign-in." : "/api/chat is open to anyone who can reach the site, and every reply is billed to your key: put it behind sign-in or a rate limit before you deploy.",
3417
+ `Set ${keys.join(" and ")} on each deploy target with \`vela env set\`.`,
3418
+ "Pick the model in src/lib/server/ai.ts and the instructions in src/routes/api/chat/+server.ts."
3419
+ ],
3420
+ task: {
3421
+ title: "Enabling AI",
3422
+ success: `Enabled AI with ${provider.label}`,
3423
+ error: "Failed to enable AI"
3424
+ }
3425
+ }
3426
+ );
3427
+ }, "Failed to enable AI.")
3428
+ );
3429
+
3430
+ // src/commands/enable/analytics.ts
3431
+ import { Command as Command13 } from "commander";
3432
+ var analytics = new Command13("analytics").description("enable web analytics (Plausible, Google Analytics or PostHog)").option("--provider <provider>", "analytics provider: plausible, google or posthog").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3338
3433
  (opts, cmd) => runCommand(async () => {
3339
3434
  const provider = await resolveProvider("enable-analytics", opts.provider);
3340
3435
  const providerEnv = await collectProviderEnv(provider);
@@ -3364,8 +3459,8 @@ var analytics = new Command12("analytics").description("enable web analytics (Pl
3364
3459
  );
3365
3460
 
3366
3461
  // src/commands/enable/auth.ts
3367
- import { Command as Command13 } from "commander";
3368
- var auth = new Command13("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3462
+ import { Command as Command14 } from "commander";
3463
+ var auth = new Command14("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3369
3464
  (_opts, cmd) => runCommand(
3370
3465
  () => runPattern(
3371
3466
  "enable-auth",
@@ -3390,8 +3485,8 @@ var auth = new Command13("auth").description("enable authentication (email/passw
3390
3485
  );
3391
3486
 
3392
3487
  // src/commands/enable/api.ts
3393
- import { Command as Command14 } from "commander";
3394
- var api = new Command14("api").description("enable the PocketBase REST API").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3488
+ import { Command as Command15 } from "commander";
3489
+ var api = new Command15("api").description("enable the PocketBase REST API").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3395
3490
  (_opts, cmd) => runCommand(
3396
3491
  () => runPattern(
3397
3492
  "enable-api",
@@ -3416,8 +3511,8 @@ var api = new Command14("api").description("enable the PocketBase REST API").all
3416
3511
  );
3417
3512
 
3418
3513
  // src/commands/enable/api-keys.ts
3419
- import { Command as Command15 } from "commander";
3420
- var apiKeys = new Command15("api-keys").description("enable API key management").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3514
+ import { Command as Command16 } from "commander";
3515
+ var apiKeys = new Command16("api-keys").description("enable API key management").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3421
3516
  (_opts, cmd) => runCommand(
3422
3517
  () => runPattern(
3423
3518
  "enable-api-keys",
@@ -3442,8 +3537,8 @@ var apiKeys = new Command15("api-keys").description("enable API key management")
3442
3537
  );
3443
3538
 
3444
3539
  // src/commands/enable/backend.ts
3445
- import { Command as Command16 } from "commander";
3446
- var backend = new Command16("backend").description("enable the PocketBase backend").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3540
+ import { Command as Command17 } from "commander";
3541
+ var backend = new Command17("backend").description("enable the PocketBase backend").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3447
3542
  (_opts, cmd) => runCommand(
3448
3543
  () => runPattern(
3449
3544
  "enable-backend",
@@ -3468,8 +3563,8 @@ var backend = new Command16("backend").description("enable the PocketBase backen
3468
3563
  );
3469
3564
 
3470
3565
  // src/commands/enable/i18n.ts
3471
- import { Command as Command17 } from "commander";
3472
- var i18n = new Command17("i18n").description("enable internationalization").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3566
+ import { Command as Command18 } from "commander";
3567
+ var i18n = new Command18("i18n").description("enable internationalization").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3473
3568
  (_opts, cmd) => runCommand(
3474
3569
  () => runPattern(
3475
3570
  "enable-i18n",
@@ -3480,7 +3575,7 @@ var i18n = new Command17("i18n").description("enable internationalization").allo
3480
3575
  nextSteps: [
3481
3576
  "Add or adjust locales in wuchale.config.js.",
3482
3577
  "Run `vela i18n extract` to pull translatable strings from your components.",
3483
- "Edit the generated .po files under locales/ to add translations."
3578
+ "Edit the generated .po files under src/locales/ to add translations."
3484
3579
  ],
3485
3580
  task: {
3486
3581
  title: "Enabling i18n",
@@ -3494,8 +3589,8 @@ var i18n = new Command17("i18n").description("enable internationalization").allo
3494
3589
  );
3495
3590
 
3496
3591
  // src/commands/enable/teams.ts
3497
- import { Command as Command18 } from "commander";
3498
- var teams = new Command18("teams").description("enable team / multi-tenant support").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3592
+ import { Command as Command19 } from "commander";
3593
+ var teams = new Command19("teams").description("enable team / multi-tenant support").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3499
3594
  (_opts, cmd) => runCommand(
3500
3595
  () => runPattern(
3501
3596
  "enable-teams",
@@ -3521,10 +3616,10 @@ var teams = new Command18("teams").description("enable team / multi-tenant suppo
3521
3616
 
3522
3617
  // src/commands/enable/payments.ts
3523
3618
  import process12 from "node:process";
3524
- import { Command as Command19 } from "commander";
3619
+ import { Command as Command20 } from "commander";
3525
3620
  import * as p17 from "@clack/prompts";
3526
3621
  var PROVIDERS = [{ value: "stripe", label: "Stripe" }];
3527
- var payments = new Command19("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3622
+ var payments = new Command20("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3528
3623
  (opts, cmd) => runCommand(async () => {
3529
3624
  const provider = await resolveProvider2(opts.provider, cmd.getOptionValueSource("provider"));
3530
3625
  const input = {
@@ -3621,8 +3716,8 @@ async function promptPassword(message) {
3621
3716
  }
3622
3717
 
3623
3718
  // src/commands/enable/subscriptions.ts
3624
- import { Command as Command20 } from "commander";
3625
- var subscriptions = new Command20("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3719
+ import { Command as Command21 } from "commander";
3720
+ var subscriptions = new Command21("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3626
3721
  (_opts, cmd) => runCommand(
3627
3722
  () => runPattern(
3628
3723
  "enable-subscriptions",
@@ -3647,8 +3742,8 @@ var subscriptions = new Command20("subscriptions").description("enable Stripe su
3647
3742
  );
3648
3743
 
3649
3744
  // src/commands/enable/notifications.ts
3650
- import { Command as Command21 } from "commander";
3651
- var notifications = new Command21("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3745
+ import { Command as Command22 } from "commander";
3746
+ var notifications = new Command22("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
3652
3747
  (_opts, cmd) => runCommand(
3653
3748
  () => runPattern(
3654
3749
  "enable-notifications",
@@ -3674,7 +3769,7 @@ var notifications = new Command21("notifications").description("enable in-app no
3674
3769
 
3675
3770
  // src/commands/enable/s3.ts
3676
3771
  import process16 from "node:process";
3677
- import { Command as Command22 } from "commander";
3772
+ import { Command as Command23 } from "commander";
3678
3773
  import * as p20 from "@clack/prompts";
3679
3774
  import pc8 from "picocolors";
3680
3775
 
@@ -3685,8 +3780,8 @@ import * as p18 from "@clack/prompts";
3685
3780
  import pc5 from "picocolors";
3686
3781
 
3687
3782
  // src/lib/deploy-config.ts
3688
- import fs19 from "node:fs";
3689
- import path19 from "node:path";
3783
+ import fs20 from "node:fs";
3784
+ import path20 from "node:path";
3690
3785
  import crypto from "node:crypto";
3691
3786
  import { pathToFileURL } from "node:url";
3692
3787
  var CONFIG_BASENAMES = [
@@ -3697,8 +3792,8 @@ var CONFIG_BASENAMES = [
3697
3792
  ];
3698
3793
  function findConfigFile(workspaceRootDir) {
3699
3794
  for (const name of CONFIG_BASENAMES) {
3700
- const file = path19.join(workspaceRootDir, name);
3701
- if (fs19.existsSync(file)) return file;
3795
+ const file = path20.join(workspaceRootDir, name);
3796
+ if (fs20.existsSync(file)) return file;
3702
3797
  }
3703
3798
  return null;
3704
3799
  }
@@ -3706,49 +3801,49 @@ async function loadDeployConfig(workspaceRootDir) {
3706
3801
  const file = findConfigFile(workspaceRootDir);
3707
3802
  if (!file) return {};
3708
3803
  if (file.endsWith(".json")) {
3709
- return JSON.parse(fs19.readFileSync(file, "utf8"));
3804
+ return JSON.parse(fs20.readFileSync(file, "utf8"));
3710
3805
  }
3711
3806
  const url = file.endsWith(".ts") ? await transpileToTemp(file) : pathToFileURL(file).href;
3712
3807
  try {
3713
3808
  const mod = await import(url);
3714
3809
  const config = mod.default;
3715
3810
  if (!config || typeof config !== "object") {
3716
- throw new Error(`${path19.basename(file)} must export a config object as its default export.`);
3811
+ throw new Error(`${path20.basename(file)} must export a config object as its default export.`);
3717
3812
  }
3718
3813
  return config;
3719
3814
  } finally {
3720
- if (url !== pathToFileURL(file).href) fs19.rmSync(new URL(url), { force: true });
3815
+ if (url !== pathToFileURL(file).href) fs20.rmSync(new URL(url), { force: true });
3721
3816
  }
3722
3817
  }
3723
3818
  async function transpileToTemp(file) {
3724
3819
  const { ts } = await import("ts-morph");
3725
- const source = fs19.readFileSync(file, "utf8");
3820
+ const source = fs20.readFileSync(file, "utf8");
3726
3821
  const { outputText } = ts.transpileModule(source, {
3727
3822
  compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 }
3728
3823
  });
3729
- const temp = path19.join(
3730
- path19.dirname(file),
3824
+ const temp = path20.join(
3825
+ path20.dirname(file),
3731
3826
  `.velastack.config.${crypto.randomBytes(4).toString("hex")}.mjs`
3732
3827
  );
3733
- fs19.writeFileSync(temp, outputText);
3828
+ fs20.writeFileSync(temp, outputText);
3734
3829
  return pathToFileURL(temp).href;
3735
3830
  }
3736
3831
  function projectFilePath(workspaceRootDir) {
3737
- return path19.join(workspaceRootDir, ".vela", "project.json");
3832
+ return path20.join(workspaceRootDir, ".vela", "project.json");
3738
3833
  }
3739
3834
  function readProjectFile(workspaceRootDir) {
3740
3835
  const file = projectFilePath(workspaceRootDir);
3741
- if (!fs19.existsSync(file)) return {};
3836
+ if (!fs20.existsSync(file)) return {};
3742
3837
  try {
3743
- return JSON.parse(fs19.readFileSync(file, "utf8"));
3838
+ return JSON.parse(fs20.readFileSync(file, "utf8"));
3744
3839
  } catch {
3745
3840
  return {};
3746
3841
  }
3747
3842
  }
3748
3843
  function writeProjectFile(workspaceRootDir, data) {
3749
3844
  const file = projectFilePath(workspaceRootDir);
3750
- fs19.mkdirSync(path19.dirname(file), { recursive: true });
3751
- fs19.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
3845
+ fs20.mkdirSync(path20.dirname(file), { recursive: true });
3846
+ fs20.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
3752
3847
  }
3753
3848
  function resolveAppIdentity(workspaceRootDir, config = {}) {
3754
3849
  const project = readProjectFile(workspaceRootDir);
@@ -3773,11 +3868,11 @@ function readAppIdentity(workspaceRootDir, config = {}) {
3773
3868
  }
3774
3869
  function defaultProjectName(workspaceRootDir) {
3775
3870
  try {
3776
- const pkg = readPackageJson(path19.join(workspaceRootDir, "package.json"));
3871
+ const pkg = readPackageJson(path20.join(workspaceRootDir, "package.json"));
3777
3872
  if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
3778
3873
  } catch {
3779
3874
  }
3780
- return path19.basename(workspaceRootDir);
3875
+ return path20.basename(workspaceRootDir);
3781
3876
  }
3782
3877
  function slug(value) {
3783
3878
  return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
@@ -3848,15 +3943,15 @@ function randomSuffix() {
3848
3943
  }
3849
3944
 
3850
3945
  // src/lib/artifact.ts
3851
- import fs21 from "node:fs";
3852
- import path21 from "node:path";
3946
+ import fs22 from "node:fs";
3947
+ import path22 from "node:path";
3853
3948
  import { detect as detect4 } from "package-manager-detector";
3854
3949
  import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
3855
3950
 
3856
3951
  // src/lib/ssh.ts
3857
- import fs20 from "node:fs";
3952
+ import fs21 from "node:fs";
3858
3953
  import os4 from "node:os";
3859
- import path20 from "node:path";
3954
+ import path21 from "node:path";
3860
3955
  import crypto3 from "node:crypto";
3861
3956
  import process13 from "node:process";
3862
3957
  import { spawn as spawn2 } from "node:child_process";
@@ -3899,9 +3994,9 @@ var SshSession = class {
3899
3994
  }
3900
3995
  async open() {
3901
3996
  if (this.controlPath) return;
3902
- const dir = path20.join(os4.tmpdir(), "vela-ssh");
3903
- fs20.mkdirSync(dir, { recursive: true, mode: 448 });
3904
- const socket = path20.join(dir, `${crypto3.randomBytes(6).toString("hex")}.sock`);
3997
+ const dir = path21.join(os4.tmpdir(), "vela-ssh");
3998
+ fs21.mkdirSync(dir, { recursive: true, mode: 448 });
3999
+ const socket = path21.join(dir, `${crypto3.randomBytes(6).toString("hex")}.sock`);
3905
4000
  this.controlPath = socket;
3906
4001
  const args = [
3907
4002
  ...this.sshArgs(),
@@ -4191,11 +4286,11 @@ function collectArtifact(cwd, config = {}) {
4191
4286
  const outputDir = config.outputDir ?? DEFAULT_OUTPUT_DIR;
4192
4287
  const entries = [];
4193
4288
  const add2 = (rel, remoteDir = "") => {
4194
- const localPath = path21.join(cwd, rel);
4195
- if (fs21.existsSync(localPath)) entries.push({ localPath, remoteDir });
4289
+ const localPath = path22.join(cwd, rel);
4290
+ if (fs22.existsSync(localPath)) entries.push({ localPath, remoteDir });
4196
4291
  };
4197
- const buildPath = path21.join(cwd, outputDir);
4198
- if (!fs21.existsSync(path21.join(buildPath, "index.js"))) {
4292
+ const buildPath = path22.join(cwd, outputDir);
4293
+ if (!fs22.existsSync(path22.join(buildPath, "index.js"))) {
4199
4294
  throw new BuildError(
4200
4295
  `No ${outputDir}/index.js to deploy.
4201
4296
 
@@ -4209,8 +4304,8 @@ matches where it writes), then deploy again.`
4209
4304
  add2("package-lock.json");
4210
4305
  add2(".npmrc");
4211
4306
  add2(MIGRATIONS_DIR);
4212
- const hooks = path21.join(cwd, DATA_DIR, "hooks");
4213
- if (fs21.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
4307
+ const hooks = path22.join(cwd, DATA_DIR, "hooks");
4308
+ if (fs22.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
4214
4309
  for (const extra of config.include ?? []) add2(extra);
4215
4310
  return entries;
4216
4311
  }
@@ -4251,8 +4346,8 @@ function sshOptionsFrom(options) {
4251
4346
 
4252
4347
  // src/lib/remote.ts
4253
4348
  import crypto4 from "node:crypto";
4254
- import fs22 from "node:fs";
4255
- import path22 from "node:path";
4349
+ import fs23 from "node:fs";
4350
+ import path23 from "node:path";
4256
4351
  import process14 from "node:process";
4257
4352
  var VELA_ROOT = "/var/lib/vela";
4258
4353
  var VELA_ETC = "/etc/vela";
@@ -4265,19 +4360,19 @@ function instanceHasBackend(state) {
4265
4360
  return state.backend ?? Boolean(state.pbPort);
4266
4361
  }
4267
4362
  function serverTemplatesDir() {
4268
- return path22.join(templatesDir(), "server");
4363
+ return path23.join(templatesDir(), "server");
4269
4364
  }
4270
4365
  var DIGEST_LENGTH = 12;
4271
4366
  function serverScriptsDigest(dir = serverTemplatesDir()) {
4272
4367
  const hash = crypto4.createHash("sha256");
4273
4368
  for (const file of listFiles(dir).sort()) {
4274
- hash.update(file).update("\0").update(fs22.readFileSync(path22.join(dir, file))).update("\0");
4369
+ hash.update(file).update("\0").update(fs23.readFileSync(path23.join(dir, file))).update("\0");
4275
4370
  }
4276
4371
  return hash.digest("hex").slice(0, DIGEST_LENGTH);
4277
4372
  }
4278
4373
  function listFiles(root, prefix = "") {
4279
4374
  const files = [];
4280
- for (const entry of fs22.readdirSync(path22.join(root, prefix), { withFileTypes: true })) {
4375
+ for (const entry of fs23.readdirSync(path23.join(root, prefix), { withFileTypes: true })) {
4281
4376
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
4282
4377
  if (entry.isDirectory()) files.push(...listFiles(root, rel));
4283
4378
  else if (entry.isFile()) files.push(rel);
@@ -4396,7 +4491,7 @@ var remotePaths = {
4396
4491
  };
4397
4492
 
4398
4493
  // src/lib/remote-env.ts
4399
- import fs23 from "node:fs";
4494
+ import fs24 from "node:fs";
4400
4495
  import dotenv from "dotenv";
4401
4496
  var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
4402
4497
  function isValidKey(key) {
@@ -4444,7 +4539,7 @@ function quote(value) {
4444
4539
  return `"${escaped}"`;
4445
4540
  }
4446
4541
  function readLocalEnvFile(file) {
4447
- const parsed = dotenv.parse(fs23.readFileSync(file));
4542
+ const parsed = dotenv.parse(fs24.readFileSync(file));
4448
4543
  const result = {};
4449
4544
  for (const [key, value] of Object.entries(parsed)) {
4450
4545
  if (isValidKey(key)) result[key] = value;
@@ -4773,17 +4868,17 @@ function envFilePath(workspaceRootDir) {
4773
4868
  import pc7 from "picocolors";
4774
4869
 
4775
4870
  // src/lib/local-env.ts
4776
- import fs24 from "node:fs";
4871
+ import fs25 from "node:fs";
4777
4872
  import * as p19 from "@clack/prompts";
4778
4873
  import pc6 from "picocolors";
4779
4874
  function readLocalEnv(envFile) {
4780
- if (!fs24.existsSync(envFile)) return {};
4875
+ if (!fs25.existsSync(envFile)) return {};
4781
4876
  return readLocalEnvFile(envFile);
4782
4877
  }
4783
4878
  function editLocalEnv(envFile, edit) {
4784
- const before = fs24.existsSync(envFile) ? fs24.readFileSync(envFile, "utf8") : "";
4879
+ const before = fs25.existsSync(envFile) ? fs25.readFileSync(envFile, "utf8") : "";
4785
4880
  const after = edit(before);
4786
- if (after !== before) fs24.writeFileSync(envFile, after);
4881
+ if (after !== before) fs25.writeFileSync(envFile, after);
4787
4882
  }
4788
4883
  function setLocalEnv(envFile, key, value) {
4789
4884
  editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
@@ -4795,10 +4890,10 @@ async function applyLocalEnvChange(ctx, changed) {
4795
4890
  if (touchesSuperuser(changed)) {
4796
4891
  const env2 = readLocalEnv(ctx.envFile);
4797
4892
  const email3 = env2.POCKETBASE_SUPERUSER_EMAIL;
4798
- const password11 = env2.POCKETBASE_SUPERUSER_PASSWORD;
4799
- if (email3 && password11) {
4893
+ const password12 = env2.POCKETBASE_SUPERUSER_PASSWORD;
4894
+ if (email3 && password12) {
4800
4895
  process.env.POCKETBASE_SUPERUSER_EMAIL = email3;
4801
- process.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
4896
+ process.env.POCKETBASE_SUPERUSER_PASSWORD = password12;
4802
4897
  await ensureSuperuser(ctx.workspaceRootDir);
4803
4898
  p19.log.success("Local superuser updated to match");
4804
4899
  } else {
@@ -4828,8 +4923,8 @@ project with a backend (\`vela bless\` adds one).`
4828
4923
  }
4829
4924
  const env2 = await readRemoteEnv(session, instance);
4830
4925
  const email3 = env2.POCKETBASE_SUPERUSER_EMAIL;
4831
- const password11 = env2.POCKETBASE_SUPERUSER_PASSWORD;
4832
- if (!email3 || !password11) {
4926
+ const password12 = env2.POCKETBASE_SUPERUSER_PASSWORD;
4927
+ if (!email3 || !password12) {
4833
4928
  throw new Error(
4834
4929
  `${instance} has no PocketBase superuser credentials in its environment.
4835
4930
 
@@ -4841,7 +4936,7 @@ A deploy creates them. Deploy again to repair this instance.`
4841
4936
  return {
4842
4937
  url: `http://127.0.0.1:${localPort}`,
4843
4938
  email: email3,
4844
- password: password11,
4939
+ password: password12,
4845
4940
  close: () => session.cancelForward(localPort, "127.0.0.1", pbPort)
4846
4941
  };
4847
4942
  }
@@ -4871,8 +4966,8 @@ Run ${pc7.cyan("vela bless")} to add a backend.`
4871
4966
  }
4872
4967
  const creds = readLocalEnv(ctx.envFile);
4873
4968
  const email3 = creds.POCKETBASE_SUPERUSER_EMAIL;
4874
- const password11 = creds.POCKETBASE_SUPERUSER_PASSWORD;
4875
- if (!email3 || !password11) {
4969
+ const password12 = creds.POCKETBASE_SUPERUSER_PASSWORD;
4970
+ if (!email3 || !password12) {
4876
4971
  throw new Error(
4877
4972
  `The local database has no superuser credentials to sign in with.
4878
4973
 
@@ -4888,7 +4983,7 @@ Set ${pc7.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc7.cyan("POCKETBASE_SUPERUS
4888
4983
  targetName: "local",
4889
4984
  workspaceRootDir: ctx.workspaceRootDir
4890
4985
  }),
4891
- { email: email3, password: password11 }
4986
+ { email: email3, password: password12 }
4892
4987
  );
4893
4988
  },
4894
4989
  remote: async (ctx) => {
@@ -4916,8 +5011,8 @@ Set ${pc7.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc7.cyan("POCKETBASE_SUPERUS
4916
5011
  }
4917
5012
 
4918
5013
  // src/lib/s3-settings.ts
4919
- import fs25 from "node:fs";
4920
- import path23 from "node:path";
5014
+ import fs26 from "node:fs";
5015
+ import path24 from "node:path";
4921
5016
  var VIRTUAL_HOSTED = [/\.amazonaws\.com$/i, /\.r2\.cloudflarestorage\.com$/i];
4922
5017
  function defaultForcePathStyle(endpoint) {
4923
5018
  let host;
@@ -4955,25 +5050,25 @@ async function hasLocalUploads(session, instance, workspaceRootDir) {
4955
5050
  });
4956
5051
  return result.stdout.trim().length > 0;
4957
5052
  }
4958
- return hasFile(path23.join(workspaceRootDir, DATA_DIR, "storage"));
5053
+ return hasFile(path24.join(workspaceRootDir, DATA_DIR, "storage"));
4959
5054
  }
4960
5055
  function hasFile(dir) {
4961
5056
  let entries;
4962
5057
  try {
4963
- entries = fs25.readdirSync(dir, { withFileTypes: true });
5058
+ entries = fs26.readdirSync(dir, { withFileTypes: true });
4964
5059
  } catch {
4965
5060
  return false;
4966
5061
  }
4967
5062
  for (const entry of entries) {
4968
5063
  if (entry.isFile()) return true;
4969
- if (entry.isDirectory() && hasFile(path23.join(dir, entry.name))) return true;
5064
+ if (entry.isDirectory() && hasFile(path24.join(dir, entry.name))) return true;
4970
5065
  }
4971
5066
  return false;
4972
5067
  }
4973
5068
 
4974
5069
  // src/commands/enable/s3.ts
4975
5070
  var s3 = addTargetOptions(
4976
- new Command22("s3").description("enable S3 file storage").option("--backups", "configure where backups are kept, not where uploads go").option("--endpoint <url>", "S3 endpoint URL").option("--bucket <name>", "S3 bucket name").option("--region <region>", "S3 region").option("--access-key <key>", "S3 access key").option("--secret <secret>", "S3 secret key \u2014 prefer VELA_S3_SECRET").option("--force-path-style", "address the bucket in the path (MinIO, Ceph)").option("--no-force-path-style", "address the bucket as a subdomain (AWS, R2)").option("--force", "enable it even though uploads already exist on disk").configureHelp(helpConfig),
5071
+ new Command23("s3").description("enable S3 file storage").option("--backups", "configure where backups are kept, not where uploads go").option("--endpoint <url>", "S3 endpoint URL").option("--bucket <name>", "S3 bucket name").option("--region <region>", "S3 region").option("--access-key <key>", "S3 access key").option("--secret <secret>", "S3 secret key \u2014 prefer VELA_S3_SECRET").option("--force-path-style", "address the bucket in the path (MinIO, Ceph)").option("--no-force-path-style", "address the bucket as a subdomain (AWS, R2)").option("--force", "enable it even though uploads already exist on disk").configureHelp(helpConfig),
4977
5072
  "local"
4978
5073
  ).action(
4979
5074
  (raw) => runCommand(() => {
@@ -5039,7 +5134,7 @@ async function promptConfig(options, existing) {
5039
5134
  const bucket = options.bucket ?? await text9("S3 bucket name", existing.bucket);
5040
5135
  const region = options.region ?? await text9("S3 region", existing.region || "us-east-1");
5041
5136
  const accessKey = options.accessKey ?? await text9("S3 access key", existing.accessKey);
5042
- const secret = options.secret ?? process16.env.VELA_S3_SECRET ?? await password6("S3 secret key");
5137
+ const secret = options.secret ?? process16.env.VELA_S3_SECRET ?? await password7("S3 secret key");
5043
5138
  const forcePathStyle = options.forcePathStyle ?? await confirm4(
5044
5139
  "Address the bucket in the path? (MinIO, Ceph and most self-hosted gateways need this)",
5045
5140
  defaultForcePathStyle(endpoint)
@@ -5058,7 +5153,7 @@ async function text9(message, initialValue = "") {
5058
5153
  }
5059
5154
  return value.trim();
5060
5155
  }
5061
- async function password6(message) {
5156
+ async function password7(message) {
5062
5157
  const value = await p20.password({
5063
5158
  message,
5064
5159
  validate: (input) => input ? void 0 : `${message} is required`
@@ -5080,9 +5175,9 @@ async function confirm4(message, initialValue) {
5080
5175
 
5081
5176
  // src/commands/enable/smtp.ts
5082
5177
  import process17 from "node:process";
5083
- import { Command as Command23 } from "commander";
5178
+ import { Command as Command24 } from "commander";
5084
5179
  import * as p21 from "@clack/prompts";
5085
- var smtp = new Command23("smtp").description("configure SMTP for transactional email").configureHelp(helpConfig).action(
5180
+ var smtp = new Command24("smtp").description("configure SMTP for transactional email").configureHelp(helpConfig).action(
5086
5181
  () => runCommand(async () => {
5087
5182
  const { workspaceRootDir } = await getWorkspace();
5088
5183
  const config = await p21.group(
@@ -5136,10 +5231,10 @@ var smtp = new Command23("smtp").description("configure SMTP for transactional e
5136
5231
 
5137
5232
  // src/commands/enable/cms.ts
5138
5233
  import process18 from "node:process";
5139
- import { Command as Command24 } from "commander";
5234
+ import { Command as Command25 } from "commander";
5140
5235
  import * as p22 from "@clack/prompts";
5141
5236
  import pc9 from "picocolors";
5142
- var cms = new Command24("cms").description("enable an inline-editing CMS with an admin bar").option(
5237
+ var cms = new Command25("cms").description("enable an inline-editing CMS with an admin bar").option(
5143
5238
  "--endpoint <url>",
5144
5239
  "read from a hosted CMS at this URL instead of installing the backend in this app"
5145
5240
  ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
@@ -5172,8 +5267,8 @@ Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${
5172
5267
  );
5173
5268
 
5174
5269
  // src/commands/enable/blog.ts
5175
- import { Command as Command25 } from "commander";
5176
- var blog = new Command25("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5270
+ import { Command as Command26 } from "commander";
5271
+ var blog = new Command26("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5177
5272
  (_opts, cmd) => runCommand(
5178
5273
  () => runPattern(
5179
5274
  "enable-blog",
@@ -5198,8 +5293,8 @@ var blog = new Command25("blog").description("enable an mdsvex blog with posts,
5198
5293
  );
5199
5294
 
5200
5295
  // src/commands/enable/content-negotiation.ts
5201
- import { Command as Command26 } from "commander";
5202
- var contentNegotiation = new Command26("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5296
+ import { Command as Command27 } from "commander";
5297
+ var contentNegotiation = new Command27("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5203
5298
  (_opts, cmd) => runCommand(
5204
5299
  () => runPattern(
5205
5300
  "enable-content-negotiation",
@@ -5223,8 +5318,8 @@ var contentNegotiation = new Command26("content-negotiation").description("enabl
5223
5318
  );
5224
5319
 
5225
5320
  // src/commands/enable/workflows.ts
5226
- import { Command as Command27 } from "commander";
5227
- var workflows = new Command27("workflows").description("add background workflows to a project created before they were built in").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5321
+ import { Command as Command28 } from "commander";
5322
+ var workflows = new Command28("workflows").description("add background workflows to a project created before they were built in").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5228
5323
  (_opts, cmd) => runCommand(
5229
5324
  () => runPattern(
5230
5325
  "enable-workflows",
@@ -5249,13 +5344,13 @@ var workflows = new Command27("workflows").description("add background workflows
5249
5344
  );
5250
5345
 
5251
5346
  // src/commands/enable.ts
5252
- var enable = new Command28("enable").description("enable features").configureHelp(helpConfig).addCommand(analytics).addCommand(auth).addCommand(api).addCommand(apiKeys).addCommand(backend).addCommand(contentNegotiation).addCommand(i18n).addCommand(teams).addCommand(payments).addCommand(subscriptions).addCommand(notifications).addCommand(s3).addCommand(smtp).addCommand(cms).addCommand(blog).addCommand(workflows);
5347
+ var enable = new Command29("enable").description("enable features").configureHelp(helpConfig).addCommand(ai).addCommand(analytics).addCommand(auth).addCommand(api).addCommand(apiKeys).addCommand(backend).addCommand(contentNegotiation).addCommand(i18n).addCommand(teams).addCommand(payments).addCommand(subscriptions).addCommand(notifications).addCommand(s3).addCommand(smtp).addCommand(cms).addCommand(blog).addCommand(workflows);
5253
5348
 
5254
5349
  // src/commands/disable.ts
5255
- import { Command as Command41 } from "commander";
5350
+ import { Command as Command44 } from "commander";
5256
5351
 
5257
- // src/commands/disable/auth.ts
5258
- import { Command as Command29 } from "commander";
5352
+ // src/commands/disable/ai.ts
5353
+ import { Command as Command30 } from "commander";
5259
5354
 
5260
5355
  // src/commands/disable/_shared.ts
5261
5356
  import process19 from "node:process";
@@ -5274,8 +5369,62 @@ async function runDisable(opts, flags, cmdArgs) {
5274
5369
  await runPattern(opts.slug, cmdArgs, { destructive: true }, opts.report);
5275
5370
  }
5276
5371
 
5372
+ // src/commands/disable/ai.ts
5373
+ var ai2 = new Command30("ai").description("disable AI chat").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5374
+ (opts, cmd) => runCommand(
5375
+ () => runDisable(
5376
+ {
5377
+ slug: "disable-ai",
5378
+ confirmMessage: "Disable AI? Deletes src/lib/server/ai.ts, the /api/chat endpoint and the /ai demo page, removes the provider's API key from .env and uninstalls the AI SDK packages.",
5379
+ report: {
5380
+ summary: "Disabled AI.",
5381
+ nextSteps: [
5382
+ "Remove the API key from each deploy target with `vela env unset` if you set one there."
5383
+ ],
5384
+ task: {
5385
+ title: "Disabling AI",
5386
+ success: "Disabled AI",
5387
+ error: "Failed to disable AI"
5388
+ }
5389
+ }
5390
+ },
5391
+ opts,
5392
+ cmd.args
5393
+ ),
5394
+ "Failed to disable AI."
5395
+ )
5396
+ );
5397
+
5398
+ // src/commands/disable/analytics.ts
5399
+ import { Command as Command31 } from "commander";
5400
+ var analytics2 = new Command31("analytics").description("disable web analytics").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5401
+ (opts, cmd) => runCommand(
5402
+ () => runDisable(
5403
+ {
5404
+ slug: "disable-analytics",
5405
+ confirmMessage: "Disable analytics? Deletes the analytics component, removes <Analytics /> from the root layout, strips the provider's variables from .env and uninstalls posthog-js.",
5406
+ report: {
5407
+ summary: "Disabled analytics.",
5408
+ nextSteps: [
5409
+ "Remove the PUBLIC_* analytics variables from each deploy target with `vela env unset` if you set them there."
5410
+ ],
5411
+ task: {
5412
+ title: "Disabling analytics",
5413
+ success: "Disabled analytics",
5414
+ error: "Failed to disable analytics"
5415
+ }
5416
+ }
5417
+ },
5418
+ opts,
5419
+ cmd.args
5420
+ ),
5421
+ "Failed to disable analytics."
5422
+ )
5423
+ );
5424
+
5277
5425
  // src/commands/disable/auth.ts
5278
- var auth2 = new Command29("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5426
+ import { Command as Command32 } from "commander";
5427
+ var auth2 = new Command32("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5279
5428
  (opts, cmd) => runCommand(
5280
5429
  () => runDisable(
5281
5430
  {
@@ -5301,8 +5450,8 @@ var auth2 = new Command29("auth").description("disable authentication").option("
5301
5450
  );
5302
5451
 
5303
5452
  // src/commands/disable/api.ts
5304
- import { Command as Command30 } from "commander";
5305
- var api2 = new Command30("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5453
+ import { Command as Command33 } from "commander";
5454
+ var api2 = new Command33("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5306
5455
  (opts, cmd) => runCommand(
5307
5456
  () => runDisable(
5308
5457
  {
@@ -5325,8 +5474,8 @@ var api2 = new Command30("api").description("disable the REST API").option("-y,
5325
5474
  );
5326
5475
 
5327
5476
  // src/commands/disable/api-keys.ts
5328
- import { Command as Command31 } from "commander";
5329
- var apiKeys2 = new Command31("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5477
+ import { Command as Command34 } from "commander";
5478
+ var apiKeys2 = new Command34("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5330
5479
  (opts, cmd) => runCommand(
5331
5480
  () => runDisable(
5332
5481
  {
@@ -5349,13 +5498,13 @@ var apiKeys2 = new Command31("api-keys").description("disable API key management
5349
5498
  );
5350
5499
 
5351
5500
  // src/commands/disable/backend.ts
5352
- import { Command as Command32 } from "commander";
5353
- var backend2 = new Command32("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5501
+ import { Command as Command35 } from "commander";
5502
+ var backend2 = new Command35("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5354
5503
  (opts, cmd) => runCommand(
5355
5504
  () => runDisable(
5356
5505
  {
5357
5506
  slug: "disable-backend",
5358
- confirmMessage: "Disable the PocketBase backend? Takes the PocketBase handle and workflow worker out of hooks.server.ts (deleting it if nothing else is left), removes the data/ scaffold, and reverts the SvelteKit adapter. The @velastack/pocketbase and pocketbase-sveltekit packages stay installed.",
5507
+ confirmMessage: "Disable the PocketBase backend? Deletes data/ (the local database, fixtures, hooks and seeds), src/lib/server/workflows.ts, src/lib/workflows/ and every server.test.ts, and uninstalls the workflow packages. Takes the PocketBase handle and workflow worker out of hooks.server.ts (deleting it if nothing else is left) and switches the SvelteKit adapter back to static. The @velastack/pocketbase and pocketbase-sveltekit packages stay installed.",
5359
5508
  report: {
5360
5509
  summary: "Disabled the PocketBase backend.",
5361
5510
  task: {
@@ -5373,8 +5522,8 @@ var backend2 = new Command32("backend").description("disable the PocketBase back
5373
5522
  );
5374
5523
 
5375
5524
  // src/commands/disable/content-negotiation.ts
5376
- import { Command as Command33 } from "commander";
5377
- var contentNegotiation2 = new Command33("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5525
+ import { Command as Command36 } from "commander";
5526
+ var contentNegotiation2 = new Command36("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5378
5527
  (opts, cmd) => runCommand(
5379
5528
  () => runDisable(
5380
5529
  {
@@ -5397,18 +5546,16 @@ var contentNegotiation2 = new Command33("content-negotiation").description("disa
5397
5546
  );
5398
5547
 
5399
5548
  // src/commands/disable/i18n.ts
5400
- import { Command as Command34 } from "commander";
5401
- var i18n2 = new Command34("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5549
+ import { Command as Command37 } from "commander";
5550
+ var i18n2 = new Command37("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5402
5551
  (opts, cmd) => runCommand(
5403
5552
  () => runDisable(
5404
5553
  {
5405
5554
  slug: "disable-i18n",
5406
- confirmMessage: "Disable i18n? Removes i18n scaffolding files and the Wuchale .gitignore block. Manual reverts are still required in vite.config, svelte.config, hooks.server, app.html, and +layout.ts.",
5555
+ confirmMessage: "Disable i18n? Deletes the Wuchale config, reroute hook, URL helpers and language select, uninstalls wuchale, and reverts vite.config, svelte.config, hooks.server, app.html, the root +layout.ts and layout, and .gitignore. The translation catalogs in src/locales stay.",
5407
5556
  report: {
5408
- summary: "Disabled i18n scaffolding.",
5409
- nextSteps: [
5410
- "Manually revert the Wuchale wiring in vite.config, svelte.config, hooks.server, app.html, and +layout.ts."
5411
- ],
5557
+ summary: "Disabled i18n.",
5558
+ nextSteps: ["Delete src/locales if you no longer need the translation catalogs."],
5412
5559
  task: {
5413
5560
  title: "Disabling i18n",
5414
5561
  success: "Disabled i18n",
@@ -5424,8 +5571,8 @@ var i18n2 = new Command34("i18n").description("disable internationalization").op
5424
5571
  );
5425
5572
 
5426
5573
  // src/commands/disable/notifications.ts
5427
- import { Command as Command35 } from "commander";
5428
- var notifications2 = new Command35("notifications").description("disable in-app notifications").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5574
+ import { Command as Command38 } from "commander";
5575
+ var notifications2 = new Command38("notifications").description("disable in-app notifications").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5429
5576
  (opts, cmd) => runCommand(
5430
5577
  () => runDisable(
5431
5578
  {
@@ -5451,8 +5598,8 @@ var notifications2 = new Command35("notifications").description("disable in-app
5451
5598
  );
5452
5599
 
5453
5600
  // src/commands/disable/teams.ts
5454
- import { Command as Command36 } from "commander";
5455
- var teams2 = new Command36("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5601
+ import { Command as Command39 } from "commander";
5602
+ var teams2 = new Command39("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5456
5603
  (opts, cmd) => runCommand(
5457
5604
  () => runDisable(
5458
5605
  {
@@ -5475,8 +5622,8 @@ var teams2 = new Command36("teams").description("disable teams").option("-y, --y
5475
5622
  );
5476
5623
 
5477
5624
  // src/commands/disable/payments.ts
5478
- import { Command as Command37 } from "commander";
5479
- var payments2 = new Command37("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5625
+ import { Command as Command40 } from "commander";
5626
+ var payments2 = new Command40("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5480
5627
  (opts, cmd) => runCommand(
5481
5628
  () => runDisable(
5482
5629
  {
@@ -5503,11 +5650,11 @@ var payments2 = new Command37("payments").description("disable payments").option
5503
5650
  );
5504
5651
 
5505
5652
  // src/commands/disable/s3.ts
5506
- import { Command as Command38 } from "commander";
5653
+ import { Command as Command41 } from "commander";
5507
5654
  import * as p24 from "@clack/prompts";
5508
5655
  import pc10 from "picocolors";
5509
5656
  var s32 = addTargetOptions(
5510
- new Command38("s3").description("disable S3 file storage").option("--backups", "keep backups on the server again, rather than uploads").configureHelp(helpConfig),
5657
+ new Command41("s3").description("disable S3 file storage").option("--backups", "keep backups on the server again, rather than uploads").configureHelp(helpConfig),
5511
5658
  "local"
5512
5659
  ).action(
5513
5660
  (raw) => runCommand(() => {
@@ -5536,8 +5683,8 @@ function label2(filesystem) {
5536
5683
  }
5537
5684
 
5538
5685
  // src/commands/disable/subscriptions.ts
5539
- import { Command as Command39 } from "commander";
5540
- var subscriptions2 = new Command39("subscriptions").description("disable Stripe subscriptions").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5686
+ import { Command as Command42 } from "commander";
5687
+ var subscriptions2 = new Command42("subscriptions").description("disable Stripe subscriptions").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5541
5688
  (opts, cmd) => runCommand(
5542
5689
  () => runDisable(
5543
5690
  {
@@ -5564,8 +5711,8 @@ var subscriptions2 = new Command39("subscriptions").description("disable Stripe
5564
5711
  );
5565
5712
 
5566
5713
  // src/commands/disable/smtp.ts
5567
- import { Command as Command40 } from "commander";
5568
- var smtp2 = new Command40("smtp").description("disable SMTP configuration").configureHelp(helpConfig).action(
5714
+ import { Command as Command43 } from "commander";
5715
+ var smtp2 = new Command43("smtp").description("disable SMTP configuration").configureHelp(helpConfig).action(
5569
5716
  () => runCommand(async () => {
5570
5717
  const { workspaceRootDir } = await getWorkspace();
5571
5718
  await withPocketbase(workspaceRootDir, async (pb) => {
@@ -5582,13 +5729,13 @@ var smtp2 = new Command40("smtp").description("disable SMTP configuration").conf
5582
5729
  );
5583
5730
 
5584
5731
  // src/commands/disable.ts
5585
- var disable = new Command41("disable").description("disable features").configureHelp(helpConfig).addCommand(auth2).addCommand(api2).addCommand(apiKeys2).addCommand(backend2).addCommand(contentNegotiation2).addCommand(i18n2).addCommand(notifications2).addCommand(teams2).addCommand(payments2).addCommand(subscriptions2).addCommand(s32).addCommand(smtp2);
5732
+ var disable = new Command44("disable").description("disable features").configureHelp(helpConfig).addCommand(ai2).addCommand(analytics2).addCommand(auth2).addCommand(api2).addCommand(apiKeys2).addCommand(backend2).addCommand(contentNegotiation2).addCommand(i18n2).addCommand(notifications2).addCommand(teams2).addCommand(payments2).addCommand(subscriptions2).addCommand(s32).addCommand(smtp2);
5586
5733
 
5587
5734
  // src/commands/destroy.ts
5588
- import { Command as Command47 } from "commander";
5735
+ import { Command as Command50 } from "commander";
5589
5736
 
5590
5737
  // src/commands/destroy/form.ts
5591
- import { Command as Command42 } from "commander";
5738
+ import { Command as Command45 } from "commander";
5592
5739
 
5593
5740
  // src/commands/destroy/_shared.ts
5594
5741
  import process20 from "node:process";
@@ -5605,7 +5752,7 @@ async function runDestroy(slug2, model, confirmMessage, report4, flags) {
5605
5752
  }
5606
5753
 
5607
5754
  // src/commands/destroy/form.ts
5608
- var form2 = new Command42("form").description("destroy a form generated by `vela generate form`").argument("<model>", "model name used when the form was generated (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").option(
5755
+ var form2 = new Command45("form").description("destroy a form generated by `vela generate form`").argument("<model>", "model name used when the form was generated (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").option(
5609
5756
  "--route <route>",
5610
5757
  "custom route the form was generated at (must match the --route used at generation)"
5611
5758
  ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
@@ -5629,8 +5776,8 @@ var form2 = new Command42("form").description("destroy a form generated by `vela
5629
5776
  );
5630
5777
 
5631
5778
  // src/commands/destroy/schema.ts
5632
- import { Command as Command43 } from "commander";
5633
- var schema2 = new Command43("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5779
+ import { Command as Command46 } from "commander";
5780
+ var schema2 = new Command46("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5634
5781
  (model, opts) => runCommand(
5635
5782
  () => runDestroy(
5636
5783
  "destroy-schema",
@@ -5651,8 +5798,8 @@ var schema2 = new Command43("schema").description("destroy a zod schema generate
5651
5798
  );
5652
5799
 
5653
5800
  // src/commands/destroy/resource.ts
5654
- import { Command as Command44 } from "commander";
5655
- var resource2 = new Command44("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5801
+ import { Command as Command47 } from "commander";
5802
+ var resource2 = new Command47("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
5656
5803
  (model, opts) => runCommand(
5657
5804
  () => runDestroy(
5658
5805
  "destroy-resource",
@@ -5673,8 +5820,8 @@ var resource2 = new Command44("resource").description("destroy a resource genera
5673
5820
  );
5674
5821
 
5675
5822
  // src/commands/destroy/scaffold.ts
5676
- import { Command as Command45 } from "commander";
5677
- var scaffold2 = new Command45("scaffold").description("destroy a scaffold generated by `vela generate scaffold`").argument("<model>", "model name used when the scaffold was generated (e.g., contact, todo)").option("-y, --yes", "skip confirmation prompt").option(
5823
+ import { Command as Command48 } from "commander";
5824
+ var scaffold2 = new Command48("scaffold").description("destroy a scaffold generated by `vela generate scaffold`").argument("<model>", "model name used when the scaffold was generated (e.g., contact, todo)").option("-y, --yes", "skip confirmation prompt").option(
5678
5825
  "--route <route>",
5679
5826
  "custom route the scaffold was generated at (must match the --route used at generation)"
5680
5827
  ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
@@ -5702,7 +5849,7 @@ var scaffold2 = new Command45("scaffold").description("destroy a scaffold genera
5702
5849
 
5703
5850
  // src/commands/destroy/deployment.ts
5704
5851
  import process21 from "node:process";
5705
- import { Command as Command46 } from "commander";
5852
+ import { Command as Command49 } from "commander";
5706
5853
  import * as p28 from "@clack/prompts";
5707
5854
  import pc13 from "picocolors";
5708
5855
 
@@ -5868,7 +6015,7 @@ ${pc12.dim(err instanceof Error ? err.message : String(err))}`
5868
6015
  // src/commands/destroy/deployment.ts
5869
6016
  var deployment = addLockWaitOption(
5870
6017
  addTargetOptions(
5871
- new Command46("deployment").description("remove a deployed environment from its server").configureHelp(helpConfig),
6018
+ new Command49("deployment").description("remove a deployed environment from its server").configureHelp(helpConfig),
5872
6019
  "production"
5873
6020
  )
5874
6021
  ).option("--purge", "also delete the database and uploaded files").option("-y, --yes", "skip the confirmation prompt").option(
@@ -5947,13 +6094,13 @@ async function confirm8(appName, targetName, byName) {
5947
6094
  }
5948
6095
 
5949
6096
  // src/commands/destroy.ts
5950
- var destroy = new Command47("destroy").description("destroy scaffolding, or a deployment").configureHelp(helpConfig).addCommand(form2).addCommand(schema2).addCommand(resource2).addCommand(scaffold2).addCommand(deployment);
6097
+ var destroy = new Command50("destroy").description("destroy scaffolding, or a deployment").configureHelp(helpConfig).addCommand(form2).addCommand(schema2).addCommand(resource2).addCommand(scaffold2).addCommand(deployment);
5951
6098
 
5952
6099
  // src/commands/ui.ts
5953
- import { Command as Command53 } from "commander";
6100
+ import { Command as Command56 } from "commander";
5954
6101
 
5955
6102
  // src/commands/ui/add.ts
5956
- import { Command as Command48 } from "commander";
6103
+ import { Command as Command51 } from "commander";
5957
6104
  import * as p29 from "@clack/prompts";
5958
6105
  import { installComponents } from "@velastack/patterns";
5959
6106
 
@@ -6003,7 +6150,7 @@ function uiAddReport(requested, outcome) {
6003
6150
  }
6004
6151
 
6005
6152
  // src/commands/ui/add.ts
6006
- var add = new Command48("add").description("add ui components (shadcn-svelte items and vela components such as data-table)").argument("<components...>", "the components to add").option("--overwrite", "replace components that already exist", false).configureHelp(helpConfig).action(
6153
+ var add = new Command51("add").description("add ui components (shadcn-svelte items and vela components such as data-table)").argument("<components...>", "the components to add").option("--overwrite", "replace components that already exist", false).configureHelp(helpConfig).action(
6007
6154
  (components, options) => runCommand(async () => {
6008
6155
  const { workspaceRootDir } = await getWorkspace();
6009
6156
  const log50 = p29.taskLog({ title: "Adding UI components..." });
@@ -6025,10 +6172,10 @@ var add = new Command48("add").description("add ui components (shadcn-svelte ite
6025
6172
  );
6026
6173
 
6027
6174
  // src/commands/ui/base.ts
6028
- import { Command as Command49 } from "commander";
6175
+ import { Command as Command52 } from "commander";
6029
6176
  import * as p30 from "@clack/prompts";
6030
6177
  import { applyBaseColor } from "@velastack/patterns";
6031
- var base = new Command49("base").description("change the base (gray) palette").argument("<color>", `base color to use (${BASE_COLORS.join(", ")})`).configureHelp(helpConfig).action(
6178
+ var base = new Command52("base").description("change the base (gray) palette").argument("<color>", `base color to use (${BASE_COLORS.join(", ")})`).configureHelp(helpConfig).action(
6032
6179
  (color) => runCommand(async () => {
6033
6180
  const { workspaceRootDir } = await getWorkspace();
6034
6181
  const log50 = p30.taskLog({ title: `Applying the ${color} palette...` });
@@ -6053,7 +6200,7 @@ var base = new Command49("base").description("change the base (gray) palette").a
6053
6200
  );
6054
6201
 
6055
6202
  // src/commands/ui/list.ts
6056
- import { Command as Command50 } from "commander";
6203
+ import { Command as Command53 } from "commander";
6057
6204
  import * as p31 from "@clack/prompts";
6058
6205
  import { listComponents } from "@velastack/patterns";
6059
6206
 
@@ -6085,7 +6232,7 @@ function uiListReport(result) {
6085
6232
  }
6086
6233
 
6087
6234
  // src/commands/ui/list.ts
6088
- var list = new Command50("list").description("list installed ui components, vela components and the style registry").option("--json", "print the result as JSON", false).configureHelp(helpConfig).action(
6235
+ var list = new Command53("list").description("list installed ui components, vela components and the style registry").option("--json", "print the result as JSON", false).configureHelp(helpConfig).action(
6089
6236
  (options) => runCommand(async () => {
6090
6237
  const { workspaceRootDir } = await getWorkspace();
6091
6238
  if (options.json) {
@@ -6112,7 +6259,7 @@ Registry components are not listed.`);
6112
6259
  );
6113
6260
 
6114
6261
  // src/commands/ui/style.ts
6115
- import { Command as Command51 } from "commander";
6262
+ import { Command as Command54 } from "commander";
6116
6263
  import * as p32 from "@clack/prompts";
6117
6264
  import { switchStyle } from "@velastack/patterns";
6118
6265
 
@@ -6139,7 +6286,7 @@ function uiStyleReport(result) {
6139
6286
  }
6140
6287
 
6141
6288
  // src/commands/ui/style.ts
6142
- var style = new Command51("style").description("switch the shadcn-svelte style, re-adding its components").argument("<style>", `style to switch to (${STYLES.join(", ")})`).option("-y, --yes", "skip the confirmation prompt").option("--no-font", "keep the current font instead of applying the style's").configureHelp(helpConfig).action(
6289
+ var style = new Command54("style").description("switch the shadcn-svelte style, re-adding its components").argument("<style>", `style to switch to (${STYLES.join(", ")})`).option("-y, --yes", "skip the confirmation prompt").option("--no-font", "keep the current font instead of applying the style's").configureHelp(helpConfig).action(
6143
6290
  (name, options) => runCommand(async () => {
6144
6291
  const { workspaceRootDir } = await getWorkspace();
6145
6292
  const spinner8 = p32.spinner();
@@ -6192,10 +6339,10 @@ ${components.map((c) => `- ${c}`).join("\n")}`
6192
6339
  );
6193
6340
 
6194
6341
  // src/commands/ui/theme.ts
6195
- import { Command as Command52 } from "commander";
6342
+ import { Command as Command55 } from "commander";
6196
6343
  import * as p33 from "@clack/prompts";
6197
6344
  import { applyTheme } from "@velastack/patterns";
6198
- var theme = new Command52("theme").description("change the accent color, keeping the base palette").argument("<accent>", `accent to use (${THEMES.join(", ")})`).configureHelp(helpConfig).action(
6345
+ var theme = new Command55("theme").description("change the accent color, keeping the base palette").argument("<accent>", `accent to use (${THEMES.join(", ")})`).configureHelp(helpConfig).action(
6199
6346
  (accent) => runCommand(async () => {
6200
6347
  const { workspaceRootDir } = await getWorkspace();
6201
6348
  const log50 = p33.taskLog({ title: `Applying the ${accent} accent...` });
@@ -6220,39 +6367,46 @@ var theme = new Command52("theme").description("change the accent color, keeping
6220
6367
  );
6221
6368
 
6222
6369
  // src/commands/ui.ts
6223
- var ui = new Command53("ui").description("generate ui components").configureHelp(helpConfig).addCommand(add).addCommand(list).addCommand(style).addCommand(base).addCommand(theme);
6370
+ var ui = new Command56("ui").description("generate ui components").configureHelp(helpConfig).addCommand(add).addCommand(list).addCommand(style).addCommand(base).addCommand(theme);
6224
6371
 
6225
6372
  // src/commands/legal.ts
6226
- import { Command as Command56 } from "commander";
6373
+ import { Command as Command59 } from "commander";
6227
6374
 
6228
6375
  // src/commands/legal/terms.ts
6229
- import fs26 from "node:fs";
6230
- import path24 from "node:path";
6231
- import { Command as Command54 } from "commander";
6376
+ import fs27 from "node:fs";
6377
+ import path25 from "node:path";
6378
+ import { Command as Command57 } from "commander";
6232
6379
  import * as p35 from "@clack/prompts";
6233
6380
 
6234
6381
  // src/commands/legal/shared.ts
6235
6382
  import process22 from "node:process";
6236
6383
  import * as p34 from "@clack/prompts";
6237
- var sharedFields = {
6238
- websiteUrl: () => p34.text({
6239
- message: "What is your website URL?",
6240
- placeholder: "http://www.mysite.com",
6241
- validate: (value) => {
6242
- if (!value || !value.startsWith("http")) {
6243
- return "Please enter a valid URL starting with http or https";
6384
+ function siteFields(site) {
6385
+ const url = site?.url && !isLocalUrl(site.url) ? site.url : void 0;
6386
+ return {
6387
+ websiteUrl: () => p34.text({
6388
+ message: "What is your website URL?",
6389
+ placeholder: "http://www.mysite.com",
6390
+ initialValue: url,
6391
+ validate: (value) => {
6392
+ if (!value || !value.startsWith("http")) {
6393
+ return "Please enter a valid URL starting with http or https";
6394
+ }
6244
6395
  }
6245
- }
6246
- }),
6247
- websiteName: () => p34.text({
6248
- message: "What is your website name?",
6249
- placeholder: "My Site",
6250
- validate: (value) => {
6251
- if (!value) {
6252
- return "Please enter a website name";
6396
+ }),
6397
+ websiteName: () => p34.text({
6398
+ message: "What is your website name?",
6399
+ placeholder: "My Site",
6400
+ initialValue: site?.name,
6401
+ validate: (value) => {
6402
+ if (!value) {
6403
+ return "Please enter a website name";
6404
+ }
6253
6405
  }
6254
- }
6255
- }),
6406
+ })
6407
+ };
6408
+ }
6409
+ var sharedFields = {
6256
6410
  entityType: () => p34.select({
6257
6411
  message: "Entity type",
6258
6412
  options: [
@@ -6761,10 +6915,11 @@ var generateTermsHtml = (answers) => {
6761
6915
  };
6762
6916
  async function termsAction() {
6763
6917
  const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
6918
+ const site = siteFields(await readSite(workspaceRootDir));
6764
6919
  const core = await p35.group(
6765
6920
  {
6766
- websiteUrl: sharedFields.websiteUrl,
6767
- websiteName: sharedFields.websiteName,
6921
+ websiteUrl: site.websiteUrl,
6922
+ websiteName: site.websiteName,
6768
6923
  entityType: sharedFields.entityType,
6769
6924
  businessName: sharedFields.businessName,
6770
6925
  businessAddress: sharedFields.businessAddress,
@@ -6886,22 +7041,22 @@ async function termsAction() {
6886
7041
  mobileApp,
6887
7042
  contact
6888
7043
  });
6889
- const termsPage = path24.join(
7044
+ const termsPage = path25.join(
6890
7045
  workspaceRootDir,
6891
7046
  publicRoutesDir,
6892
7047
  LEGAL_DIR,
6893
7048
  "terms",
6894
7049
  "+page.svelte"
6895
7050
  );
6896
- const termsPageTs = path24.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
6897
- fs26.mkdirSync(path24.dirname(termsPage), { recursive: true });
6898
- fs26.writeFileSync(termsPage, html);
6899
- fs26.writeFileSync(
7051
+ const termsPageTs = path25.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
7052
+ fs27.mkdirSync(path25.dirname(termsPage), { recursive: true });
7053
+ fs27.writeFileSync(termsPage, html);
7054
+ fs27.writeFileSync(
6900
7055
  termsPageTs,
6901
7056
  pageMetaTagsLoader("Terms of Service", `Terms of Service for ${core.websiteName}`)
6902
7057
  );
6903
- const relativeTermsPage = path24.relative(workspaceRootDir, termsPage);
6904
- const relativeTermsPageTs = path24.relative(workspaceRootDir, termsPageTs);
7058
+ const relativeTermsPage = path25.relative(workspaceRootDir, termsPage);
7059
+ const relativeTermsPageTs = path25.relative(workspaceRootDir, termsPageTs);
6905
7060
  reportResult({
6906
7061
  summary: "Generated placeholder terms and conditions.",
6907
7062
  filesCreated: [relativeTermsPage, relativeTermsPageTs],
@@ -6912,12 +7067,12 @@ async function termsAction() {
6912
7067
  ]
6913
7068
  });
6914
7069
  }
6915
- var terms = new Command54("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
7070
+ var terms = new Command57("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
6916
7071
 
6917
7072
  // src/commands/legal/privacy.ts
6918
- import fs27 from "node:fs";
6919
- import path25 from "node:path";
6920
- import { Command as Command55 } from "commander";
7073
+ import fs28 from "node:fs";
7074
+ import path26 from "node:path";
7075
+ import { Command as Command58 } from "commander";
6921
7076
  import * as p36 from "@clack/prompts";
6922
7077
  var mapLabels = {
6923
7078
  personalInfo: {
@@ -7350,10 +7505,11 @@ async function promptWithCustom(message, options, customMessage) {
7350
7505
  }
7351
7506
  async function privacyAction() {
7352
7507
  const { workspaceRootDir, publicRoutesDir } = await getWorkspace();
7508
+ const site = siteFields(await readSite(workspaceRootDir));
7353
7509
  const core = await p36.group(
7354
7510
  {
7355
- websiteUrl: sharedFields.websiteUrl,
7356
- websiteName: sharedFields.websiteName,
7511
+ websiteUrl: site.websiteUrl,
7512
+ websiteName: site.websiteName,
7357
7513
  entityType: sharedFields.entityType,
7358
7514
  businessName: sharedFields.businessName,
7359
7515
  businessAddress: sharedFields.businessAddress,
@@ -7629,28 +7785,28 @@ async function privacyAction() {
7629
7785
  kids,
7630
7786
  retention
7631
7787
  });
7632
- const privacyPage = path25.join(
7788
+ const privacyPage = path26.join(
7633
7789
  workspaceRootDir,
7634
7790
  publicRoutesDir,
7635
7791
  LEGAL_DIR,
7636
7792
  "privacy",
7637
7793
  "+page.svelte"
7638
7794
  );
7639
- const privacyPageTs = path25.join(
7795
+ const privacyPageTs = path26.join(
7640
7796
  workspaceRootDir,
7641
7797
  publicRoutesDir,
7642
7798
  LEGAL_DIR,
7643
7799
  "privacy",
7644
7800
  "+page.ts"
7645
7801
  );
7646
- fs27.mkdirSync(path25.dirname(privacyPage), { recursive: true });
7647
- fs27.writeFileSync(privacyPage, html);
7648
- fs27.writeFileSync(
7802
+ fs28.mkdirSync(path26.dirname(privacyPage), { recursive: true });
7803
+ fs28.writeFileSync(privacyPage, html);
7804
+ fs28.writeFileSync(
7649
7805
  privacyPageTs,
7650
7806
  pageMetaTagsLoader("Privacy Policy", `Privacy Policy for ${core.websiteName}`)
7651
7807
  );
7652
- const relativePrivacyPage = path25.relative(workspaceRootDir, privacyPage);
7653
- const relativePrivacyPageTs = path25.relative(workspaceRootDir, privacyPageTs);
7808
+ const relativePrivacyPage = path26.relative(workspaceRootDir, privacyPage);
7809
+ const relativePrivacyPageTs = path26.relative(workspaceRootDir, privacyPageTs);
7654
7810
  reportResult({
7655
7811
  summary: "Generated placeholder privacy policy.",
7656
7812
  filesCreated: [relativePrivacyPage, relativePrivacyPageTs],
@@ -7661,20 +7817,20 @@ async function privacyAction() {
7661
7817
  ]
7662
7818
  });
7663
7819
  }
7664
- var privacy = new Command55("privacy").description("generate placeholder privacy policy").configureHelp(helpConfig).action(() => runCommand(privacyAction, "Failed to generate privacy policy."));
7820
+ var privacy = new Command58("privacy").description("generate placeholder privacy policy").configureHelp(helpConfig).action(() => runCommand(privacyAction, "Failed to generate privacy policy."));
7665
7821
 
7666
7822
  // src/commands/legal.ts
7667
- var legal = new Command56("legal").description("generate placeholder legal documents").configureHelp(helpConfig).addCommand(terms).addCommand(privacy);
7823
+ var legal = new Command59("legal").description("generate placeholder legal documents").configureHelp(helpConfig).addCommand(terms).addCommand(privacy);
7668
7824
 
7669
7825
  // src/commands/fixtures.ts
7670
- import { Command as Command62 } from "commander";
7826
+ import { Command as Command65 } from "commander";
7671
7827
 
7672
7828
  // src/commands/fixtures/load.ts
7673
- import { Command as Command57 } from "commander";
7829
+ import { Command as Command60 } from "commander";
7674
7830
 
7675
7831
  // src/lib/data.ts
7676
- import fs28 from "node:fs";
7677
- import path26 from "node:path";
7832
+ import fs29 from "node:fs";
7833
+ import path27 from "node:path";
7678
7834
  import { ClientResponseError } from "pocketbase";
7679
7835
 
7680
7836
  // src/lib/collections.ts
@@ -7711,14 +7867,14 @@ function dependencyOrder(collections2, startingCollectionId) {
7711
7867
 
7712
7868
  // src/lib/data.ts
7713
7869
  function dataDir(cwd, kind) {
7714
- return path26.join(cwd, DATA_DIR, kind);
7870
+ return path27.join(cwd, DATA_DIR, kind);
7715
7871
  }
7716
7872
  function getDataFiles(cwd, kind) {
7717
7873
  const dir = dataDir(cwd, kind);
7718
- if (!fs28.existsSync(dir)) return [];
7719
- return fs28.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
7874
+ if (!fs29.existsSync(dir)) return [];
7875
+ return fs29.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
7720
7876
  collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
7721
- filePath: path26.join(dir, file)
7877
+ filePath: path27.join(dir, file)
7722
7878
  }));
7723
7879
  }
7724
7880
  function getSeedFiles(cwd) {
@@ -7728,7 +7884,7 @@ function getFixtureFiles(cwd) {
7728
7884
  return getDataFiles(cwd, "fixtures");
7729
7885
  }
7730
7886
  function readRecords(filePath) {
7731
- return JSON.parse(fs28.readFileSync(filePath, "utf8"));
7887
+ return JSON.parse(fs29.readFileSync(filePath, "utf8"));
7732
7888
  }
7733
7889
  function readSeedIds(cwd) {
7734
7890
  const ids = /* @__PURE__ */ new Map();
@@ -7765,7 +7921,7 @@ function describeError(e) {
7765
7921
  return e instanceof Error ? e.message : String(e);
7766
7922
  }
7767
7923
  function label3(cwd, filePath, count) {
7768
- return `${path26.relative(cwd, filePath)} (${count} records)`;
7924
+ return `${path27.relative(cwd, filePath)} (${count} records)`;
7769
7925
  }
7770
7926
  async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
7771
7927
  const records = readRecords(filePath);
@@ -7773,7 +7929,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
7773
7929
  try {
7774
7930
  await pb.collection(collectionName).create(record);
7775
7931
  } catch (e) {
7776
- throw new DataLoadError(kind, path26.relative(cwd, filePath), index, e);
7932
+ throw new DataLoadError(kind, path27.relative(cwd, filePath), index, e);
7777
7933
  }
7778
7934
  }
7779
7935
  return records.length;
@@ -7860,7 +8016,7 @@ async function hasLoadedFixtures(pb) {
7860
8016
  }
7861
8017
 
7862
8018
  // src/commands/fixtures/load.ts
7863
- var load = new Command57("load").description("load fixtures into the database").configureHelp(helpConfig).action(
8019
+ var load = new Command60("load").description("load fixtures into the database").configureHelp(helpConfig).action(
7864
8020
  () => runCommand(async () => {
7865
8021
  const { workspaceRootDir } = await getWorkspace();
7866
8022
  let loaded = [];
@@ -7886,8 +8042,8 @@ var load = new Command57("load").description("load fixtures into the database").
7886
8042
  );
7887
8043
 
7888
8044
  // src/commands/fixtures/clear.ts
7889
- import { Command as Command58 } from "commander";
7890
- var clear = new Command58("clear").description("clear loaded fixtures").configureHelp(helpConfig).action(
8045
+ import { Command as Command61 } from "commander";
8046
+ var clear = new Command61("clear").description("clear loaded fixtures").configureHelp(helpConfig).action(
7891
8047
  () => runCommand(async () => {
7892
8048
  const { workspaceRootDir } = await getWorkspace();
7893
8049
  let cleared = [];
@@ -7916,8 +8072,8 @@ var clear = new Command58("clear").description("clear loaded fixtures").configur
7916
8072
  );
7917
8073
 
7918
8074
  // src/commands/fixtures/reset.ts
7919
- import { Command as Command59 } from "commander";
7920
- var reset = new Command59("reset").description("clear and reload fixtures").configureHelp(helpConfig).action(
8075
+ import { Command as Command62 } from "commander";
8076
+ var reset = new Command62("reset").description("clear and reload fixtures").configureHelp(helpConfig).action(
7921
8077
  () => runCommand(async () => {
7922
8078
  const { workspaceRootDir } = await getWorkspace();
7923
8079
  let cleared = [];
@@ -7947,9 +8103,9 @@ var reset = new Command59("reset").description("clear and reload fixtures").conf
7947
8103
  );
7948
8104
 
7949
8105
  // src/commands/fixtures/generate.ts
7950
- import fs29 from "node:fs";
7951
- import path27 from "node:path";
7952
- import { Command as Command60, InvalidArgumentError } from "commander";
8106
+ import fs30 from "node:fs";
8107
+ import path28 from "node:path";
8108
+ import { Command as Command63, InvalidArgumentError } from "commander";
7953
8109
  import * as p37 from "@clack/prompts";
7954
8110
  import { annotate } from "annotate-json-schema";
7955
8111
  import { createGenerator } from "json-schema-faker";
@@ -7985,9 +8141,9 @@ async function loadCollections(pb) {
7985
8141
  }
7986
8142
  async function generateFixtureFiles(pb, workspaceRootDir, opts) {
7987
8143
  const fixturesDir = dataDir(workspaceRootDir, "fixtures");
7988
- fs29.mkdirSync(fixturesDir, { recursive: true });
7989
- for (const file of fs29.readdirSync(fixturesDir)) {
7990
- if (file.endsWith(".json")) fs29.unlinkSync(path27.join(fixturesDir, file));
8144
+ fs30.mkdirSync(fixturesDir, { recursive: true });
8145
+ for (const file of fs30.readdirSync(fixturesDir)) {
8146
+ if (file.endsWith(".json")) fs30.unlinkSync(path28.join(fixturesDir, file));
7991
8147
  }
7992
8148
  if (opts.seed !== void 0) faker.seed(opts.seed);
7993
8149
  const generator = createGenerator({
@@ -8054,13 +8210,13 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
8054
8210
  items.push(record);
8055
8211
  }
8056
8212
  const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
8057
- fs29.writeFileSync(path27.join(fixturesDir, filename), JSON.stringify(items, null, 2));
8058
- writtenFiles.push(`${path27.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
8213
+ fs30.writeFileSync(path28.join(fixturesDir, filename), JSON.stringify(items, null, 2));
8214
+ writtenFiles.push(`${path28.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
8059
8215
  fileIndex++;
8060
8216
  }
8061
8217
  return { writtenFiles, warnings };
8062
8218
  }
8063
- var generate2 = new Command60("generate").description("generate fixture data").option("-c, --count <count>", "number of records per collection", parseCount, 10).option("-s, --seed <seed>", "seed for deterministic output", parseSeed).option("-f, --force", "overwrite existing fixture files and clear loaded fixtures").configureHelp(helpConfig).action(
8219
+ var generate2 = new Command63("generate").description("generate fixture data").option("-c, --count <count>", "number of records per collection", parseCount, 10).option("-s, --seed <seed>", "seed for deterministic output", parseSeed).option("-f, --force", "overwrite existing fixture files and clear loaded fixtures").configureHelp(helpConfig).action(
8064
8220
  (opts) => runCommand(async () => {
8065
8221
  const { workspaceRootDir } = await getWorkspace();
8066
8222
  const existing = getFixtureFiles(workspaceRootDir);
@@ -8113,7 +8269,7 @@ var generate2 = new Command60("generate").description("generate fixture data").o
8113
8269
  );
8114
8270
 
8115
8271
  // src/commands/fixtures/regen.ts
8116
- import { Command as Command61, InvalidArgumentError as InvalidArgumentError2 } from "commander";
8272
+ import { Command as Command64, InvalidArgumentError as InvalidArgumentError2 } from "commander";
8117
8273
  import * as p38 from "@clack/prompts";
8118
8274
  function parseCount2(value) {
8119
8275
  const n = parseInt(value, 10);
@@ -8129,7 +8285,7 @@ function parseSeed2(value) {
8129
8285
  }
8130
8286
  return n;
8131
8287
  }
8132
- var regen = new Command61("regen").description("clear the database, regenerate fixture files, and reload them").option("-c, --count <count>", "number of records per collection", parseCount2, 10).option("-s, --seed <seed>", "seed for deterministic output", parseSeed2).configureHelp(helpConfig).action(
8288
+ var regen = new Command64("regen").description("clear the database, regenerate fixture files, and reload them").option("-c, --count <count>", "number of records per collection", parseCount2, 10).option("-s, --seed <seed>", "seed for deterministic output", parseSeed2).configureHelp(helpConfig).action(
8133
8289
  (opts) => runCommand(async () => {
8134
8290
  const { workspaceRootDir } = await getWorkspace();
8135
8291
  let cleared = [];
@@ -8158,14 +8314,14 @@ var regen = new Command61("regen").description("clear the database, regenerate f
8158
8314
  );
8159
8315
 
8160
8316
  // src/commands/fixtures.ts
8161
- var fixtures = new Command62("fixtures").description("manage fixture data").configureHelp(helpConfig).addCommand(generate2).addCommand(load).addCommand(clear).addCommand(reset).addCommand(regen);
8317
+ var fixtures = new Command65("fixtures").description("manage fixture data").configureHelp(helpConfig).addCommand(generate2).addCommand(load).addCommand(clear).addCommand(reset).addCommand(regen);
8162
8318
 
8163
8319
  // src/commands/seeds.ts
8164
- import { Command as Command66 } from "commander";
8320
+ import { Command as Command69 } from "commander";
8165
8321
 
8166
8322
  // src/commands/seeds/load.ts
8167
- import { Command as Command63 } from "commander";
8168
- var load2 = new Command63("load").description("load seeds into the database").option("-f, --force", "load even if target collections already have records").configureHelp(helpConfig).action(
8323
+ import { Command as Command66 } from "commander";
8324
+ var load2 = new Command66("load").description("load seeds into the database").option("-f, --force", "load even if target collections already have records").configureHelp(helpConfig).action(
8169
8325
  (opts) => runCommand(async () => {
8170
8326
  const { workspaceRootDir } = await getWorkspace();
8171
8327
  const seedFiles = getSeedFiles(workspaceRootDir);
@@ -8202,9 +8358,9 @@ var load2 = new Command63("load").description("load seeds into the database").op
8202
8358
  );
8203
8359
 
8204
8360
  // src/commands/seeds/save.ts
8205
- import fs30 from "node:fs";
8206
- import path28 from "node:path";
8207
- import { Command as Command64 } from "commander";
8361
+ import fs31 from "node:fs";
8362
+ import path29 from "node:path";
8363
+ import { Command as Command67 } from "commander";
8208
8364
  var padZeros2 = (num, length) => num.toString().padStart(length, "0");
8209
8365
  function filterSystemFields(record, systemFieldNames) {
8210
8366
  const out = {};
@@ -8215,7 +8371,7 @@ function filterSystemFields(record, systemFieldNames) {
8215
8371
  }
8216
8372
  return out;
8217
8373
  }
8218
- var save = new Command64("save").description("save the current data as seeds").option("-f, --force", "overwrite existing seed files").configureHelp(helpConfig).action(
8374
+ var save = new Command67("save").description("save the current data as seeds").option("-f, --force", "overwrite existing seed files").configureHelp(helpConfig).action(
8219
8375
  (opts) => runCommand(async () => {
8220
8376
  const { workspaceRootDir } = await getWorkspace();
8221
8377
  const seedsPath = dataDir(workspaceRootDir, "seeds");
@@ -8223,10 +8379,10 @@ var save = new Command64("save").description("save the current data as seeds").o
8223
8379
  if (existing.length > 0 && !opts.force) {
8224
8380
  throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
8225
8381
  }
8226
- fs30.mkdirSync(seedsPath, { recursive: true });
8382
+ fs31.mkdirSync(seedsPath, { recursive: true });
8227
8383
  if (opts.force) {
8228
- for (const file of fs30.readdirSync(seedsPath)) {
8229
- if (file.endsWith(".json")) fs30.unlinkSync(path28.join(seedsPath, file));
8384
+ for (const file of fs31.readdirSync(seedsPath)) {
8385
+ if (file.endsWith(".json")) fs31.unlinkSync(path29.join(seedsPath, file));
8230
8386
  }
8231
8387
  }
8232
8388
  const saved = [];
@@ -8255,13 +8411,13 @@ var save = new Command64("save").description("save the current data as seeds").o
8255
8411
  const filtered = records.map(
8256
8412
  (r) => filterSystemFields(r, systemFieldNames)
8257
8413
  );
8258
- const relativeSeedPath = path28.join(
8414
+ const relativeSeedPath = path29.join(
8259
8415
  DATA_DIR,
8260
8416
  "seeds",
8261
8417
  `${padZeros2(count, 2)}-${collectionName}.json`
8262
8418
  );
8263
- const seedPath = path28.join(workspaceRootDir, relativeSeedPath);
8264
- fs30.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
8419
+ const seedPath = path29.join(workspaceRootDir, relativeSeedPath);
8420
+ fs31.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
8265
8421
  saved.push(`${relativeSeedPath} (${filtered.length} records)`);
8266
8422
  count++;
8267
8423
  }
@@ -8287,8 +8443,8 @@ var save = new Command64("save").description("save the current data as seeds").o
8287
8443
  );
8288
8444
 
8289
8445
  // src/commands/seeds/clear.ts
8290
- import { Command as Command65 } from "commander";
8291
- var clear2 = new Command65("clear").description("clear seeded records").configureHelp(helpConfig).action(
8446
+ import { Command as Command68 } from "commander";
8447
+ var clear2 = new Command68("clear").description("clear seeded records").configureHelp(helpConfig).action(
8292
8448
  () => runCommand(async () => {
8293
8449
  const { workspaceRootDir } = await getWorkspace();
8294
8450
  const seedFiles = getSeedFiles(workspaceRootDir);
@@ -8319,20 +8475,20 @@ var clear2 = new Command65("clear").description("clear seeded records").configur
8319
8475
  );
8320
8476
 
8321
8477
  // src/commands/seeds.ts
8322
- var seeds = new Command66("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
8478
+ var seeds = new Command69("seeds").description("manage seed data").configureHelp(helpConfig).addCommand(load2).addCommand(save).addCommand(clear2);
8323
8479
 
8324
8480
  // src/commands/signup.ts
8325
- import { Command as Command67 } from "commander";
8481
+ import { Command as Command70 } from "commander";
8326
8482
  import * as p39 from "@clack/prompts";
8327
8483
  import makeFetchCookie2 from "fetch-cookie";
8328
- var signup = new Command67("signup").description("signup to velastack.dev").configureHelp(helpConfig).action(
8484
+ var signup = new Command70("signup").description("signup to velastack.dev").configureHelp(helpConfig).action(
8329
8485
  () => runCommand(async () => {
8330
- const { email: email3, password: password11, passwordConfirm } = await p39.group({
8486
+ const { email: email3, password: password12, passwordConfirm } = await p39.group({
8331
8487
  email: () => p39.text({ message: "Email" }),
8332
8488
  password: () => p39.password({ message: "Password" }),
8333
8489
  passwordConfirm: () => p39.password({ message: "Confirm password" })
8334
8490
  });
8335
- if (password11 !== passwordConfirm) {
8491
+ if (password12 !== passwordConfirm) {
8336
8492
  throw new Error("Passwords do not match.");
8337
8493
  }
8338
8494
  const fetchCookie = makeFetchCookie2(fetch);
@@ -8345,7 +8501,7 @@ var signup = new Command67("signup").description("signup to velastack.dev").conf
8345
8501
  body: new URLSearchParams({
8346
8502
  type: "password",
8347
8503
  email: email3,
8348
- password: password11,
8504
+ password: password12,
8349
8505
  passwordConfirm
8350
8506
  }).toString()
8351
8507
  });
@@ -8360,9 +8516,9 @@ var signup = new Command67("signup").description("signup to velastack.dev").conf
8360
8516
  );
8361
8517
 
8362
8518
  // src/commands/logout.ts
8363
- import { Command as Command68 } from "commander";
8519
+ import { Command as Command71 } from "commander";
8364
8520
  import * as p40 from "@clack/prompts";
8365
- var logout = new Command68("logout").alias("signout").description("logout from velastack.dev").configureHelp(helpConfig).action(
8521
+ var logout = new Command71("logout").alias("signout").description("logout from velastack.dev").configureHelp(helpConfig).action(
8366
8522
  () => runCommand(() => {
8367
8523
  if (!readConfig()) {
8368
8524
  p40.log.info("Not logged in");
@@ -8374,9 +8530,9 @@ var logout = new Command68("logout").alias("signout").description("logout from v
8374
8530
  );
8375
8531
 
8376
8532
  // src/commands/whoami.ts
8377
- import { Command as Command69 } from "commander";
8533
+ import { Command as Command72 } from "commander";
8378
8534
  import * as p41 from "@clack/prompts";
8379
- var whoami = new Command69("whoami").description("show the current user").configureHelp(helpConfig).action(
8535
+ var whoami = new Command72("whoami").description("show the current user").configureHelp(helpConfig).action(
8380
8536
  () => runCommand(async () => {
8381
8537
  const apiKey = readConfig()?.apiKey;
8382
8538
  if (!apiKey) {
@@ -8393,13 +8549,13 @@ var whoami = new Command69("whoami").description("show the current user").config
8393
8549
  );
8394
8550
 
8395
8551
  // src/commands/migrate.ts
8396
- import { Command as Command75 } from "commander";
8552
+ import { Command as Command78 } from "commander";
8397
8553
 
8398
8554
  // src/commands/migrate/up.ts
8399
- import { Command as Command70 } from "commander";
8555
+ import { Command as Command73 } from "commander";
8400
8556
 
8401
8557
  // src/lib/migrate.ts
8402
- import path29 from "node:path";
8558
+ import path30 from "node:path";
8403
8559
  import process23 from "node:process";
8404
8560
  import { x as x2 } from "tinyexec";
8405
8561
  async function runPocketbaseMigrate(args) {
@@ -8410,9 +8566,9 @@ async function runPocketbaseMigrate(args) {
8410
8566
  binaryPath,
8411
8567
  [
8412
8568
  "--dir",
8413
- path29.join(cwd, DATA_DIR),
8569
+ path30.join(cwd, DATA_DIR),
8414
8570
  "--migrationsDir",
8415
- path29.join(cwd, MIGRATIONS_DIR),
8571
+ path30.join(cwd, MIGRATIONS_DIR),
8416
8572
  "migrate",
8417
8573
  ...args
8418
8574
  ],
@@ -8435,10 +8591,10 @@ async function runMigrateUp() {
8435
8591
  ]
8436
8592
  });
8437
8593
  }
8438
- var up = new Command70("up").description("apply all pending migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations."));
8594
+ var up = new Command73("up").description("apply all pending migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations."));
8439
8595
 
8440
8596
  // src/commands/migrate/down.ts
8441
- import { Command as Command71, InvalidArgumentError as InvalidArgumentError3 } from "commander";
8597
+ import { Command as Command74, InvalidArgumentError as InvalidArgumentError3 } from "commander";
8442
8598
  function parseSteps(value) {
8443
8599
  const n = parseInt(value, 10);
8444
8600
  if (!Number.isFinite(n) || n <= 0) {
@@ -8446,7 +8602,7 @@ function parseSteps(value) {
8446
8602
  }
8447
8603
  return n;
8448
8604
  }
8449
- var down = new Command71("down").alias("rollback").description("revert the last N applied migrations").argument("[number]", "how many migrations to revert", parseSteps, 1).configureHelp(helpConfig).action(
8605
+ var down = new Command74("down").alias("rollback").description("revert the last N applied migrations").argument("[number]", "how many migrations to revert", parseSteps, 1).configureHelp(helpConfig).action(
8450
8606
  (n) => runCommand(async () => {
8451
8607
  await runPocketbaseMigrate(["down", String(n)]);
8452
8608
  reportResult({
@@ -8460,11 +8616,11 @@ var down = new Command71("down").alias("rollback").description("revert the last
8460
8616
  );
8461
8617
 
8462
8618
  // src/commands/migrate/create.ts
8463
- import fs31 from "node:fs";
8464
- import path30 from "node:path";
8619
+ import fs32 from "node:fs";
8620
+ import path31 from "node:path";
8465
8621
  import process24 from "node:process";
8466
- import { Command as Command72 } from "commander";
8467
- var create2 = new Command72("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
8622
+ import { Command as Command75 } from "commander";
8623
+ var create2 = new Command75("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
8468
8624
  (name) => runCommand(async () => {
8469
8625
  const cwd = process24.cwd();
8470
8626
  const before = listMigrationFiles(cwd);
@@ -8473,7 +8629,7 @@ var create2 = new Command72("create").alias("new").description("create a new bla
8473
8629
  const added = [...after].filter((f) => !before.has(f));
8474
8630
  reportResult({
8475
8631
  summary: `Created blank migration ${name}.`,
8476
- filesCreated: added.map((f) => path30.join(MIGRATIONS_DIR, f)),
8632
+ filesCreated: added.map((f) => path31.join(MIGRATIONS_DIR, f)),
8477
8633
  nextSteps: [
8478
8634
  `Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
8479
8635
  "Run `vela migrate up` to apply the migration once the handlers are written."
@@ -8482,17 +8638,17 @@ var create2 = new Command72("create").alias("new").description("create a new bla
8482
8638
  }, "Failed to create migration.")
8483
8639
  );
8484
8640
  function listMigrationFiles(cwd) {
8485
- const dir = path30.join(cwd, MIGRATIONS_DIR);
8486
- if (!fs31.existsSync(dir)) return /* @__PURE__ */ new Set();
8487
- return new Set(fs31.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
8641
+ const dir = path31.join(cwd, MIGRATIONS_DIR);
8642
+ if (!fs32.existsSync(dir)) return /* @__PURE__ */ new Set();
8643
+ return new Set(fs32.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
8488
8644
  }
8489
8645
 
8490
8646
  // src/commands/migrate/collections.ts
8491
- import fs32 from "node:fs";
8492
- import path31 from "node:path";
8647
+ import fs33 from "node:fs";
8648
+ import path32 from "node:path";
8493
8649
  import process25 from "node:process";
8494
- import { Command as Command73 } from "commander";
8495
- var collections = new Command73("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
8650
+ import { Command as Command76 } from "commander";
8651
+ var collections = new Command76("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
8496
8652
  () => runCommand(async () => {
8497
8653
  const cwd = process25.cwd();
8498
8654
  const before = listMigrationFiles2(cwd);
@@ -8507,7 +8663,7 @@ var collections = new Command73("collections").alias("snapshot").description("sn
8507
8663
  }
8508
8664
  reportResult({
8509
8665
  summary: "Snapshotted local collections into a new migration.",
8510
- filesCreated: added.map((f) => path31.join(MIGRATIONS_DIR, f)),
8666
+ filesCreated: added.map((f) => path32.join(MIGRATIONS_DIR, f)),
8511
8667
  nextSteps: [
8512
8668
  `Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
8513
8669
  "Commit the snapshot so teammates pick up the new schema.",
@@ -8517,14 +8673,14 @@ var collections = new Command73("collections").alias("snapshot").description("sn
8517
8673
  }, "Failed to snapshot collections.")
8518
8674
  );
8519
8675
  function listMigrationFiles2(cwd) {
8520
- const dir = path31.join(cwd, MIGRATIONS_DIR);
8521
- if (!fs32.existsSync(dir)) return /* @__PURE__ */ new Set();
8522
- return new Set(fs32.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
8676
+ const dir = path32.join(cwd, MIGRATIONS_DIR);
8677
+ if (!fs33.existsSync(dir)) return /* @__PURE__ */ new Set();
8678
+ return new Set(fs33.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
8523
8679
  }
8524
8680
 
8525
8681
  // src/commands/migrate/history-sync.ts
8526
- import { Command as Command74 } from "commander";
8527
- var historySync = new Command74("history-sync").description("drop _migrations rows whose files no longer exist").configureHelp(helpConfig).action(
8682
+ import { Command as Command77 } from "commander";
8683
+ var historySync = new Command77("history-sync").description("drop _migrations rows whose files no longer exist").configureHelp(helpConfig).action(
8528
8684
  () => runCommand(async () => {
8529
8685
  await runPocketbaseMigrate(["history-sync"]);
8530
8686
  reportResult({
@@ -8535,14 +8691,14 @@ var historySync = new Command74("history-sync").description("drop _migrations ro
8535
8691
  );
8536
8692
 
8537
8693
  // src/commands/migrate.ts
8538
- var migrate = new Command75("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
8694
+ var migrate = new Command78("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
8539
8695
 
8540
8696
  // src/commands/dev.ts
8541
- import fs33 from "node:fs";
8542
- import path33 from "node:path";
8697
+ import fs34 from "node:fs";
8698
+ import path34 from "node:path";
8543
8699
  import process27 from "node:process";
8544
8700
  import { performance } from "node:perf_hooks";
8545
- import { Command as Command76, InvalidArgumentError as InvalidArgumentError4 } from "commander";
8701
+ import { Command as Command79, InvalidArgumentError as InvalidArgumentError4 } from "commander";
8546
8702
  import pc15 from "picocolors";
8547
8703
  import PocketBase4 from "pocketbase";
8548
8704
 
@@ -8571,7 +8727,7 @@ function createPocketbaseLogFilter() {
8571
8727
  }
8572
8728
 
8573
8729
  // src/lib/vite.ts
8574
- import path32 from "node:path";
8730
+ import path33 from "node:path";
8575
8731
  import process26 from "node:process";
8576
8732
  import { createRequire as createRequire2 } from "node:module";
8577
8733
  import { pathToFileURL as pathToFileURL2 } from "node:url";
@@ -8591,7 +8747,7 @@ function viteVersionError(version) {
8591
8747
  }
8592
8748
  function resolveProjectVite(cwd) {
8593
8749
  try {
8594
- return createRequire2(path32.join(cwd, "package.json")).resolve("vite");
8750
+ return createRequire2(path33.join(cwd, "package.json")).resolve("vite");
8595
8751
  } catch {
8596
8752
  return null;
8597
8753
  }
@@ -8615,26 +8771,26 @@ function parsePort(value) {
8615
8771
  }
8616
8772
  return port;
8617
8773
  }
8618
- var dev = new Command76("dev").description("start the development server").option("--open [path]", "open the app in a browser once the server is ready").option("--host [host]", "expose the server on the network").option("--port <port>", "port to listen on", parsePort).option("--strictPort", "exit if the port is already in use instead of taking the next one").option("--cors", "enable CORS").option("--force", "re-bundle dependencies, ignoring the optimizer cache").option("--all-sql", "also print the auth lookup PocketBase runs on every request").configureHelp(helpConfig).action(async (options) => {
8774
+ var dev = new Command79("dev").description("start the development server").option("--open [path]", "open the app in a browser once the server is ready").option("--host [host]", "expose the server on the network").option("--port <port>", "port to listen on", parsePort).option("--strictPort", "exit if the port is already in use instead of taking the next one").option("--cors", "enable CORS").option("--force", "re-bundle dependencies, ignoring the optimizer cache").option("--all-sql", "also print the auth lookup PocketBase runs on every request").configureHelp(helpConfig).action(async (options) => {
8619
8775
  const cwd = process27.cwd();
8620
8776
  process27.env.VELA_DATA_DIR ??= localDataDir(cwd);
8621
8777
  const startTime = performance.now();
8622
8778
  const { createServer, version } = await loadVite(cwd);
8623
- const viteMetadataDir = path33.join(cwd, "node_modules", ".vite");
8624
- const viteMetadataFile = path33.join(viteMetadataDir, "_pocketbase_metadata.json");
8779
+ const viteMetadataDir = path34.join(cwd, "node_modules", ".vite");
8780
+ const viteMetadataFile = path34.join(viteMetadataDir, "_pocketbase_metadata.json");
8625
8781
  let pbProc;
8626
8782
  const backend3 = hasBackend(cwd);
8627
8783
  const needsStart = backend3 && !process27.env.POCKETBASE_URL;
8628
8784
  const cleanup = () => {
8629
8785
  if (pbProc?.pid) pbProc.kill();
8630
- if (fs33.existsSync(viteMetadataFile)) fs33.rmSync(viteMetadataFile);
8786
+ if (fs34.existsSync(viteMetadataFile)) fs34.rmSync(viteMetadataFile);
8631
8787
  };
8632
8788
  if (needsStart) {
8633
- const dataDir2 = path33.join(cwd, DATA_DIR);
8789
+ const dataDir2 = path34.join(cwd, DATA_DIR);
8634
8790
  const started = await startPocketbaseServe({
8635
8791
  dataDir: dataDir2,
8636
8792
  migrationsDir: MIGRATIONS_DIR,
8637
- hooksDir: path33.join(dataDir2, "hooks"),
8793
+ hooksDir: path34.join(dataDir2, "hooks"),
8638
8794
  dev: true,
8639
8795
  stdio: "pipe"
8640
8796
  });
@@ -8666,8 +8822,8 @@ var dev = new Command76("dev").description("start the development server").optio
8666
8822
  if (!backend3) return;
8667
8823
  const { address, port: vitePort } = server.httpServer.address();
8668
8824
  const viteHost = address === "::1" ? "localhost" : address;
8669
- await fs33.promises.mkdir(viteMetadataDir, { recursive: true });
8670
- await fs33.promises.writeFile(
8825
+ await fs34.promises.mkdir(viteMetadataDir, { recursive: true });
8826
+ await fs34.promises.writeFile(
8671
8827
  viteMetadataFile,
8672
8828
  JSON.stringify({
8673
8829
  pocketbaseUrl: process27.env.POCKETBASE_URL,
@@ -8680,7 +8836,20 @@ var dev = new Command76("dev").description("start the development server").optio
8680
8836
  process27.env.POCKETBASE_SUPERUSER_EMAIL,
8681
8837
  process27.env.POCKETBASE_SUPERUSER_PASSWORD
8682
8838
  );
8683
- await pb.settings.update({ meta: { appURL: `http://${viteHost}:${vitePort}` } });
8839
+ const site = await readSite(cwd);
8840
+ await pb.settings.update({
8841
+ meta: {
8842
+ appURL: `http://${viteHost}:${vitePort}`,
8843
+ ...site?.name && { appName: site.name }
8844
+ }
8845
+ });
8846
+ if (!site?.name) {
8847
+ console.log(
8848
+ pc15.dim(
8849
+ `No app name in ${SITE_FILE}, so PocketBase keeps the one it has. Add \`export const site = { name: '\u2026', url: '\u2026' }\` there to set it from code.`
8850
+ )
8851
+ );
8852
+ }
8684
8853
  await startWatchingTypes(cwd, pb);
8685
8854
  });
8686
8855
  await server.listen();
@@ -8699,18 +8868,18 @@ var dev = new Command76("dev").description("start the development server").optio
8699
8868
  });
8700
8869
  async function startWatchingTypes(cwd, pb) {
8701
8870
  const { processTypes } = await import("@velastack/pocketbase-codegen");
8702
- const typesDir = path33.resolve(cwd, ".svelte-kit", "types");
8703
- const pocketbaseDir = path33.join(typesDir, "pocketbase");
8704
- const pocketbaseTypes = path33.join(pocketbaseDir, "$types.d.ts");
8871
+ const typesDir = path34.resolve(cwd, ".svelte-kit", "types");
8872
+ const pocketbaseDir = path34.join(typesDir, "pocketbase");
8873
+ const pocketbaseTypes = path34.join(pocketbaseDir, "$types.d.ts");
8705
8874
  const regenerate = () => processTypes(pb, typesDir).catch(() => {
8706
8875
  });
8707
8876
  await regenerate();
8708
8877
  void (async () => {
8709
8878
  for (; ; ) {
8710
8879
  try {
8711
- await fs33.promises.mkdir(pocketbaseDir, { recursive: true });
8712
- for await (const event of fs33.promises.watch(pocketbaseDir)) {
8713
- if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs33.existsSync(pocketbaseTypes)) {
8880
+ await fs34.promises.mkdir(pocketbaseDir, { recursive: true });
8881
+ for await (const event of fs34.promises.watch(pocketbaseDir)) {
8882
+ if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs34.existsSync(pocketbaseTypes)) {
8714
8883
  setTimeout(regenerate, 100);
8715
8884
  }
8716
8885
  }
@@ -8722,10 +8891,10 @@ async function startWatchingTypes(cwd, pb) {
8722
8891
  }
8723
8892
 
8724
8893
  // src/commands/build.ts
8725
- import fs34 from "node:fs";
8726
- import path34 from "node:path";
8894
+ import fs35 from "node:fs";
8895
+ import path35 from "node:path";
8727
8896
  import process29 from "node:process";
8728
- import { Command as Command77 } from "commander";
8897
+ import { Command as Command80 } from "commander";
8729
8898
  import * as p42 from "@clack/prompts";
8730
8899
  import pc16 from "picocolors";
8731
8900
  import { x as x3 } from "tinyexec";
@@ -8761,8 +8930,8 @@ function splitHosts(value) {
8761
8930
  }
8762
8931
 
8763
8932
  // src/commands/build.ts
8764
- var PRERENDERED_DIR = path34.join(".svelte-kit", "output", "prerendered");
8765
- var build = new Command77("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
8933
+ var PRERENDERED_DIR = path35.join(".svelte-kit", "output", "prerendered");
8934
+ var build = new Command80("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
8766
8935
  const cwd = process29.cwd();
8767
8936
  applyBuildEnv(cwd);
8768
8937
  const origin = await originForBuild(cwd, options.target);
@@ -8774,11 +8943,11 @@ var build = new Command77("build").description("build the app").configureHelp(he
8774
8943
  };
8775
8944
  if (needsStart) {
8776
8945
  await ensureSuperuser(cwd);
8777
- const dataDir2 = path34.join(cwd, DATA_DIR);
8946
+ const dataDir2 = path35.join(cwd, DATA_DIR);
8778
8947
  const started = await startPocketbaseServe({
8779
8948
  dataDir: dataDir2,
8780
8949
  migrationsDir: MIGRATIONS_DIR,
8781
- hooksDir: path34.join(dataDir2, "hooks"),
8950
+ hooksDir: path35.join(dataDir2, "hooks"),
8782
8951
  dev: true
8783
8952
  });
8784
8953
  pbProc = started.proc;
@@ -8817,24 +8986,26 @@ async function originForBuild(cwd, target) {
8817
8986
  }
8818
8987
  }
8819
8988
  function warnIfPrerendered(cwd) {
8820
- const dir = path34.join(cwd, PRERENDERED_DIR);
8821
- if (!fs34.existsSync(dir) || fs34.readdirSync(dir).length === 0) return;
8989
+ const dir = path35.join(cwd, PRERENDERED_DIR);
8990
+ if (!fs35.existsSync(dir) || fs35.readdirSync(dir).length === 0) return;
8822
8991
  p42.log.warn(
8823
- `Prerendered pages were built with no domain configured, so their canonical
8824
- links point at SvelteKit's placeholder host rather than at this site.
8992
+ `Prerendered pages were built with no domain configured, so anything they take
8993
+ from the request's origin points at SvelteKit's placeholder host rather than at
8994
+ this site. Links built from ${pc16.cyan("src/lib/site.ts")}, as the templates' canonical
8995
+ links are, don't depend on it.
8825
8996
 
8826
8997
  Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cyan("VELA_ORIGIN")}.`
8827
8998
  );
8828
8999
  }
8829
9000
 
8830
9001
  // src/commands/preview.ts
8831
- import path35 from "node:path";
9002
+ import path36 from "node:path";
8832
9003
  import process30 from "node:process";
8833
- import { Command as Command78 } from "commander";
9004
+ import { Command as Command81 } from "commander";
8834
9005
  import { x as x4 } from "tinyexec";
8835
9006
  import { detect as detect6 } from "package-manager-detector";
8836
9007
  import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
8837
- var preview = new Command78("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
9008
+ var preview = new Command81("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
8838
9009
  const cwd = process30.cwd();
8839
9010
  process30.env.VELA_DATA_DIR ??= localDataDir(cwd);
8840
9011
  let pbProc;
@@ -8843,11 +9014,11 @@ var preview = new Command78("preview").description("preview the built app").conf
8843
9014
  if (pbProc?.pid) pbProc.kill();
8844
9015
  };
8845
9016
  if (needsStart) {
8846
- const dataDir2 = path35.join(cwd, DATA_DIR);
9017
+ const dataDir2 = path36.join(cwd, DATA_DIR);
8847
9018
  const started = await startPocketbaseServe({
8848
9019
  dataDir: dataDir2,
8849
9020
  migrationsDir: MIGRATIONS_DIR,
8850
- hooksDir: path35.join(dataDir2, "hooks"),
9021
+ hooksDir: path36.join(dataDir2, "hooks"),
8851
9022
  dev: true
8852
9023
  });
8853
9024
  pbProc = started.proc;
@@ -8873,12 +9044,12 @@ var preview = new Command78("preview").description("preview the built app").conf
8873
9044
  });
8874
9045
 
8875
9046
  // src/commands/sync.ts
8876
- import path36 from "node:path";
8877
- import { Command as Command79 } from "commander";
8878
- var sync = new Command79("sync").description("sync types from the database").configureHelp(helpConfig).action(
9047
+ import path37 from "node:path";
9048
+ import { Command as Command82 } from "commander";
9049
+ var sync = new Command82("sync").description("sync types from the database").configureHelp(helpConfig).action(
8879
9050
  () => runCommand(async () => {
8880
9051
  const { workspaceRootDir } = await getWorkspace();
8881
- const typesDir = path36.join(workspaceRootDir, ".svelte-kit", "types");
9052
+ const typesDir = path37.join(workspaceRootDir, ".svelte-kit", "types");
8882
9053
  const { processTypes } = await import("@velastack/pocketbase-codegen");
8883
9054
  await withPocketbase(workspaceRootDir, async (pb) => {
8884
9055
  await processTypes(pb, typesDir);
@@ -8888,7 +9059,7 @@ var sync = new Command79("sync").description("sync types from the database").con
8888
9059
  );
8889
9060
 
8890
9061
  // src/commands/provision.ts
8891
- import { Command as Command80 } from "commander";
9062
+ import { Command as Command83 } from "commander";
8892
9063
  import * as p43 from "@clack/prompts";
8893
9064
  import pc17 from "picocolors";
8894
9065
  import * as v7 from "valibot";
@@ -8898,7 +9069,7 @@ var OptionsSchema2 = v7.object({
8898
9069
  nodeMajor: v7.optional(v7.string())
8899
9070
  });
8900
9071
  var provision = addSshOptions(
8901
- new Command80("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
9072
+ new Command83("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
8902
9073
  ).option("--pb-version <version>", "PocketBase version to install").option("--node-major <version>", "Node.js major version to install", "22").action(
8903
9074
  (target, raw) => runCommand(async () => {
8904
9075
  const options = parseOptions(OptionsSchema2, raw);
@@ -8940,35 +9111,35 @@ var provision = addSshOptions(
8940
9111
  );
8941
9112
 
8942
9113
  // src/commands/deploy.ts
8943
- import path39 from "node:path";
8944
- import fs37 from "node:fs";
8945
- import { Command as Command81, Option as Option2 } from "commander";
9114
+ import path40 from "node:path";
9115
+ import fs38 from "node:fs";
9116
+ import { Command as Command84, Option as Option2 } from "commander";
8946
9117
  import * as p44 from "@clack/prompts";
8947
9118
  import pc18 from "picocolors";
8948
9119
  import * as v8 from "valibot";
8949
9120
 
8950
9121
  // src/lib/pocketbase-settings.ts
8951
- import fs35 from "node:fs";
8952
- import path37 from "node:path";
9122
+ import fs36 from "node:fs";
9123
+ import path38 from "node:path";
8953
9124
  import process31 from "node:process";
8954
9125
  import PocketBase5 from "pocketbase";
8955
- var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
9126
+ var COPIED_KEYS = ["senderName", "senderAddress"];
8956
9127
  async function readLocalMeta(cwd) {
8957
- const dataDir2 = path37.join(cwd, DATA_DIR);
8958
- if (!fs35.existsSync(dataDir2)) return null;
9128
+ const dataDir2 = path38.join(cwd, DATA_DIR);
9129
+ if (!fs36.existsSync(dataDir2)) return null;
8959
9130
  const email3 = process31.env.POCKETBASE_SUPERUSER_EMAIL;
8960
- const password11 = process31.env.POCKETBASE_SUPERUSER_PASSWORD;
8961
- if (!email3 || !password11) return null;
9131
+ const password12 = process31.env.POCKETBASE_SUPERUSER_PASSWORD;
9132
+ if (!email3 || !password12) return null;
8962
9133
  let proc;
8963
9134
  try {
8964
9135
  const started = await startPocketbaseServe({
8965
9136
  dataDir: dataDir2,
8966
9137
  migrationsDir: MIGRATIONS_DIR,
8967
- hooksDir: path37.join(dataDir2, "hooks")
9138
+ hooksDir: path38.join(dataDir2, "hooks")
8968
9139
  });
8969
9140
  proc = started.proc;
8970
9141
  const pb = new PocketBase5(started.url);
8971
- await authWithRetries(pb, email3, password11);
9142
+ await authWithRetries(pb, email3, password12);
8972
9143
  const settings = await pb.settings.getAll();
8973
9144
  return settings.meta ?? null;
8974
9145
  } catch {
@@ -8977,37 +9148,39 @@ async function readLocalMeta(cwd) {
8977
9148
  proc?.kill();
8978
9149
  }
8979
9150
  }
8980
- async function readRemoteAppURL(session, instance) {
8981
- try {
8982
- let appURL = null;
8983
- await withRemotePocketbase(session, instance, async (pb) => {
8984
- const settings = await pb.settings.getAll();
8985
- const value = settings.meta?.appURL;
8986
- appURL = typeof value === "string" && value.trim() ? value : null;
8987
- });
8988
- return appURL;
8989
- } catch {
8990
- return null;
8991
- }
8992
- }
8993
- async function seedRemoteMeta(session, instance, local, appURL) {
8994
- const patch = {};
9151
+ function copiedMeta(local) {
9152
+ const copied = {};
8995
9153
  for (const key of COPIED_KEYS) {
8996
- const value = local[key];
8997
- if (typeof value === "string" && value.trim()) patch[key] = value;
9154
+ const value = local?.[key];
9155
+ if (typeof value === "string" && value.trim()) copied[key] = value;
8998
9156
  }
8999
- if (appURL) patch.appURL = appURL;
9000
- if (Object.keys(patch).length === 0) return [];
9157
+ return copied;
9158
+ }
9159
+ async function syncRemoteMeta(session, instance, patch) {
9160
+ const wanted = Object.fromEntries(
9161
+ Object.entries(patch).filter(([, value]) => typeof value === "string" && value.trim())
9162
+ );
9163
+ let written = [];
9164
+ let appURL = null;
9001
9165
  await withRemotePocketbase(session, instance, async (pb) => {
9002
9166
  const settings = await pb.settings.getAll();
9003
- await pb.settings.update({ meta: { ...settings.meta ?? {}, ...patch } });
9167
+ const meta = settings.meta ?? {};
9168
+ const changed = Object.fromEntries(
9169
+ Object.entries(wanted).filter(([key, value2]) => meta[key] !== value2)
9170
+ );
9171
+ written = Object.keys(changed);
9172
+ if (written.length > 0) {
9173
+ await pb.settings.update({ meta: { ...meta, ...changed } });
9174
+ }
9175
+ const value = { ...meta, ...changed }.appURL;
9176
+ appURL = typeof value === "string" && value.trim() ? value : null;
9004
9177
  });
9005
- return Object.keys(patch);
9178
+ return { written, appURL };
9006
9179
  }
9007
9180
 
9008
9181
  // src/lib/adapter.ts
9009
- import fs36 from "node:fs";
9010
- import path38 from "node:path";
9182
+ import fs37 from "node:fs";
9183
+ import path39 from "node:path";
9011
9184
  import {
9012
9185
  Project as Project2,
9013
9186
  QuoteKind as QuoteKind2,
@@ -9063,7 +9236,7 @@ function resolveKitTarget(root) {
9063
9236
  }
9064
9237
  const sveltePath = probeFirstExisting(root, SVELTE_CONFIG_CANDIDATES);
9065
9238
  if (sveltePath) {
9066
- const name = path38.basename(sveltePath);
9239
+ const name = path39.basename(sveltePath);
9067
9240
  if (sveltePath.endsWith(".cjs")) {
9068
9241
  throw new AdapterError(`${name} is CommonJS, which vela does not edit.`);
9069
9242
  }
@@ -9083,7 +9256,7 @@ function resolveKitTarget(root) {
9083
9256
  };
9084
9257
  }
9085
9258
  if (vite?.sveltekitCall) {
9086
- const name = path38.basename(vite.filePath);
9259
+ const name = path39.basename(vite.filePath);
9087
9260
  if (vite.nonObjectArg) {
9088
9261
  throw new AdapterError(`${name} passes sveltekit() something other than an object literal.`);
9089
9262
  }
@@ -9136,7 +9309,7 @@ function inspectAdapter(target) {
9136
9309
  async function ensureNodeAdapter(root, { install = true } = {}) {
9137
9310
  const target = resolveKitTarget(root);
9138
9311
  const { info, importDecl } = inspectAdapter(target);
9139
- const name = path38.basename(target.filePath);
9312
+ const name = path39.basename(target.filePath);
9140
9313
  const outcome = {
9141
9314
  previous: info.kind,
9142
9315
  removedDeps: [],
@@ -9169,8 +9342,8 @@ vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}:`
9169
9342
  break;
9170
9343
  }
9171
9344
  if (outcome.configFile) saveTarget(target);
9172
- const pkgPath = path38.join(root, "package.json");
9173
- if (fs36.existsSync(pkgPath)) {
9345
+ const pkgPath = path39.join(root, "package.json");
9346
+ if (fs37.existsSync(pkgPath)) {
9174
9347
  const pkg = readPackageJson(pkgPath);
9175
9348
  const { changed, removed } = adoptNodeAdapter(pkg);
9176
9349
  if (changed) {
@@ -9222,7 +9395,7 @@ function addAdapter(target) {
9222
9395
  const taken = importOf(target.sourceFile, "adapter") ?? target.sourceFile.getVariableDeclaration("adapter");
9223
9396
  if (taken) {
9224
9397
  throw new AdapterError(
9225
- `${path38.basename(target.filePath)} already binds the name \`adapter\` to something that is not the SvelteKit adapter.`
9398
+ `${path39.basename(target.filePath)} already binds the name \`adapter\` to something that is not the SvelteKit adapter.`
9226
9399
  );
9227
9400
  }
9228
9401
  target.sourceFile.addImportDeclaration({
@@ -9286,13 +9459,13 @@ var OptionsSchema3 = v8.object({
9286
9459
  });
9287
9460
  var deploy = addLockWaitOption(
9288
9461
  addTargetOptions(
9289
- new Command81("deploy").description("deploy the app").configureHelp(helpConfig),
9462
+ new Command84("deploy").description("deploy the app").configureHelp(helpConfig),
9290
9463
  "production"
9291
9464
  )
9292
9465
  ).option("--project <name>", "override the project name").option("--domain <hosts>", "hostname(s) to serve on, comma separated").option("--health-path <path>", "path the health check requests").option("--keep <count>", "how many old releases to keep on the server").option("--pb-version <version>", "PocketBase version to run").option("--no-build", "deploy the existing build output without rebuilding").addOption(
9293
9466
  new Option2(
9294
9467
  "--remote-db",
9295
- "render the build against the database on the server, over an SSH tunnel \u2014 on by default once the target has been deployed to"
9468
+ "render the build against the database on the server, over an SSH tunnel \u2014 on by default once the target has been deployed to with a backend"
9296
9469
  ).default(void 0)
9297
9470
  ).addOption(
9298
9471
  new Option2("--no-remote-db", "render the build against a throwaway local database").default(
@@ -9450,12 +9623,14 @@ ${pc18.dim(String(err))}`
9450
9623
  if (managed && managed !== existing?.managed) {
9451
9624
  p44.log.info(`${pc18.cyan(managed)} goes live within a minute.`);
9452
9625
  }
9626
+ const site = await readSite(workspaceRootDir);
9453
9627
  if (result?.superuserCreated) {
9454
- await copyLocalBranding(
9628
+ await seedNewDatabase(
9455
9629
  session,
9456
9630
  instance,
9457
9631
  workspaceRootDir,
9458
- primaryHost ? result?.url ?? "" : ""
9632
+ primaryHost ? result?.url ?? "" : "",
9633
+ site?.name
9459
9634
  );
9460
9635
  p44.log.info(
9461
9636
  `Created the PocketBase superuser this app authenticates as.
@@ -9464,9 +9639,10 @@ Its credentials are stored in the environment on the server. To use
9464
9639
  your own instead, ${pc18.cyan("vela env set POCKETBASE_SUPERUSER_PASSWORD")}
9465
9640
  and deploy again.`
9466
9641
  );
9467
- } else if (backend3 && primaryHost) {
9468
- await reportAppURLDrift(session, instance, primaryHost);
9642
+ } else if (backend3) {
9643
+ await syncAppName(session, instance, site?.name, primaryHost);
9469
9644
  }
9645
+ reportSiteUrl(site?.url, primaryUrl, isPreview2);
9470
9646
  if (!primaryHost) {
9471
9647
  p44.log.warn(
9472
9648
  `No domain configured, so nothing is proxied to this app yet.
@@ -9513,40 +9689,65 @@ ${pc18.cyan(err.snippet)}` : err.message);
9513
9689
  }
9514
9690
  p44.log.warn(`Commit ${changed.join(", ")} so every deploy builds the same way.`);
9515
9691
  }
9516
- async function reportAppURLDrift(session, instance, domain) {
9692
+ async function syncAppName(session, instance, appName, domain) {
9693
+ if (!appName && !domain) return;
9694
+ let result;
9695
+ try {
9696
+ result = await syncRemoteMeta(session, instance, { appName });
9697
+ } catch (err) {
9698
+ if (appName) {
9699
+ p44.log.warn(
9700
+ `Could not set this app's name in its PocketBase settings, which its emails use.
9701
+ ${pc18.dim(String(err))}`
9702
+ );
9703
+ }
9704
+ return;
9705
+ }
9706
+ if (result.written.length > 0) {
9707
+ p44.log.success(`Named the app ${pc18.cyan(appName ?? "")} in PocketBase, from ${SITE_FILE}`);
9708
+ }
9517
9709
  const expected = normalizeOrigin(domain);
9518
- if (!expected) return;
9519
- const current = await readRemoteAppURL(session, instance);
9520
- if (!current || normalizeOrigin(current) === expected) return;
9710
+ if (!expected || !result.appURL || normalizeOrigin(result.appURL) === expected) return;
9521
9711
  p44.log.warn(
9522
- `This app's PocketBase ${pc18.cyan("appURL")} is ${pc18.dim(current)}, but it is served on ${pc18.dim(expected)}.
9712
+ `This app's PocketBase ${pc18.cyan("appURL")} is ${pc18.dim(result.appURL)}, but it is served on ${pc18.dim(expected)}.
9523
9713
 
9524
9714
  Emails and anything else PocketBase links to will use the former. Update it in
9525
9715
  the admin panel if that is not deliberate.`
9526
9716
  );
9527
9717
  }
9528
- async function copyLocalBranding(session, instance, workspaceRootDir, appURL) {
9718
+ async function seedNewDatabase(session, instance, workspaceRootDir, appURL, appName) {
9529
9719
  const local = await readLocalMeta(workspaceRootDir);
9530
- if (!local) return;
9531
9720
  try {
9532
- const copied = await seedRemoteMeta(session, instance, local, appURL);
9533
- if (copied.length === 0) return;
9534
- const outcome = await restartInstance(session, instance);
9535
- if (outcome.deployed && !outcome.restarted) {
9536
- p44.log.warn(
9537
- `Copied ${copied.join(", ")}, but the app did not restart to pick them up.
9538
- ${pc18.dim(outcome.error ?? "")}`
9539
- );
9540
- return;
9541
- }
9542
- p44.log.success(`Copied ${copied.join(", ")} from this project's database`);
9721
+ const { written } = await syncRemoteMeta(session, instance, {
9722
+ ...copiedMeta(local),
9723
+ appURL,
9724
+ appName
9725
+ });
9726
+ if (written.length > 0) p44.log.success(`Set ${written.join(", ")} in the new database`);
9543
9727
  } catch (err) {
9544
9728
  p44.log.warn(
9545
- `Could not copy this project's PocketBase settings across.
9546
- Set them in the admin panel instead. ${pc18.dim(String(err))}`
9729
+ `Could not set up this app's PocketBase settings.
9730
+ Set its name and sender in the admin panel instead. ${pc18.dim(String(err))}`
9547
9731
  );
9548
9732
  }
9549
9733
  }
9734
+ function reportSiteUrl(url, primaryUrl, isPreview2) {
9735
+ const expected = normalizeOrigin(primaryUrl);
9736
+ if (!url || !expected) return;
9737
+ if (isLocalUrl(url)) {
9738
+ p44.log.warn(
9739
+ `${SITE_FILE} still says the site is at ${pc18.dim(url)}. Canonical links, Open Graph
9740
+ images and feeds are built from it; set ${pc18.cyan("url")} to ${pc18.cyan(expected)} and deploy again.`
9741
+ );
9742
+ return;
9743
+ }
9744
+ if (isPreview2 || normalizeOrigin(url) === expected) return;
9745
+ p44.log.warn(
9746
+ `${SITE_FILE} says the site is at ${pc18.dim(url)}, but this deploy serves ${pc18.dim(expected)}.
9747
+ Canonical links, Open Graph images and feeds point at the former. Update ${pc18.cyan("url")}
9748
+ if that is not deliberate.`
9749
+ );
9750
+ }
9550
9751
  async function openDatabaseTunnel(session, instance, state) {
9551
9752
  const pbPort = instanceHasBackend(state) ? state?.pbPort : void 0;
9552
9753
  if (!pbPort) {
@@ -9558,8 +9759,8 @@ Deploy once without it, then turn it on.`
9558
9759
  }
9559
9760
  const remoteEnv = await readRemoteEnv(session, instance);
9560
9761
  const email3 = remoteEnv.POCKETBASE_SUPERUSER_EMAIL;
9561
- const password11 = remoteEnv.POCKETBASE_SUPERUSER_PASSWORD;
9562
- if (!email3 || !password11) {
9762
+ const password12 = remoteEnv.POCKETBASE_SUPERUSER_PASSWORD;
9763
+ if (!email3 || !password12) {
9563
9764
  throw new Error(
9564
9765
  `--remote-db renders the build as the superuser of ${instance}, and that environment has no credentials for one.
9565
9766
 
@@ -9568,7 +9769,7 @@ Set them with \`vela env set POCKETBASE_SUPERUSER_EMAIL\` and \`vela env set POC
9568
9769
  }
9569
9770
  const localPort = await findFreePort("127.0.0.1");
9570
9771
  await session.forwardLocalPort(localPort, "127.0.0.1", pbPort);
9571
- if (!await superuserAuthenticates(localPort, email3, password11)) {
9772
+ if (!await superuserAuthenticates(localPort, email3, password12)) {
9572
9773
  await session.cancelForward(localPort, "127.0.0.1", pbPort);
9573
9774
  throw new Error(
9574
9775
  `${instance} does not accept the superuser credentials in its own environment.
@@ -9589,19 +9790,19 @@ or build against a throwaway local database instead:
9589
9790
  env: {
9590
9791
  POCKETBASE_URL: `http://127.0.0.1:${localPort}`,
9591
9792
  POCKETBASE_SUPERUSER_EMAIL: email3,
9592
- POCKETBASE_SUPERUSER_PASSWORD: password11
9793
+ POCKETBASE_SUPERUSER_PASSWORD: password12
9593
9794
  },
9594
9795
  close: () => session.cancelForward(localPort, "127.0.0.1", pbPort)
9595
9796
  };
9596
9797
  }
9597
- async function superuserAuthenticates(port, identity, password11) {
9798
+ async function superuserAuthenticates(port, identity, password12) {
9598
9799
  try {
9599
9800
  const response = await fetch(
9600
9801
  `http://127.0.0.1:${port}/api/collections/_superusers/auth-with-password`,
9601
9802
  {
9602
9803
  method: "POST",
9603
9804
  headers: { "content-type": "application/json" },
9604
- body: JSON.stringify({ identity, password: password11 })
9805
+ body: JSON.stringify({ identity, password: password12 })
9605
9806
  }
9606
9807
  );
9607
9808
  return response.ok;
@@ -9625,7 +9826,7 @@ async function uploadRelease(session, instance, release, entries) {
9625
9826
  }
9626
9827
  function isDirectory(target) {
9627
9828
  try {
9628
- return fs37.statSync(target).isDirectory();
9829
+ return fs38.statSync(target).isDirectory();
9629
9830
  } catch {
9630
9831
  return false;
9631
9832
  }
@@ -9633,7 +9834,7 @@ function isDirectory(target) {
9633
9834
  async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
9634
9835
  const remote = await readRemoteEnv(session, instance);
9635
9836
  if (Object.keys(remote).length > 0) return;
9636
- if (!fs37.existsSync(path39.join(workspaceRootDir, ".env"))) return;
9837
+ if (!fs38.existsSync(path40.join(workspaceRootDir, ".env"))) return;
9637
9838
  p44.log.warn(
9638
9839
  `This app has no production environment variables yet.
9639
9840
 
@@ -9651,12 +9852,12 @@ async function serverTimeOrLocal(session) {
9651
9852
  }
9652
9853
 
9653
9854
  // src/commands/link.ts
9654
- import path40 from "node:path";
9855
+ import path41 from "node:path";
9655
9856
  import process32 from "node:process";
9656
- import { Command as Command82 } from "commander";
9857
+ import { Command as Command85 } from "commander";
9657
9858
  import * as p45 from "@clack/prompts";
9658
9859
  var CREATE_NEW = "__new__";
9659
- var link = new Command82("link").description("link this project to a velastack.dev project").configureHelp(helpConfig).action(() => runCommand(linkProject, "Failed to link the project."));
9860
+ var link = new Command85("link").description("link this project to a velastack.dev project").configureHelp(helpConfig).action(() => runCommand(linkProject, "Failed to link the project."));
9660
9861
  async function linkProject() {
9661
9862
  const { workspaceRootDir } = await getWorkspace();
9662
9863
  const existing = readProjectConfig(workspaceRootDir);
@@ -9714,23 +9915,23 @@ async function promptProjectName(workspaceRootDir) {
9714
9915
  }
9715
9916
  function defaultProjectName2(workspaceRootDir) {
9716
9917
  try {
9717
- const pkg = readPackageJson(path40.join(workspaceRootDir, "package.json"));
9918
+ const pkg = readPackageJson(path41.join(workspaceRootDir, "package.json"));
9718
9919
  const name = pkg.name;
9719
9920
  if (typeof name === "string" && name.trim()) return name.trim();
9720
9921
  } catch {
9721
9922
  }
9722
- return path40.basename(workspaceRootDir);
9923
+ return path41.basename(workspaceRootDir);
9723
9924
  }
9724
9925
 
9725
9926
  // src/commands/env.ts
9726
- import { Command as Command87 } from "commander";
9927
+ import { Command as Command90 } from "commander";
9727
9928
 
9728
9929
  // src/commands/env/list.ts
9729
- import { Command as Command83 } from "commander";
9930
+ import { Command as Command86 } from "commander";
9730
9931
  import * as p46 from "@clack/prompts";
9731
9932
  import pc19 from "picocolors";
9732
9933
  var envList = addTargetOptions(
9733
- new Command83("list").description("list environment variable names").configureHelp(helpConfig),
9934
+ new Command86("list").description("list environment variable names").configureHelp(helpConfig),
9734
9935
  "local"
9735
9936
  ).action(
9736
9937
  (raw) => runCommand(
@@ -9764,11 +9965,11 @@ function report(keys, where) {
9764
9965
 
9765
9966
  // src/commands/env/set.ts
9766
9967
  import process33 from "node:process";
9767
- import { Command as Command84 } from "commander";
9968
+ import { Command as Command87 } from "commander";
9768
9969
  import * as p47 from "@clack/prompts";
9769
9970
  import pc20 from "picocolors";
9770
9971
  var envSet = addTargetOptions(
9771
- new Command84("set").description("set an environment variable").argument("<key>", "variable name").argument("[value]", "value \u2014 prompted for, without echo, when omitted").configureHelp(helpConfig),
9972
+ new Command87("set").description("set an environment variable").argument("<key>", "variable name").argument("[value]", "value \u2014 prompted for, without echo, when omitted").configureHelp(helpConfig),
9772
9973
  "local"
9773
9974
  ).action(
9774
9975
  (key, value, raw) => runCommand(
@@ -9811,11 +10012,11 @@ async function promptValue(key) {
9811
10012
  }
9812
10013
 
9813
10014
  // src/commands/env/unset.ts
9814
- import { Command as Command85 } from "commander";
10015
+ import { Command as Command88 } from "commander";
9815
10016
  import * as p48 from "@clack/prompts";
9816
10017
  import pc21 from "picocolors";
9817
10018
  var envUnset = addTargetOptions(
9818
- new Command85("unset").description("remove an environment variable").argument("<key>", "variable name").configureHelp(helpConfig),
10019
+ new Command88("unset").description("remove an environment variable").argument("<key>", "variable name").configureHelp(helpConfig),
9819
10020
  "local"
9820
10021
  ).action(
9821
10022
  (key, raw) => runCommand(
@@ -9850,14 +10051,14 @@ var envUnset = addTargetOptions(
9850
10051
  );
9851
10052
 
9852
10053
  // src/commands/env/import.ts
9853
- import fs38 from "node:fs";
9854
- import path41 from "node:path";
10054
+ import fs39 from "node:fs";
10055
+ import path42 from "node:path";
9855
10056
  import process34 from "node:process";
9856
- import { Command as Command86 } from "commander";
10057
+ import { Command as Command89 } from "commander";
9857
10058
  import * as p49 from "@clack/prompts";
9858
10059
  import pc22 from "picocolors";
9859
10060
  var envImport = addTargetOptions(
9860
- new Command86("import").description("merge a dotenv file into the environment").argument("<file>", "dotenv file to read").configureHelp(helpConfig),
10061
+ new Command89("import").description("merge a dotenv file into the environment").argument("<file>", "dotenv file to read").configureHelp(helpConfig),
9861
10062
  "local"
9862
10063
  ).action(
9863
10064
  (file, raw) => runCommand(
@@ -9897,24 +10098,24 @@ var envImport = addTargetOptions(
9897
10098
  )
9898
10099
  );
9899
10100
  function resolve(file) {
9900
- return path41.resolve(process34.cwd(), file);
10101
+ return path42.resolve(process34.cwd(), file);
9901
10102
  }
9902
10103
  function read(resolved, shown) {
9903
- if (!fs38.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
10104
+ if (!fs39.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
9904
10105
  const incoming = readLocalEnvFile(resolved);
9905
10106
  if (Object.keys(incoming).length === 0) p49.log.info(`${shown} has no variables to import.`);
9906
10107
  return incoming;
9907
10108
  }
9908
10109
 
9909
10110
  // src/commands/env.ts
9910
- var env = new Command87("env").description("manage environment variables, locally or on a target").configureHelp(helpConfig).addCommand(envList).addCommand(envSet).addCommand(envUnset).addCommand(envImport);
10111
+ var env = new Command90("env").description("manage environment variables, locally or on a target").configureHelp(helpConfig).addCommand(envList).addCommand(envSet).addCommand(envUnset).addCommand(envImport);
9911
10112
 
9912
10113
  // src/commands/status.ts
9913
- import { Command as Command88 } from "commander";
10114
+ import { Command as Command91 } from "commander";
9914
10115
  import * as p50 from "@clack/prompts";
9915
10116
  import pc23 from "picocolors";
9916
10117
  var status = addTargetOptions(
9917
- new Command88("status").description("show what is deployed").configureHelp(helpConfig),
10118
+ new Command91("status").description("show what is deployed").configureHelp(helpConfig),
9918
10119
  "production"
9919
10120
  ).option("--all", "show every app on the server, not just this project").option("--json", "print raw JSON").action(
9920
10121
  (raw) => runCommand(async () => {
@@ -9973,12 +10174,12 @@ function describe2(state) {
9973
10174
  }
9974
10175
 
9975
10176
  // src/commands/rollback.ts
9976
- import { Command as Command89 } from "commander";
10177
+ import { Command as Command92 } from "commander";
9977
10178
  import * as p51 from "@clack/prompts";
9978
10179
  import pc24 from "picocolors";
9979
10180
  var rollback = addLockWaitOption(
9980
10181
  addTargetOptions(
9981
- new Command89("rollback").description("put the previous release back").configureHelp(helpConfig),
10182
+ new Command92("rollback").description("put the previous release back").configureHelp(helpConfig),
9982
10183
  "production"
9983
10184
  )
9984
10185
  ).option("--to <release>", "roll back to a specific release instead of the previous one").action(
@@ -10017,9 +10218,9 @@ var rollback = addLockWaitOption(
10017
10218
  );
10018
10219
 
10019
10220
  // src/commands/logs.ts
10020
- import { Command as Command90 } from "commander";
10221
+ import { Command as Command93 } from "commander";
10021
10222
  var logs = addTargetOptions(
10022
- new Command90("logs").description("tail the logs of a deployed app").configureHelp(helpConfig),
10223
+ new Command93("logs").description("tail the logs of a deployed app").configureHelp(helpConfig),
10023
10224
  "production"
10024
10225
  ).option("-f, --follow", "keep streaming new output").option("-n, --lines <count>", "how many lines of history to show", "100").option("--pocketbase", "show the PocketBase service instead of the app").action(
10025
10226
  (raw) => runCommand(async () => {
@@ -10053,16 +10254,16 @@ var logs = addTargetOptions(
10053
10254
  );
10054
10255
 
10055
10256
  // src/commands/admin.ts
10056
- import { Command as Command92 } from "commander";
10257
+ import { Command as Command95 } from "commander";
10057
10258
 
10058
10259
  // src/commands/admin/create.ts
10059
10260
  import process35 from "node:process";
10060
- import { Command as Command91 } from "commander";
10261
+ import { Command as Command94 } from "commander";
10061
10262
  import * as p52 from "@clack/prompts";
10062
10263
  import pc25 from "picocolors";
10063
10264
  var MIN_PASSWORD = 10;
10064
10265
  var adminCreate = addTargetOptions(
10065
- new Command91("create").description("create a login for the admin panel").argument("[email]", "email to sign in with \u2014 prompted for when omitted").configureHelp(helpConfig),
10266
+ new Command94("create").description("create a login for the admin panel").argument("[email]", "email to sign in with \u2014 prompted for when omitted").configureHelp(helpConfig),
10066
10267
  "local"
10067
10268
  ).action(
10068
10269
  (email3, raw) => runCommand(
@@ -10072,12 +10273,12 @@ var adminCreate = addTargetOptions(
10072
10273
  local: async (ctx) => {
10073
10274
  const creds = readLocalEnv(ctx.envFile);
10074
10275
  const address = email3 ?? await promptEmail();
10075
- const password11 = await promptPassword2();
10276
+ const password12 = await promptPassword2();
10076
10277
  let signIn = "";
10077
10278
  await withPocketbase(
10078
10279
  ctx.workspaceRootDir,
10079
10280
  async (pb) => {
10080
- await upsertSuperuser(pb, address, password11);
10281
+ await upsertSuperuser(pb, address, password12);
10081
10282
  const settings = await pb.settings.getAll();
10082
10283
  signIn = settings.meta?.appURL ?? "";
10083
10284
  },
@@ -10096,12 +10297,12 @@ var adminCreate = addTargetOptions(
10096
10297
  },
10097
10298
  remote: async (ctx) => {
10098
10299
  const address = email3 ?? await promptEmail();
10099
- const password11 = await promptPassword2();
10300
+ const password12 = await promptPassword2();
10100
10301
  const [state] = await readInstanceStates(ctx.session, ctx.instance);
10101
10302
  await withRemotePocketbase(
10102
10303
  ctx.session,
10103
10304
  ctx.instance,
10104
- (pb) => upsertSuperuser(pb, address, password11)
10305
+ (pb) => upsertSuperuser(pb, address, password12)
10105
10306
  );
10106
10307
  const base2 = state?.domain ? `https://${state.domain.split(",")[0].trim()}` : "";
10107
10308
  p52.log.info(
@@ -10114,7 +10315,7 @@ var adminCreate = addTargetOptions(
10114
10315
  "Failed to create the admin login."
10115
10316
  )
10116
10317
  );
10117
- async function upsertSuperuser(pb, email3, password11) {
10318
+ async function upsertSuperuser(pb, email3, password12) {
10118
10319
  const existing = await findSuperuser(pb, email3);
10119
10320
  if (existing) {
10120
10321
  const confirmed = await p52.confirm({
@@ -10125,11 +10326,11 @@ async function upsertSuperuser(pb, email3, password11) {
10125
10326
  p52.cancel("Operation cancelled.");
10126
10327
  process35.exit(0);
10127
10328
  }
10128
- await pb.collection("_superusers").update(existing, { password: password11, passwordConfirm: password11 });
10329
+ await pb.collection("_superusers").update(existing, { password: password12, passwordConfirm: password12 });
10129
10330
  p52.log.success(`Password updated for ${pc25.cyan(email3)}, you can sign in now`);
10130
10331
  return;
10131
10332
  }
10132
- await pb.collection("_superusers").create({ email: email3, password: password11, passwordConfirm: password11 });
10333
+ await pb.collection("_superusers").create({ email: email3, password: password12, passwordConfirm: password12 });
10133
10334
  p52.log.success(`${pc25.cyan(email3)} can now sign in`);
10134
10335
  }
10135
10336
  async function findSuperuser(pb, email3) {
@@ -10172,15 +10373,15 @@ async function promptPassword2() {
10172
10373
  }
10173
10374
 
10174
10375
  // src/commands/admin.ts
10175
- var admin = new Command92("admin").description("manage admin panel logins").configureHelp(helpConfig).addCommand(adminCreate);
10376
+ var admin = new Command95("admin").description("manage admin panel logins").configureHelp(helpConfig).addCommand(adminCreate);
10176
10377
 
10177
10378
  // src/commands/backup.ts
10178
- import { Command as Command98 } from "commander";
10379
+ import { Command as Command101 } from "commander";
10179
10380
 
10180
10381
  // src/commands/backup/create.ts
10181
- import fs39 from "node:fs";
10182
- import path42 from "node:path";
10183
- import { Command as Command93 } from "commander";
10382
+ import fs40 from "node:fs";
10383
+ import path43 from "node:path";
10384
+ import { Command as Command96 } from "commander";
10184
10385
  import * as p53 from "@clack/prompts";
10185
10386
  import pc26 from "picocolors";
10186
10387
 
@@ -10269,7 +10470,7 @@ async function writeSchedule(pb, cron, maxKeep) {
10269
10470
  // src/commands/backup/create.ts
10270
10471
  var DEFAULT_BACKUP_DIR = "backups";
10271
10472
  var backupCreate = addTargetOptions(
10272
- new Command93("create").description("take a backup of the database and uploads").argument("[name]", "name for the archive \u2014 generated when omitted").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).option("--no-download", "leave the archive on the server").configureHelp(helpConfig),
10473
+ new Command96("create").description("take a backup of the database and uploads").argument("[name]", "name for the archive \u2014 generated when omitted").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).option("--no-download", "leave the archive on the server").configureHelp(helpConfig),
10273
10474
  "production"
10274
10475
  ).action(
10275
10476
  (name, raw) => runCommand(() => {
@@ -10333,12 +10534,12 @@ Your bucket's own versioning is what protects the uploaded files.`
10333
10534
  }, "Failed to create the backup.")
10334
10535
  );
10335
10536
  async function download(ctx, key, outputDir) {
10336
- const dir = path42.resolve(ctx.workspaceRootDir, outputDir);
10337
- fs39.mkdirSync(dir, { recursive: true });
10338
- const destination = path42.join(dir, key);
10537
+ const dir = path43.resolve(ctx.workspaceRootDir, outputDir);
10538
+ fs40.mkdirSync(dir, { recursive: true });
10539
+ const destination = path43.join(dir, key);
10339
10540
  if (!ctx.session) {
10340
- fs39.copyFileSync(path42.join(ctx.workspaceRootDir, "data", "backups", key), destination);
10341
- return path42.relative(ctx.workspaceRootDir, destination);
10541
+ fs40.copyFileSync(path43.join(ctx.workspaceRootDir, "data", "backups", key), destination);
10542
+ return path43.relative(ctx.workspaceRootDir, destination);
10342
10543
  }
10343
10544
  const spinner8 = p53.spinner();
10344
10545
  spinner8.start(`Downloading ${key}`);
@@ -10349,15 +10550,15 @@ async function download(ctx, key, outputDir) {
10349
10550
  throw error;
10350
10551
  }
10351
10552
  spinner8.stop(`Downloaded ${key}`);
10352
- return path42.relative(ctx.workspaceRootDir, destination);
10553
+ return path43.relative(ctx.workspaceRootDir, destination);
10353
10554
  }
10354
10555
 
10355
10556
  // src/commands/backup/list.ts
10356
- import { Command as Command94 } from "commander";
10557
+ import { Command as Command97 } from "commander";
10357
10558
  import * as p54 from "@clack/prompts";
10358
10559
  import pc27 from "picocolors";
10359
10560
  var backupList = addTargetOptions(
10360
- new Command94("list").description("list the backups on a target").configureHelp(helpConfig),
10561
+ new Command97("list").description("list the backups on a target").configureHelp(helpConfig),
10361
10562
  "production"
10362
10563
  ).action(
10363
10564
  (raw) => runCommand(
@@ -10383,13 +10584,13 @@ Take one with ${pc27.cyan("vela backup create")}.`
10383
10584
  );
10384
10585
 
10385
10586
  // src/commands/backup/download.ts
10386
- import fs40 from "node:fs";
10387
- import path43 from "node:path";
10388
- import { Command as Command95 } from "commander";
10587
+ import fs41 from "node:fs";
10588
+ import path44 from "node:path";
10589
+ import { Command as Command98 } from "commander";
10389
10590
  import * as p55 from "@clack/prompts";
10390
10591
  import pc28 from "picocolors";
10391
10592
  var backupDownload = addTargetOptions(
10392
- new Command95("download").description("save a backup off the server").argument("<key>", "archive to download, as shown by `vela backup list`").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).configureHelp(helpConfig),
10593
+ new Command98("download").description("save a backup off the server").argument("<key>", "archive to download, as shown by `vela backup list`").option("-o, --output <dir>", "where to save the archive", DEFAULT_BACKUP_DIR).configureHelp(helpConfig),
10393
10594
  "production"
10394
10595
  ).action(
10395
10596
  (key, raw) => runCommand(() => {
@@ -10411,11 +10612,11 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
10411
10612
  Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
10412
10613
  );
10413
10614
  }
10414
- const dir = path43.resolve(ctx.workspaceRootDir, options.output);
10415
- fs40.mkdirSync(dir, { recursive: true });
10416
- const destination = path43.join(dir, key);
10615
+ const dir = path44.resolve(ctx.workspaceRootDir, options.output);
10616
+ fs41.mkdirSync(dir, { recursive: true });
10617
+ const destination = path44.join(dir, key);
10417
10618
  if (!ctx.session) {
10418
- fs40.copyFileSync(path43.join(ctx.workspaceRootDir, "data", "backups", key), destination);
10619
+ fs41.copyFileSync(path44.join(ctx.workspaceRootDir, "data", "backups", key), destination);
10419
10620
  } else {
10420
10621
  const spinner8 = p55.spinner();
10421
10622
  spinner8.start(`Downloading ${key} (${formatBytes(found.size)})`);
@@ -10429,7 +10630,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
10429
10630
  }
10430
10631
  reportResult({
10431
10632
  summary: `Saved ${key} from ${ctx.targetName}.`,
10432
- filesCreated: [path43.relative(ctx.workspaceRootDir, destination)]
10633
+ filesCreated: [path44.relative(ctx.workspaceRootDir, destination)]
10433
10634
  });
10434
10635
  });
10435
10636
  }, "Failed to download the backup.")
@@ -10437,11 +10638,11 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
10437
10638
 
10438
10639
  // src/commands/backup/delete.ts
10439
10640
  import process36 from "node:process";
10440
- import { Command as Command96 } from "commander";
10641
+ import { Command as Command99 } from "commander";
10441
10642
  import * as p56 from "@clack/prompts";
10442
10643
  import pc29 from "picocolors";
10443
10644
  var backupDelete = addTargetOptions(
10444
- new Command96("delete").description("remove a backup from a target").argument("<key>", "archive to delete, as shown by `vela backup list`").option("-y, --yes", "skip the confirmation").configureHelp(helpConfig),
10645
+ new Command99("delete").description("remove a backup from a target").argument("<key>", "archive to delete, as shown by `vela backup list`").option("-y, --yes", "skip the confirmation").configureHelp(helpConfig),
10445
10646
  "production"
10446
10647
  ).action(
10447
10648
  (key, raw) => runCommand(() => {
@@ -10472,12 +10673,12 @@ Run ${pc29.cyan("vela backup list")} to see what it does have.`
10472
10673
  );
10473
10674
 
10474
10675
  // src/commands/backup/schedule.ts
10475
- import { Command as Command97 } from "commander";
10676
+ import { Command as Command100 } from "commander";
10476
10677
  import * as p57 from "@clack/prompts";
10477
10678
  import pc30 from "picocolors";
10478
10679
  var DEFAULT_KEEP = 7;
10479
10680
  var backupSchedule = addTargetOptions(
10480
- new Command97("schedule").description("back up automatically on a schedule").argument("[cron]", "when to run, as a cron expression \u2014 shows the current one when omitted").option("--keep <n>", "how many scheduled archives to keep", String(DEFAULT_KEEP)).option("--off", "stop backing up automatically").configureHelp(helpConfig),
10681
+ new Command100("schedule").description("back up automatically on a schedule").argument("[cron]", "when to run, as a cron expression \u2014 shows the current one when omitted").option("--keep <n>", "how many scheduled archives to keep", String(DEFAULT_KEEP)).option("--off", "stop backing up automatically").configureHelp(helpConfig),
10481
10682
  "production"
10482
10683
  ).action(
10483
10684
  (cron, raw) => runCommand(() => {
@@ -10521,18 +10722,18 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
10521
10722
  );
10522
10723
 
10523
10724
  // src/commands/backup.ts
10524
- var backup = new Command98("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);
10725
+ var backup = new Command101("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);
10525
10726
 
10526
10727
  // src/commands/restore.ts
10527
- import fs41 from "node:fs";
10528
- import path44 from "node:path";
10728
+ import fs42 from "node:fs";
10729
+ import path45 from "node:path";
10529
10730
  import process37 from "node:process";
10530
- import { Command as Command99 } from "commander";
10731
+ import { Command as Command102 } from "commander";
10531
10732
  import * as p58 from "@clack/prompts";
10532
10733
  import pc31 from "picocolors";
10533
10734
  var restore = addLockWaitOption(
10534
10735
  addTargetOptions(
10535
- new Command99("restore").description("replace a deployment\u2019s database and uploads from a backup").argument("[source]", "a backup key on the target, or a path to a local archive").configureHelp(helpConfig),
10736
+ new Command102("restore").description("replace a deployment\u2019s database and uploads from a backup").argument("[source]", "a backup key on the target, or a path to a local archive").configureHelp(helpConfig),
10536
10737
  "production"
10537
10738
  )
10538
10739
  ).option("-y, --yes", "skip the confirmation prompt").option("--no-migrate", "do not run migrations against the restored database").option("--keep-previous <n>", "how many replaced databases to keep", "1").action(
@@ -10548,7 +10749,7 @@ var restore = addLockWaitOption(
10548
10749
  `${ctx.targetName} was deployed without a database, so there is nothing to restore.`
10549
10750
  );
10550
10751
  }
10551
- const local = source && fs41.existsSync(source) ? source : void 0;
10752
+ const local = source && fs42.existsSync(source) ? source : void 0;
10552
10753
  const key = local ? void 0 : await resolveKey(ctx, source);
10553
10754
  if (!options.yes) {
10554
10755
  await confirm13(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
@@ -10571,7 +10772,7 @@ var restore = addLockWaitOption(
10571
10772
  });
10572
10773
  p58.log.success(
10573
10774
  `Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
10574
- local ? path44.basename(local) : key
10775
+ local ? path45.basename(local) : key
10575
10776
  )}.`
10576
10777
  );
10577
10778
  if (result?.storageCarriedOver) {
@@ -10637,21 +10838,21 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
10637
10838
  }
10638
10839
  async function stage(ctx, file) {
10639
10840
  const dir = remotePaths.restoreStage(ctx.instance);
10640
- const remote = `${dir}/${path44.basename(file)}`;
10841
+ const remote = `${dir}/${path45.basename(file)}`;
10641
10842
  const spinner8 = p58.spinner();
10642
- spinner8.start(`Uploading ${path44.basename(file)}`);
10843
+ spinner8.start(`Uploading ${path45.basename(file)}`);
10643
10844
  try {
10644
10845
  await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
10645
10846
  await ctx.session.upload([file], dir);
10646
10847
  } catch (error) {
10647
- spinner8.stop(`Could not upload ${path44.basename(file)}.`);
10848
+ spinner8.stop(`Could not upload ${path45.basename(file)}.`);
10648
10849
  throw error;
10649
10850
  }
10650
- spinner8.stop(`Uploaded ${path44.basename(file)}`);
10851
+ spinner8.stop(`Uploaded ${path45.basename(file)}`);
10651
10852
  return remote;
10652
10853
  }
10653
10854
  async function confirm13(appName, targetName, envTag, from) {
10654
- const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path44.basename(from))}`;
10855
+ const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path45.basename(from))}`;
10655
10856
  if (isProd(envTag)) {
10656
10857
  const answer = await p58.text({
10657
10858
  message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
@@ -10674,7 +10875,7 @@ async function confirm13(appName, targetName, envTag, from) {
10674
10875
  }
10675
10876
 
10676
10877
  // src/commands/targets.ts
10677
- import { Command as Command100 } from "commander";
10878
+ import { Command as Command103 } from "commander";
10678
10879
  import * as p59 from "@clack/prompts";
10679
10880
  import pc32 from "picocolors";
10680
10881
  import * as v9 from "valibot";
@@ -10684,7 +10885,7 @@ var OptionsSchema4 = v9.object({
10684
10885
  offline: v9.optional(v9.boolean())
10685
10886
  });
10686
10887
  var targets = addSshOptions(
10687
- new Command100("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
10888
+ new Command103("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
10688
10889
  ).option("--json", "print raw JSON").option("--offline", "skip connecting to servers").action(
10689
10890
  (raw) => runCommand(async () => {
10690
10891
  const options = parseOptions(OptionsSchema4, raw);
@@ -10762,34 +10963,34 @@ Release and domain are shown from what this project recorded.`
10762
10963
  }
10763
10964
 
10764
10965
  // src/commands/test.ts
10765
- import path45 from "node:path";
10966
+ import path46 from "node:path";
10766
10967
  import process38 from "node:process";
10767
- import { Command as Command101 } from "commander";
10968
+ import { Command as Command104 } from "commander";
10768
10969
  import PocketBase6 from "pocketbase";
10769
10970
  import pc33 from "picocolors";
10770
10971
  import { x as x5 } from "tinyexec";
10771
10972
  import { detect as detect8 } from "package-manager-detector";
10772
10973
  import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
10773
- import fs42 from "node:fs";
10774
- var testServer = new Command101("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
10974
+ import fs43 from "node:fs";
10975
+ var testServer = new Command104("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
10775
10976
  const cwd = process38.cwd();
10776
10977
  const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
10777
- const password11 = "password";
10778
- const testDataDir = path45.join(cwd, "test-data");
10779
- fs42.rmSync(testDataDir, { recursive: true, force: true });
10978
+ const password12 = "password";
10979
+ const testDataDir = path46.join(cwd, "test-data");
10980
+ fs43.rmSync(testDataDir, { recursive: true, force: true });
10780
10981
  const { stop, url } = await launchPocketbase(cwd, {
10781
10982
  dir: testDataDir,
10782
- migrationsDir: path45.join(cwd, MIGRATIONS_DIR),
10983
+ migrationsDir: path46.join(cwd, MIGRATIONS_DIR),
10783
10984
  // The app's PocketBase hooks (slug generation, personal teams, …) are part
10784
10985
  // of its behaviour; the suite runs against the same server dev and build
10785
10986
  // start, so it loads them from the same place.
10786
- hooksDir: path45.join(cwd, DATA_DIR, "hooks"),
10987
+ hooksDir: path46.join(cwd, DATA_DIR, "hooks"),
10787
10988
  email: email3,
10788
- password: password11
10989
+ password: password12
10789
10990
  });
10790
10991
  process38.env.POCKETBASE_URL = url;
10791
10992
  process38.env.POCKETBASE_SUPERUSER_EMAIL = email3;
10792
- process38.env.POCKETBASE_SUPERUSER_PASSWORD = password11;
10993
+ process38.env.POCKETBASE_SUPERUSER_PASSWORD = password12;
10793
10994
  process38.env.VELA_DATA_DIR = testDataDir;
10794
10995
  process38.env.TEST = "true";
10795
10996
  console.log(`${pc33.greenBright("\u2713")} Created test database`);
@@ -10799,7 +11000,7 @@ var testServer = new Command101("test:server").description("run server tests").a
10799
11000
  if (cleanedUp) return;
10800
11001
  cleanedUp = true;
10801
11002
  stop();
10802
- fs42.rmSync(testDataDir, { recursive: true, force: true });
11003
+ fs43.rmSync(testDataDir, { recursive: true, force: true });
10803
11004
  };
10804
11005
  const cleanup = async () => {
10805
11006
  if (cleanedUp) return;
@@ -10820,7 +11021,7 @@ var testServer = new Command101("test:server").description("run server tests").a
10820
11021
  });
10821
11022
  const pb = new PocketBase6(url);
10822
11023
  try {
10823
- await authWithRetries(pb, email3, password11);
11024
+ await authWithRetries(pb, email3, password12);
10824
11025
  } catch (e) {
10825
11026
  await fail(`Auth failed: ${e.message}`);
10826
11027
  }
@@ -10900,9 +11101,9 @@ function stubPagesPlugin() {
10900
11101
  }
10901
11102
 
10902
11103
  // src/commands/routes.ts
10903
- import fs43 from "node:fs";
10904
- import path46 from "node:path";
10905
- import { Command as Command102 } from "commander";
11104
+ import fs44 from "node:fs";
11105
+ import path47 from "node:path";
11106
+ import { Command as Command105 } from "commander";
10906
11107
  var HTTP_METHODS = /* @__PURE__ */ new Set([
10907
11108
  "GET",
10908
11109
  "POST",
@@ -10913,32 +11114,32 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
10913
11114
  "HEAD",
10914
11115
  "fallback"
10915
11116
  ]);
10916
- var routes = new Command102("routes").description("list routes").configureHelp(helpConfig).action(async () => {
11117
+ var routes = new Command105("routes").description("list routes").configureHelp(helpConfig).action(async () => {
10917
11118
  const { workspaceRootDir, routesDir } = await getWorkspace();
10918
- const routesRoot = path46.join(workspaceRootDir, routesDir);
11119
+ const routesRoot = path47.join(workspaceRootDir, routesDir);
10919
11120
  const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
10920
11121
  found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
10921
11122
  printTable(found);
10922
11123
  });
10923
11124
  function walk(root, dir) {
10924
- const entries = fs43.readdirSync(dir, { withFileTypes: true });
11125
+ const entries = fs44.readdirSync(dir, { withFileTypes: true });
10925
11126
  const routes2 = [];
10926
11127
  const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
10927
11128
  if (hasLeaf) {
10928
- const id = "/" + path46.relative(root, dir).split(path46.sep).filter(Boolean).join("/");
11129
+ const id = "/" + path47.relative(root, dir).split(path47.sep).filter(Boolean).join("/");
10929
11130
  const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
10930
11131
  const methods = /* @__PURE__ */ new Set();
10931
11132
  for (const entry of entries) {
10932
11133
  if (!entry.isFile()) continue;
10933
11134
  if (entry.name.endsWith("+page.svelte")) methods.add("GET");
10934
11135
  if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
10935
- extractMethods(path46.join(dir, entry.name)).forEach((m) => methods.add(m));
11136
+ extractMethods(path47.join(dir, entry.name)).forEach((m) => methods.add(m));
10936
11137
  }
10937
11138
  }
10938
11139
  routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
10939
11140
  }
10940
11141
  for (const entry of entries) {
10941
- if (entry.isDirectory()) routes2.push(...walk(root, path46.join(dir, entry.name)));
11142
+ if (entry.isDirectory()) routes2.push(...walk(root, path47.join(dir, entry.name)));
10942
11143
  }
10943
11144
  return routes2;
10944
11145
  }
@@ -10947,7 +11148,7 @@ function isRouteFile(name) {
10947
11148
  }
10948
11149
  function extractMethods(file) {
10949
11150
  try {
10950
- const content = fs43.readFileSync(file, "utf8");
11151
+ const content = fs44.readFileSync(file, "utf8");
10951
11152
  const methods = [];
10952
11153
  const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
10953
11154
  let match;
@@ -10988,17 +11189,17 @@ function printTable(routes2) {
10988
11189
  }
10989
11190
 
10990
11191
  // src/commands/i18n.ts
10991
- import fs44 from "node:fs";
10992
- import path47 from "node:path";
11192
+ import fs45 from "node:fs";
11193
+ import path48 from "node:path";
10993
11194
  import process39 from "node:process";
10994
- import { Command as Command103 } from "commander";
11195
+ import { Command as Command106 } from "commander";
10995
11196
  import { x as x6 } from "tinyexec";
10996
11197
  import { detect as detect9 } from "package-manager-detector";
10997
11198
  import { resolveCommand as resolveCommand8 } from "package-manager-detector/commands";
10998
11199
  var WUCHALE_CONFIG_NAMES = ["js", "mjs", "ts", "mts"].map((ext) => `wuchale.config.${ext}`);
10999
11200
  async function runWuchale(extraArgs) {
11000
11201
  const cwd = findWorkspaceRoot() ?? process39.cwd();
11001
- if (!WUCHALE_CONFIG_NAMES.some((name) => fs44.existsSync(path47.join(cwd, name)))) {
11202
+ if (!WUCHALE_CONFIG_NAMES.some((name) => fs45.existsSync(path48.join(cwd, name)))) {
11002
11203
  throw new Error("No wuchale config found. Run `vela enable i18n` to set up i18n.");
11003
11204
  }
11004
11205
  const pm = (await detect9({ cwd }))?.name ?? "npm";
@@ -11010,11 +11211,11 @@ async function runWuchale(extraArgs) {
11010
11211
  throwOnError: true
11011
11212
  });
11012
11213
  }
11013
- var extract2 = new Command103("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runCommand(() => runWuchale([])));
11014
- var watch = new Command103("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runCommand(() => runWuchale(["--watch"])));
11015
- var status2 = new Command103("status").description("show i18n status").configureHelp(helpConfig).action(() => runCommand(() => runWuchale(["status"])));
11016
- var clean = new Command103("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runCommand(() => runWuchale(["--clean"])));
11017
- var i18n3 = new Command103("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
11214
+ var extract2 = new Command106("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runCommand(() => runWuchale([])));
11215
+ var watch = new Command106("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runCommand(() => runWuchale(["--watch"])));
11216
+ var status2 = new Command106("status").description("show i18n status").configureHelp(helpConfig).action(() => runCommand(() => runWuchale(["status"])));
11217
+ var clean = new Command106("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runCommand(() => runWuchale(["--clean"])));
11218
+ var i18n3 = new Command106("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
11018
11219
 
11019
11220
  // src/commands/oauth.ts
11020
11221
  var oauth = stubCommand("oauth", "configure OAuth providers");
@@ -11023,17 +11224,17 @@ var oauth = stubCommand("oauth", "configure OAuth providers");
11023
11224
  var schemas = stubCommand("schemas", "manage database schemas");
11024
11225
 
11025
11226
  // src/commands/cms.ts
11026
- import { Command as Command109 } from "commander";
11227
+ import { Command as Command112 } from "commander";
11027
11228
 
11028
11229
  // src/commands/cms/deploy.ts
11029
11230
  import process40 from "node:process";
11030
- import { Command as Command104 } from "commander";
11231
+ import { Command as Command107 } from "commander";
11031
11232
  import * as p60 from "@clack/prompts";
11032
11233
  import pc34 from "picocolors";
11033
11234
  var POLL_INTERVAL2 = 5e3;
11034
11235
  var POLL_TIMEOUT = 30 * 6e4;
11035
11236
  var inFlight = (run) => run?.status === "pending" || run?.status === "building";
11036
- var deploy2 = new Command104("deploy").description("rebuild the hosted site with the latest published content").option(
11237
+ var deploy2 = new Command107("deploy").description("rebuild the hosted site with the latest published content").option(
11037
11238
  "--project <id>",
11038
11239
  "velastack.dev project whose site to rebuild, instead of the linked one"
11039
11240
  ).option("--no-wait", "return once the build has started instead of waiting for it").configureHelp(helpConfig).action(
@@ -11122,17 +11323,17 @@ async function waitForRun(apiKey, projectId, runId) {
11122
11323
  }
11123
11324
 
11124
11325
  // src/commands/cms/editor.ts
11125
- import { Command as Command108 } from "commander";
11326
+ import { Command as Command111 } from "commander";
11126
11327
 
11127
11328
  // src/commands/cms/editor/add.ts
11128
11329
  import { randomBytes } from "node:crypto";
11129
- import { Command as Command105 } from "commander";
11330
+ import { Command as Command108 } from "commander";
11130
11331
  import * as p61 from "@clack/prompts";
11131
11332
  import pc36 from "picocolors";
11132
11333
 
11133
11334
  // src/lib/cms-backend.ts
11134
11335
  import { createRequire as createRequire3 } from "node:module";
11135
- import path48 from "node:path";
11336
+ import path49 from "node:path";
11136
11337
  import process41 from "node:process";
11137
11338
  import { pathToFileURL as pathToFileURL3 } from "node:url";
11138
11339
  import pc35 from "picocolors";
@@ -11140,7 +11341,7 @@ var DEFAULT_PROJECT = "default";
11140
11341
  async function loadBackendModule(root) {
11141
11342
  let entry;
11142
11343
  try {
11143
- entry = createRequire3(path48.join(root, "package.json")).resolve("@velastack/cms/backend");
11344
+ entry = createRequire3(path49.join(root, "package.json")).resolve("@velastack/cms/backend");
11144
11345
  } catch {
11145
11346
  throw new Error(
11146
11347
  `@velastack/cms is not installed in this project.
@@ -11158,8 +11359,8 @@ async function withCmsBackend(fn, cwd = process41.cwd()) {
11158
11359
  const { createCmsBackend } = await loadBackendModule(root);
11159
11360
  const dataDir2 = localDataDir(root);
11160
11361
  const backend3 = createCmsBackend({
11161
- dbPath: path48.join(dataDir2, "cms.sqlite"),
11162
- uploadDir: path48.join(dataDir2, "uploads")
11362
+ dbPath: path49.join(dataDir2, "cms.sqlite"),
11363
+ uploadDir: path49.join(dataDir2, "uploads")
11163
11364
  });
11164
11365
  try {
11165
11366
  return await fn(backend3);
@@ -11169,16 +11370,16 @@ async function withCmsBackend(fn, cwd = process41.cwd()) {
11169
11370
  }
11170
11371
 
11171
11372
  // src/commands/cms/editor/add.ts
11172
- var editorAdd = new Command105("add").description("create an editor who can sign in to the admin bar").argument("<email>", "email the editor signs in with").option("--password <password>", "password to set \u2014 generated and shown once when omitted").option("--project <id>", "project the editor may edit", DEFAULT_PROJECT).configureHelp(helpConfig).action(
11373
+ var editorAdd = new Command108("add").description("create an editor who can sign in to the admin bar").argument("<email>", "email the editor signs in with").option("--password <password>", "password to set \u2014 generated and shown once when omitted").option("--project <id>", "project the editor may edit", DEFAULT_PROJECT).configureHelp(helpConfig).action(
11173
11374
  (email3, options) => runCommand(async () => {
11174
11375
  const generated = options.password === void 0;
11175
- const password11 = options.password ?? randomBytes(12).toString("base64url");
11376
+ const password12 = options.password ?? randomBytes(12).toString("base64url");
11176
11377
  const editor2 = await withCmsBackend(
11177
- (cms3) => cms3.editors.create({ email: email3, password: password11, projects: [options.project] })
11378
+ (cms3) => cms3.editors.create({ email: email3, password: password12, projects: [options.project] })
11178
11379
  );
11179
11380
  const lines = [`Added ${pc36.cyan(editor2.email)} as an editor of ${pc36.cyan(options.project)}.`];
11180
11381
  if (generated) {
11181
- lines.push("", `Password: ${pc36.bold(password11)}`, "", "It is shown once; copy it now.");
11382
+ lines.push("", `Password: ${pc36.bold(password12)}`, "", "It is shown once; copy it now.");
11182
11383
  }
11183
11384
  p61.log.success(lines.join("\n"));
11184
11385
  p61.log.info(
@@ -11188,12 +11389,12 @@ var editorAdd = new Command105("add").description("create an editor who can sign
11188
11389
  );
11189
11390
 
11190
11391
  // src/commands/cms/editor/password.ts
11191
- import { Command as Command106 } from "commander";
11392
+ import { Command as Command109 } from "commander";
11192
11393
  import * as p62 from "@clack/prompts";
11193
11394
  import pc37 from "picocolors";
11194
- var editorPassword = new Command106("password").description("set an editor's password").argument("<email>", "email of the editor").argument("<password>", "new password").configureHelp(helpConfig).action(
11195
- (email3, password11) => runCommand(async () => {
11196
- await withCmsBackend((cms3) => cms3.editors.setPassword(email3, password11));
11395
+ var editorPassword = new Command109("password").description("set an editor's password").argument("<email>", "email of the editor").argument("<password>", "new password").configureHelp(helpConfig).action(
11396
+ (email3, password12) => runCommand(async () => {
11397
+ await withCmsBackend((cms3) => cms3.editors.setPassword(email3, password12));
11197
11398
  p62.log.success(
11198
11399
  `Updated the password for ${pc37.cyan(email3)}. Existing sessions were signed out.`
11199
11400
  );
@@ -11201,10 +11402,10 @@ var editorPassword = new Command106("password").description("set an editor's pas
11201
11402
  );
11202
11403
 
11203
11404
  // src/commands/cms/editor/list.ts
11204
- import { Command as Command107 } from "commander";
11405
+ import { Command as Command110 } from "commander";
11205
11406
  import * as p63 from "@clack/prompts";
11206
11407
  import pc38 from "picocolors";
11207
- var editorList = new Command107("list").description("list editors and the projects they may edit").configureHelp(helpConfig).action(
11408
+ var editorList = new Command110("list").description("list editors and the projects they may edit").configureHelp(helpConfig).action(
11208
11409
  () => runCommand(async () => {
11209
11410
  const rows = await withCmsBackend(
11210
11411
  async (cms3) => cms3.editors.list().map((editor2) => ({
@@ -11228,17 +11429,17 @@ var editorList = new Command107("list").description("list editors and the projec
11228
11429
  );
11229
11430
 
11230
11431
  // src/commands/cms/editor.ts
11231
- var editor = new Command108("editor").description("manage who can sign in to the admin bar").configureHelp(helpConfig).addCommand(editorAdd).addCommand(editorPassword).addCommand(editorList);
11432
+ var editor = new Command111("editor").description("manage who can sign in to the admin bar").configureHelp(helpConfig).addCommand(editorAdd).addCommand(editorPassword).addCommand(editorList);
11232
11433
 
11233
11434
  // src/commands/cms.ts
11234
- var cms2 = new Command109("cms").description("manage the CMS").configureHelp(helpConfig).addCommand(editor).addCommand(deploy2);
11435
+ var cms2 = new Command112("cms").description("manage the CMS").configureHelp(helpConfig).addCommand(editor).addCommand(deploy2);
11235
11436
 
11236
11437
  // src/commands/workflows.ts
11237
- import { Command as Command113 } from "commander";
11438
+ import { Command as Command116 } from "commander";
11238
11439
 
11239
11440
  // src/commands/workflows/list.ts
11240
11441
  import process42 from "node:process";
11241
- import { Command as Command110, InvalidArgumentError as InvalidArgumentError5 } from "commander";
11442
+ import { Command as Command113, InvalidArgumentError as InvalidArgumentError5 } from "commander";
11242
11443
  import * as p64 from "@clack/prompts";
11243
11444
  import pc39 from "picocolors";
11244
11445
 
@@ -11313,7 +11514,7 @@ function formatRun(run, nameWidth) {
11313
11514
  const error = run.status === "failed" && run.error?.message ? pc39.red(` ${run.error.message}`) : "";
11314
11515
  return `${run.id} ${run.workflowName.padEnd(nameWidth)} ${status3}${attempts} ${when}${error}`;
11315
11516
  }
11316
- var workflowsList = new Command110("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(
11517
+ var workflowsList = new Command113("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(
11317
11518
  (options) => runCommand(async () => {
11318
11519
  await withPocketbase(process42.cwd(), async (pb) => {
11319
11520
  const runs = await listRuns(pb, {
@@ -11337,7 +11538,7 @@ Start one from server code with ${pc39.cyan("<workflow>.run(input)")}, or with $
11337
11538
 
11338
11539
  // src/commands/workflows/run.ts
11339
11540
  import process43 from "node:process";
11340
- import { Command as Command111, InvalidArgumentError as InvalidArgumentError6 } from "commander";
11541
+ import { Command as Command114, InvalidArgumentError as InvalidArgumentError6 } from "commander";
11341
11542
  import * as p65 from "@clack/prompts";
11342
11543
  import pc40 from "picocolors";
11343
11544
  function parseInput(value) {
@@ -11347,7 +11548,7 @@ function parseInput(value) {
11347
11548
  throw new InvalidArgumentError6(`must be JSON, e.g. '{"userId":"abc"}'.`);
11348
11549
  }
11349
11550
  }
11350
- var workflowsRun = new Command111("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(
11551
+ var workflowsRun = new Command114("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(
11351
11552
  (name, input) => runCommand(async () => {
11352
11553
  await withPocketbase(process43.cwd(), async (pb) => {
11353
11554
  const run = await createRun(pb, name, input);
@@ -11362,10 +11563,10 @@ It runs once the app is up (${pc40.cyan("vela dev")}); ${pc40.cyan("vela workflo
11362
11563
 
11363
11564
  // src/commands/workflows/cancel.ts
11364
11565
  import process44 from "node:process";
11365
- import { Command as Command112 } from "commander";
11566
+ import { Command as Command115 } from "commander";
11366
11567
  import * as p66 from "@clack/prompts";
11367
11568
  import pc41 from "picocolors";
11368
- var workflowsCancel = new Command112("cancel").description("cancel a pending or running workflow run").argument("<run-id>", "the run id from `vela workflows list`").configureHelp(helpConfig).action(
11569
+ var workflowsCancel = new Command115("cancel").description("cancel a pending or running workflow run").argument("<run-id>", "the run id from `vela workflows list`").configureHelp(helpConfig).action(
11369
11570
  (id) => runCommand(async () => {
11370
11571
  await withPocketbase(process44.cwd(), async (pb) => {
11371
11572
  const run = await cancelRun(pb, id);
@@ -11375,7 +11576,7 @@ var workflowsCancel = new Command112("cancel").description("cancel a pending or
11375
11576
  );
11376
11577
 
11377
11578
  // src/commands/workflows.ts
11378
- var workflows2 = new Command113("workflows").description("list, start and cancel background workflow runs").configureHelp(helpConfig).addCommand(workflowsList).addCommand(workflowsRun).addCommand(workflowsCancel);
11579
+ var workflows2 = new Command116("workflows").description("list, start and cancel background workflow runs").configureHelp(helpConfig).addCommand(workflowsList).addCommand(workflowsRun).addCommand(workflowsCancel);
11379
11580
 
11380
11581
  // src/program.ts
11381
11582
  var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
@@ -11397,8 +11598,16 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
11397
11598
  "destroy form",
11398
11599
  // The CMS keeps its own SQLite database and editors; PocketBase is never involved.
11399
11600
  "enable cms",
11601
+ // Adds PocketBase to a project that has none, so it can never require one.
11602
+ "enable backend",
11400
11603
  // Analytics only touches the root layout and .env; it must work on static sites.
11401
11604
  "enable analytics",
11605
+ // The model is called from a SvelteKit endpoint; PocketBase is only read for
11606
+ // the signed-in check when auth is on.
11607
+ "enable ai",
11608
+ // Both only delete files and strip .env, so they run wherever enabling did.
11609
+ "disable ai",
11610
+ "disable analytics",
11402
11611
  // Only wires hooks, reroute and the root layout; no collections involved.
11403
11612
  "enable content-negotiation",
11404
11613
  "disable content-negotiation",
@@ -11427,19 +11636,19 @@ var NO_BACKEND_COMMMANDS = /* @__PURE__ */ new Set([
11427
11636
  ]);
11428
11637
  var BACKEND_OPTIONAL_COMMANDS = /* @__PURE__ */ new Set(["dev", "build", "preview", "deploy"]);
11429
11638
  var SELF_CREDENTIALED_COMMANDS = /* @__PURE__ */ new Set(["test:server"]);
11430
- var program = new Command114().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
11639
+ var program = new Command117().name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version").configureHelp(helpConfig);
11431
11640
  program.hook("preAction", (_thisCommand, actionCommand) => {
11432
11641
  if (isStub(actionCommand)) return;
11433
11642
  const envRoot = findWorkspaceRoot() ?? process45.cwd();
11434
11643
  dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
11435
- const path49 = getCommandPath(actionCommand);
11436
- if (NO_BACKEND_COMMMANDS.has(path49)) return;
11437
- const top = path49.split(" ", 1)[0];
11644
+ const path50 = getCommandPath(actionCommand);
11645
+ if (NO_BACKEND_COMMMANDS.has(path50)) return;
11646
+ const top = path50.split(" ", 1)[0];
11438
11647
  if (NO_BACKEND_COMMMANDS.has(top)) return;
11439
11648
  if (!hasBackend()) {
11440
11649
  if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
11441
11650
  p67.log.error(
11442
- `${pc42.cyan(`vela ${path49}`)} needs a backend, and this project does not have one.
11651
+ `${pc42.cyan(`vela ${path50}`)} needs a backend, and this project does not have one.
11443
11652
 
11444
11653
  Static projects have no database to talk to.
11445
11654
 
@@ -11449,7 +11658,7 @@ To add a backend to this project, run ${pc42.cyan("vela bless")}.`
11449
11658
  p67.cancel("Operation failed.");
11450
11659
  process45.exit(1);
11451
11660
  }
11452
- if (SELF_CREDENTIALED_COMMANDS.has(path49)) return;
11661
+ if (SELF_CREDENTIALED_COMMANDS.has(path50)) return;
11453
11662
  if (!process45.env.POCKETBASE_SUPERUSER_EMAIL || !process45.env.POCKETBASE_SUPERUSER_PASSWORD) {
11454
11663
  p67.log.error(
11455
11664
  `PocketBase superuser credentials are required.