vela 0.11.0 → 0.11.2

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
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
21
21
  // package.json
22
22
  var package_default = {
23
23
  name: "vela",
24
- version: "0.11.0",
24
+ version: "0.11.2",
25
25
  type: "module",
26
26
  description: "A CLI for creating and updating SvelteKit projects",
27
27
  license: "MIT",
@@ -71,6 +71,7 @@ var package_default = {
71
71
  "pocketbase-server": "^0.39.11",
72
72
  stripe: "^19.3.0",
73
73
  svelte: "^5.56.10",
74
+ tar: "^7.5.22",
74
75
  tinyexec: "^1.3.0",
75
76
  "ts-morph": "^28.0.0",
76
77
  valibot: "^1.4.2"
@@ -236,6 +237,7 @@ var API_URL = (process2.env.VELA_API_URL?.trim() || "https://velastack.dev").rep
236
237
  ""
237
238
  );
238
239
  var FIXTURE_PREFIX = "vela";
240
+ var TEMPLATE_INDEX_URL = process2.env.VELA_TEMPLATE_INDEX_URL?.trim() || "https://templates.velastack.app/index.json";
239
241
 
240
242
  // src/lib/package-json.ts
241
243
  import fs from "node:fs";
@@ -286,8 +288,8 @@ function mergePackageJson(user, template) {
286
288
  }
287
289
  return { merged, added, conflicts, replaced };
288
290
  }
289
- function readPackageJson(path45) {
290
- return JSON.parse(fs.readFileSync(path45, "utf8"));
291
+ function readPackageJson(path46) {
292
+ return JSON.parse(fs.readFileSync(path46, "utf8"));
291
293
  }
292
294
  var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
293
295
  var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
@@ -300,12 +302,12 @@ function fillTemplatePlaceholders(raw, values) {
300
302
  function escapeSingleQuoted(value) {
301
303
  return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
302
304
  }
303
- function readTemplatePackageJson(path45, values) {
304
- const raw = fillTemplatePlaceholders(fs.readFileSync(path45, "utf8"), values);
305
+ function readTemplatePackageJson(path46, values) {
306
+ const raw = fillTemplatePlaceholders(fs.readFileSync(path46, "utf8"), values);
305
307
  return JSON.parse(raw);
306
308
  }
307
- function writePackageJson(path45, pkg) {
308
- fs.writeFileSync(path45, JSON.stringify(pkg, null, " ") + "\n");
309
+ function writePackageJson(path46, pkg) {
310
+ fs.writeFileSync(path46, JSON.stringify(pkg, null, " ") + "\n");
309
311
  }
310
312
  function toValidPackageName(name) {
311
313
  return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
@@ -383,10 +385,10 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
383
385
  }
384
386
 
385
387
  // src/commands/bless.ts
386
- import fs13 from "node:fs";
387
- import path11 from "node:path";
388
- import process6 from "node:process";
389
- import * as v2 from "valibot";
388
+ import fs15 from "node:fs";
389
+ import path13 from "node:path";
390
+ import process7 from "node:process";
391
+ import * as v3 from "valibot";
390
392
  import { Command as Command2 } from "commander";
391
393
  import * as p4 from "@clack/prompts";
392
394
  import pc3 from "picocolors";
@@ -420,32 +422,279 @@ function toFlag(key) {
420
422
  }
421
423
 
422
424
  // src/lib/templates.ts
425
+ import fs6 from "node:fs";
426
+ import path5 from "node:path";
427
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
428
+
429
+ // src/lib/template-files.ts
423
430
  import fs3 from "node:fs";
424
431
  import path2 from "node:path";
432
+ var PUBLISH_SAFE_NAMES = {
433
+ ".gitignore": "_gitignore",
434
+ ".npmrc": "_npmrc"
435
+ };
436
+ function templateName(projectRelPath) {
437
+ const safe = PUBLISH_SAFE_NAMES[path2.basename(projectRelPath)];
438
+ if (!safe) return projectRelPath;
439
+ const dir = path2.dirname(projectRelPath);
440
+ return dir === "." ? safe : path2.join(dir, safe);
441
+ }
442
+ function restoreTemplateNames(target) {
443
+ for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
444
+ const from = path2.join(target, safe);
445
+ if (!fs3.existsSync(from)) continue;
446
+ fs3.renameSync(from, path2.join(target, real));
447
+ }
448
+ }
449
+ var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
450
+ function applyTemplateFiles(target, values) {
451
+ const written = [];
452
+ for (const source of findTemplateSources(target)) {
453
+ const raw = fs3.readFileSync(source, "utf8");
454
+ const dest = source.replace(TEMPLATE_SOURCE, ".$1");
455
+ fs3.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
456
+ fs3.unlinkSync(source);
457
+ written.push(path2.relative(target, dest));
458
+ }
459
+ return written.sort();
460
+ }
461
+ function findTemplateSources(dir) {
462
+ const found = [];
463
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
464
+ const full = path2.join(dir, entry.name);
465
+ if (entry.isDirectory()) {
466
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
467
+ found.push(...findTemplateSources(full));
468
+ } else if (entry.isFile() && TEMPLATE_SOURCE.test(entry.name)) {
469
+ found.push(full);
470
+ }
471
+ }
472
+ return found;
473
+ }
474
+
475
+ // src/lib/template-registry.ts
476
+ import fs5 from "node:fs";
477
+ import os2 from "node:os";
478
+ import path4 from "node:path";
479
+ import { createHash } from "node:crypto";
425
480
  import { fileURLToPath } from "node:url";
481
+ import * as v2 from "valibot";
482
+ import * as tar from "tar";
483
+
484
+ // src/lib/config.ts
485
+ import fs4 from "node:fs";
486
+ import os from "node:os";
487
+ import path3 from "node:path";
488
+ import process4 from "node:process";
489
+ function configDir() {
490
+ return path3.join(os.homedir(), ".vela");
491
+ }
492
+ var CONFIG_DIR = configDir();
493
+ var CONFIG_PATH = path3.join(CONFIG_DIR, "config.json");
494
+ function readConfig() {
495
+ if (!fs4.existsSync(CONFIG_PATH)) return null;
496
+ try {
497
+ return JSON.parse(fs4.readFileSync(CONFIG_PATH, "utf8"));
498
+ } catch {
499
+ return null;
500
+ }
501
+ }
502
+ function writeConfig(config) {
503
+ fs4.mkdirSync(CONFIG_DIR, { recursive: true });
504
+ fs4.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
505
+ }
506
+ function clearConfig() {
507
+ if (fs4.existsSync(CONFIG_PATH)) fs4.unlinkSync(CONFIG_PATH);
508
+ }
509
+ function readApiKey() {
510
+ const fromEnv = process4.env.VELA_API_KEY?.trim();
511
+ if (fromEnv) return fromEnv;
512
+ return readConfig()?.apiKey ?? null;
513
+ }
514
+ function requireApiKey() {
515
+ const apiKey = readApiKey();
516
+ if (!apiKey) {
517
+ throw new Error("Not logged in. Run `vela login` to login, or set VELA_API_KEY.");
518
+ }
519
+ return apiKey;
520
+ }
521
+
522
+ // src/lib/template-registry.ts
523
+ var CACHE_DIR_NAME = "templates";
524
+ var INDEX_CACHE_FILE = "index.json";
525
+ var TARBALL_CACHE_DIR = "cache";
526
+ var INDEX_CACHE_TTL_MS = 60 * 60 * 1e3;
527
+ var DEFAULT_TIMEOUT_MS = 5e3;
528
+ var entrySchema = v2.object({
529
+ name: v2.pipe(v2.string(), v2.regex(/^[a-z0-9][a-z0-9-]*$/)),
530
+ description: v2.string(),
531
+ backend: v2.boolean(),
532
+ title: v2.optional(v2.string()),
533
+ category: v2.optional(v2.string()),
534
+ tags: v2.optional(v2.array(v2.string())),
535
+ price: v2.optional(v2.number()),
536
+ previewUrl: v2.optional(v2.string()),
537
+ nextSteps: v2.optional(v2.array(v2.string())),
538
+ /** Tarball location, relative to the index URL. */
539
+ file: v2.string(),
540
+ sha256: v2.pipe(v2.string(), v2.regex(/^[0-9a-f]{64}$/)),
541
+ size: v2.optional(v2.number()),
542
+ version: v2.optional(v2.string())
543
+ });
544
+ var indexSchema = v2.object({
545
+ schemaVersion: v2.literal(1),
546
+ templates: v2.array(v2.unknown())
547
+ });
548
+ function cacheRoot() {
549
+ return path4.join(configDir(), CACHE_DIR_NAME);
550
+ }
551
+ function indexCachePath() {
552
+ return path4.join(cacheRoot(), INDEX_CACHE_FILE);
553
+ }
554
+ function readCachedIndex(url) {
555
+ const file = indexCachePath();
556
+ if (!fs5.existsSync(file)) return null;
557
+ try {
558
+ const cached2 = JSON.parse(fs5.readFileSync(file, "utf8"));
559
+ if (cached2.url !== url) return null;
560
+ return cached2;
561
+ } catch {
562
+ return null;
563
+ }
564
+ }
565
+ function writeCachedIndex(cached2) {
566
+ fs5.mkdirSync(cacheRoot(), { recursive: true });
567
+ fs5.writeFileSync(indexCachePath(), JSON.stringify(cached2, null, 2));
568
+ }
569
+ function parseTemplateIndex(text18, url) {
570
+ let parsed;
571
+ try {
572
+ parsed = JSON.parse(text18);
573
+ } catch (e) {
574
+ throw new Error(`Template index at ${url} is not valid JSON: ${e.message}`);
575
+ }
576
+ const doc = v2.safeParse(indexSchema, parsed);
577
+ if (!doc.success) {
578
+ throw new Error(`Template index at ${url} has an unsupported format`);
579
+ }
580
+ const templates = [];
581
+ let skipped = 0;
582
+ for (const raw of doc.output.templates) {
583
+ const entry = v2.safeParse(entrySchema, raw);
584
+ if (entry.success) templates.push(entry.output);
585
+ else skipped++;
586
+ }
587
+ return { url, templates, skipped };
588
+ }
589
+ function isFileUrl(url) {
590
+ return url.startsWith("file:");
591
+ }
592
+ async function readBytes(url, options) {
593
+ if (isFileUrl(url)) {
594
+ return new Uint8Array(fs5.readFileSync(fileURLToPath(url)));
595
+ }
596
+ const res = await fetch(url, {
597
+ headers: options.headers,
598
+ signal: AbortSignal.timeout(options.timeoutMs)
599
+ });
600
+ if (!res.ok) {
601
+ throw new Error(`${res.status} ${res.statusText}`.trim());
602
+ }
603
+ return new Uint8Array(await res.arrayBuffer());
604
+ }
605
+ async function fetchTemplateIndex(url, options = {}) {
606
+ const now = options.now ?? Date.now();
607
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
608
+ const cached2 = options.noCache ? null : readCachedIndex(url);
609
+ if (cached2 && now - cached2.fetchedAt < INDEX_CACHE_TTL_MS && !isFileUrl(url)) {
610
+ return { index: cached2.index, stale: false };
611
+ }
612
+ try {
613
+ const bytes = await readBytes(url, { timeoutMs, headers: options.headers });
614
+ const index = parseTemplateIndex(Buffer.from(bytes).toString("utf8"), url);
615
+ if (!options.noCache && !isFileUrl(url)) {
616
+ writeCachedIndex({ url, fetchedAt: now, index });
617
+ }
618
+ return { index, stale: false };
619
+ } catch (e) {
620
+ const reason = e.message;
621
+ if (cached2) return { index: cached2.index, stale: true, reason };
622
+ return { index: null, stale: false, reason };
623
+ }
624
+ }
625
+ function resolveDownloadUrl(entry, indexUrl) {
626
+ return new URL(entry.file, indexUrl).href;
627
+ }
628
+ function sha256(bytes) {
629
+ return createHash("sha256").update(bytes).digest("hex");
630
+ }
631
+ function tarballCachePath(entry) {
632
+ return path4.join(
633
+ cacheRoot(),
634
+ TARBALL_CACHE_DIR,
635
+ `${entry.name}-${entry.sha256.slice(0, 12)}.tgz`
636
+ );
637
+ }
638
+ async function downloadTemplate(entry, indexUrl, options = {}) {
639
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS * 6;
640
+ const cacheFile = tarballCachePath(entry);
641
+ let haveTarball = false;
642
+ if (fs5.existsSync(cacheFile)) {
643
+ const cached2 = new Uint8Array(fs5.readFileSync(cacheFile));
644
+ haveTarball = sha256(cached2) === entry.sha256;
645
+ }
646
+ if (!haveTarball) {
647
+ const url = resolveDownloadUrl(entry, indexUrl);
648
+ let fetched;
649
+ try {
650
+ fetched = await readBytes(url, { timeoutMs, headers: options.headers });
651
+ } catch (e) {
652
+ throw new Error(`Could not download template ${entry.name}: ${e.message}`);
653
+ }
654
+ const digest = sha256(fetched);
655
+ if (digest !== entry.sha256) {
656
+ throw new Error(
657
+ `Downloaded template ${entry.name} did not match its checksum (expected ${entry.sha256}, got ${digest}). Try again, or set VELA_TEMPLATE_INDEX_URL to a registry you trust.`
658
+ );
659
+ }
660
+ fs5.mkdirSync(path4.dirname(cacheFile), { recursive: true });
661
+ fs5.writeFileSync(cacheFile, fetched);
662
+ }
663
+ const dir = fs5.mkdtempSync(path4.join(os2.tmpdir(), `vela-template-${entry.name}-`));
664
+ try {
665
+ await tar.extract({ file: cacheFile, cwd: dir, strip: 1 });
666
+ } catch (e) {
667
+ fs5.rmSync(dir, { recursive: true, force: true });
668
+ throw new Error(`Could not unpack template ${entry.name}: ${e.message}`);
669
+ }
670
+ return dir;
671
+ }
672
+
673
+ // src/lib/templates.ts
426
674
  var TEMPLATE_MANIFEST = "template.json";
427
675
  var DEFAULT_TEMPLATE = "minimal";
676
+ var DEFAULT_CATEGORY = "starter";
428
677
  var cached;
429
678
  function templatesDir() {
430
- let dir = path2.dirname(fileURLToPath(import.meta.url));
431
- const { root } = path2.parse(dir);
679
+ let dir = path5.dirname(fileURLToPath2(import.meta.url));
680
+ const { root } = path5.parse(dir);
432
681
  while (dir !== root) {
433
- const candidate = path2.join(dir, "templates");
682
+ const candidate = path5.join(dir, "templates");
434
683
  if (holdsManifest(candidate)) return candidate;
435
- dir = path2.dirname(dir);
684
+ dir = path5.dirname(dir);
436
685
  }
437
686
  throw new Error("Could not locate the templates directory");
438
687
  }
439
688
  function holdsManifest(dir) {
440
- if (!fs3.existsSync(dir)) return false;
441
- return fs3.readdirSync(dir, { withFileTypes: true }).some(
442
- (entry) => entry.isDirectory() && fs3.existsSync(path2.join(dir, entry.name, TEMPLATE_MANIFEST))
689
+ if (!fs6.existsSync(dir)) return false;
690
+ return fs6.readdirSync(dir, { withFileTypes: true }).some(
691
+ (entry) => entry.isDirectory() && fs6.existsSync(path5.join(dir, entry.name, TEMPLATE_MANIFEST))
443
692
  );
444
693
  }
445
694
  function listProjectTemplates() {
446
695
  if (cached) return cached;
447
696
  const root = templatesDir();
448
- cached = fs3.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readManifest(root, entry.name)).filter((template) => template !== void 0).sort((a, b) => a.name.localeCompare(b.name));
697
+ cached = fs6.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readManifest(root, entry.name)).filter((template) => template !== void 0).sort((a, b) => a.name.localeCompare(b.name));
449
698
  return cached;
450
699
  }
451
700
  function projectTemplateNames(options = {}) {
@@ -458,12 +707,84 @@ function findProjectTemplate(name) {
458
707
  if (!template) throw new Error(`Template not found: ${name}`);
459
708
  return template;
460
709
  }
710
+ async function listAllTemplates(options = {}) {
711
+ const indexUrl = options.indexUrl ?? TEMPLATE_INDEX_URL;
712
+ const builtin = listProjectTemplates();
713
+ const names = new Set(builtin.map((template) => template.name));
714
+ const templates = [...builtin];
715
+ const result = await fetchTemplateIndex(indexUrl);
716
+ for (const entry of result.index?.templates ?? []) {
717
+ if (names.has(entry.name)) continue;
718
+ names.add(entry.name);
719
+ templates.push({
720
+ name: entry.name,
721
+ description: entry.description,
722
+ backend: entry.backend,
723
+ source: "remote",
724
+ category: entry.category ?? DEFAULT_CATEGORY,
725
+ title: entry.title,
726
+ tags: entry.tags,
727
+ price: entry.price,
728
+ nextSteps: entry.nextSteps,
729
+ entry,
730
+ indexUrl
731
+ });
732
+ }
733
+ templates.sort(compareTemplates);
734
+ return result.index ? { templates } : { templates, registryError: result.reason };
735
+ }
736
+ function compareTemplates(a, b) {
737
+ if (a.category !== b.category) {
738
+ if (a.category === DEFAULT_CATEGORY) return -1;
739
+ if (b.category === DEFAULT_CATEGORY) return 1;
740
+ return a.category.localeCompare(b.category);
741
+ }
742
+ return a.name.localeCompare(b.name);
743
+ }
744
+ function findTemplate(listing, name) {
745
+ const template = listing.templates.find((candidate) => candidate.name === name);
746
+ if (!template) throw new Error(`Template not found: ${name}`);
747
+ return template;
748
+ }
749
+ function templateChoicesMessage(templates) {
750
+ const groups = /* @__PURE__ */ new Map();
751
+ for (const template of [...templates].sort(compareTemplates)) {
752
+ const names = groups.get(template.category) ?? [];
753
+ names.push(template.name);
754
+ groups.set(template.category, names);
755
+ }
756
+ return [...groups].map(([category, names]) => `${category}: ${names.join(", ")}`).join("; ");
757
+ }
758
+ async function resolveTemplate(template) {
759
+ if (!("entry" in template)) {
760
+ return { ...template, cleanup() {
761
+ } };
762
+ }
763
+ const { entry, indexUrl, ...info } = template;
764
+ const dir = await downloadTemplate(entry, indexUrl);
765
+ return {
766
+ ...info,
767
+ dir,
768
+ cleanup() {
769
+ fs6.rmSync(dir, { recursive: true, force: true });
770
+ }
771
+ };
772
+ }
773
+ function copyTemplate(template, target) {
774
+ fs6.mkdirSync(target, { recursive: true });
775
+ fs6.cpSync(template.dir, target, {
776
+ recursive: true,
777
+ // The manifest describes the template to the CLI; it isn't part of the project.
778
+ filter: (src) => path5.basename(src) !== ".DS_Store" && path5.relative(template.dir, src) !== TEMPLATE_MANIFEST
779
+ });
780
+ restoreTemplateNames(target);
781
+ }
461
782
  function readManifest(root, name) {
462
- const manifestPath = path2.join(root, name, TEMPLATE_MANIFEST);
463
- if (!fs3.existsSync(manifestPath)) return void 0;
783
+ const manifestPath = path5.join(root, name, TEMPLATE_MANIFEST);
784
+ if (!fs6.existsSync(manifestPath)) return void 0;
464
785
  let parsed;
465
786
  try {
466
- parsed = JSON.parse(fs3.readFileSync(manifestPath, "utf8"));
787
+ parsed = JSON.parse(fs6.readFileSync(manifestPath, "utf8"));
467
788
  } catch (e) {
468
789
  throw new Error(
469
790
  `Template ${name} has an unreadable ${TEMPLATE_MANIFEST}: ${e.message}`
@@ -479,14 +800,28 @@ function readManifest(root, name) {
479
800
  name,
480
801
  description: manifest.description,
481
802
  backend: manifest.backend,
482
- dir: path2.join(root, name)
803
+ source: "builtin",
804
+ category: optionalString(manifest.category) ?? DEFAULT_CATEGORY,
805
+ title: optionalString(manifest.title),
806
+ tags: optionalStringArray(manifest.tags),
807
+ price: typeof manifest.price === "number" ? manifest.price : void 0,
808
+ nextSteps: optionalStringArray(manifest.nextSteps),
809
+ dir: path5.join(root, name)
483
810
  };
484
811
  }
812
+ function optionalString(value) {
813
+ return typeof value === "string" && value.length > 0 ? value : void 0;
814
+ }
815
+ function optionalStringArray(value) {
816
+ if (!Array.isArray(value)) return void 0;
817
+ const strings = value.filter((item) => typeof item === "string");
818
+ return strings.length > 0 ? strings : void 0;
819
+ }
485
820
 
486
821
  // src/lib/package-manager.ts
487
- import fs4 from "node:fs";
488
- import path3 from "node:path";
489
- import process4 from "node:process";
822
+ import fs7 from "node:fs";
823
+ import path6 from "node:path";
824
+ import process5 from "node:process";
490
825
  import { exec } from "tinyexec";
491
826
  import { Option } from "commander";
492
827
  import * as p2 from "@clack/prompts";
@@ -502,7 +837,7 @@ var installOption = new Option(
502
837
  "installs dependencies with a specified package manager"
503
838
  ).choices(AGENT_NAMES);
504
839
  function getUserAgent() {
505
- const userAgent = process4.env.npm_config_user_agent;
840
+ const userAgent = process5.env.npm_config_user_agent;
506
841
  if (!userAgent) return void 0;
507
842
  const pmSpec = userAgent.split(" ")[0];
508
843
  const separatorPos = pmSpec.lastIndexOf("/");
@@ -512,7 +847,7 @@ function getUserAgent() {
512
847
  async function packageManagerPrompt(cwd) {
513
848
  const detected = await detect({ cwd });
514
849
  const agent = detected?.name ?? getUserAgent();
515
- if (!process4.stdout.isTTY) return agent;
850
+ if (!process5.stdout.isTTY) return agent;
516
851
  const options = [
517
852
  { label: "None", value: void 0 },
518
853
  ...AGENT_NAMES.map((pm2) => ({ value: pm2, label: pm2 }))
@@ -524,14 +859,14 @@ async function packageManagerPrompt(cwd) {
524
859
  });
525
860
  if (p2.isCancel(pm)) {
526
861
  p2.cancel("Operation cancelled.");
527
- process4.exit(1);
862
+ process5.exit(1);
528
863
  }
529
864
  return pm;
530
865
  }
531
866
  async function installDependencies(agent, cwd) {
532
867
  const task = p2.taskLog({
533
868
  title: `Installing dependencies with ${agent}...`,
534
- limit: Math.ceil(process4.stdout.rows / 2),
869
+ limit: Math.ceil(process5.stdout.rows / 2),
535
870
  spacing: 0,
536
871
  retainLog: true
537
872
  });
@@ -548,14 +883,14 @@ async function installDependencies(agent, cwd) {
548
883
  } catch {
549
884
  task.error("Failed to install dependencies");
550
885
  p2.cancel("Operation failed.");
551
- process4.exit(2);
886
+ process5.exit(2);
552
887
  }
553
888
  }
554
889
  function addPnpmBuildDependencies(cwd, packageManager, allowedPackages) {
555
890
  if (!packageManager || packageManager !== "pnpm") return;
556
- const pkgPath = path3.join(cwd, "package.json");
557
- if (!fs4.existsSync(pkgPath)) return;
558
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
891
+ const pkgPath = path6.join(cwd, "package.json");
892
+ if (!fs7.existsSync(pkgPath)) return;
893
+ const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
559
894
  pkg.pnpm ??= {};
560
895
  pkg.pnpm.onlyBuiltDependencies ??= [];
561
896
  for (const name of allowedPackages) {
@@ -563,14 +898,14 @@ function addPnpmBuildDependencies(cwd, packageManager, allowedPackages) {
563
898
  pkg.pnpm.onlyBuiltDependencies.push(name);
564
899
  }
565
900
  }
566
- fs4.writeFileSync(pkgPath, JSON.stringify(pkg, null, " ") + "\n");
901
+ fs7.writeFileSync(pkgPath, JSON.stringify(pkg, null, " ") + "\n");
567
902
  }
568
903
 
569
904
  // src/lib/pocketbase.ts
570
- import fs5 from "node:fs";
905
+ import fs8 from "node:fs";
571
906
  import net from "node:net";
572
- import path4 from "node:path";
573
- import process5 from "node:process";
907
+ import path7 from "node:path";
908
+ import process6 from "node:process";
574
909
  import { createRequire } from "node:module";
575
910
  import { spawn } from "node:child_process";
576
911
  import PocketBase from "pocketbase";
@@ -682,9 +1017,9 @@ async function authWithRetries(pb, email3, password11, attempts = 3) {
682
1017
  }
683
1018
  }
684
1019
  function getPocketbaseMetadata(cwd) {
685
- const metadataPath = path4.join(cwd, "node_modules", ".vite", "_pocketbase_metadata.json");
686
- if (fs5.existsSync(metadataPath)) {
687
- return JSON.parse(fs5.readFileSync(metadataPath, "utf8"));
1020
+ const metadataPath = path7.join(cwd, "node_modules", ".vite", "_pocketbase_metadata.json");
1021
+ if (fs8.existsSync(metadataPath)) {
1022
+ return JSON.parse(fs8.readFileSync(metadataPath, "utf8"));
688
1023
  }
689
1024
  return null;
690
1025
  }
@@ -697,12 +1032,12 @@ async function execPackageBin(cwd, args, stdio = "pipe") {
697
1032
  return x(command, resolvedArgs, { nodeOptions: { cwd, stdio }, throwOnError: true });
698
1033
  }
699
1034
  async function withPocketbase(cwd, fn, creds) {
700
- const dir = path4.join(cwd, DATA_DIR);
701
- const migrationsDir = path4.join(cwd, MIGRATIONS_DIR);
1035
+ const dir = path7.join(cwd, DATA_DIR);
1036
+ const migrationsDir = path7.join(cwd, MIGRATIONS_DIR);
702
1037
  const host = "localhost";
703
- const email3 = creds?.email ?? process5.env.POCKETBASE_SUPERUSER_EMAIL;
704
- const password11 = creds?.password ?? process5.env.POCKETBASE_SUPERUSER_PASSWORD;
705
- if (!fs5.existsSync(dir)) {
1038
+ const email3 = creds?.email ?? process6.env.POCKETBASE_SUPERUSER_EMAIL;
1039
+ const password11 = creds?.password ?? process6.env.POCKETBASE_SUPERUSER_PASSWORD;
1040
+ if (!fs8.existsSync(dir)) {
706
1041
  throw new Error("PocketBase data directory does not exist");
707
1042
  }
708
1043
  const metadata = getPocketbaseMetadata(cwd);
@@ -727,10 +1062,10 @@ async function withPocketbase(cwd, fn, creds) {
727
1062
  }
728
1063
  }
729
1064
  async function createSuperuser(cwd, email3, password11) {
730
- const dir = path4.join(cwd, DATA_DIR);
731
- const migrationsDir = path4.join(cwd, MIGRATIONS_DIR);
732
- fs5.mkdirSync(dir, { recursive: true });
733
- fs5.mkdirSync(migrationsDir, { recursive: true });
1065
+ const dir = path7.join(cwd, DATA_DIR);
1066
+ const migrationsDir = path7.join(cwd, MIGRATIONS_DIR);
1067
+ fs8.mkdirSync(dir, { recursive: true });
1068
+ fs8.mkdirSync(migrationsDir, { recursive: true });
734
1069
  await execPackageBin(
735
1070
  cwd,
736
1071
  [
@@ -755,8 +1090,8 @@ async function launchPocketbase(cwd, {
755
1090
  password: password11
756
1091
  }) {
757
1092
  const host = "localhost";
758
- fs5.mkdirSync(dir, { recursive: true });
759
- fs5.mkdirSync(migrationsDir, { recursive: true });
1093
+ fs8.mkdirSync(dir, { recursive: true });
1094
+ fs8.mkdirSync(migrationsDir, { recursive: true });
760
1095
  await execPackageBin(
761
1096
  cwd,
762
1097
  [
@@ -795,11 +1130,11 @@ function pocketbaseVersion() {
795
1130
  return pkg.version;
796
1131
  }
797
1132
  async function ensureSuperuser(cwd) {
798
- const email3 = process5.env.POCKETBASE_SUPERUSER_EMAIL;
799
- const password11 = process5.env.POCKETBASE_SUPERUSER_PASSWORD;
1133
+ const email3 = process6.env.POCKETBASE_SUPERUSER_EMAIL;
1134
+ const password11 = process6.env.POCKETBASE_SUPERUSER_PASSWORD;
800
1135
  if (!email3 || !password11) return;
801
- const dir = path4.join(cwd, DATA_DIR);
802
- if (!fs5.existsSync(dir)) return;
1136
+ const dir = path7.join(cwd, DATA_DIR);
1137
+ if (!fs8.existsSync(dir)) return;
803
1138
  const { getBinaryPath } = await import("pocketbase-server");
804
1139
  await x(
805
1140
  getBinaryPath(),
@@ -807,7 +1142,7 @@ async function ensureSuperuser(cwd) {
807
1142
  "--dir",
808
1143
  dir,
809
1144
  "--migrationsDir",
810
- path4.join(cwd, MIGRATIONS_DIR),
1145
+ path7.join(cwd, MIGRATIONS_DIR),
811
1146
  "superuser",
812
1147
  "upsert",
813
1148
  email3,
@@ -818,8 +1153,8 @@ async function ensureSuperuser(cwd) {
818
1153
  }
819
1154
 
820
1155
  // src/lib/env.ts
821
- import fs6 from "node:fs";
822
- import path5 from "node:path";
1156
+ import fs9 from "node:fs";
1157
+ import path8 from "node:path";
823
1158
  function addEnvVar(content, key, value) {
824
1159
  if (content.includes(`${key}=`)) return content;
825
1160
  return appendLine(content, `${key}=${value}`);
@@ -834,11 +1169,11 @@ function appendLine(existing, line) {
834
1169
  return withNewline + line + "\n";
835
1170
  }
836
1171
  function writeEnvFile(cwd, vars, comments = []) {
837
- const envPath = path5.join(cwd, ".env");
838
- let content = fs6.existsSync(envPath) ? fs6.readFileSync(envPath, "utf8") : "";
1172
+ const envPath = path8.join(cwd, ".env");
1173
+ let content = fs9.existsSync(envPath) ? fs9.readFileSync(envPath, "utf8") : "";
839
1174
  for (const comment of comments) content = addEnvComment(content, comment);
840
1175
  for (const [key, value] of Object.entries(vars)) content = addEnvVar(content, key, value);
841
- fs6.writeFileSync(envPath, content);
1176
+ fs9.writeFileSync(envPath, content);
842
1177
  }
843
1178
  function upsertEnvVar(content, key, value) {
844
1179
  const line = `${key}=${quoteEnvValue(value)}`;
@@ -871,7 +1206,7 @@ function quoteEnvValue(value) {
871
1206
  }
872
1207
 
873
1208
  // src/lib/app-css.ts
874
- import fs7 from "node:fs";
1209
+ import fs10 from "node:fs";
875
1210
  var SHADCN_TAILWIND_CSS = "shadcn-svelte/tailwind.css";
876
1211
  var SHADCN_TAILWIND_IMPORT = `@import '${SHADCN_TAILWIND_CSS}';`;
877
1212
  function hasShadcnImport(css) {
@@ -897,21 +1232,21 @@ ${css}`;
897
1232
  return lines.join("\n");
898
1233
  }
899
1234
  function ensureShadcnImport(appCssPath) {
900
- if (!fs7.existsSync(appCssPath)) return false;
901
- const css = fs7.readFileSync(appCssPath, "utf8");
1235
+ if (!fs10.existsSync(appCssPath)) return false;
1236
+ const css = fs10.readFileSync(appCssPath, "utf8");
902
1237
  if (hasShadcnImport(css)) return false;
903
- fs7.writeFileSync(appCssPath, insertShadcnImport(css));
1238
+ fs10.writeFileSync(appCssPath, insertShadcnImport(css));
904
1239
  return true;
905
1240
  }
906
1241
 
907
1242
  // src/lib/components-json.ts
908
- import fs8 from "node:fs";
909
- import path6 from "node:path";
1243
+ import fs11 from "node:fs";
1244
+ import path9 from "node:path";
910
1245
  function readComponentsJson(root) {
911
- const file = path6.join(root, "components.json");
912
- if (!fs8.existsSync(file)) return void 0;
1246
+ const file = path9.join(root, "components.json");
1247
+ if (!fs11.existsSync(file)) return void 0;
913
1248
  try {
914
- const parsed = JSON.parse(fs8.readFileSync(file, "utf8"));
1249
+ const parsed = JSON.parse(fs11.readFileSync(file, "utf8"));
915
1250
  return parsed && typeof parsed === "object" ? parsed : void 0;
916
1251
  } catch {
917
1252
  return void 0;
@@ -933,12 +1268,12 @@ function componentsJsonHints(config) {
933
1268
  }
934
1269
 
935
1270
  // src/lib/config-merge.ts
936
- import fs10 from "node:fs";
937
- import path8 from "node:path";
1271
+ import fs13 from "node:fs";
1272
+ import path11 from "node:path";
938
1273
 
939
1274
  // src/lib/config-target.ts
940
- import fs9 from "node:fs";
941
- import path7 from "node:path";
1275
+ import fs12 from "node:fs";
1276
+ import path10 from "node:path";
942
1277
  import {
943
1278
  Project,
944
1279
  QuoteKind,
@@ -958,8 +1293,8 @@ var SVELTE_CONFIG_CANDIDATES = [
958
1293
  ];
959
1294
  function probeFirstExisting(root, candidates) {
960
1295
  for (const rel of candidates) {
961
- const abs = path7.join(root, rel);
962
- if (fs9.existsSync(abs)) return abs;
1296
+ const abs = path10.join(root, rel);
1297
+ if (fs12.existsSync(abs)) return abs;
963
1298
  }
964
1299
  return null;
965
1300
  }
@@ -1035,7 +1370,7 @@ function mergeSvelteConfig(projectRoot) {
1035
1370
  };
1036
1371
  }
1037
1372
  function mergeRunesIntoViteArg(vite, arg) {
1038
- const file = path8.basename(vite.filePath);
1373
+ const file = path11.basename(vite.filePath);
1039
1374
  const compilerOptions = getOrCreateObjectLiteralProperty(arg, "compilerOptions", "{}");
1040
1375
  if (!compilerOptions) {
1041
1376
  return {
@@ -1054,8 +1389,8 @@ function mergeRunesIntoViteArg(vite, arg) {
1054
1389
  return { applied: true, reason: "added runes compilerOption", file };
1055
1390
  }
1056
1391
  function mergeRunesIntoSvelteConfig(filePath) {
1057
- const file = path8.basename(filePath);
1058
- const original = fs10.readFileSync(filePath, "utf8");
1392
+ const file = path11.basename(filePath);
1393
+ const original = fs13.readFileSync(filePath, "utf8");
1059
1394
  if (/runes\s*:/m.test(original)) {
1060
1395
  return { applied: false, reason: "runes already configured", file };
1061
1396
  }
@@ -1078,11 +1413,11 @@ function mergeRunesIntoSvelteConfig(filePath) {
1078
1413
  }
1079
1414
  const insertAt = anchor.index + anchor[0].length;
1080
1415
  const updated = original.slice(0, insertAt) + RUNES_SNIPPET + original.slice(insertAt);
1081
- fs10.writeFileSync(filePath, updated);
1416
+ fs13.writeFileSync(filePath, updated);
1082
1417
  return { applied: true, reason: "added runes compilerOption", file };
1083
1418
  }
1084
1419
  function mergeViteConfig(filePath) {
1085
- if (!fs10.existsSync(filePath)) {
1420
+ if (!fs13.existsSync(filePath)) {
1086
1421
  return {
1087
1422
  applied: false,
1088
1423
  reason: "vite.config.ts not found",
@@ -1090,7 +1425,7 @@ function mergeViteConfig(filePath) {
1090
1425
  // then add tailwindcss() to the plugins array`
1091
1426
  };
1092
1427
  }
1093
- const original = fs10.readFileSync(filePath, "utf8");
1428
+ const original = fs13.readFileSync(filePath, "utf8");
1094
1429
  if (original.includes("@tailwindcss/vite")) {
1095
1430
  return { applied: false, reason: "tailwindcss plugin already present" };
1096
1431
  }
@@ -1109,14 +1444,14 @@ function mergeViteConfig(filePath) {
1109
1444
  const trailing = withImport.slice(insertAt);
1110
1445
  const prefix = /^\s*\]/.test(trailing) ? "tailwindcss()" : "tailwindcss(), ";
1111
1446
  const updated = withImport.slice(0, insertAt) + prefix + withImport.slice(insertAt);
1112
- fs10.writeFileSync(filePath, updated);
1447
+ fs13.writeFileSync(filePath, updated);
1113
1448
  return { applied: true, reason: "added @tailwindcss/vite plugin" };
1114
1449
  }
1115
1450
  function mergeTsconfig(filePath) {
1116
- if (!fs10.existsSync(filePath)) {
1451
+ if (!fs13.existsSync(filePath)) {
1117
1452
  return { applied: false, reason: "tsconfig.json not found" };
1118
1453
  }
1119
- const original = fs10.readFileSync(filePath, "utf8");
1454
+ const original = fs13.readFileSync(filePath, "utf8");
1120
1455
  if (/rewriteRelativeImportExtensions/.test(original)) {
1121
1456
  return { applied: false, reason: "rewriteRelativeImportExtensions already set" };
1122
1457
  }
@@ -1132,7 +1467,7 @@ function mergeTsconfig(filePath) {
1132
1467
  const indent = detectIndent(original, insertAt);
1133
1468
  const updated = original.slice(0, insertAt) + `
1134
1469
  ${indent}"rewriteRelativeImportExtensions": true,` + original.slice(insertAt);
1135
- fs10.writeFileSync(filePath, updated);
1470
+ fs13.writeFileSync(filePath, updated);
1136
1471
  return { applied: true, reason: "added rewriteRelativeImportExtensions" };
1137
1472
  }
1138
1473
  var GITIGNORE_ENTRIES = [
@@ -1144,7 +1479,7 @@ var GITIGNORE_ENTRIES = [
1144
1479
  "vite.config.ts.timestamp-*"
1145
1480
  ];
1146
1481
  function mergeGitignore(filePath) {
1147
- const existing = fs10.existsSync(filePath) ? fs10.readFileSync(filePath, "utf8") : "";
1482
+ const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf8") : "";
1148
1483
  const lines = existing.split("\n").map((l) => l.trim());
1149
1484
  const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.includes(entry));
1150
1485
  if (missing.length === 0) {
@@ -1153,7 +1488,7 @@ function mergeGitignore(filePath) {
1153
1488
  const needsNewline = existing.length > 0 && !existing.endsWith("\n");
1154
1489
  const appended = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
1155
1490
  `;
1156
- fs10.writeFileSync(filePath, appended);
1491
+ fs13.writeFileSync(filePath, appended);
1157
1492
  return { applied: true, reason: `added ${missing.length} gitignore entries` };
1158
1493
  }
1159
1494
  function addImport(source, importLine) {
@@ -1178,14 +1513,14 @@ function detectIndent(source, atOffset) {
1178
1513
  }
1179
1514
 
1180
1515
  // src/lib/scaffold-detect.ts
1181
- import fs11 from "node:fs";
1182
- import path9 from "node:path";
1516
+ import fs14 from "node:fs";
1517
+ import path12 from "node:path";
1183
1518
  var VANILLA_MARKER = "Welcome to SvelteKit";
1184
- var PAGE_REL = path9.join("src", "routes", "+page.svelte");
1519
+ var PAGE_REL = path12.join("src", "routes", "+page.svelte");
1185
1520
  function isVanillaRoutes(cwd) {
1186
- const pagePath = path9.join(cwd, PAGE_REL);
1187
- if (!fs11.existsSync(pagePath)) return false;
1188
- return fs11.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
1521
+ const pagePath = path12.join(cwd, PAGE_REL);
1522
+ if (!fs14.existsSync(pagePath)) return false;
1523
+ return fs14.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
1189
1524
  }
1190
1525
 
1191
1526
  // src/lib/result-report.ts
@@ -1232,62 +1567,16 @@ ${failure.message}` : headline);
1232
1567
  }
1233
1568
  }
1234
1569
 
1235
- // src/lib/template-files.ts
1236
- import fs12 from "node:fs";
1237
- import path10 from "node:path";
1238
- var PUBLISH_SAFE_NAMES = {
1239
- ".gitignore": "_gitignore",
1240
- ".npmrc": "_npmrc"
1241
- };
1242
- function templateName(projectRelPath) {
1243
- const safe = PUBLISH_SAFE_NAMES[path10.basename(projectRelPath)];
1244
- if (!safe) return projectRelPath;
1245
- const dir = path10.dirname(projectRelPath);
1246
- return dir === "." ? safe : path10.join(dir, safe);
1247
- }
1248
- function restoreTemplateNames(target) {
1249
- for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
1250
- const from = path10.join(target, safe);
1251
- if (!fs12.existsSync(from)) continue;
1252
- fs12.renameSync(from, path10.join(target, real));
1253
- }
1254
- }
1255
- var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
1256
- function applyTemplateFiles(target, values) {
1257
- const written = [];
1258
- for (const source of findTemplateSources(target)) {
1259
- const raw = fs12.readFileSync(source, "utf8");
1260
- const dest = source.replace(TEMPLATE_SOURCE, ".$1");
1261
- fs12.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
1262
- fs12.unlinkSync(source);
1263
- written.push(path10.relative(target, dest));
1264
- }
1265
- return written.sort();
1266
- }
1267
- function findTemplateSources(dir) {
1268
- const found = [];
1269
- for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
1270
- const full = path10.join(dir, entry.name);
1271
- if (entry.isDirectory()) {
1272
- if (entry.name === "node_modules" || entry.name === ".git") continue;
1273
- found.push(...findTemplateSources(full));
1274
- } else if (entry.isFile() && TEMPLATE_SOURCE.test(entry.name)) {
1275
- found.push(full);
1276
- }
1277
- }
1278
- return found;
1279
- }
1280
-
1281
1570
  // src/commands/bless.ts
1282
1571
  function optionsSchema() {
1283
1572
  const templates = projectTemplateNames({ backend: true });
1284
- return v2.strictObject({
1285
- install: v2.union([v2.boolean(), v2.picklist(AGENT_NAMES)], "must be a package manager"),
1286
- template: v2.optional(v2.picklist(templates, `must be one of: ${templates.join(", ")}`)),
1287
- email: v2.optional(v2.pipe(v2.string(), v2.email("must be a valid email address"))),
1288
- password: v2.optional(v2.pipe(v2.string(), v2.minLength(8, "must be at least 8 characters long"))),
1289
- skipRoutes: v2.optional(v2.boolean()),
1290
- forceRoutes: v2.optional(v2.boolean())
1573
+ return v3.strictObject({
1574
+ install: v3.union([v3.boolean(), v3.picklist(AGENT_NAMES)], "must be a package manager"),
1575
+ template: v3.optional(v3.picklist(templates, `must be one of: ${templates.join(", ")}`)),
1576
+ email: v3.optional(v3.pipe(v3.string(), v3.email("must be a valid email address"))),
1577
+ password: v3.optional(v3.pipe(v3.string(), v3.minLength(8, "must be at least 8 characters long"))),
1578
+ skipRoutes: v3.optional(v3.boolean()),
1579
+ forceRoutes: v3.optional(v3.boolean())
1291
1580
  });
1292
1581
  }
1293
1582
  var VELA_ONLY_FILES = [
@@ -1343,7 +1632,7 @@ async function blessProject(cwdArg, options) {
1343
1632
  {
1344
1633
  onCancel: () => {
1345
1634
  p4.cancel("Operation cancelled.");
1346
- process6.exit(0);
1635
+ process7.exit(0);
1347
1636
  }
1348
1637
  }
1349
1638
  );
@@ -1378,7 +1667,7 @@ async function blessProject(cwdArg, options) {
1378
1667
  printNextSteps(projectPath, packageManager);
1379
1668
  }
1380
1669
  function ensureShadcnCss(projectPath) {
1381
- if (ensureShadcnImport(path11.join(projectPath, "src", "app.css"))) {
1670
+ if (ensureShadcnImport(path13.join(projectPath, "src", "app.css"))) {
1382
1671
  p4.log.info(
1383
1672
  "src/app.css: added the shadcn-svelte/tailwind.css import its registry components rely on."
1384
1673
  );
@@ -1390,22 +1679,22 @@ function hintComponentsJson(projectPath) {
1390
1679
  for (const hint of componentsJsonHints(config)) p4.log.warn(hint);
1391
1680
  }
1392
1681
  function resolveProjectPath(cwdArg) {
1393
- const projectPath = path11.resolve(cwdArg);
1394
- if (!fs13.existsSync(projectPath)) {
1682
+ const projectPath = path13.resolve(cwdArg);
1683
+ if (!fs15.existsSync(projectPath)) {
1395
1684
  throw new Error(`Path does not exist: ${projectPath}`);
1396
1685
  }
1397
- if (!fs13.existsSync(path11.join(projectPath, "package.json"))) {
1686
+ if (!fs15.existsSync(path13.join(projectPath, "package.json"))) {
1398
1687
  throw new Error(`No package.json found at ${projectPath}`);
1399
1688
  }
1400
- if (!fs13.existsSync(path11.join(projectPath, "src", "routes"))) {
1689
+ if (!fs15.existsSync(path13.join(projectPath, "src", "routes"))) {
1401
1690
  throw new Error(`No src/routes directory found at ${projectPath}`);
1402
1691
  }
1403
1692
  return projectPath;
1404
1693
  }
1405
1694
  function assertNotAlreadyBlessed(projectPath) {
1406
- const hooksPath = path11.join(projectPath, "src", "hooks.server.ts");
1407
- if (!fs13.existsSync(hooksPath)) return;
1408
- const content = fs13.readFileSync(hooksPath, "utf8");
1695
+ const hooksPath = path13.join(projectPath, "src", "hooks.server.ts");
1696
+ if (!fs15.existsSync(hooksPath)) return;
1697
+ const content = fs15.readFileSync(hooksPath, "utf8");
1409
1698
  if (content.includes("@velastack/pocketbase")) {
1410
1699
  throw new Error(
1411
1700
  "This project already looks blessed (src/hooks.server.ts imports @velastack/pocketbase). Run `vela sync` instead."
@@ -1413,8 +1702,8 @@ function assertNotAlreadyBlessed(projectPath) {
1413
1702
  }
1414
1703
  }
1415
1704
  function mergeDependencies(projectPath, templateDir) {
1416
- const userPkgPath = path11.join(projectPath, "package.json");
1417
- const templatePkgPath = path11.join(templateDir, "package.template.json");
1705
+ const userPkgPath = path13.join(projectPath, "package.json");
1706
+ const templatePkgPath = path13.join(templateDir, "package.template.json");
1418
1707
  const userPkg = readPackageJson(userPkgPath);
1419
1708
  const appName = typeof userPkg.name === "string" ? userPkg.name : "sveltekit";
1420
1709
  const templatePkg = readTemplatePackageJson(templatePkgPath, {
@@ -1446,21 +1735,21 @@ ${lines.join("\n")}`);
1446
1735
  function copyVelaOnlyFiles(templateDir, projectPath) {
1447
1736
  const kept = [];
1448
1737
  for (const file of VELA_ONLY_FILES) {
1449
- const src = path11.join(templateDir, templateName(file.path));
1450
- const dest = path11.join(projectPath, file.path);
1451
- if (!fs13.existsSync(src)) continue;
1452
- if (fs13.existsSync(dest)) {
1738
+ const src = path13.join(templateDir, templateName(file.path));
1739
+ const dest = path13.join(projectPath, file.path);
1740
+ if (!fs15.existsSync(src)) continue;
1741
+ if (fs15.existsSync(dest)) {
1453
1742
  kept.push(file);
1454
1743
  continue;
1455
1744
  }
1456
- fs13.mkdirSync(path11.dirname(dest), { recursive: true });
1457
- fs13.copyFileSync(src, dest);
1745
+ fs15.mkdirSync(path13.dirname(dest), { recursive: true });
1746
+ fs15.copyFileSync(src, dest);
1458
1747
  }
1459
1748
  reportKeptFiles(kept);
1460
1749
  for (const rel of VELA_ONLY_DIRS) {
1461
- const src = path11.join(templateDir, rel);
1462
- const dest = path11.join(projectPath, rel);
1463
- if (!fs13.existsSync(src)) continue;
1750
+ const src = path13.join(templateDir, rel);
1751
+ const dest = path13.join(projectPath, rel);
1752
+ if (!fs15.existsSync(src)) continue;
1464
1753
  copyDirShallow(src, dest);
1465
1754
  }
1466
1755
  }
@@ -1474,15 +1763,15 @@ ${lines.join("\n")}`
1474
1763
  );
1475
1764
  }
1476
1765
  function copyDirShallow(src, dest) {
1477
- fs13.mkdirSync(dest, { recursive: true });
1478
- for (const entry of fs13.readdirSync(src, { withFileTypes: true })) {
1766
+ fs15.mkdirSync(dest, { recursive: true });
1767
+ for (const entry of fs15.readdirSync(src, { withFileTypes: true })) {
1479
1768
  if (entry.name === ".DS_Store") continue;
1480
- const srcChild = path11.join(src, entry.name);
1481
- const destChild = path11.join(dest, entry.name);
1769
+ const srcChild = path13.join(src, entry.name);
1770
+ const destChild = path13.join(dest, entry.name);
1482
1771
  if (entry.isDirectory()) {
1483
1772
  copyDirShallow(srcChild, destChild);
1484
- } else if (entry.isFile() && !fs13.existsSync(destChild)) {
1485
- fs13.copyFileSync(srcChild, destChild);
1773
+ } else if (entry.isFile() && !fs15.existsSync(destChild)) {
1774
+ fs15.copyFileSync(srcChild, destChild);
1486
1775
  }
1487
1776
  }
1488
1777
  }
@@ -1490,9 +1779,9 @@ function mergeConfigFiles(projectPath) {
1490
1779
  const runes = mergeSvelteConfig(projectPath);
1491
1780
  const outcomes = [
1492
1781
  [runes.file ?? "svelte.config", runes],
1493
- ["vite.config.ts", mergeViteConfig(path11.join(projectPath, "vite.config.ts"))],
1494
- ["tsconfig.json", mergeTsconfig(path11.join(projectPath, "tsconfig.json"))],
1495
- [".gitignore", mergeGitignore(path11.join(projectPath, ".gitignore"))]
1782
+ ["vite.config.ts", mergeViteConfig(path13.join(projectPath, "vite.config.ts"))],
1783
+ ["tsconfig.json", mergeTsconfig(path13.join(projectPath, "tsconfig.json"))],
1784
+ [".gitignore", mergeGitignore(path13.join(projectPath, ".gitignore"))]
1496
1785
  ];
1497
1786
  for (const [name, outcome] of outcomes) {
1498
1787
  if (outcome.applied) {
@@ -1509,14 +1798,14 @@ ${pc3.cyan(outcome.snippet)}`
1509
1798
  }
1510
1799
  }
1511
1800
  function mergeAppDts(templateDir, projectPath) {
1512
- const dest = path11.join(projectPath, "src", "app.d.ts");
1513
- const templateFile = path11.join(templateDir, "src", "app.d.ts");
1514
- if (!fs13.existsSync(dest)) {
1515
- if (!fs13.existsSync(templateFile)) return;
1516
- fs13.copyFileSync(templateFile, dest);
1801
+ const dest = path13.join(projectPath, "src", "app.d.ts");
1802
+ const templateFile = path13.join(templateDir, "src", "app.d.ts");
1803
+ if (!fs15.existsSync(dest)) {
1804
+ if (!fs15.existsSync(templateFile)) return;
1805
+ fs15.copyFileSync(templateFile, dest);
1517
1806
  return;
1518
1807
  }
1519
- const current = fs13.readFileSync(dest, "utf8");
1808
+ const current = fs15.readFileSync(dest, "utf8");
1520
1809
  if (current.includes("namespace Superforms")) return;
1521
1810
  const block = ` namespace Superforms {
1522
1811
  type Message = {
@@ -1535,7 +1824,7 @@ ${pc3.cyan(block)}`
1535
1824
  }
1536
1825
  const insertAt = match.index + match[0].length;
1537
1826
  const updated = current.slice(0, insertAt) + block + current.slice(insertAt);
1538
- fs13.writeFileSync(dest, updated);
1827
+ fs15.writeFileSync(dest, updated);
1539
1828
  }
1540
1829
  function maybeReplaceRoutes(projectPath, templateDir, options) {
1541
1830
  if (options.skipRoutes) {
@@ -1546,12 +1835,12 @@ function maybeReplaceRoutes(projectPath, templateDir, options) {
1546
1835
  p4.log.info("Leaving src/routes alone (looks customized).");
1547
1836
  return;
1548
1837
  }
1549
- const target = path11.join(projectPath, "src", "routes");
1550
- fs13.rmSync(target, { recursive: true, force: true });
1551
- const src = path11.join(templateDir, "src", "routes");
1552
- fs13.cpSync(src, target, {
1838
+ const target = path13.join(projectPath, "src", "routes");
1839
+ fs15.rmSync(target, { recursive: true, force: true });
1840
+ const src = path13.join(templateDir, "src", "routes");
1841
+ fs15.cpSync(src, target, {
1553
1842
  recursive: true,
1554
- filter: (s) => path11.basename(s) !== ".DS_Store"
1843
+ filter: (s) => path13.basename(s) !== ".DS_Store"
1555
1844
  });
1556
1845
  p4.log.success("Replaced src/routes with the vela template.");
1557
1846
  }
@@ -1560,7 +1849,7 @@ function summarize(names) {
1560
1849
  return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
1561
1850
  }
1562
1851
  function printNextSteps(projectPath, packageManager) {
1563
- const relative = path11.relative(process6.cwd(), projectPath);
1852
+ const relative = path13.relative(process7.cwd(), projectPath);
1564
1853
  const pm = packageManager ?? getUserAgent() ?? "npm";
1565
1854
  const nextSteps = [];
1566
1855
  if (relative !== "") {
@@ -1584,31 +1873,37 @@ function printNextSteps(projectPath, packageManager) {
1584
1873
  }
1585
1874
 
1586
1875
  // src/commands/create.ts
1587
- import fs14 from "node:fs";
1588
- import path12 from "node:path";
1589
- import process7 from "node:process";
1590
- import * as v3 from "valibot";
1876
+ import fs16 from "node:fs";
1877
+ import path14 from "node:path";
1878
+ import process8 from "node:process";
1879
+ import * as v4 from "valibot";
1591
1880
  import { Command as Command3 } from "commander";
1592
1881
  import * as p5 from "@clack/prompts";
1593
1882
  import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
1594
- function optionsSchema2() {
1595
- const templates = projectTemplateNames();
1596
- return v3.strictObject({
1597
- install: v3.union([v3.boolean(), v3.picklist(AGENT_NAMES)], "must be a package manager"),
1598
- template: v3.optional(v3.picklist(templates, `must be one of: ${templates.join(", ")}`)),
1599
- name: v3.optional(v3.pipe(v3.string(), v3.trim(), v3.minLength(1, "must not be empty"))),
1600
- email: v3.optional(v3.pipe(v3.string(), v3.email("must be a valid email address"))),
1601
- password: v3.optional(v3.pipe(v3.string(), v3.minLength(8, "must be at least 8 characters long")))
1883
+ function optionsSchema2(listing) {
1884
+ const names = listing.templates.map((template) => template.name);
1885
+ let choices = `must be one of: ${templateChoicesMessage(listing.templates)}`;
1886
+ if (listing.registryError) {
1887
+ choices += ` (could not reach the template registry: ${listing.registryError})`;
1888
+ }
1889
+ return v4.strictObject({
1890
+ install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
1891
+ template: v4.optional(v4.picklist(names, choices)),
1892
+ name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
1893
+ email: v4.optional(v4.pipe(v4.string(), v4.email("must be a valid email address"))),
1894
+ password: v4.optional(v4.pipe(v4.string(), v4.minLength(8, "must be at least 8 characters long")))
1602
1895
  });
1603
1896
  }
1604
- var create = new Command3("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold", "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").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
1897
+ var create = new Command3("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").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
1605
1898
  return runCommand(async () => {
1606
- const options = parseOptions(optionsSchema2(), rawOpts);
1899
+ const listing = await listAllTemplates();
1900
+ const options = parseOptions(optionsSchema2(listing), rawOpts);
1607
1901
  const { directory, packageManager, name, template } = await createProject(
1608
1902
  projectPath,
1609
- options
1903
+ options,
1904
+ listing
1610
1905
  );
1611
- const relative = path12.relative(process7.cwd(), directory);
1906
+ const relative = path14.relative(process8.cwd(), directory);
1612
1907
  const pm = packageManager ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
1613
1908
  const nextSteps = [];
1614
1909
  if (relative !== "") {
@@ -1629,7 +1924,9 @@ var create = new Command3("create").description("scaffold a new velastack projec
1629
1924
  `\`${runDev.command} ${runDev.args.join(" ")}\` to start the dev server (Ctrl-C to stop)`
1630
1925
  );
1631
1926
  }
1632
- if (template.backend) {
1927
+ if (template.nextSteps) {
1928
+ nextSteps.push(...template.nextSteps);
1929
+ } else if (template.backend) {
1633
1930
  nextSteps.push("Run `vela generate scaffold <model>` to generate your first CRUD pages.");
1634
1931
  } else {
1635
1932
  nextSteps.push(
@@ -1644,12 +1941,12 @@ var create = new Command3("create").description("scaffold a new velastack projec
1644
1941
  });
1645
1942
  }, "Failed to create project.");
1646
1943
  });
1647
- async function createProject(cwdArg, options) {
1944
+ async function createProject(cwdArg, options, listing) {
1648
1945
  const onCancel2 = () => {
1649
1946
  p5.cancel("Operation cancelled.");
1650
- process7.exit(0);
1947
+ process8.exit(0);
1651
1948
  };
1652
- const template = findProjectTemplate(options.template ?? DEFAULT_TEMPLATE);
1949
+ const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
1653
1950
  if (!template.backend && (options.email || options.password)) {
1654
1951
  throw new Error(
1655
1952
  `--email and --password don't apply to the ${template.name} template \u2014 it has no backend.`
@@ -1657,7 +1954,7 @@ async function createProject(cwdArg, options) {
1657
1954
  }
1658
1955
  let directory;
1659
1956
  if (cwdArg) {
1660
- directory = path12.resolve(cwdArg);
1957
+ directory = path14.resolve(cwdArg);
1661
1958
  } else {
1662
1959
  const answer = await p5.text({
1663
1960
  message: "Where would you like your project to be created?",
@@ -1665,16 +1962,16 @@ async function createProject(cwdArg, options) {
1665
1962
  defaultValue: "./"
1666
1963
  });
1667
1964
  if (p5.isCancel(answer)) onCancel2();
1668
- directory = path12.resolve(answer);
1965
+ directory = path14.resolve(answer);
1669
1966
  }
1670
- if (fs14.existsSync(directory) && fs14.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
1967
+ if (fs16.existsSync(directory) && fs16.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
1671
1968
  const force = await p5.confirm({
1672
1969
  message: "Directory not empty. Continue?",
1673
1970
  initialValue: false
1674
1971
  });
1675
1972
  if (p5.isCancel(force) || !force) onCancel2();
1676
1973
  }
1677
- const dirName = path12.basename(directory);
1974
+ const dirName = path14.basename(directory);
1678
1975
  const { name } = await p5.group(
1679
1976
  {
1680
1977
  name: () => {
@@ -1690,9 +1987,15 @@ async function createProject(cwdArg, options) {
1690
1987
  );
1691
1988
  const credentials = template.backend ? await promptCredentials(options, onCancel2) : void 0;
1692
1989
  const projectPath = directory;
1693
- copyTemplate(template, projectPath);
1694
- applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
1695
- if (!fs14.existsSync(path12.join(projectPath, "package.json"))) {
1990
+ if (template.source === "remote") p5.log.step(`Downloading template ${template.name}...`);
1991
+ const resolved = await resolveTemplate(template);
1992
+ try {
1993
+ copyTemplate(resolved, projectPath);
1994
+ applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
1995
+ } finally {
1996
+ resolved.cleanup();
1997
+ }
1998
+ if (!fs16.existsSync(path14.join(projectPath, "package.json"))) {
1696
1999
  throw new Error(`Template ${template.name} is missing package.template.json`);
1697
2000
  }
1698
2001
  p5.log.success("Project created");
@@ -1753,15 +2056,6 @@ function promptCredentials(options, onCancel2) {
1753
2056
  { onCancel: onCancel2 }
1754
2057
  );
1755
2058
  }
1756
- function copyTemplate(template, target) {
1757
- fs14.mkdirSync(target, { recursive: true });
1758
- fs14.cpSync(template.dir, target, {
1759
- recursive: true,
1760
- // The manifest describes the template to the CLI; it isn't part of the project.
1761
- filter: (src) => path12.basename(src) !== ".DS_Store" && path12.relative(template.dir, src) !== TEMPLATE_MANIFEST
1762
- });
1763
- restoreTemplateNames(target);
1764
- }
1765
2059
 
1766
2060
  // src/commands/generate.ts
1767
2061
  import { Command as Command9 } from "commander";
@@ -1771,11 +2065,11 @@ import { Command as Command4 } from "commander";
1771
2065
  import * as p11 from "@clack/prompts";
1772
2066
 
1773
2067
  // src/lib/pattern-runner.ts
1774
- import path13 from "node:path";
2068
+ import path15 from "node:path";
1775
2069
  import * as p6 from "@clack/prompts";
1776
2070
  import { bySlug } from "@velastack/patterns";
1777
2071
  function toRelative(root, filePath) {
1778
- return path13.isAbsolute(filePath) ? path13.relative(root, filePath) : filePath;
2072
+ return path15.isAbsolute(filePath) ? path15.relative(root, filePath) : filePath;
1779
2073
  }
1780
2074
  var isSuccess = (f) => (f.status ?? "success") === "success";
1781
2075
  async function runPattern(slug2, argv, input, report4) {
@@ -1842,57 +2136,22 @@ async function runPattern(slug2, argv, input, report4) {
1842
2136
  }
1843
2137
 
1844
2138
  // src/lib/ai-flow.ts
1845
- import fs17 from "node:fs";
1846
- import path16 from "node:path";
2139
+ import fs18 from "node:fs";
2140
+ import path17 from "node:path";
1847
2141
  import * as p10 from "@clack/prompts";
1848
2142
  import pc4 from "picocolors";
1849
2143
 
1850
- // src/lib/config.ts
1851
- import fs15 from "node:fs";
1852
- import os from "node:os";
1853
- import path14 from "node:path";
1854
- import process8 from "node:process";
1855
- var CONFIG_DIR = path14.join(os.homedir(), ".vela");
1856
- var CONFIG_PATH = path14.join(CONFIG_DIR, "config.json");
1857
- function readConfig() {
1858
- if (!fs15.existsSync(CONFIG_PATH)) return null;
1859
- try {
1860
- return JSON.parse(fs15.readFileSync(CONFIG_PATH, "utf8"));
1861
- } catch {
1862
- return null;
1863
- }
1864
- }
1865
- function writeConfig(config) {
1866
- fs15.mkdirSync(CONFIG_DIR, { recursive: true });
1867
- fs15.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
1868
- }
1869
- function clearConfig() {
1870
- if (fs15.existsSync(CONFIG_PATH)) fs15.unlinkSync(CONFIG_PATH);
1871
- }
1872
- function readApiKey() {
1873
- const fromEnv = process8.env.VELA_API_KEY?.trim();
1874
- if (fromEnv) return fromEnv;
1875
- return readConfig()?.apiKey ?? null;
1876
- }
1877
- function requireApiKey() {
1878
- const apiKey = readApiKey();
1879
- if (!apiKey) {
1880
- throw new Error("Not logged in. Run `vela login` to login, or set VELA_API_KEY.");
1881
- }
1882
- return apiKey;
1883
- }
1884
-
1885
2144
  // src/lib/project-config.ts
1886
- import fs16 from "node:fs";
1887
- import path15 from "node:path";
2145
+ import fs17 from "node:fs";
2146
+ import path16 from "node:path";
1888
2147
  function projectConfigPath(workspaceRootDir) {
1889
- return path15.join(workspaceRootDir, ".vela", "project.json");
2148
+ return path16.join(workspaceRootDir, ".vela", "project.json");
1890
2149
  }
1891
2150
  function readProjectConfig(workspaceRootDir) {
1892
2151
  const file = projectConfigPath(workspaceRootDir);
1893
- if (!fs16.existsSync(file)) return null;
2152
+ if (!fs17.existsSync(file)) return null;
1894
2153
  try {
1895
- const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
2154
+ const parsed = JSON.parse(fs17.readFileSync(file, "utf8"));
1896
2155
  if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
1897
2156
  return null;
1898
2157
  }
@@ -1907,15 +2166,15 @@ function readProjectConfig(workspaceRootDir) {
1907
2166
  }
1908
2167
  function writeProjectConfig(workspaceRootDir, config) {
1909
2168
  const file = projectConfigPath(workspaceRootDir);
1910
- fs16.mkdirSync(path15.dirname(file), { recursive: true });
2169
+ fs17.mkdirSync(path16.dirname(file), { recursive: true });
1911
2170
  let existing = {};
1912
- if (fs16.existsSync(file)) {
2171
+ if (fs17.existsSync(file)) {
1913
2172
  try {
1914
- existing = JSON.parse(fs16.readFileSync(file, "utf8"));
2173
+ existing = JSON.parse(fs17.readFileSync(file, "utf8"));
1915
2174
  } catch {
1916
2175
  }
1917
2176
  }
1918
- fs16.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
2177
+ fs17.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
1919
2178
  }
1920
2179
 
1921
2180
  // src/lib/ai-client.ts
@@ -2189,11 +2448,11 @@ function specToArgv(spec) {
2189
2448
  return collectionSpecToArgv(spec);
2190
2449
  }
2191
2450
  function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
2192
- const dir = path16.join(workspaceRootDir, "data", "ai-form-layouts");
2193
- fs17.mkdirSync(dir, { recursive: true });
2194
- const file = path16.join(dir, `${modelName}.json`);
2195
- fs17.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
2196
- return path16.relative(workspaceRootDir, file);
2451
+ const dir = path17.join(workspaceRootDir, "data", "ai-form-layouts");
2452
+ fs18.mkdirSync(dir, { recursive: true });
2453
+ const file = path17.join(dir, `${modelName}.json`);
2454
+ fs18.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
2455
+ return path17.relative(workspaceRootDir, file);
2197
2456
  }
2198
2457
 
2199
2458
  // src/commands/generate/form.ts
@@ -2675,7 +2934,7 @@ async function ensureKey(envVar, message) {
2675
2934
  async function promptPassword(message) {
2676
2935
  const value = await p14.password({
2677
2936
  message,
2678
- validate: (v9) => v9 && v9.length ? void 0 : "Required"
2937
+ validate: (v10) => v10 && v10.length ? void 0 : "Required"
2679
2938
  });
2680
2939
  if (p14.isCancel(value)) {
2681
2940
  p14.cancel("Operation cancelled.");
@@ -2744,13 +3003,13 @@ import pc8 from "picocolors";
2744
3003
 
2745
3004
  // src/lib/server-command.ts
2746
3005
  import process11 from "node:process";
2747
- import * as v5 from "valibot";
3006
+ import * as v6 from "valibot";
2748
3007
  import * as p15 from "@clack/prompts";
2749
3008
  import pc5 from "picocolors";
2750
3009
 
2751
3010
  // src/lib/deploy-config.ts
2752
- import fs18 from "node:fs";
2753
- import path17 from "node:path";
3011
+ import fs19 from "node:fs";
3012
+ import path18 from "node:path";
2754
3013
  import crypto from "node:crypto";
2755
3014
  import { pathToFileURL } from "node:url";
2756
3015
  var CONFIG_BASENAMES = [
@@ -2761,8 +3020,8 @@ var CONFIG_BASENAMES = [
2761
3020
  ];
2762
3021
  function findConfigFile(workspaceRootDir) {
2763
3022
  for (const name of CONFIG_BASENAMES) {
2764
- const file = path17.join(workspaceRootDir, name);
2765
- if (fs18.existsSync(file)) return file;
3023
+ const file = path18.join(workspaceRootDir, name);
3024
+ if (fs19.existsSync(file)) return file;
2766
3025
  }
2767
3026
  return null;
2768
3027
  }
@@ -2770,49 +3029,49 @@ async function loadDeployConfig(workspaceRootDir) {
2770
3029
  const file = findConfigFile(workspaceRootDir);
2771
3030
  if (!file) return {};
2772
3031
  if (file.endsWith(".json")) {
2773
- return JSON.parse(fs18.readFileSync(file, "utf8"));
3032
+ return JSON.parse(fs19.readFileSync(file, "utf8"));
2774
3033
  }
2775
3034
  const url = file.endsWith(".ts") ? await transpileToTemp(file) : pathToFileURL(file).href;
2776
3035
  try {
2777
3036
  const mod = await import(url);
2778
3037
  const config = mod.default;
2779
3038
  if (!config || typeof config !== "object") {
2780
- throw new Error(`${path17.basename(file)} must export a config object as its default export.`);
3039
+ throw new Error(`${path18.basename(file)} must export a config object as its default export.`);
2781
3040
  }
2782
3041
  return config;
2783
3042
  } finally {
2784
- if (url !== pathToFileURL(file).href) fs18.rmSync(new URL(url), { force: true });
3043
+ if (url !== pathToFileURL(file).href) fs19.rmSync(new URL(url), { force: true });
2785
3044
  }
2786
3045
  }
2787
3046
  async function transpileToTemp(file) {
2788
3047
  const { ts } = await import("ts-morph");
2789
- const source = fs18.readFileSync(file, "utf8");
3048
+ const source = fs19.readFileSync(file, "utf8");
2790
3049
  const { outputText } = ts.transpileModule(source, {
2791
3050
  compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 }
2792
3051
  });
2793
- const temp = path17.join(
2794
- path17.dirname(file),
3052
+ const temp = path18.join(
3053
+ path18.dirname(file),
2795
3054
  `.velastack.config.${crypto.randomBytes(4).toString("hex")}.mjs`
2796
3055
  );
2797
- fs18.writeFileSync(temp, outputText);
3056
+ fs19.writeFileSync(temp, outputText);
2798
3057
  return pathToFileURL(temp).href;
2799
3058
  }
2800
3059
  function projectFilePath(workspaceRootDir) {
2801
- return path17.join(workspaceRootDir, ".vela", "project.json");
3060
+ return path18.join(workspaceRootDir, ".vela", "project.json");
2802
3061
  }
2803
3062
  function readProjectFile(workspaceRootDir) {
2804
3063
  const file = projectFilePath(workspaceRootDir);
2805
- if (!fs18.existsSync(file)) return {};
3064
+ if (!fs19.existsSync(file)) return {};
2806
3065
  try {
2807
- return JSON.parse(fs18.readFileSync(file, "utf8"));
3066
+ return JSON.parse(fs19.readFileSync(file, "utf8"));
2808
3067
  } catch {
2809
3068
  return {};
2810
3069
  }
2811
3070
  }
2812
3071
  function writeProjectFile(workspaceRootDir, data) {
2813
3072
  const file = projectFilePath(workspaceRootDir);
2814
- fs18.mkdirSync(path17.dirname(file), { recursive: true });
2815
- fs18.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
3073
+ fs19.mkdirSync(path18.dirname(file), { recursive: true });
3074
+ fs19.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
2816
3075
  }
2817
3076
  function resolveAppIdentity(workspaceRootDir, config = {}) {
2818
3077
  const project = readProjectFile(workspaceRootDir);
@@ -2837,11 +3096,11 @@ function readAppIdentity(workspaceRootDir, config = {}) {
2837
3096
  }
2838
3097
  function defaultProjectName(workspaceRootDir) {
2839
3098
  try {
2840
- const pkg = readPackageJson(path17.join(workspaceRootDir, "package.json"));
3099
+ const pkg = readPackageJson(path18.join(workspaceRootDir, "package.json"));
2841
3100
  if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
2842
3101
  } catch {
2843
3102
  }
2844
- return path17.basename(workspaceRootDir);
3103
+ return path18.basename(workspaceRootDir);
2845
3104
  }
2846
3105
  function slug(value) {
2847
3106
  return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
@@ -2902,15 +3161,15 @@ function releaseId(date = /* @__PURE__ */ new Date()) {
2902
3161
  }
2903
3162
 
2904
3163
  // src/lib/artifact.ts
2905
- import fs20 from "node:fs";
2906
- import path19 from "node:path";
3164
+ import fs21 from "node:fs";
3165
+ import path20 from "node:path";
2907
3166
  import { detect as detect4 } from "package-manager-detector";
2908
3167
  import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
2909
3168
 
2910
3169
  // src/lib/ssh.ts
2911
- import fs19 from "node:fs";
2912
- import os2 from "node:os";
2913
- import path18 from "node:path";
3170
+ import fs20 from "node:fs";
3171
+ import os3 from "node:os";
3172
+ import path19 from "node:path";
2914
3173
  import crypto2 from "node:crypto";
2915
3174
  import process10 from "node:process";
2916
3175
  import { spawn as spawn2 } from "node:child_process";
@@ -2953,9 +3212,9 @@ var SshSession = class {
2953
3212
  }
2954
3213
  async open() {
2955
3214
  if (this.controlPath) return;
2956
- const dir = path18.join(os2.tmpdir(), "vela-ssh");
2957
- fs19.mkdirSync(dir, { recursive: true, mode: 448 });
2958
- const socket = path18.join(dir, `${crypto2.randomBytes(6).toString("hex")}.sock`);
3215
+ const dir = path19.join(os3.tmpdir(), "vela-ssh");
3216
+ fs20.mkdirSync(dir, { recursive: true, mode: 448 });
3217
+ const socket = path19.join(dir, `${crypto2.randomBytes(6).toString("hex")}.sock`);
2959
3218
  this.controlPath = socket;
2960
3219
  const args = [
2961
3220
  ...this.sshArgs(),
@@ -3245,11 +3504,11 @@ function collectArtifact(cwd, config = {}) {
3245
3504
  const outputDir = config.outputDir ?? DEFAULT_OUTPUT_DIR;
3246
3505
  const entries = [];
3247
3506
  const add2 = (rel, remoteDir = "") => {
3248
- const localPath = path19.join(cwd, rel);
3249
- if (fs20.existsSync(localPath)) entries.push({ localPath, remoteDir });
3507
+ const localPath = path20.join(cwd, rel);
3508
+ if (fs21.existsSync(localPath)) entries.push({ localPath, remoteDir });
3250
3509
  };
3251
- const buildPath = path19.join(cwd, outputDir);
3252
- if (!fs20.existsSync(path19.join(buildPath, "index.js"))) {
3510
+ const buildPath = path20.join(cwd, outputDir);
3511
+ if (!fs21.existsSync(path20.join(buildPath, "index.js"))) {
3253
3512
  throw new BuildError(
3254
3513
  `No ${outputDir}/index.js after the build.
3255
3514
 
@@ -3262,8 +3521,8 @@ the adapter in your Vite or Svelte config, then build again.`
3262
3521
  add2("package-lock.json");
3263
3522
  add2(".npmrc");
3264
3523
  add2(MIGRATIONS_DIR);
3265
- const hooks = path19.join(cwd, DATA_DIR, "hooks");
3266
- if (fs20.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
3524
+ const hooks = path20.join(cwd, DATA_DIR, "hooks");
3525
+ if (fs21.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
3267
3526
  for (const extra of config.include ?? []) add2(extra);
3268
3527
  return entries;
3269
3528
  }
@@ -3285,11 +3544,11 @@ Name it: \`-t preview:<branch>\`.`
3285
3544
  }
3286
3545
 
3287
3546
  // src/lib/ssh-options.ts
3288
- import * as v4 from "valibot";
3547
+ import * as v5 from "valibot";
3289
3548
  var SSH_OPTION_SCHEMA = {
3290
- identity: v4.optional(v4.string()),
3291
- sshPort: v4.optional(v4.string()),
3292
- acceptHostKeys: v4.optional(v4.boolean())
3549
+ identity: v5.optional(v5.string()),
3550
+ sshPort: v5.optional(v5.string()),
3551
+ acceptHostKeys: v5.optional(v5.boolean())
3293
3552
  };
3294
3553
  function addSshOptions(command) {
3295
3554
  return command.option("-i, --identity <file>", "SSH private key to authenticate with").option("--ssh-port <port>", "SSH port").option("--accept-host-keys", "trust an unknown host key on first connect (CI)");
@@ -3303,7 +3562,7 @@ function sshOptionsFrom(options) {
3303
3562
  }
3304
3563
 
3305
3564
  // src/lib/remote.ts
3306
- import path20 from "node:path";
3565
+ import path21 from "node:path";
3307
3566
  var VELA_ROOT = "/var/lib/vela";
3308
3567
  var VELA_ETC = "/etc/vela";
3309
3568
  var VELA_USER = "vela";
@@ -3311,7 +3570,7 @@ var SCRIPTS_DIR = `${VELA_ROOT}/scripts`;
3311
3570
  var PROVISIONED_MARKER = `${VELA_ETC}/provisioned`;
3312
3571
  var ORIGIN_FILE = `${VELA_ETC}/origin.json`;
3313
3572
  function serverTemplatesDir() {
3314
- return path20.join(templatesDir(), "server");
3573
+ return path21.join(templatesDir(), "server");
3315
3574
  }
3316
3575
  async function syncServerScripts(session) {
3317
3576
  await session.script(`mkdir -p "$1" && chmod 0755 "$1"`, { args: [SCRIPTS_DIR] });
@@ -3394,7 +3653,7 @@ var remotePaths = {
3394
3653
  };
3395
3654
 
3396
3655
  // src/lib/remote-env.ts
3397
- import fs21 from "node:fs";
3656
+ import fs22 from "node:fs";
3398
3657
  import dotenv from "dotenv";
3399
3658
  var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3400
3659
  function isValidKey(key) {
@@ -3442,7 +3701,7 @@ function quote(value) {
3442
3701
  return `"${escaped}"`;
3443
3702
  }
3444
3703
  function readLocalEnvFile(file) {
3445
- const parsed = dotenv.parse(fs21.readFileSync(file));
3704
+ const parsed = dotenv.parse(fs22.readFileSync(file));
3446
3705
  const result = {};
3447
3706
  for (const [key, value] of Object.entries(parsed)) {
3448
3707
  if (isValidKey(key)) result[key] = value;
@@ -3554,10 +3813,10 @@ function bold(text18) {
3554
3813
  // src/lib/server-command.ts
3555
3814
  var SERVER_OPTIONS_SCHEMA = {
3556
3815
  ...SSH_OPTION_SCHEMA,
3557
- target: v5.optional(v5.string()),
3558
- server: v5.optional(v5.string())
3816
+ target: v6.optional(v6.string()),
3817
+ server: v6.optional(v6.string())
3559
3818
  };
3560
- var OptionsSchema = v5.object(SERVER_OPTIONS_SCHEMA);
3819
+ var OptionsSchema = v6.object(SERVER_OPTIONS_SCHEMA);
3561
3820
  function addTargetOptions(command, fallback) {
3562
3821
  return addSshOptions(command).option("-t, --target <target>", "which copy of the app to act on", fallback).option("--server <ssh>", "server this target runs on \u2014 recorded on first use");
3563
3822
  }
@@ -3737,17 +3996,17 @@ function envFilePath(workspaceRootDir) {
3737
3996
  import pc7 from "picocolors";
3738
3997
 
3739
3998
  // src/lib/local-env.ts
3740
- import fs22 from "node:fs";
3999
+ import fs23 from "node:fs";
3741
4000
  import * as p16 from "@clack/prompts";
3742
4001
  import pc6 from "picocolors";
3743
4002
  function readLocalEnv(envFile) {
3744
- if (!fs22.existsSync(envFile)) return {};
4003
+ if (!fs23.existsSync(envFile)) return {};
3745
4004
  return readLocalEnvFile(envFile);
3746
4005
  }
3747
4006
  function editLocalEnv(envFile, edit) {
3748
- const before = fs22.existsSync(envFile) ? fs22.readFileSync(envFile, "utf8") : "";
4007
+ const before = fs23.existsSync(envFile) ? fs23.readFileSync(envFile, "utf8") : "";
3749
4008
  const after = edit(before);
3750
- if (after !== before) fs22.writeFileSync(envFile, after);
4009
+ if (after !== before) fs23.writeFileSync(envFile, after);
3751
4010
  }
3752
4011
  function setLocalEnv(envFile, key, value) {
3753
4012
  editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
@@ -3879,8 +4138,8 @@ Set ${pc7.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc7.cyan("POCKETBASE_SUPERUS
3879
4138
  }
3880
4139
 
3881
4140
  // src/lib/s3-settings.ts
3882
- import fs23 from "node:fs";
3883
- import path21 from "node:path";
4141
+ import fs24 from "node:fs";
4142
+ import path22 from "node:path";
3884
4143
  var VIRTUAL_HOSTED = [/\.amazonaws\.com$/i, /\.r2\.cloudflarestorage\.com$/i];
3885
4144
  function defaultForcePathStyle(endpoint) {
3886
4145
  let host;
@@ -3918,18 +4177,18 @@ async function hasLocalUploads(session, instance, workspaceRootDir) {
3918
4177
  });
3919
4178
  return result.stdout.trim().length > 0;
3920
4179
  }
3921
- return hasFile(path21.join(workspaceRootDir, DATA_DIR, "storage"));
4180
+ return hasFile(path22.join(workspaceRootDir, DATA_DIR, "storage"));
3922
4181
  }
3923
4182
  function hasFile(dir) {
3924
4183
  let entries;
3925
4184
  try {
3926
- entries = fs23.readdirSync(dir, { withFileTypes: true });
4185
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
3927
4186
  } catch {
3928
4187
  return false;
3929
4188
  }
3930
4189
  for (const entry of entries) {
3931
4190
  if (entry.isFile()) return true;
3932
- if (entry.isDirectory() && hasFile(path21.join(dir, entry.name))) return true;
4191
+ if (entry.isDirectory() && hasFile(path22.join(dir, entry.name))) return true;
3933
4192
  }
3934
4193
  return false;
3935
4194
  }
@@ -4053,14 +4312,14 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
4053
4312
  host: () => p18.text({
4054
4313
  message: "SMTP host",
4055
4314
  placeholder: "smtp.example.com",
4056
- validate: (v9) => v9 ? void 0 : "Host is required"
4315
+ validate: (v10) => v10 ? void 0 : "Host is required"
4057
4316
  }),
4058
4317
  port: () => p18.text({
4059
4318
  message: "SMTP port",
4060
4319
  initialValue: "587",
4061
- validate: (v9) => {
4062
- if (!v9) return "Port is required";
4063
- const n = Number(v9);
4320
+ validate: (v10) => {
4321
+ if (!v10) return "Port is required";
4322
+ const n = Number(v10);
4064
4323
  if (!Number.isInteger(n) || n <= 0 || n > 65535) return "Invalid port";
4065
4324
  return void 0;
4066
4325
  }
@@ -5119,8 +5378,8 @@ var ui = new Command47("ui").description("generate ui components").configureHelp
5119
5378
  import { Command as Command50 } from "commander";
5120
5379
 
5121
5380
  // src/commands/legal/terms.ts
5122
- import fs24 from "node:fs";
5123
- import path22 from "node:path";
5381
+ import fs25 from "node:fs";
5382
+ import path23 from "node:path";
5124
5383
  import { Command as Command48 } from "commander";
5125
5384
  import * as p32 from "@clack/prompts";
5126
5385
 
@@ -5779,22 +6038,22 @@ async function termsAction() {
5779
6038
  mobileApp,
5780
6039
  contact
5781
6040
  });
5782
- const termsPage = path22.join(
6041
+ const termsPage = path23.join(
5783
6042
  workspaceRootDir,
5784
6043
  publicRoutesDir,
5785
6044
  LEGAL_DIR,
5786
6045
  "terms",
5787
6046
  "+page.svelte"
5788
6047
  );
5789
- const termsPageTs = path22.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
5790
- fs24.mkdirSync(path22.dirname(termsPage), { recursive: true });
5791
- fs24.writeFileSync(termsPage, html);
5792
- fs24.writeFileSync(
6048
+ const termsPageTs = path23.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
6049
+ fs25.mkdirSync(path23.dirname(termsPage), { recursive: true });
6050
+ fs25.writeFileSync(termsPage, html);
6051
+ fs25.writeFileSync(
5793
6052
  termsPageTs,
5794
6053
  pageMetaTagsLoader("Terms of Service", `Terms of Service for ${core.websiteName}`)
5795
6054
  );
5796
- const relativeTermsPage = path22.relative(workspaceRootDir, termsPage);
5797
- const relativeTermsPageTs = path22.relative(workspaceRootDir, termsPageTs);
6055
+ const relativeTermsPage = path23.relative(workspaceRootDir, termsPage);
6056
+ const relativeTermsPageTs = path23.relative(workspaceRootDir, termsPageTs);
5798
6057
  reportResult({
5799
6058
  summary: "Generated placeholder terms and conditions.",
5800
6059
  filesCreated: [relativeTermsPage, relativeTermsPageTs],
@@ -5808,8 +6067,8 @@ async function termsAction() {
5808
6067
  var terms = new Command48("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
5809
6068
 
5810
6069
  // src/commands/legal/privacy.ts
5811
- import fs25 from "node:fs";
5812
- import path23 from "node:path";
6070
+ import fs26 from "node:fs";
6071
+ import path24 from "node:path";
5813
6072
  import { Command as Command49 } from "commander";
5814
6073
  import * as p33 from "@clack/prompts";
5815
6074
  var mapLabels = {
@@ -5898,9 +6157,9 @@ var compute2 = (a) => {
5898
6157
  });
5899
6158
  const piSelections = a.personalInfo ?? [];
5900
6159
  const piLabels = piSelections.map(
5901
- (v9) => mapLabels.personalInfo[v9] ?? v9
6160
+ (v10) => mapLabels.personalInfo[v10] ?? v10
5902
6161
  );
5903
- const lookup = (map, vs) => (vs ?? []).map((v9) => map[v9] ?? v9);
6162
+ const lookup = (map, vs) => (vs ?? []).map((v10) => map[v10] ?? v10);
5904
6163
  const companyName = a.core?.entityType === "business" ? a.core?.businessName ?? a.core?.websiteName : a.core?.websiteName ?? "Our Company";
5905
6164
  const companyAddress = a.core?.entityType === "business" ? a.core?.businessAddress ?? "" : "";
5906
6165
  const websiteName = a.core?.websiteName ?? "our website";
@@ -6522,28 +6781,28 @@ async function privacyAction() {
6522
6781
  kids,
6523
6782
  retention
6524
6783
  });
6525
- const privacyPage = path23.join(
6784
+ const privacyPage = path24.join(
6526
6785
  workspaceRootDir,
6527
6786
  publicRoutesDir,
6528
6787
  LEGAL_DIR,
6529
6788
  "privacy",
6530
6789
  "+page.svelte"
6531
6790
  );
6532
- const privacyPageTs = path23.join(
6791
+ const privacyPageTs = path24.join(
6533
6792
  workspaceRootDir,
6534
6793
  publicRoutesDir,
6535
6794
  LEGAL_DIR,
6536
6795
  "privacy",
6537
6796
  "+page.ts"
6538
6797
  );
6539
- fs25.mkdirSync(path23.dirname(privacyPage), { recursive: true });
6540
- fs25.writeFileSync(privacyPage, html);
6541
- fs25.writeFileSync(
6798
+ fs26.mkdirSync(path24.dirname(privacyPage), { recursive: true });
6799
+ fs26.writeFileSync(privacyPage, html);
6800
+ fs26.writeFileSync(
6542
6801
  privacyPageTs,
6543
6802
  pageMetaTagsLoader("Privacy Policy", `Privacy Policy for ${core.websiteName}`)
6544
6803
  );
6545
- const relativePrivacyPage = path23.relative(workspaceRootDir, privacyPage);
6546
- const relativePrivacyPageTs = path23.relative(workspaceRootDir, privacyPageTs);
6804
+ const relativePrivacyPage = path24.relative(workspaceRootDir, privacyPage);
6805
+ const relativePrivacyPageTs = path24.relative(workspaceRootDir, privacyPageTs);
6547
6806
  reportResult({
6548
6807
  summary: "Generated placeholder privacy policy.",
6549
6808
  filesCreated: [relativePrivacyPage, relativePrivacyPageTs],
@@ -6566,8 +6825,8 @@ import { Command as Command56 } from "commander";
6566
6825
  import { Command as Command51 } from "commander";
6567
6826
 
6568
6827
  // src/lib/data.ts
6569
- import fs26 from "node:fs";
6570
- import path24 from "node:path";
6828
+ import fs27 from "node:fs";
6829
+ import path25 from "node:path";
6571
6830
  import { ClientResponseError } from "pocketbase";
6572
6831
 
6573
6832
  // src/lib/collections.ts
@@ -6604,14 +6863,14 @@ function dependencyOrder(collections2, startingCollectionId) {
6604
6863
 
6605
6864
  // src/lib/data.ts
6606
6865
  function dataDir(cwd, kind) {
6607
- return path24.join(cwd, DATA_DIR, kind);
6866
+ return path25.join(cwd, DATA_DIR, kind);
6608
6867
  }
6609
6868
  function getDataFiles(cwd, kind) {
6610
6869
  const dir = dataDir(cwd, kind);
6611
- if (!fs26.existsSync(dir)) return [];
6612
- return fs26.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
6870
+ if (!fs27.existsSync(dir)) return [];
6871
+ return fs27.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
6613
6872
  collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
6614
- filePath: path24.join(dir, file)
6873
+ filePath: path25.join(dir, file)
6615
6874
  }));
6616
6875
  }
6617
6876
  function getSeedFiles(cwd) {
@@ -6621,7 +6880,7 @@ function getFixtureFiles(cwd) {
6621
6880
  return getDataFiles(cwd, "fixtures");
6622
6881
  }
6623
6882
  function readRecords(filePath) {
6624
- return JSON.parse(fs26.readFileSync(filePath, "utf8"));
6883
+ return JSON.parse(fs27.readFileSync(filePath, "utf8"));
6625
6884
  }
6626
6885
  function readSeedIds(cwd) {
6627
6886
  const ids = /* @__PURE__ */ new Map();
@@ -6658,7 +6917,7 @@ function describeError(e) {
6658
6917
  return e instanceof Error ? e.message : String(e);
6659
6918
  }
6660
6919
  function label3(cwd, filePath, count) {
6661
- return `${path24.relative(cwd, filePath)} (${count} records)`;
6920
+ return `${path25.relative(cwd, filePath)} (${count} records)`;
6662
6921
  }
6663
6922
  async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
6664
6923
  const records = readRecords(filePath);
@@ -6666,7 +6925,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
6666
6925
  try {
6667
6926
  await pb.collection(collectionName).create(record);
6668
6927
  } catch (e) {
6669
- throw new DataLoadError(kind, path24.relative(cwd, filePath), index, e);
6928
+ throw new DataLoadError(kind, path25.relative(cwd, filePath), index, e);
6670
6929
  }
6671
6930
  }
6672
6931
  return records.length;
@@ -6840,8 +7099,8 @@ var reset = new Command53("reset").description("clear and reload fixtures").conf
6840
7099
  );
6841
7100
 
6842
7101
  // src/commands/fixtures/generate.ts
6843
- import fs27 from "node:fs";
6844
- import path25 from "node:path";
7102
+ import fs28 from "node:fs";
7103
+ import path26 from "node:path";
6845
7104
  import { Command as Command54, InvalidArgumentError } from "commander";
6846
7105
  import * as p34 from "@clack/prompts";
6847
7106
  import { annotate } from "annotate-json-schema";
@@ -6878,9 +7137,9 @@ async function loadCollections(pb) {
6878
7137
  }
6879
7138
  async function generateFixtureFiles(pb, workspaceRootDir, opts) {
6880
7139
  const fixturesDir = dataDir(workspaceRootDir, "fixtures");
6881
- fs27.mkdirSync(fixturesDir, { recursive: true });
6882
- for (const file of fs27.readdirSync(fixturesDir)) {
6883
- if (file.endsWith(".json")) fs27.unlinkSync(path25.join(fixturesDir, file));
7140
+ fs28.mkdirSync(fixturesDir, { recursive: true });
7141
+ for (const file of fs28.readdirSync(fixturesDir)) {
7142
+ if (file.endsWith(".json")) fs28.unlinkSync(path26.join(fixturesDir, file));
6884
7143
  }
6885
7144
  if (opts.seed !== void 0) faker.seed(opts.seed);
6886
7145
  const generator = createGenerator({
@@ -6947,8 +7206,8 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
6947
7206
  items.push(record);
6948
7207
  }
6949
7208
  const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
6950
- fs27.writeFileSync(path25.join(fixturesDir, filename), JSON.stringify(items, null, 2));
6951
- writtenFiles.push(`${path25.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
7209
+ fs28.writeFileSync(path26.join(fixturesDir, filename), JSON.stringify(items, null, 2));
7210
+ writtenFiles.push(`${path26.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
6952
7211
  fileIndex++;
6953
7212
  }
6954
7213
  return { writtenFiles, warnings };
@@ -7095,8 +7354,8 @@ var load2 = new Command57("load").description("load seeds into the database").op
7095
7354
  );
7096
7355
 
7097
7356
  // src/commands/seeds/save.ts
7098
- import fs28 from "node:fs";
7099
- import path26 from "node:path";
7357
+ import fs29 from "node:fs";
7358
+ import path27 from "node:path";
7100
7359
  import { Command as Command58 } from "commander";
7101
7360
  var padZeros2 = (num, length) => num.toString().padStart(length, "0");
7102
7361
  function filterSystemFields(record, systemFieldNames) {
@@ -7116,10 +7375,10 @@ var save = new Command58("save").description("save the current data as seeds").o
7116
7375
  if (existing.length > 0 && !opts.force) {
7117
7376
  throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
7118
7377
  }
7119
- fs28.mkdirSync(seedsPath, { recursive: true });
7378
+ fs29.mkdirSync(seedsPath, { recursive: true });
7120
7379
  if (opts.force) {
7121
- for (const file of fs28.readdirSync(seedsPath)) {
7122
- if (file.endsWith(".json")) fs28.unlinkSync(path26.join(seedsPath, file));
7380
+ for (const file of fs29.readdirSync(seedsPath)) {
7381
+ if (file.endsWith(".json")) fs29.unlinkSync(path27.join(seedsPath, file));
7123
7382
  }
7124
7383
  }
7125
7384
  const saved = [];
@@ -7148,13 +7407,13 @@ var save = new Command58("save").description("save the current data as seeds").o
7148
7407
  const filtered = records.map(
7149
7408
  (r) => filterSystemFields(r, systemFieldNames)
7150
7409
  );
7151
- const relativeSeedPath = path26.join(
7410
+ const relativeSeedPath = path27.join(
7152
7411
  DATA_DIR,
7153
7412
  "seeds",
7154
7413
  `${padZeros2(count, 2)}-${collectionName}.json`
7155
7414
  );
7156
- const seedPath = path26.join(workspaceRootDir, relativeSeedPath);
7157
- fs28.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
7415
+ const seedPath = path27.join(workspaceRootDir, relativeSeedPath);
7416
+ fs29.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
7158
7417
  saved.push(`${relativeSeedPath} (${filtered.length} records)`);
7159
7418
  count++;
7160
7419
  }
@@ -7220,7 +7479,7 @@ import * as p37 from "@clack/prompts";
7220
7479
  import makeFetchCookie2 from "fetch-cookie";
7221
7480
 
7222
7481
  // src/commands/login.ts
7223
- import os3 from "node:os";
7482
+ import os4 from "node:os";
7224
7483
  import { Command as Command61 } from "commander";
7225
7484
  import * as p36 from "@clack/prompts";
7226
7485
  import makeFetchCookie from "fetch-cookie";
@@ -7254,7 +7513,7 @@ var login = new Command61("login").description("login to velastack.dev").configu
7254
7513
  }, "Failed to login.")
7255
7514
  );
7256
7515
  async function issueApiKey(fetchCookie) {
7257
- const label4 = `CLI - ${os3.hostname()}`;
7516
+ const label4 = `CLI - ${os4.hostname()}`;
7258
7517
  await fetchCookie(`${API_URL}/api-keys/new`, {
7259
7518
  method: "POST",
7260
7519
  headers: {
@@ -7365,7 +7624,7 @@ import { Command as Command70 } from "commander";
7365
7624
  import { Command as Command65 } from "commander";
7366
7625
 
7367
7626
  // src/lib/migrate.ts
7368
- import path27 from "node:path";
7627
+ import path28 from "node:path";
7369
7628
  import process19 from "node:process";
7370
7629
  import { x as x2 } from "tinyexec";
7371
7630
  async function runPocketbaseMigrate(args) {
@@ -7376,9 +7635,9 @@ async function runPocketbaseMigrate(args) {
7376
7635
  binaryPath,
7377
7636
  [
7378
7637
  "--dir",
7379
- path27.join(cwd, DATA_DIR),
7638
+ path28.join(cwd, DATA_DIR),
7380
7639
  "--migrationsDir",
7381
- path27.join(cwd, MIGRATIONS_DIR),
7640
+ path28.join(cwd, MIGRATIONS_DIR),
7382
7641
  "migrate",
7383
7642
  ...args
7384
7643
  ],
@@ -7426,8 +7685,8 @@ var down = new Command66("down").alias("rollback").description("revert the last
7426
7685
  );
7427
7686
 
7428
7687
  // src/commands/migrate/create.ts
7429
- import fs29 from "node:fs";
7430
- import path28 from "node:path";
7688
+ import fs30 from "node:fs";
7689
+ import path29 from "node:path";
7431
7690
  import process20 from "node:process";
7432
7691
  import { Command as Command67 } from "commander";
7433
7692
  var create2 = new Command67("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
@@ -7439,7 +7698,7 @@ var create2 = new Command67("create").alias("new").description("create a new bla
7439
7698
  const added = [...after].filter((f) => !before.has(f));
7440
7699
  reportResult({
7441
7700
  summary: `Created blank migration ${name}.`,
7442
- filesCreated: added.map((f) => path28.join(MIGRATIONS_DIR, f)),
7701
+ filesCreated: added.map((f) => path29.join(MIGRATIONS_DIR, f)),
7443
7702
  nextSteps: [
7444
7703
  `Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
7445
7704
  "Run `vela migrate up` to apply the migration once the handlers are written."
@@ -7448,14 +7707,14 @@ var create2 = new Command67("create").alias("new").description("create a new bla
7448
7707
  }, "Failed to create migration.")
7449
7708
  );
7450
7709
  function listMigrationFiles(cwd) {
7451
- const dir = path28.join(cwd, MIGRATIONS_DIR);
7452
- if (!fs29.existsSync(dir)) return /* @__PURE__ */ new Set();
7453
- return new Set(fs29.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7710
+ const dir = path29.join(cwd, MIGRATIONS_DIR);
7711
+ if (!fs30.existsSync(dir)) return /* @__PURE__ */ new Set();
7712
+ return new Set(fs30.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7454
7713
  }
7455
7714
 
7456
7715
  // src/commands/migrate/collections.ts
7457
- import fs30 from "node:fs";
7458
- import path29 from "node:path";
7716
+ import fs31 from "node:fs";
7717
+ import path30 from "node:path";
7459
7718
  import process21 from "node:process";
7460
7719
  import { Command as Command68 } from "commander";
7461
7720
  var collections = new Command68("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
@@ -7473,7 +7732,7 @@ var collections = new Command68("collections").alias("snapshot").description("sn
7473
7732
  }
7474
7733
  reportResult({
7475
7734
  summary: "Snapshotted local collections into a new migration.",
7476
- filesCreated: added.map((f) => path29.join(MIGRATIONS_DIR, f)),
7735
+ filesCreated: added.map((f) => path30.join(MIGRATIONS_DIR, f)),
7477
7736
  nextSteps: [
7478
7737
  `Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
7479
7738
  "Commit the snapshot so teammates pick up the new schema.",
@@ -7483,9 +7742,9 @@ var collections = new Command68("collections").alias("snapshot").description("sn
7483
7742
  }, "Failed to snapshot collections.")
7484
7743
  );
7485
7744
  function listMigrationFiles2(cwd) {
7486
- const dir = path29.join(cwd, MIGRATIONS_DIR);
7487
- if (!fs30.existsSync(dir)) return /* @__PURE__ */ new Set();
7488
- return new Set(fs30.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7745
+ const dir = path30.join(cwd, MIGRATIONS_DIR);
7746
+ if (!fs31.existsSync(dir)) return /* @__PURE__ */ new Set();
7747
+ return new Set(fs31.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7489
7748
  }
7490
7749
 
7491
7750
  // src/commands/migrate/history-sync.ts
@@ -7504,8 +7763,8 @@ var historySync = new Command69("history-sync").description("drop _migrations ro
7504
7763
  var migrate = new Command70("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
7505
7764
 
7506
7765
  // src/commands/dev.ts
7507
- import fs31 from "node:fs";
7508
- import path31 from "node:path";
7766
+ import fs32 from "node:fs";
7767
+ import path32 from "node:path";
7509
7768
  import process23 from "node:process";
7510
7769
  import { performance } from "node:perf_hooks";
7511
7770
  import { Command as Command71, InvalidArgumentError as InvalidArgumentError4 } from "commander";
@@ -7513,7 +7772,7 @@ import pc15 from "picocolors";
7513
7772
  import PocketBase4 from "pocketbase";
7514
7773
 
7515
7774
  // src/lib/vite.ts
7516
- import path30 from "node:path";
7775
+ import path31 from "node:path";
7517
7776
  import process22 from "node:process";
7518
7777
  import { createRequire as createRequire2 } from "node:module";
7519
7778
  import { pathToFileURL as pathToFileURL2 } from "node:url";
@@ -7533,7 +7792,7 @@ function viteVersionError(version) {
7533
7792
  }
7534
7793
  function resolveProjectVite(cwd) {
7535
7794
  try {
7536
- return createRequire2(path30.join(cwd, "package.json")).resolve("vite");
7795
+ return createRequire2(path31.join(cwd, "package.json")).resolve("vite");
7537
7796
  } catch {
7538
7797
  return null;
7539
7798
  }
@@ -7562,21 +7821,21 @@ var dev = new Command71("dev").description("start the development server").optio
7562
7821
  process23.env.VELA_DATA_DIR ??= localDataDir(cwd);
7563
7822
  const startTime = performance.now();
7564
7823
  const { createServer, version } = await loadVite(cwd);
7565
- const viteMetadataDir = path31.join(cwd, "node_modules", ".vite");
7566
- const viteMetadataFile = path31.join(viteMetadataDir, "_pocketbase_metadata.json");
7824
+ const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
7825
+ const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
7567
7826
  let pbProc;
7568
7827
  const backend3 = hasBackend(cwd);
7569
7828
  const needsStart = backend3 && !process23.env.POCKETBASE_URL;
7570
7829
  const cleanup = () => {
7571
7830
  if (pbProc?.pid) pbProc.kill();
7572
- if (fs31.existsSync(viteMetadataFile)) fs31.rmSync(viteMetadataFile);
7831
+ if (fs32.existsSync(viteMetadataFile)) fs32.rmSync(viteMetadataFile);
7573
7832
  };
7574
7833
  if (needsStart) {
7575
- const dataDir2 = path31.join(cwd, DATA_DIR);
7834
+ const dataDir2 = path32.join(cwd, DATA_DIR);
7576
7835
  const started = await startPocketbaseServe({
7577
7836
  dataDir: dataDir2,
7578
7837
  migrationsDir: MIGRATIONS_DIR,
7579
- hooksDir: path31.join(dataDir2, "hooks"),
7838
+ hooksDir: path32.join(dataDir2, "hooks"),
7580
7839
  dev: true,
7581
7840
  stdio: "pipe"
7582
7841
  });
@@ -7607,8 +7866,8 @@ var dev = new Command71("dev").description("start the development server").optio
7607
7866
  if (!backend3) return;
7608
7867
  const { address, port: vitePort } = server.httpServer.address();
7609
7868
  const viteHost = address === "::1" ? "localhost" : address;
7610
- await fs31.promises.mkdir(viteMetadataDir, { recursive: true });
7611
- await fs31.promises.writeFile(
7869
+ await fs32.promises.mkdir(viteMetadataDir, { recursive: true });
7870
+ await fs32.promises.writeFile(
7612
7871
  viteMetadataFile,
7613
7872
  JSON.stringify({
7614
7873
  pocketbaseUrl: process23.env.POCKETBASE_URL,
@@ -7640,18 +7899,18 @@ var dev = new Command71("dev").description("start the development server").optio
7640
7899
  });
7641
7900
  async function startWatchingTypes(cwd, pb) {
7642
7901
  const { processTypes } = await import("@velastack/pocketbase-codegen");
7643
- const typesDir = path31.resolve(cwd, ".svelte-kit", "types");
7644
- const pocketbaseDir = path31.join(typesDir, "pocketbase");
7645
- const pocketbaseTypes = path31.join(pocketbaseDir, "$types.d.ts");
7902
+ const typesDir = path32.resolve(cwd, ".svelte-kit", "types");
7903
+ const pocketbaseDir = path32.join(typesDir, "pocketbase");
7904
+ const pocketbaseTypes = path32.join(pocketbaseDir, "$types.d.ts");
7646
7905
  const regenerate = () => processTypes(pb, typesDir).catch(() => {
7647
7906
  });
7648
7907
  await regenerate();
7649
7908
  void (async () => {
7650
7909
  for (; ; ) {
7651
7910
  try {
7652
- await fs31.promises.mkdir(pocketbaseDir, { recursive: true });
7653
- for await (const event of fs31.promises.watch(pocketbaseDir)) {
7654
- if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs31.existsSync(pocketbaseTypes)) {
7911
+ await fs32.promises.mkdir(pocketbaseDir, { recursive: true });
7912
+ for await (const event of fs32.promises.watch(pocketbaseDir)) {
7913
+ if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs32.existsSync(pocketbaseTypes)) {
7655
7914
  setTimeout(regenerate, 100);
7656
7915
  }
7657
7916
  }
@@ -7663,8 +7922,8 @@ async function startWatchingTypes(cwd, pb) {
7663
7922
  }
7664
7923
 
7665
7924
  // src/commands/build.ts
7666
- import fs32 from "node:fs";
7667
- import path32 from "node:path";
7925
+ import fs33 from "node:fs";
7926
+ import path33 from "node:path";
7668
7927
  import process25 from "node:process";
7669
7928
  import { Command as Command72 } from "commander";
7670
7929
  import * as p40 from "@clack/prompts";
@@ -7702,7 +7961,7 @@ function splitHosts(value) {
7702
7961
  }
7703
7962
 
7704
7963
  // src/commands/build.ts
7705
- var PRERENDERED_DIR = path32.join(".svelte-kit", "output", "prerendered");
7964
+ var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
7706
7965
  var build = new Command72("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
7707
7966
  const cwd = process25.cwd();
7708
7967
  applyBuildEnv(cwd);
@@ -7715,11 +7974,11 @@ var build = new Command72("build").description("build the app").configureHelp(he
7715
7974
  };
7716
7975
  if (needsStart) {
7717
7976
  await ensureSuperuser(cwd);
7718
- const dataDir2 = path32.join(cwd, DATA_DIR);
7977
+ const dataDir2 = path33.join(cwd, DATA_DIR);
7719
7978
  const started = await startPocketbaseServe({
7720
7979
  dataDir: dataDir2,
7721
7980
  migrationsDir: MIGRATIONS_DIR,
7722
- hooksDir: path32.join(dataDir2, "hooks"),
7981
+ hooksDir: path33.join(dataDir2, "hooks"),
7723
7982
  dev: true
7724
7983
  });
7725
7984
  pbProc = started.proc;
@@ -7758,8 +8017,8 @@ async function originForBuild(cwd, target) {
7758
8017
  }
7759
8018
  }
7760
8019
  function warnIfPrerendered(cwd) {
7761
- const dir = path32.join(cwd, PRERENDERED_DIR);
7762
- if (!fs32.existsSync(dir) || fs32.readdirSync(dir).length === 0) return;
8020
+ const dir = path33.join(cwd, PRERENDERED_DIR);
8021
+ if (!fs33.existsSync(dir) || fs33.readdirSync(dir).length === 0) return;
7763
8022
  p40.log.warn(
7764
8023
  `Prerendered pages were built with no domain configured, so their canonical
7765
8024
  links point at SvelteKit's placeholder host rather than at this site.
@@ -7769,7 +8028,7 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
7769
8028
  }
7770
8029
 
7771
8030
  // src/commands/preview.ts
7772
- import path33 from "node:path";
8031
+ import path34 from "node:path";
7773
8032
  import process26 from "node:process";
7774
8033
  import { Command as Command73 } from "commander";
7775
8034
  import { x as x4 } from "tinyexec";
@@ -7784,11 +8043,11 @@ var preview = new Command73("preview").description("preview the built app").conf
7784
8043
  if (pbProc?.pid) pbProc.kill();
7785
8044
  };
7786
8045
  if (needsStart) {
7787
- const dataDir2 = path33.join(cwd, DATA_DIR);
8046
+ const dataDir2 = path34.join(cwd, DATA_DIR);
7788
8047
  const started = await startPocketbaseServe({
7789
8048
  dataDir: dataDir2,
7790
8049
  migrationsDir: MIGRATIONS_DIR,
7791
- hooksDir: path33.join(dataDir2, "hooks"),
8050
+ hooksDir: path34.join(dataDir2, "hooks"),
7792
8051
  dev: true
7793
8052
  });
7794
8053
  pbProc = started.proc;
@@ -7814,12 +8073,12 @@ var preview = new Command73("preview").description("preview the built app").conf
7814
8073
  });
7815
8074
 
7816
8075
  // src/commands/sync.ts
7817
- import path34 from "node:path";
8076
+ import path35 from "node:path";
7818
8077
  import { Command as Command74 } from "commander";
7819
8078
  var sync = new Command74("sync").description("sync types from the database").configureHelp(helpConfig).action(
7820
8079
  () => runCommand(async () => {
7821
8080
  const { workspaceRootDir } = await getWorkspace();
7822
- const typesDir = path34.join(workspaceRootDir, ".svelte-kit", "types");
8081
+ const typesDir = path35.join(workspaceRootDir, ".svelte-kit", "types");
7823
8082
  const { processTypes } = await import("@velastack/pocketbase-codegen");
7824
8083
  await withPocketbase(workspaceRootDir, async (pb) => {
7825
8084
  await processTypes(pb, typesDir);
@@ -7832,11 +8091,11 @@ var sync = new Command74("sync").description("sync types from the database").con
7832
8091
  import { Command as Command75 } from "commander";
7833
8092
  import * as p41 from "@clack/prompts";
7834
8093
  import pc17 from "picocolors";
7835
- import * as v6 from "valibot";
7836
- var OptionsSchema2 = v6.object({
8094
+ import * as v7 from "valibot";
8095
+ var OptionsSchema2 = v7.object({
7837
8096
  ...SSH_OPTION_SCHEMA,
7838
- pbVersion: v6.optional(v6.string()),
7839
- nodeMajor: v6.optional(v6.string())
8097
+ pbVersion: v7.optional(v7.string()),
8098
+ nodeMajor: v7.optional(v7.string())
7840
8099
  });
7841
8100
  var provision = addSshOptions(
7842
8101
  new Command75("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
@@ -7881,22 +8140,22 @@ var provision = addSshOptions(
7881
8140
  );
7882
8141
 
7883
8142
  // src/commands/deploy.ts
7884
- import path36 from "node:path";
7885
- import fs34 from "node:fs";
8143
+ import path37 from "node:path";
8144
+ import fs35 from "node:fs";
7886
8145
  import { Command as Command76, Option as Option2 } from "commander";
7887
8146
  import * as p42 from "@clack/prompts";
7888
8147
  import pc18 from "picocolors";
7889
- import * as v7 from "valibot";
8148
+ import * as v8 from "valibot";
7890
8149
 
7891
8150
  // src/lib/pocketbase-settings.ts
7892
- import fs33 from "node:fs";
7893
- import path35 from "node:path";
8151
+ import fs34 from "node:fs";
8152
+ import path36 from "node:path";
7894
8153
  import process27 from "node:process";
7895
8154
  import PocketBase5 from "pocketbase";
7896
8155
  var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
7897
8156
  async function readLocalMeta(cwd) {
7898
- const dataDir2 = path35.join(cwd, DATA_DIR);
7899
- if (!fs33.existsSync(dataDir2)) return null;
8157
+ const dataDir2 = path36.join(cwd, DATA_DIR);
8158
+ if (!fs34.existsSync(dataDir2)) return null;
7900
8159
  const email3 = process27.env.POCKETBASE_SUPERUSER_EMAIL;
7901
8160
  const password11 = process27.env.POCKETBASE_SUPERUSER_PASSWORD;
7902
8161
  if (!email3 || !password11) return null;
@@ -7905,7 +8164,7 @@ async function readLocalMeta(cwd) {
7905
8164
  const started = await startPocketbaseServe({
7906
8165
  dataDir: dataDir2,
7907
8166
  migrationsDir: MIGRATIONS_DIR,
7908
- hooksDir: path35.join(dataDir2, "hooks")
8167
+ hooksDir: path36.join(dataDir2, "hooks")
7909
8168
  });
7910
8169
  proc = started.proc;
7911
8170
  const pb = new PocketBase5(started.url);
@@ -7947,16 +8206,16 @@ async function seedRemoteMeta(session, instance, local, appURL) {
7947
8206
  }
7948
8207
 
7949
8208
  // src/commands/deploy.ts
7950
- var OptionsSchema3 = v7.object({
8209
+ var OptionsSchema3 = v8.object({
7951
8210
  ...SSH_OPTION_SCHEMA,
7952
- env: v7.optional(v7.string()),
7953
- project: v7.optional(v7.string()),
7954
- remoteDb: v7.optional(v7.boolean()),
7955
- domain: v7.optional(v7.string()),
7956
- healthPath: v7.optional(v7.string()),
7957
- keep: v7.optional(v7.string()),
7958
- pbVersion: v7.optional(v7.string()),
7959
- build: v7.optional(v7.boolean())
8211
+ env: v8.optional(v8.string()),
8212
+ project: v8.optional(v8.string()),
8213
+ remoteDb: v8.optional(v8.boolean()),
8214
+ domain: v8.optional(v8.string()),
8215
+ healthPath: v8.optional(v8.string()),
8216
+ keep: v8.optional(v8.string()),
8217
+ pbVersion: v8.optional(v8.string()),
8218
+ build: v8.optional(v8.boolean())
7960
8219
  });
7961
8220
  var deploy = addTargetOptions(
7962
8221
  new Command76("deploy").description("deploy the app").configureHelp(helpConfig),
@@ -8255,7 +8514,7 @@ async function uploadRelease(session, instance, release, entries) {
8255
8514
  }
8256
8515
  function isDirectory(target) {
8257
8516
  try {
8258
- return fs34.statSync(target).isDirectory();
8517
+ return fs35.statSync(target).isDirectory();
8259
8518
  } catch {
8260
8519
  return false;
8261
8520
  }
@@ -8263,7 +8522,7 @@ function isDirectory(target) {
8263
8522
  async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
8264
8523
  const remote = await readRemoteEnv(session, instance);
8265
8524
  if (Object.keys(remote).length > 0) return;
8266
- if (!fs34.existsSync(path36.join(workspaceRootDir, ".env"))) return;
8525
+ if (!fs35.existsSync(path37.join(workspaceRootDir, ".env"))) return;
8267
8526
  p42.log.warn(
8268
8527
  `This app has no production environment variables yet.
8269
8528
 
@@ -8273,7 +8532,7 @@ ${pc18.cyan("vela env set KEY")}, or copy a file across with ${pc18.cyan("vela e
8273
8532
  }
8274
8533
 
8275
8534
  // src/commands/link.ts
8276
- import path37 from "node:path";
8535
+ import path38 from "node:path";
8277
8536
  import process28 from "node:process";
8278
8537
  import { Command as Command77 } from "commander";
8279
8538
  import * as p43 from "@clack/prompts";
@@ -8351,7 +8610,7 @@ async function promptProjectName(workspaceRootDir) {
8351
8610
  defaultValue,
8352
8611
  initialValue: defaultValue,
8353
8612
  placeholder: defaultValue,
8354
- validate: (v9) => !v9?.trim() ? "Required" : void 0
8613
+ validate: (v10) => !v10?.trim() ? "Required" : void 0
8355
8614
  });
8356
8615
  if (p43.isCancel(value)) {
8357
8616
  p43.cancel("Operation cancelled.");
@@ -8361,12 +8620,12 @@ async function promptProjectName(workspaceRootDir) {
8361
8620
  }
8362
8621
  function defaultProjectName2(workspaceRootDir) {
8363
8622
  try {
8364
- const pkg = readPackageJson(path37.join(workspaceRootDir, "package.json"));
8623
+ const pkg = readPackageJson(path38.join(workspaceRootDir, "package.json"));
8365
8624
  const name = pkg.name;
8366
8625
  if (typeof name === "string" && name.trim()) return name.trim();
8367
8626
  } catch {
8368
8627
  }
8369
- return path37.basename(workspaceRootDir);
8628
+ return path38.basename(workspaceRootDir);
8370
8629
  }
8371
8630
 
8372
8631
  // src/commands/env.ts
@@ -8497,8 +8756,8 @@ var envUnset = addTargetOptions(
8497
8756
  );
8498
8757
 
8499
8758
  // src/commands/env/import.ts
8500
- import fs35 from "node:fs";
8501
- import path38 from "node:path";
8759
+ import fs36 from "node:fs";
8760
+ import path39 from "node:path";
8502
8761
  import process30 from "node:process";
8503
8762
  import { Command as Command81 } from "commander";
8504
8763
  import * as p47 from "@clack/prompts";
@@ -8544,10 +8803,10 @@ var envImport = addTargetOptions(
8544
8803
  )
8545
8804
  );
8546
8805
  function resolve(file) {
8547
- return path38.resolve(process30.cwd(), file);
8806
+ return path39.resolve(process30.cwd(), file);
8548
8807
  }
8549
8808
  function read(resolved, shown) {
8550
- if (!fs35.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
8809
+ if (!fs36.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
8551
8810
  const incoming = readLocalEnvFile(resolved);
8552
8811
  if (Object.keys(incoming).length === 0) p47.log.info(`${shown} has no variables to import.`);
8553
8812
  return incoming;
@@ -8819,8 +9078,8 @@ var admin = new Command87("admin").description("manage admin panel logins").conf
8819
9078
  import { Command as Command93 } from "commander";
8820
9079
 
8821
9080
  // src/commands/backup/create.ts
8822
- import fs36 from "node:fs";
8823
- import path39 from "node:path";
9081
+ import fs37 from "node:fs";
9082
+ import path40 from "node:path";
8824
9083
  import { Command as Command88 } from "commander";
8825
9084
  import * as p51 from "@clack/prompts";
8826
9085
  import pc26 from "picocolors";
@@ -8974,12 +9233,12 @@ Your bucket's own versioning is what protects the uploaded files.`
8974
9233
  }, "Failed to create the backup.")
8975
9234
  );
8976
9235
  async function download(ctx, key, outputDir) {
8977
- const dir = path39.resolve(ctx.workspaceRootDir, outputDir);
8978
- fs36.mkdirSync(dir, { recursive: true });
8979
- const destination = path39.join(dir, key);
9236
+ const dir = path40.resolve(ctx.workspaceRootDir, outputDir);
9237
+ fs37.mkdirSync(dir, { recursive: true });
9238
+ const destination = path40.join(dir, key);
8980
9239
  if (!ctx.session) {
8981
- fs36.copyFileSync(path39.join(ctx.workspaceRootDir, "data", "backups", key), destination);
8982
- return path39.relative(ctx.workspaceRootDir, destination);
9240
+ fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
9241
+ return path40.relative(ctx.workspaceRootDir, destination);
8983
9242
  }
8984
9243
  const spinner7 = p51.spinner();
8985
9244
  spinner7.start(`Downloading ${key}`);
@@ -8990,7 +9249,7 @@ async function download(ctx, key, outputDir) {
8990
9249
  throw error;
8991
9250
  }
8992
9251
  spinner7.stop(`Downloaded ${key}`);
8993
- return path39.relative(ctx.workspaceRootDir, destination);
9252
+ return path40.relative(ctx.workspaceRootDir, destination);
8994
9253
  }
8995
9254
 
8996
9255
  // src/commands/backup/list.ts
@@ -9024,8 +9283,8 @@ Take one with ${pc27.cyan("vela backup create")}.`
9024
9283
  );
9025
9284
 
9026
9285
  // src/commands/backup/download.ts
9027
- import fs37 from "node:fs";
9028
- import path40 from "node:path";
9286
+ import fs38 from "node:fs";
9287
+ import path41 from "node:path";
9029
9288
  import { Command as Command90 } from "commander";
9030
9289
  import * as p53 from "@clack/prompts";
9031
9290
  import pc28 from "picocolors";
@@ -9052,11 +9311,11 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
9052
9311
  Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
9053
9312
  );
9054
9313
  }
9055
- const dir = path40.resolve(ctx.workspaceRootDir, options.output);
9056
- fs37.mkdirSync(dir, { recursive: true });
9057
- const destination = path40.join(dir, key);
9314
+ const dir = path41.resolve(ctx.workspaceRootDir, options.output);
9315
+ fs38.mkdirSync(dir, { recursive: true });
9316
+ const destination = path41.join(dir, key);
9058
9317
  if (!ctx.session) {
9059
- fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
9318
+ fs38.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
9060
9319
  } else {
9061
9320
  const spinner7 = p53.spinner();
9062
9321
  spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
@@ -9070,7 +9329,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
9070
9329
  }
9071
9330
  reportResult({
9072
9331
  summary: `Saved ${key} from ${ctx.targetName}.`,
9073
- filesCreated: [path40.relative(ctx.workspaceRootDir, destination)]
9332
+ filesCreated: [path41.relative(ctx.workspaceRootDir, destination)]
9074
9333
  });
9075
9334
  });
9076
9335
  }, "Failed to download the backup.")
@@ -9165,8 +9424,8 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
9165
9424
  var backup = new Command93("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
9166
9425
 
9167
9426
  // src/commands/restore.ts
9168
- import fs38 from "node:fs";
9169
- import path41 from "node:path";
9427
+ import fs39 from "node:fs";
9428
+ import path42 from "node:path";
9170
9429
  import process33 from "node:process";
9171
9430
  import { Command as Command94 } from "commander";
9172
9431
  import * as p56 from "@clack/prompts";
@@ -9187,7 +9446,7 @@ var restore = addTargetOptions(
9187
9446
  `${ctx.targetName} was deployed without a database, so there is nothing to restore.`
9188
9447
  );
9189
9448
  }
9190
- const local = source && fs38.existsSync(source) ? source : void 0;
9449
+ const local = source && fs39.existsSync(source) ? source : void 0;
9191
9450
  const key = local ? void 0 : await resolveKey(ctx, source);
9192
9451
  if (!options.yes) {
9193
9452
  await confirm12(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
@@ -9209,7 +9468,7 @@ var restore = addTargetOptions(
9209
9468
  });
9210
9469
  p56.log.success(
9211
9470
  `Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
9212
- local ? path41.basename(local) : key
9471
+ local ? path42.basename(local) : key
9213
9472
  )}.`
9214
9473
  );
9215
9474
  if (result?.storageCarriedOver) {
@@ -9275,21 +9534,21 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
9275
9534
  }
9276
9535
  async function stage(ctx, file) {
9277
9536
  const dir = remotePaths.restoreStage(ctx.instance);
9278
- const remote = `${dir}/${path41.basename(file)}`;
9537
+ const remote = `${dir}/${path42.basename(file)}`;
9279
9538
  const spinner7 = p56.spinner();
9280
- spinner7.start(`Uploading ${path41.basename(file)}`);
9539
+ spinner7.start(`Uploading ${path42.basename(file)}`);
9281
9540
  try {
9282
9541
  await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
9283
9542
  await ctx.session.upload([file], dir);
9284
9543
  } catch (error) {
9285
- spinner7.stop(`Could not upload ${path41.basename(file)}.`);
9544
+ spinner7.stop(`Could not upload ${path42.basename(file)}.`);
9286
9545
  throw error;
9287
9546
  }
9288
- spinner7.stop(`Uploaded ${path41.basename(file)}`);
9547
+ spinner7.stop(`Uploaded ${path42.basename(file)}`);
9289
9548
  return remote;
9290
9549
  }
9291
9550
  async function confirm12(appName, targetName, envTag, from) {
9292
- const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path41.basename(from))}`;
9551
+ const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path42.basename(from))}`;
9293
9552
  if (isProd(envTag)) {
9294
9553
  const answer = await p56.text({
9295
9554
  message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
@@ -9315,11 +9574,11 @@ async function confirm12(appName, targetName, envTag, from) {
9315
9574
  import { Command as Command95 } from "commander";
9316
9575
  import * as p57 from "@clack/prompts";
9317
9576
  import pc32 from "picocolors";
9318
- import * as v8 from "valibot";
9319
- var OptionsSchema4 = v8.object({
9577
+ import * as v9 from "valibot";
9578
+ var OptionsSchema4 = v9.object({
9320
9579
  ...SSH_OPTION_SCHEMA,
9321
- json: v8.optional(v8.boolean()),
9322
- offline: v8.optional(v8.boolean())
9580
+ json: v9.optional(v9.boolean()),
9581
+ offline: v9.optional(v9.boolean())
9323
9582
  });
9324
9583
  var targets = addSshOptions(
9325
9584
  new Command95("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
@@ -9400,7 +9659,7 @@ Release and domain are shown from what this project recorded.`
9400
9659
  }
9401
9660
 
9402
9661
  // src/commands/test.ts
9403
- import path42 from "node:path";
9662
+ import path43 from "node:path";
9404
9663
  import process34 from "node:process";
9405
9664
  import { Command as Command96 } from "commander";
9406
9665
  import PocketBase6 from "pocketbase";
@@ -9408,20 +9667,20 @@ import pc33 from "picocolors";
9408
9667
  import { x as x5 } from "tinyexec";
9409
9668
  import { detect as detect7 } from "package-manager-detector";
9410
9669
  import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
9411
- import fs39 from "node:fs";
9670
+ import fs40 from "node:fs";
9412
9671
  var testServer = new Command96("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
9413
9672
  const cwd = process34.cwd();
9414
9673
  const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
9415
9674
  const password11 = "password";
9416
- const testDataDir = path42.join(cwd, "test-data");
9417
- fs39.rmSync(testDataDir, { recursive: true, force: true });
9675
+ const testDataDir = path43.join(cwd, "test-data");
9676
+ fs40.rmSync(testDataDir, { recursive: true, force: true });
9418
9677
  const { stop, url } = await launchPocketbase(cwd, {
9419
9678
  dir: testDataDir,
9420
- migrationsDir: path42.join(cwd, MIGRATIONS_DIR),
9679
+ migrationsDir: path43.join(cwd, MIGRATIONS_DIR),
9421
9680
  // The app's PocketBase hooks (slug generation, personal teams, …) are part
9422
9681
  // of its behaviour; the suite runs against the same server dev and build
9423
9682
  // start, so it loads them from the same place.
9424
- hooksDir: path42.join(cwd, DATA_DIR, "hooks"),
9683
+ hooksDir: path43.join(cwd, DATA_DIR, "hooks"),
9425
9684
  email: email3,
9426
9685
  password: password11
9427
9686
  });
@@ -9437,7 +9696,7 @@ var testServer = new Command96("test:server").description("run server tests").al
9437
9696
  if (cleanedUp) return;
9438
9697
  cleanedUp = true;
9439
9698
  stop();
9440
- fs39.rmSync(testDataDir, { recursive: true, force: true });
9699
+ fs40.rmSync(testDataDir, { recursive: true, force: true });
9441
9700
  };
9442
9701
  const cleanup = async () => {
9443
9702
  if (cleanedUp) return;
@@ -9536,8 +9795,8 @@ function stubPagesPlugin() {
9536
9795
  }
9537
9796
 
9538
9797
  // src/commands/routes.ts
9539
- import fs40 from "node:fs";
9540
- import path43 from "node:path";
9798
+ import fs41 from "node:fs";
9799
+ import path44 from "node:path";
9541
9800
  import { Command as Command97 } from "commander";
9542
9801
  var HTTP_METHODS = /* @__PURE__ */ new Set([
9543
9802
  "GET",
@@ -9551,30 +9810,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
9551
9810
  ]);
9552
9811
  var routes = new Command97("routes").description("list routes").configureHelp(helpConfig).action(async () => {
9553
9812
  const { workspaceRootDir, routesDir } = await getWorkspace();
9554
- const routesRoot = path43.join(workspaceRootDir, routesDir);
9813
+ const routesRoot = path44.join(workspaceRootDir, routesDir);
9555
9814
  const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
9556
9815
  found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
9557
9816
  printTable(found);
9558
9817
  });
9559
9818
  function walk(root, dir) {
9560
- const entries = fs40.readdirSync(dir, { withFileTypes: true });
9819
+ const entries = fs41.readdirSync(dir, { withFileTypes: true });
9561
9820
  const routes2 = [];
9562
9821
  const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
9563
9822
  if (hasLeaf) {
9564
- const id = "/" + path43.relative(root, dir).split(path43.sep).filter(Boolean).join("/");
9823
+ const id = "/" + path44.relative(root, dir).split(path44.sep).filter(Boolean).join("/");
9565
9824
  const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
9566
9825
  const methods = /* @__PURE__ */ new Set();
9567
9826
  for (const entry of entries) {
9568
9827
  if (!entry.isFile()) continue;
9569
9828
  if (entry.name.endsWith("+page.svelte")) methods.add("GET");
9570
9829
  if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
9571
- extractMethods(path43.join(dir, entry.name)).forEach((m) => methods.add(m));
9830
+ extractMethods(path44.join(dir, entry.name)).forEach((m) => methods.add(m));
9572
9831
  }
9573
9832
  }
9574
9833
  routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
9575
9834
  }
9576
9835
  for (const entry of entries) {
9577
- if (entry.isDirectory()) routes2.push(...walk(root, path43.join(dir, entry.name)));
9836
+ if (entry.isDirectory()) routes2.push(...walk(root, path44.join(dir, entry.name)));
9578
9837
  }
9579
9838
  return routes2;
9580
9839
  }
@@ -9583,7 +9842,7 @@ function isRouteFile(name) {
9583
9842
  }
9584
9843
  function extractMethods(file) {
9585
9844
  try {
9586
- const content = fs40.readFileSync(file, "utf8");
9845
+ const content = fs41.readFileSync(file, "utf8");
9587
9846
  const methods = [];
9588
9847
  const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
9589
9848
  let match;
@@ -9640,11 +9899,11 @@ async function runWuchale(extraArgs) {
9640
9899
  throwOnError: true
9641
9900
  });
9642
9901
  }
9643
- var extract = new Command98("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
9902
+ var extract2 = new Command98("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
9644
9903
  var watch = new Command98("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
9645
9904
  var status2 = new Command98("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
9646
9905
  var clean = new Command98("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--clean"]));
9647
- var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
9906
+ var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
9648
9907
 
9649
9908
  // src/commands/oauth.ts
9650
9909
  var oauth = stubCommand("oauth", "configure OAuth providers");
@@ -9666,7 +9925,7 @@ import pc35 from "picocolors";
9666
9925
 
9667
9926
  // src/lib/cms-backend.ts
9668
9927
  import { createRequire as createRequire3 } from "node:module";
9669
- import path44 from "node:path";
9928
+ import path45 from "node:path";
9670
9929
  import process36 from "node:process";
9671
9930
  import { pathToFileURL as pathToFileURL3 } from "node:url";
9672
9931
  import pc34 from "picocolors";
@@ -9674,7 +9933,7 @@ var DEFAULT_PROJECT = "default";
9674
9933
  async function loadBackendModule(root) {
9675
9934
  let entry;
9676
9935
  try {
9677
- entry = createRequire3(path44.join(root, "package.json")).resolve("@velastack/cms/backend");
9936
+ entry = createRequire3(path45.join(root, "package.json")).resolve("@velastack/cms/backend");
9678
9937
  } catch {
9679
9938
  throw new Error(
9680
9939
  `@velastack/cms is not installed in this project.
@@ -9692,8 +9951,8 @@ async function withCmsBackend(fn, cwd = process36.cwd()) {
9692
9951
  const { createCmsBackend } = await loadBackendModule(root);
9693
9952
  const dataDir2 = localDataDir(root);
9694
9953
  const backend3 = createCmsBackend({
9695
- dbPath: path44.join(dataDir2, "cms.sqlite"),
9696
- uploadDir: path44.join(dataDir2, "uploads")
9954
+ dbPath: path45.join(dataDir2, "cms.sqlite"),
9955
+ uploadDir: path45.join(dataDir2, "uploads")
9697
9956
  });
9698
9957
  try {
9699
9958
  return await fn(backend3);
@@ -9805,14 +10064,14 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
9805
10064
  if (isStub(actionCommand)) return;
9806
10065
  const envRoot = findWorkspaceRoot() ?? process37.cwd();
9807
10066
  dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
9808
- const path45 = getCommandPath(actionCommand);
9809
- if (NO_BACKEND_COMMMANDS.has(path45)) return;
9810
- const top = path45.split(" ", 1)[0];
10067
+ const path46 = getCommandPath(actionCommand);
10068
+ if (NO_BACKEND_COMMMANDS.has(path46)) return;
10069
+ const top = path46.split(" ", 1)[0];
9811
10070
  if (NO_BACKEND_COMMMANDS.has(top)) return;
9812
10071
  if (!hasBackend()) {
9813
10072
  if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
9814
10073
  p61.log.error(
9815
- `${pc38.cyan(`vela ${path45}`)} needs a backend, and this project does not have one.
10074
+ `${pc38.cyan(`vela ${path46}`)} needs a backend, and this project does not have one.
9816
10075
 
9817
10076
  Static projects have no database to talk to.
9818
10077
 
@@ -9822,7 +10081,7 @@ To add a backend to this project, run ${pc38.cyan("vela bless")}.`
9822
10081
  p61.cancel("Operation failed.");
9823
10082
  process37.exit(1);
9824
10083
  }
9825
- if (SELF_CREDENTIALED_COMMANDS.has(path45)) return;
10084
+ if (SELF_CREDENTIALED_COMMANDS.has(path46)) return;
9826
10085
  if (!process37.env.POCKETBASE_SUPERUSER_EMAIL || !process37.env.POCKETBASE_SUPERUSER_PASSWORD) {
9827
10086
  p61.log.error(
9828
10087
  `PocketBase superuser credentials are required.