vela 0.15.0-next.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -21,7 +21,7 @@ import pc45 from "picocolors";
21
21
  // package.json
22
22
  var package_default = {
23
23
  name: "vela",
24
- version: "0.15.0-next.1",
24
+ version: "0.15.0",
25
25
  type: "module",
26
26
  description: "A CLI for creating and updating SvelteKit projects",
27
27
  license: "MIT",
@@ -298,8 +298,8 @@ function dropTemplateAdapters(user, template) {
298
298
  }
299
299
  return copy;
300
300
  }
301
- function readPackageJson(path61) {
302
- return JSON.parse(fs2.readFileSync(path61, "utf8"));
301
+ function readPackageJson(path62) {
302
+ return JSON.parse(fs2.readFileSync(path62, "utf8"));
303
303
  }
304
304
  var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
305
305
  var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
@@ -328,12 +328,12 @@ function jsString(value) {
328
328
  const quote2 = count("'") > count('"') ? '"' : "'";
329
329
  return `${quote2}${escapeFor(quote2, value)}${quote2}`;
330
330
  }
331
- function readTemplatePackageJson(path61, values) {
332
- const raw = fillTemplatePlaceholders(fs2.readFileSync(path61, "utf8"), values);
331
+ function readTemplatePackageJson(path62, values) {
332
+ const raw = fillTemplatePlaceholders(fs2.readFileSync(path62, "utf8"), values);
333
333
  return JSON.parse(raw);
334
334
  }
335
- function writePackageJson(path61, pkg) {
336
- fs2.writeFileSync(path61, JSON.stringify(pkg, null, " ") + "\n");
335
+ function writePackageJson(path62, pkg) {
336
+ fs2.writeFileSync(path62, JSON.stringify(pkg, null, " ") + "\n");
337
337
  }
338
338
  function toValidPackageName(name) {
339
339
  return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
@@ -1603,20 +1603,20 @@ var SITE_FILE = path10.join("src", "lib", "site.ts");
1603
1603
  async function readSite(root) {
1604
1604
  const file = path10.join(root, SITE_FILE);
1605
1605
  if (!fs12.existsSync(file)) return null;
1606
- const { Project: Project4, Node: Node3 } = await import("ts-morph");
1606
+ const { Project: Project4, Node: Node4 } = await import("ts-morph");
1607
1607
  const project = new Project4({ useInMemoryFileSystem: true });
1608
1608
  const source = project.createSourceFile("site.ts", fs12.readFileSync(file, "utf8"));
1609
1609
  let object6 = source.getVariableDeclaration("site")?.getInitializer();
1610
- while (object6 && (Node3.isAsExpression(object6) || Node3.isSatisfiesExpression(object6))) {
1610
+ while (object6 && (Node4.isAsExpression(object6) || Node4.isSatisfiesExpression(object6))) {
1611
1611
  object6 = object6.getExpression();
1612
1612
  }
1613
- if (!object6 || !Node3.isObjectLiteralExpression(object6)) return null;
1613
+ if (!object6 || !Node4.isObjectLiteralExpression(object6)) return null;
1614
1614
  const info = {};
1615
1615
  for (const key of ["name", "url"]) {
1616
1616
  const property = object6.getProperty(key);
1617
- if (!property || !Node3.isPropertyAssignment(property)) continue;
1617
+ if (!property || !Node4.isPropertyAssignment(property)) continue;
1618
1618
  const value = property.getInitializer();
1619
- if (Node3.isStringLiteral(value) || Node3.isNoSubstitutionTemplateLiteral(value)) {
1619
+ if (Node4.isStringLiteral(value) || Node4.isNoSubstitutionTemplateLiteral(value)) {
1620
1620
  const text19 = value.getLiteralValue().trim();
1621
1621
  if (text19) info[key] = text19;
1622
1622
  }
@@ -2872,13 +2872,13 @@ function printNextSteps(projectPath, packageManager2) {
2872
2872
  }
2873
2873
 
2874
2874
  // src/commands/create.ts
2875
- import fs27 from "node:fs";
2876
- import path25 from "node:path";
2875
+ import fs29 from "node:fs";
2876
+ import path27 from "node:path";
2877
2877
  import process13 from "node:process";
2878
2878
  import * as v5 from "valibot";
2879
2879
  import { Command as Command3 } from "commander";
2880
2880
  import * as p10 from "@clack/prompts";
2881
- import { detect as detect4, resolveCommand as resolveCommand3 } from "package-manager-detector";
2881
+ import { detect as detect5, resolveCommand as resolveCommand3 } from "package-manager-detector";
2882
2882
 
2883
2883
  // src/lib/providers.ts
2884
2884
  import process9 from "node:process";
@@ -3311,17 +3311,17 @@ function extractApiKey(cookie) {
3311
3311
  }
3312
3312
 
3313
3313
  // src/lib/kit3-migrate.ts
3314
- import fs25 from "node:fs";
3315
- import path23 from "node:path";
3314
+ import fs27 from "node:fs";
3315
+ import path25 from "node:path";
3316
3316
  import process12 from "node:process";
3317
3317
  import { execFileSync, spawn as spawn2 } from "node:child_process";
3318
3318
  import { createRequire as createRequire2 } from "node:module";
3319
3319
  import * as p9 from "@clack/prompts";
3320
3320
  import { x as x2 } from "tinyexec";
3321
- import { detect as detect3 } from "package-manager-detector";
3321
+ import { detect as detect4 } from "package-manager-detector";
3322
3322
  import {
3323
- ADAPTER_NODE,
3324
- ADAPTER_STATIC,
3323
+ ADAPTER_NODE as ADAPTER_NODE2,
3324
+ ADAPTER_STATIC as ADAPTER_STATIC2,
3325
3325
  ensurePackageOverrides,
3326
3326
  FLASH,
3327
3327
  SUPERFORMS_VERSION,
@@ -3330,9 +3330,371 @@ import {
3330
3330
  VELASTACK_POCKETBASE
3331
3331
  } from "@velastack/patterns";
3332
3332
 
3333
- // src/lib/kit-peers.ts
3333
+ // src/lib/adapter.ts
3334
3334
  import fs20 from "node:fs";
3335
3335
  import path18 from "node:path";
3336
+ import {
3337
+ SyntaxKind as SyntaxKind3
3338
+ } from "ts-morph";
3339
+ import { detect as detect3 } from "package-manager-detector";
3340
+ var ADAPTER_NODE = "@sveltejs/adapter-node";
3341
+ var ADAPTER_AUTO = "@sveltejs/adapter-auto";
3342
+ var ADAPTER_STATIC = "@sveltejs/adapter-static";
3343
+ var ADAPTER_NODE_RANGE = "^6.0.0";
3344
+ var ADAPTER_SNIPPET = `import adapter from '${ADAPTER_NODE}';
3345
+
3346
+ // ...
3347
+ adapter: adapter()`;
3348
+ var AdapterError = class extends Error {
3349
+ constructor(message, snippet = ADAPTER_SNIPPET) {
3350
+ super(message);
3351
+ this.snippet = snippet;
3352
+ this.name = "AdapterError";
3353
+ }
3354
+ snippet;
3355
+ };
3356
+ function resolveKitTarget(root) {
3357
+ const svelteConfig = findSvelteConfig(root);
3358
+ if (svelteConfig) {
3359
+ throw new AdapterError(
3360
+ `${path18.basename(svelteConfig)} found: this looks like a SvelteKit 2 project, and
3361
+ SvelteKit 3 reads its config only from sveltekit({...}) in vite.config.
3362
+
3363
+ Migrate it first:`,
3364
+ KIT3_MIGRATE_COMMAND
3365
+ );
3366
+ }
3367
+ const vite = inspectViteSveltekit(root);
3368
+ if (vite?.inlineArg) {
3369
+ return {
3370
+ sourceFile: vite.sourceFile,
3371
+ filePath: vite.filePath,
3372
+ kit: vite.inlineArg,
3373
+ created: false,
3374
+ originalText: vite.sourceFile.getFullText()
3375
+ };
3376
+ }
3377
+ if (vite?.sveltekitCall) {
3378
+ const name = path18.basename(vite.filePath);
3379
+ if (vite.nonObjectArg) {
3380
+ throw new AdapterError(`${name} passes sveltekit() something other than an object literal.`);
3381
+ }
3382
+ const originalText = vite.sourceFile.getFullText();
3383
+ const kit = createSveltekitArg(vite);
3384
+ if (!kit)
3385
+ throw new AdapterError(`${name} has a sveltekit() call vela cannot add an argument to.`);
3386
+ return {
3387
+ sourceFile: vite.sourceFile,
3388
+ filePath: vite.filePath,
3389
+ kit,
3390
+ created: true,
3391
+ originalText
3392
+ };
3393
+ }
3394
+ throw new AdapterError(`No vite.config with a sveltekit() plugin found in ${root}.`);
3395
+ }
3396
+ function classify(specifier) {
3397
+ if (specifier === ADAPTER_NODE) return "node";
3398
+ if (specifier === ADAPTER_AUTO) return "auto";
3399
+ if (specifier === ADAPTER_STATIC) return "static";
3400
+ return "other";
3401
+ }
3402
+ function importOf(sourceFile, identifier) {
3403
+ return sourceFile.getImportDeclarations().find((decl) => decl.getDefaultImport()?.getText() === identifier);
3404
+ }
3405
+ function inspectAdapter(target) {
3406
+ const base2 = { file: target.filePath };
3407
+ const prop = target.kit.getProperty("adapter");
3408
+ if (!prop) return { info: { ...base2, kind: "none" } };
3409
+ if (prop.getKind() !== SyntaxKind3.PropertyAssignment) {
3410
+ return { info: { ...base2, kind: "other" } };
3411
+ }
3412
+ const init = prop.asKindOrThrow(SyntaxKind3.PropertyAssignment).getInitializer();
3413
+ if (!init || init.getKind() !== SyntaxKind3.CallExpression) {
3414
+ return { info: { ...base2, kind: "other" } };
3415
+ }
3416
+ const callee = init.asKindOrThrow(SyntaxKind3.CallExpression).getExpression();
3417
+ if (callee.getKind() !== SyntaxKind3.Identifier) {
3418
+ return { info: { ...base2, kind: "other" } };
3419
+ }
3420
+ const importDecl = importOf(target.sourceFile, callee.getText());
3421
+ if (!importDecl) return { info: { ...base2, kind: "other" } };
3422
+ const specifier = importDecl.getModuleSpecifierValue();
3423
+ return { info: { ...base2, kind: classify(specifier), specifier }, importDecl };
3424
+ }
3425
+ function detectAdapter(root) {
3426
+ return inspectAdapter(resolveKitTarget(root)).info;
3427
+ }
3428
+ async function ensureNodeAdapter(root, { install: install2 = true } = {}) {
3429
+ const target = resolveKitTarget(root);
3430
+ const { info, importDecl } = inspectAdapter(target);
3431
+ const name = path18.basename(target.filePath);
3432
+ const outcome = {
3433
+ previous: info.kind,
3434
+ removedDeps: [],
3435
+ packageJsonChanged: false
3436
+ };
3437
+ switch (info.kind) {
3438
+ case "node":
3439
+ break;
3440
+ case "static":
3441
+ throw new AdapterError(
3442
+ `This project builds a static site with ${ADAPTER_STATIC} (${name}).
3443
+
3444
+ vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}. Switch
3445
+ the adapter to deploy it here, or host the static output elsewhere.`
3446
+ );
3447
+ case "other":
3448
+ throw new AdapterError(
3449
+ `This project's adapter${info.specifier ? ` (${info.specifier})` : ""} in ${name} is not one
3450
+ vela will change for you.
3451
+
3452
+ vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE}:`
3453
+ );
3454
+ case "auto":
3455
+ switchImport(target, importDecl);
3456
+ outcome.configFile = name;
3457
+ break;
3458
+ case "none":
3459
+ addAdapter(target);
3460
+ outcome.configFile = name;
3461
+ break;
3462
+ }
3463
+ if (outcome.configFile) saveTarget(target);
3464
+ const pkgPath = path18.join(root, "package.json");
3465
+ if (fs20.existsSync(pkgPath)) {
3466
+ const pkg = readPackageJson(pkgPath);
3467
+ const { changed, removed } = adoptNodeAdapter(pkg);
3468
+ if (changed) {
3469
+ writePackageJson(pkgPath, pkg);
3470
+ outcome.packageJsonChanged = true;
3471
+ outcome.removedDeps = removed;
3472
+ }
3473
+ }
3474
+ if (outcome.packageJsonChanged && install2) {
3475
+ outcome.installedWith = await installAdapterDependencies(root);
3476
+ }
3477
+ return outcome;
3478
+ }
3479
+ async function installAdapterDependencies(root) {
3480
+ const agent = await packageManager(root);
3481
+ if (!isInstalled(agent)) {
3482
+ throw new AdapterError(
3483
+ `${agent} is not installed, so ${ADAPTER_NODE} couldn't be installed.
3484
+
3485
+ The config and package.json are already updated: install ${agent}, run \`${agent} install\`, then deploy again.`,
3486
+ ""
3487
+ );
3488
+ }
3489
+ const ok = await installDependencies(agent, root, { exitOnFailure: false });
3490
+ if (!ok) {
3491
+ throw new AdapterError(
3492
+ `Installing ${ADAPTER_NODE} with ${agent} failed.
3493
+
3494
+ The config and package.json are already updated: run \`${agent} install\`, then deploy again.`,
3495
+ ""
3496
+ );
3497
+ }
3498
+ return agent;
3499
+ }
3500
+ function switchImport(target, importDecl) {
3501
+ importDecl.setModuleSpecifier(ADAPTER_NODE);
3502
+ const prop = target.kit.getPropertyOrThrow("adapter").asKindOrThrow(SyntaxKind3.PropertyAssignment);
3503
+ const call = prop.getInitializerIfKindOrThrow(SyntaxKind3.CallExpression);
3504
+ for (let i = call.getArguments().length - 1; i >= 0; i--) call.removeArgument(i);
3505
+ dropAdapterAutoComments(target);
3506
+ }
3507
+ var ADAPTER_AUTO_COMMENT = /adapter-auto|svelte\.dev\/docs\/kit\/adapters|switch out the adapter/;
3508
+ function dropAdapterAutoComments(target) {
3509
+ const prop = target.kit.getPropertyOrThrow("adapter");
3510
+ const ranges = prop.getLeadingCommentRanges();
3511
+ if (ranges.length === 0 || !ranges.every((r) => ADAPTER_AUTO_COMMENT.test(r.getText()))) return;
3512
+ const fullStart = prop.getFullStart();
3513
+ const start = prop.getStart();
3514
+ const trivia = target.sourceFile.getFullText().slice(fullStart, start);
3515
+ const lastNewline = trivia.lastIndexOf("\n");
3516
+ if (lastNewline === -1) return;
3517
+ const indent = trivia.slice(lastNewline + 1);
3518
+ target.sourceFile.replaceText([fullStart, start], `
3519
+ ${indent}`);
3520
+ }
3521
+ function addAdapter(target) {
3522
+ const taken = importOf(target.sourceFile, "adapter") ?? target.sourceFile.getVariableDeclaration("adapter");
3523
+ if (taken) {
3524
+ throw new AdapterError(
3525
+ `${path18.basename(target.filePath)} already binds the name \`adapter\` to something that is not the SvelteKit adapter.`
3526
+ );
3527
+ }
3528
+ target.sourceFile.addImportDeclaration({
3529
+ defaultImport: "adapter",
3530
+ moduleSpecifier: ADAPTER_NODE
3531
+ });
3532
+ target.kit.addPropertyAssignment({ name: "adapter", initializer: "adapter()" });
3533
+ }
3534
+ function saveTarget(target) {
3535
+ if (target.created) formatLikeSource(target.sourceFile);
3536
+ if (target.sourceFile.getFullText() === target.originalText) return;
3537
+ target.sourceFile.saveSync();
3538
+ }
3539
+ function adoptNodeAdapter(pkg) {
3540
+ const removed = [];
3541
+ let changed = false;
3542
+ for (const kind of ["dependencies", "devDependencies"]) {
3543
+ const deps = pkg[kind];
3544
+ if (deps && ADAPTER_AUTO in deps) {
3545
+ delete deps[ADAPTER_AUTO];
3546
+ removed.push(ADAPTER_AUTO);
3547
+ changed = true;
3548
+ }
3549
+ }
3550
+ if (!pkg.dependencies?.[ADAPTER_NODE] && !pkg.devDependencies?.[ADAPTER_NODE]) {
3551
+ pkg.devDependencies = sortKeys({ ...pkg.devDependencies, [ADAPTER_NODE]: ADAPTER_NODE_RANGE });
3552
+ changed = true;
3553
+ }
3554
+ return { changed, removed: [...new Set(removed)] };
3555
+ }
3556
+ function lockfileFor(agent) {
3557
+ switch (agent) {
3558
+ case "pnpm":
3559
+ return "pnpm-lock.yaml";
3560
+ case "yarn":
3561
+ return "yarn.lock";
3562
+ case "bun":
3563
+ return "bun.lock";
3564
+ case "deno":
3565
+ return "deno.lock";
3566
+ default:
3567
+ return "package-lock.json";
3568
+ }
3569
+ }
3570
+ async function packageManager(root) {
3571
+ return (await detect3({ cwd: root }))?.name ?? getUserAgent() ?? "npm";
3572
+ }
3573
+
3574
+ // src/lib/ssr-external.ts
3575
+ import fs21 from "node:fs";
3576
+ import path19 from "node:path";
3577
+ import { isBuiltin } from "node:module";
3578
+ import { Node as Node2, SyntaxKind as SyntaxKind4 } from "ts-morph";
3579
+ function packageNameOf(specifier) {
3580
+ const parts = specifier.split("/");
3581
+ return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
3582
+ }
3583
+ function unwrap2(expr) {
3584
+ let current = expr;
3585
+ for (let i = 0; current && i < 10; i++) {
3586
+ if (Node2.isParenthesizedExpression(current) || Node2.isAsExpression(current)) {
3587
+ current = current.getExpression();
3588
+ } else if (Node2.isSatisfiesExpression(current)) {
3589
+ current = current.getExpression();
3590
+ } else if (Node2.isCallExpression(current) && current.getExpression().getText() === "defineConfig") {
3591
+ current = current.getArguments()[0];
3592
+ } else if (Node2.isIdentifier(current)) {
3593
+ const decl = current.getSourceFile().getVariableDeclaration(current.getText())?.getInitializer();
3594
+ if (!decl) return current;
3595
+ current = decl;
3596
+ } else {
3597
+ return current;
3598
+ }
3599
+ }
3600
+ return current;
3601
+ }
3602
+ function exportedConfig(expr) {
3603
+ const value = unwrap2(expr);
3604
+ if (!value) return "it has no default export";
3605
+ if (Node2.isObjectLiteralExpression(value)) return value;
3606
+ if (Node2.isArrowFunction(value) || Node2.isFunctionExpression(value)) {
3607
+ return "its config is a function";
3608
+ }
3609
+ return "its default export is not an object literal";
3610
+ }
3611
+ function ssrExternalNotInDependencies(root) {
3612
+ let vite;
3613
+ try {
3614
+ vite = inspectViteSveltekit(root);
3615
+ } catch (err) {
3616
+ return { kind: "unknown", file: "vite.config", reason: err.message };
3617
+ }
3618
+ if (!vite) return { kind: "none" };
3619
+ const file = path19.basename(vite.filePath);
3620
+ const unknown2 = (reason) => ({ kind: "unknown", file, reason });
3621
+ try {
3622
+ const assignment = vite.sourceFile.getExportAssignment((d) => !d.isExportEquals());
3623
+ const config = exportedConfig(assignment?.getExpression());
3624
+ if (typeof config === "string") return unknown2(config);
3625
+ const ssrProp = config.getProperty("ssr");
3626
+ if (!ssrProp) return { kind: "none" };
3627
+ if (!Node2.isPropertyAssignment(ssrProp)) return unknown2("`ssr` is not a plain property");
3628
+ const ssr = unwrap2(ssrProp.getInitializer());
3629
+ if (!ssr || !Node2.isObjectLiteralExpression(ssr)) {
3630
+ return unknown2("`ssr` is not an object literal");
3631
+ }
3632
+ const externalProp = ssr.getProperty("external");
3633
+ if (!externalProp) return { kind: "none" };
3634
+ if (!Node2.isPropertyAssignment(externalProp)) {
3635
+ return unknown2("`ssr.external` is not a plain property");
3636
+ }
3637
+ const external = unwrap2(externalProp.getInitializer());
3638
+ if (!external) return unknown2("`ssr.external` has no value");
3639
+ if (external.getKind() === SyntaxKind4.TrueKeyword) return { kind: "all", file };
3640
+ if (!Node2.isArrayLiteralExpression(external)) {
3641
+ return unknown2("`ssr.external` is not an array literal");
3642
+ }
3643
+ const entries = [];
3644
+ for (const element of external.getElements()) {
3645
+ if (Node2.isStringLiteral(element) || Node2.isNoSubstitutionTemplateLiteral(element)) {
3646
+ entries.push(element.getLiteralValue());
3647
+ } else {
3648
+ return unknown2(`\`ssr.external\` has an entry that is not a string: ${element.getText()}`);
3649
+ }
3650
+ }
3651
+ const pkgPath = path19.join(root, "package.json");
3652
+ const pkg = fs21.existsSync(pkgPath) ? readPackageJson(pkgPath) : {};
3653
+ const missing = entries.filter((entry) => !isBuiltin(entry)).map(packageNameOf).filter((name) => !pkg.dependencies?.[name] && pkg.devDependencies?.[name] !== void 0);
3654
+ return { kind: "list", file, entries, missing: [...new Set(missing)] };
3655
+ } catch (err) {
3656
+ return unknown2(err.message);
3657
+ }
3658
+ }
3659
+ function moveToDependencies(pkg, names) {
3660
+ const moved = [];
3661
+ for (const name of names) {
3662
+ const range = pkg.devDependencies?.[name];
3663
+ if (range === void 0 || pkg.dependencies?.[name] !== void 0) continue;
3664
+ pkg.dependencies = sortKeys({ ...pkg.dependencies, [name]: range });
3665
+ delete pkg.devDependencies[name];
3666
+ moved.push(name);
3667
+ }
3668
+ return moved;
3669
+ }
3670
+ function moveSsrExternalsToDependencies(root, names) {
3671
+ const pkgPath = path19.join(root, "package.json");
3672
+ const pkg = readPackageJson(pkgPath);
3673
+ const moved = moveToDependencies(pkg, names);
3674
+ if (moved.length > 0) writePackageJson(pkgPath, pkg);
3675
+ return moved;
3676
+ }
3677
+ function ssrExternalProblem(check2) {
3678
+ if (check2.kind !== "list" || check2.missing.length === 0) return null;
3679
+ const names = check2.missing.join(", ");
3680
+ const one = check2.missing.length === 1;
3681
+ return `${check2.file} lists ${names} in ssr.external, but ${one ? "it is a devDependency" : "they are devDependencies"}.
3682
+ adapter-node 6 builds the server in one Vite pass and leaves ssr.external imports
3683
+ unbundled, and the server installs production dependencies only, so every page that
3684
+ imports ${one ? "it" : "one"} fails with ERR_MODULE_NOT_FOUND.
3685
+
3686
+ Move ${one ? "it" : "them"} to dependencies, or drop ${one ? "it" : "them"} from ssr.external.`;
3687
+ }
3688
+ function ssrExternalAllNotice(check2) {
3689
+ if (check2.kind !== "all") return null;
3690
+ return `${check2.file} sets ssr.external: true, which adapter-node 6 overrides: it bundles the
3691
+ whole server, dependencies included. Drop it, or list only the packages that must stay
3692
+ external (each in dependencies).`;
3693
+ }
3694
+
3695
+ // src/lib/kit-peers.ts
3696
+ import fs22 from "node:fs";
3697
+ import path20 from "node:path";
3336
3698
  import { execFile } from "node:child_process";
3337
3699
  var LOOKUP_TIMEOUT_MS = 15e3;
3338
3700
  var CONCURRENCY = 8;
@@ -3368,7 +3730,7 @@ function newest(data) {
3368
3730
  function installed(root, name) {
3369
3731
  try {
3370
3732
  const data = JSON.parse(
3371
- fs20.readFileSync(path18.join(root, "node_modules", name, "package.json"), "utf8")
3733
+ fs22.readFileSync(path20.join(root, "node_modules", name, "package.json"), "utf8")
3372
3734
  );
3373
3735
  return typeof data.version === "string" ? data : null;
3374
3736
  } catch {
@@ -3426,14 +3788,14 @@ async function findKit2Peers(root, pkg, skip, lookup = npmViewLookup) {
3426
3788
  }
3427
3789
 
3428
3790
  // src/lib/locales-alias.ts
3429
- import fs21 from "node:fs";
3430
- import path19 from "node:path";
3431
- import { Node as Node2, SyntaxKind as SyntaxKind3 } from "ts-morph";
3791
+ import fs23 from "node:fs";
3792
+ import path21 from "node:path";
3793
+ import { Node as Node3, SyntaxKind as SyntaxKind5 } from "ts-morph";
3432
3794
  import { ensurePackageImports } from "@velastack/patterns";
3433
3795
  var LOCALES_IMPORTS = { "#locales/*": "./src/locales/*" };
3434
3796
  var LOCALES_DIR = "src/locales";
3435
3797
  function keyName(node) {
3436
- if (!Node2.isPropertyAssignment(node)) return void 0;
3798
+ if (!Node3.isPropertyAssignment(node)) return void 0;
3437
3799
  return node.getNameNode().getText().replace(/^['"`]|['"`]$/g, "");
3438
3800
  }
3439
3801
  function localesProperty(alias) {
@@ -3441,8 +3803,8 @@ function localesProperty(alias) {
3441
3803
  }
3442
3804
  function localesSpecifier(root, rest) {
3443
3805
  if (/\.(?:js|mjs|cjs|json)$/.test(rest)) return `#locales/${rest}`;
3444
- const dir = path19.join(root, LOCALES_DIR);
3445
- const exists = (name) => fs21.existsSync(path19.join(dir, name));
3806
+ const dir = path21.join(root, LOCALES_DIR);
3807
+ const exists = (name) => fs23.existsSync(path21.join(dir, name));
3446
3808
  if (!exists(`${rest}.js`) && (exists(`${rest}.svelte.js`) || exists(`${rest}.svelte.ts`))) {
3447
3809
  return `#locales/${rest}.svelte.js`;
3448
3810
  }
@@ -3462,11 +3824,11 @@ async function migrateLocalesAlias(root) {
3462
3824
  const outcome = { changed: false, details: [], warnings: [] };
3463
3825
  const vite = inspectViteSveltekit(root);
3464
3826
  const aliasProp = vite?.inlineArg?.getProperty("alias");
3465
- if (!vite || !aliasProp || !Node2.isPropertyAssignment(aliasProp)) return outcome;
3466
- const alias = aliasProp.getInitializerIfKind(SyntaxKind3.ObjectLiteralExpression);
3827
+ if (!vite || !aliasProp || !Node3.isPropertyAssignment(aliasProp)) return outcome;
3828
+ const alias = aliasProp.getInitializerIfKind(SyntaxKind5.ObjectLiteralExpression);
3467
3829
  const entry = alias && localesProperty(alias);
3468
- if (!alias || !entry || !Node2.isPropertyAssignment(entry)) return outcome;
3469
- const target = entry.getInitializerIfKind(SyntaxKind3.StringLiteral)?.getLiteralValue();
3830
+ if (!alias || !entry || !Node3.isPropertyAssignment(entry)) return outcome;
3831
+ const target = entry.getInitializerIfKind(SyntaxKind5.StringLiteral)?.getLiteralValue();
3470
3832
  const normalized = target?.replace(/^\.\//, "").replace(/\/$/, "");
3471
3833
  if (normalized !== LOCALES_DIR) return outcome;
3472
3834
  const imports = await ensurePackageImports(root, LOCALES_IMPORTS);
@@ -3480,41 +3842,41 @@ async function migrateLocalesAlias(root) {
3480
3842
  outcome.changed = true;
3481
3843
  outcome.details.push("package.json imports #locales/*");
3482
3844
  }
3483
- const files = [...sourceFiles(path19.join(root, "src")), ...sourceFiles(path19.join(root, "test"))];
3845
+ const files = [...sourceFiles(path21.join(root, "src")), ...sourceFiles(path21.join(root, "test"))];
3484
3846
  let rewritten = 0;
3485
3847
  for (const file of files) {
3486
- const source = fs21.readFileSync(file, "utf8");
3848
+ const source = fs23.readFileSync(file, "utf8");
3487
3849
  if (!source.includes("$locales/")) continue;
3488
3850
  const { code: code2, changes } = rewriteLocalesSource(root, source);
3489
3851
  if (code2 === source) continue;
3490
- fs21.writeFileSync(file, code2);
3852
+ fs23.writeFileSync(file, code2);
3491
3853
  rewritten += changes.length;
3492
- outcome.details.push(`${path19.relative(root, file)}: ${[...new Set(changes)].join(", ")}`);
3854
+ outcome.details.push(`${path21.relative(root, file)}: ${[...new Set(changes)].join(", ")}`);
3493
3855
  }
3494
3856
  entry.remove();
3495
3857
  if (alias.getProperties().length === 0) aliasProp.remove();
3496
3858
  vite.sourceFile.saveSync();
3497
3859
  outcome.changed = true;
3498
3860
  outcome.details.push(
3499
- `${path19.basename(vite.filePath)}: removed alias.$locales${rewritten ? ` (${rewritten} specifier${rewritten === 1 ? "" : "s"} now #locales)` : ""}`
3861
+ `${path21.basename(vite.filePath)}: removed alias.$locales${rewritten ? ` (${rewritten} specifier${rewritten === 1 ? "" : "s"} now #locales)` : ""}`
3500
3862
  );
3501
3863
  return outcome;
3502
3864
  }
3503
3865
 
3504
3866
  // src/lib/params-native.ts
3505
- import fs22 from "node:fs";
3506
- import path20 from "node:path";
3867
+ import fs24 from "node:fs";
3868
+ import path22 from "node:path";
3507
3869
  import { Project as Project3, QuoteKind as QuoteKind2 } from "ts-morph";
3508
3870
  var PARAMS_FILES = ["src/params.ts", "src/params.js"];
3509
3871
  var PARAMS_DIR = "src/params";
3510
3872
  var IMPORT_SPECIFIERS = /import\s+(type\s+)?([^'";]*?)\s*from\s*(['"])([^'"]+)\3/g;
3511
3873
  function captureParamTypeImports(root) {
3512
3874
  const names = /* @__PURE__ */ new Set();
3513
- const dir = path20.join(root, PARAMS_DIR);
3514
- if (!fs22.existsSync(dir)) return names;
3515
- for (const entry of fs22.readdirSync(dir)) {
3875
+ const dir = path22.join(root, PARAMS_DIR);
3876
+ if (!fs24.existsSync(dir)) return names;
3877
+ for (const entry of fs24.readdirSync(dir)) {
3516
3878
  if (!/\.(ts|js)$/.test(entry)) continue;
3517
- const source = fs22.readFileSync(path20.join(dir, entry), "utf8");
3879
+ const source = fs24.readFileSync(path22.join(dir, entry), "utf8");
3518
3880
  for (const match of source.matchAll(IMPORT_SPECIFIERS)) {
3519
3881
  const clause = match[2];
3520
3882
  const braces = clause.match(/\{([^}]*)\}/)?.[1];
@@ -3533,18 +3895,18 @@ function captureParamTypeImports(root) {
3533
3895
  function resolveLocal(root, fromDir, spec) {
3534
3896
  let base2;
3535
3897
  if (spec.startsWith("#lib/") || spec.startsWith("$lib/")) {
3536
- base2 = path20.join(root, "src", "lib", spec.slice(5));
3898
+ base2 = path22.join(root, "src", "lib", spec.slice(5));
3537
3899
  } else if (spec.startsWith("./") || spec.startsWith("../")) {
3538
- base2 = path20.resolve(fromDir, spec);
3900
+ base2 = path22.resolve(fromDir, spec);
3539
3901
  } else {
3540
3902
  return null;
3541
3903
  }
3542
3904
  const stem = base2.replace(/\.js$/, "");
3543
- const candidates = /\.js$/.test(base2) ? [base2, `${stem}.ts`] : [base2, `${base2}.ts`, `${base2}.js`, path20.join(base2, "index.ts"), path20.join(base2, "index.js")];
3544
- return candidates.find((c) => fs22.existsSync(c) && fs22.statSync(c).isFile()) ?? null;
3905
+ const candidates = /\.js$/.test(base2) ? [base2, `${stem}.ts`] : [base2, `${base2}.ts`, `${base2}.js`, path22.join(base2, "index.ts"), path22.join(base2, "index.js")];
3906
+ return candidates.find((c) => fs24.existsSync(c) && fs24.statSync(c).isFile()) ?? null;
3545
3907
  }
3546
3908
  function declaresTypeOnly(file, name) {
3547
- const source = fs22.readFileSync(file, "utf8");
3909
+ const source = fs24.readFileSync(file, "utf8");
3548
3910
  const n = name.replace(/[$]/g, "\\$");
3549
3911
  const asValue = new RegExp(
3550
3912
  String.raw`\bexport\s+(?:declare\s+)?(?:const|let|var|function|class|enum|async\s+function)\s+${n}\b|\bexport\s*\{[^}]*\b${n}\b`
@@ -3555,20 +3917,20 @@ function declaresTypeOnly(file, name) {
3555
3917
  ).test(source);
3556
3918
  }
3557
3919
  function relativeSpecifier(root, target) {
3558
- const rel = path20.relative(path20.join(root, "src"), target).split(path20.sep).join("/");
3920
+ const rel = path22.relative(path22.join(root, "src"), target).split(path22.sep).join("/");
3559
3921
  return rel.startsWith(".") ? rel : `./${rel}`;
3560
3922
  }
3561
3923
  function fixParamsImports(root, typeNames = /* @__PURE__ */ new Set()) {
3562
- const rel = PARAMS_FILES.find((f) => fs22.existsSync(path20.join(root, f)));
3924
+ const rel = PARAMS_FILES.find((f) => fs24.existsSync(path22.join(root, f)));
3563
3925
  if (!rel) return { changes: [], viteOnly: [] };
3564
- const file = path20.join(root, rel);
3926
+ const file = path22.join(root, rel);
3565
3927
  const outcome = { file: rel, changes: [], viteOnly: [] };
3566
3928
  const project = new Project3({
3567
3929
  compilerOptions: { allowJs: true },
3568
3930
  manipulationSettings: { quoteKind: QuoteKind2.Single }
3569
3931
  });
3570
3932
  const sourceFile = project.addSourceFileAtPath(file);
3571
- const srcDir = path20.join(root, "src");
3933
+ const srcDir = path22.join(root, "src");
3572
3934
  const loaded = [];
3573
3935
  for (const decl of sourceFile.getImportDeclarations()) {
3574
3936
  const spec = decl.getModuleSpecifierValue();
@@ -3577,7 +3939,7 @@ function fixParamsImports(root, typeNames = /* @__PURE__ */ new Set()) {
3577
3939
  if (!decl.isTypeOnly()) restoreTypes(decl, target, typeNames, outcome);
3578
3940
  if (decl.isTypeOnly()) continue;
3579
3941
  loaded.push(target);
3580
- const nodeResolves = spec.startsWith("#lib/") && /\.js$/.test(spec) ? fs22.existsSync(path20.join(root, "src", "lib", spec.slice(5))) : spec.startsWith(".") && path20.resolve(srcDir, spec) === target;
3942
+ const nodeResolves = spec.startsWith("#lib/") && /\.js$/.test(spec) ? fs24.existsSync(path22.join(root, "src", "lib", spec.slice(5))) : spec.startsWith(".") && path22.resolve(srcDir, spec) === target;
3581
3943
  if (nodeResolves) continue;
3582
3944
  const next = relativeSpecifier(root, target);
3583
3945
  decl.setModuleSpecifier(next);
@@ -3609,10 +3971,10 @@ function viteOnlyImports(root, start) {
3609
3971
  const seen = /* @__PURE__ */ new Set();
3610
3972
  const queue = [...start];
3611
3973
  for (let file = queue.shift(); file; file = queue.shift()) {
3612
- if (seen.has(file) || !file.startsWith(path20.join(root, "src"))) continue;
3974
+ if (seen.has(file) || !file.startsWith(path22.join(root, "src"))) continue;
3613
3975
  seen.add(file);
3614
- const source = fs22.readFileSync(file, "utf8");
3615
- const rel = path20.relative(root, file).split(path20.sep).join("/");
3976
+ const source = fs24.readFileSync(file, "utf8");
3977
+ const rel = path22.relative(root, file).split(path22.sep).join("/");
3616
3978
  for (const match of source.matchAll(IMPORT_SPECIFIERS)) {
3617
3979
  const clause = match[2];
3618
3980
  const spec = match[4];
@@ -3622,12 +3984,12 @@ function viteOnlyImports(root, start) {
3622
3984
  found.push(`${rel}: ${spec}`);
3623
3985
  continue;
3624
3986
  }
3625
- const target = resolveLocal(root, path20.dirname(file), spec);
3987
+ const target = resolveLocal(root, path22.dirname(file), spec);
3626
3988
  if (spec.startsWith("#lib/")) {
3627
- if (!fs22.existsSync(path20.join(root, "src", "lib", spec.slice(5)))) {
3989
+ if (!fs24.existsSync(path22.join(root, "src", "lib", spec.slice(5)))) {
3628
3990
  found.push(`${rel}: ${spec}`);
3629
3991
  }
3630
- } else if (spec.startsWith(".") && target && path20.resolve(path20.dirname(file), spec) !== target) {
3992
+ } else if (spec.startsWith(".") && target && path22.resolve(path22.dirname(file), spec) !== target) {
3631
3993
  found.push(`${rel}: ${spec}`);
3632
3994
  }
3633
3995
  if (target) queue.push(target);
@@ -3637,15 +3999,15 @@ function viteOnlyImports(root, start) {
3637
3999
  }
3638
4000
 
3639
4001
  // src/lib/lib-rewrite.ts
3640
- import fs23 from "node:fs";
3641
- import path21 from "node:path";
4002
+ import fs25 from "node:fs";
4003
+ import path23 from "node:path";
3642
4004
  import { libSpecifier } from "@velastack/patterns";
3643
4005
  var KEPT_EXTENSIONS = /\.(svelte|svg|svx|css|json)$/;
3644
4006
  var MODULE_EXTENSIONS = [".ts", ".js", ".mts", ".mjs"];
3645
4007
  function resolveLibPath(root, rel) {
3646
- const lib = path21.join(root, "src", "lib");
3647
- const isFile = (p73) => fs23.existsSync(path21.join(lib, p73)) && fs23.statSync(path21.join(lib, p73)).isFile();
3648
- const isDir = (p73) => fs23.existsSync(path21.join(lib, p73)) && fs23.statSync(path21.join(lib, p73)).isDirectory();
4008
+ const lib = path23.join(root, "src", "lib");
4009
+ const isFile = (p73) => fs25.existsSync(path23.join(lib, p73)) && fs25.statSync(path23.join(lib, p73)).isFile();
4010
+ const isDir = (p73) => fs25.existsSync(path23.join(lib, p73)) && fs25.statSync(path23.join(lib, p73)).isDirectory();
3649
4011
  if (rel === "") return "";
3650
4012
  if (KEPT_EXTENSIONS.test(rel)) {
3651
4013
  if (isFile(rel)) return rel;
@@ -3685,40 +4047,40 @@ function rewriteLibSpecifiers(root, source) {
3685
4047
  }
3686
4048
  function filesOutsideSrc(root) {
3687
4049
  const files = [];
3688
- const test = path21.join(root, "test");
3689
- if (fs23.existsSync(test)) {
3690
- for (const rel of fs23.globSync("**/*.{ts,js,mts,mjs,svelte}", {
4050
+ const test = path23.join(root, "test");
4051
+ if (fs25.existsSync(test)) {
4052
+ for (const rel of fs25.globSync("**/*.{ts,js,mts,mjs,svelte}", {
3691
4053
  cwd: test,
3692
4054
  exclude: (name) => name === "node_modules"
3693
4055
  })) {
3694
- files.push(path21.join(test, rel));
4056
+ files.push(path23.join(test, rel));
3695
4057
  }
3696
4058
  }
3697
- for (const entry of fs23.readdirSync(root, { withFileTypes: true })) {
4059
+ for (const entry of fs25.readdirSync(root, { withFileTypes: true })) {
3698
4060
  if (entry.isFile() && /\.(ts|js|mts|mjs|cts|cjs)$/.test(entry.name) && !entry.name.endsWith(".d.ts")) {
3699
- files.push(path21.join(root, entry.name));
4061
+ files.push(path23.join(root, entry.name));
3700
4062
  }
3701
4063
  }
3702
- return files.filter((f) => fs23.statSync(f).isFile()).sort();
4064
+ return files.filter((f) => fs25.statSync(f).isFile()).sort();
3703
4065
  }
3704
4066
  function rewriteLibOutsideSrc(root) {
3705
4067
  const result = { rewritten: [], unresolved: [] };
3706
4068
  for (const file of filesOutsideSrc(root)) {
3707
- const source = fs23.readFileSync(file, "utf8");
4069
+ const source = fs25.readFileSync(file, "utf8");
3708
4070
  if (!source.includes("$lib")) continue;
3709
- const rel = path21.relative(root, file);
4071
+ const rel = path23.relative(root, file);
3710
4072
  const { code: code2, changes, unresolved } = rewriteLibSpecifiers(root, source);
3711
4073
  result.unresolved.push(...unresolved.map((spec) => `${rel}: ${spec}`));
3712
4074
  if (code2 === source) continue;
3713
- fs23.writeFileSync(file, code2);
4075
+ fs25.writeFileSync(file, code2);
3714
4076
  result.rewritten.push({ file: rel, changes });
3715
4077
  }
3716
4078
  return result;
3717
4079
  }
3718
4080
  function rewriteComponentsJsonAliases(root) {
3719
- const file = path21.join(root, "components.json");
3720
- if (!fs23.existsSync(file)) return null;
3721
- const source = fs23.readFileSync(file, "utf8");
4081
+ const file = path23.join(root, "components.json");
4082
+ if (!fs25.existsSync(file)) return null;
4083
+ const source = fs25.readFileSync(file, "utf8");
3722
4084
  let data;
3723
4085
  try {
3724
4086
  data = JSON.parse(source);
@@ -3736,13 +4098,13 @@ function rewriteComponentsJsonAliases(root) {
3736
4098
  changes.push(`${value} \u2192 ${next}`);
3737
4099
  }
3738
4100
  if (code2 === source) return null;
3739
- fs23.writeFileSync(file, code2);
4101
+ fs25.writeFileSync(file, code2);
3740
4102
  return { file: "components.json", changes };
3741
4103
  }
3742
4104
 
3743
4105
  // src/lib/kit3-rewrites.ts
3744
- import fs24 from "node:fs";
3745
- import path22 from "node:path";
4106
+ import fs26 from "node:fs";
4107
+ import path24 from "node:path";
3746
4108
  var MIGRATION_TASK_MARKER = "@migration-task";
3747
4109
  var NAVIGATION_IMPORT = /import\s*\{([^}]*)\}\s*from\s*['"]\$app\/navigation['"]\s*;?/g;
3748
4110
  function navigationBindings(source) {
@@ -4128,15 +4490,15 @@ function rewriteKit3Source(file, source) {
4128
4490
  }
4129
4491
  function rewriteKit3Code(root) {
4130
4492
  const results = [];
4131
- const files = [...sourceFiles(path22.join(root, "src")), ...sourceFiles(path22.join(root, "test"))];
4493
+ const files = [...sourceFiles(path24.join(root, "src")), ...sourceFiles(path24.join(root, "test"))];
4132
4494
  for (const file of files) {
4133
- const source = fs24.readFileSync(file, "utf8");
4495
+ const source = fs26.readFileSync(file, "utf8");
4134
4496
  if (!/\$app\/navigation|\$app\/environment|\$env\/|new\s+URL\(\s*\$?page\.url\s*\)/.test(source))
4135
4497
  continue;
4136
- const rel = path22.relative(root, file);
4498
+ const rel = path24.relative(root, file);
4137
4499
  const { code: code2, changes, tasks } = rewriteKit3Source(rel, source);
4138
4500
  if (code2 === source) continue;
4139
- fs24.writeFileSync(file, code2);
4501
+ fs26.writeFileSync(file, code2);
4140
4502
  results.push({ file: rel, changes, tasks });
4141
4503
  }
4142
4504
  return results;
@@ -4182,13 +4544,13 @@ function rewriteVelaEnvDefaultsSource(source) {
4182
4544
  }
4183
4545
  function rewriteVelaEnvDefaults(root) {
4184
4546
  const results = [];
4185
- for (const file of sourceFiles(path22.join(root, "src"))) {
4186
- const source = fs24.readFileSync(file, "utf8");
4547
+ for (const file of sourceFiles(path24.join(root, "src"))) {
4548
+ const source = fs26.readFileSync(file, "utf8");
4187
4549
  if (!source.includes("$app/env/") || !source.includes("??")) continue;
4188
4550
  const { code: code2, changes } = rewriteVelaEnvDefaultsSource(source);
4189
4551
  if (code2 === source) continue;
4190
- fs24.writeFileSync(file, code2);
4191
- results.push({ file: path22.relative(root, file), changes, tasks: [] });
4552
+ fs26.writeFileSync(file, code2);
4553
+ results.push({ file: path24.relative(root, file), changes, tasks: [] });
4192
4554
  }
4193
4555
  return results;
4194
4556
  }
@@ -4255,6 +4617,7 @@ async function runKit3Migration(root, options = {}) {
4255
4617
  codeFixup(root),
4256
4618
  tsconfigFixup(root),
4257
4619
  packageFixup(root, cliVersion),
4620
+ ssrExternalFixup(root),
4258
4621
  await peersFixup(root, options.peerLookup),
4259
4622
  lockfileFixup(root)
4260
4623
  ];
@@ -4269,10 +4632,10 @@ async function runKit3Migration(root, options = {}) {
4269
4632
  if (installed2) formatted = await formatChanged(root, dirtyBefore);
4270
4633
  }
4271
4634
  const found = [...collectFollowUps(root, sv), ...fixups.flatMap((f) => f.followUps ?? [])];
4272
- if (!sv.ran) found.unshift(...previousSvFollowUps(root));
4635
+ if (!sv.ran) found.unshift(...previousFollowUps(root, SV_FAILURE_ITEM));
4273
4636
  const followUps = [...new Set(found)];
4274
4637
  const genericFollowUps = depRange(
4275
- readJson(path23.join(root, "package.json")).data,
4638
+ readJson(path25.join(root, "package.json")).data,
4276
4639
  "@sveltejs/adapter-node"
4277
4640
  ) ? [
4278
4641
  "Servers need Node 22.17 or later: run `vela provision` on each before the first SvelteKit 3 deploy."
@@ -4288,9 +4651,9 @@ async function preflight(root, options) {
4288
4651
  `SvelteKit 3 needs Node ${NODE_FLOOR} or later; this is Node ${options.nodeVersion ?? process12.versions.node}.`
4289
4652
  );
4290
4653
  }
4291
- const pkgPath = path23.join(root, "package.json");
4292
- if (!fs25.existsSync(pkgPath)) throw new Kit3MigrationError(`No package.json found in ${root}.`);
4293
- const project = JSON.parse(fs25.readFileSync(pkgPath, "utf8"));
4654
+ const pkgPath = path25.join(root, "package.json");
4655
+ if (!fs27.existsSync(pkgPath)) throw new Kit3MigrationError(`No package.json found in ${root}.`);
4656
+ const project = JSON.parse(fs27.readFileSync(pkgPath, "utf8"));
4294
4657
  if (!project.devDependencies?.["@sveltejs/kit"]) {
4295
4658
  throw new Kit3MigrationError(
4296
4659
  project.dependencies?.["@sveltejs/kit"] ? "@sveltejs/kit is in dependencies; sv migrates it only from devDependencies. Move it there and run this again." : `@sveltejs/kit is not a devDependency in ${pkgPath}: this does not look like a SvelteKit project.`
@@ -4347,14 +4710,14 @@ function clearOutputDirs(root, log55) {
4347
4710
  const cleared = [];
4348
4711
  const inGit = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], root) !== null;
4349
4712
  const walk2 = (dir, depth) => {
4350
- for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
4713
+ for (const entry of fs27.readdirSync(dir, { withFileTypes: true })) {
4351
4714
  if (!entry.isDirectory() || entry.name === "node_modules" || entry.name === ".git") continue;
4352
- const full = path23.join(dir, entry.name);
4353
- const rel = path23.relative(root, full);
4715
+ const full = path25.join(dir, entry.name);
4716
+ const rel = path25.relative(root, full);
4354
4717
  if (OUTPUT_DIRS.has(entry.name)) {
4355
4718
  const ignored = inGit ? spawnSync("git", ["check-ignore", "-q", rel], root) !== null : entry.name === ".svelte-kit";
4356
4719
  if (ignored) {
4357
- fs25.rmSync(full, { recursive: true, force: true });
4720
+ fs27.rmSync(full, { recursive: true, force: true });
4358
4721
  cleared.push(rel);
4359
4722
  } else if (entry.name !== ".svelte-kit") {
4360
4723
  log55.warn(
@@ -4373,18 +4736,18 @@ function clearOutputDirs(root, log55) {
4373
4736
  }
4374
4737
  function svBin() {
4375
4738
  const entry = require_.resolve("sv");
4376
- let dir = path23.dirname(entry);
4377
- while (dir !== path23.dirname(dir)) {
4378
- const manifest = path23.join(dir, "package.json");
4379
- if (fs25.existsSync(manifest)) {
4380
- const data = JSON.parse(fs25.readFileSync(manifest, "utf8"));
4739
+ let dir = path25.dirname(entry);
4740
+ while (dir !== path25.dirname(dir)) {
4741
+ const manifest = path25.join(dir, "package.json");
4742
+ if (fs27.existsSync(manifest)) {
4743
+ const data = JSON.parse(fs27.readFileSync(manifest, "utf8"));
4381
4744
  if (data.name === "sv") {
4382
4745
  const bin = typeof data.bin === "string" ? data.bin : data.bin?.sv;
4383
4746
  if (!bin) throw new Kit3MigrationError("The installed sv package has no bin.");
4384
- return path23.join(dir, bin);
4747
+ return path25.join(dir, bin);
4385
4748
  }
4386
4749
  }
4387
- dir = path23.dirname(dir);
4750
+ dir = path25.dirname(dir);
4388
4751
  }
4389
4752
  throw new Kit3MigrationError("Could not find the sv package vela depends on. Reinstall vela.");
4390
4753
  }
@@ -4534,7 +4897,7 @@ async function envFixup(root) {
4534
4897
  }
4535
4898
  function libFixup(root, skippedBySv) {
4536
4899
  const f = fixup("#lib");
4537
- const pkgPath = path23.join(root, "package.json");
4900
+ const pkgPath = path25.join(root, "package.json");
4538
4901
  const { data, indent } = readJson(pkgPath);
4539
4902
  if (ensureLibImports(data)) {
4540
4903
  writeJson(pkgPath, data, indent);
@@ -4547,14 +4910,14 @@ function libFixup(root, skippedBySv) {
4547
4910
  f.details.push(`components.json aliases ${components.changes.join(", ")}`);
4548
4911
  }
4549
4912
  for (const rel of skippedBySv) {
4550
- const file = path23.join(root, rel);
4551
- if (!fs25.existsSync(file)) continue;
4552
- const source = fs25.readFileSync(file, "utf8");
4913
+ const file = path25.join(root, rel);
4914
+ if (!fs27.existsSync(file)) continue;
4915
+ const source = fs27.readFileSync(file, "utf8");
4553
4916
  const { code: code2, changes, unresolved } = rewriteLibSpecifiers(root, source);
4554
4917
  for (const u of unresolved)
4555
4918
  f.warnings.push(`${rel}: ${u} names nothing under src/lib; change it by hand`);
4556
4919
  if (code2 === source) continue;
4557
- fs25.writeFileSync(file, code2);
4920
+ fs27.writeFileSync(file, code2);
4558
4921
  f.changed = true;
4559
4922
  f.details.push(`${rel} (skipped by sv): ${changes.join(", ")}`);
4560
4923
  }
@@ -4622,8 +4985,8 @@ function splitSpec(spec) {
4622
4985
  }
4623
4986
  var FLOORS = [
4624
4987
  ["@sveltejs/kit", "^3.0.0"],
4625
- splitSpec(ADAPTER_NODE),
4626
- splitSpec(ADAPTER_STATIC),
4988
+ splitSpec(ADAPTER_NODE2),
4989
+ splitSpec(ADAPTER_STATIC2),
4627
4990
  ["@sveltejs/adapter-auto", "^8.0.0"],
4628
4991
  ["@sveltejs/package", "^3.0.0"],
4629
4992
  ["@sveltejs/vite-plugin-svelte", "^7.3.1"],
@@ -4647,7 +5010,7 @@ var EXACT_PINS = [
4647
5010
  var ENGINES_FLOOR = ">=22.17";
4648
5011
  function packageFixup(root, cliVersion) {
4649
5012
  const f = fixup("package.json");
4650
- const pkgPath = path23.join(root, "package.json");
5013
+ const pkgPath = path25.join(root, "package.json");
4651
5014
  const { data, indent } = readJson(pkgPath);
4652
5015
  const changed = [];
4653
5016
  for (const [name, range] of [...FLOORS, ["vela", `^${cliVersion}`]]) {
@@ -4693,13 +5056,40 @@ function packageFixup(root, cliVersion) {
4693
5056
  }
4694
5057
  return f;
4695
5058
  }
5059
+ function ssrExternalFixup(root) {
5060
+ const f = fixup("ssr.external");
5061
+ f.followUps = previousFollowUps(root, SSR_EXTERNAL_ITEM);
5062
+ let adapter;
5063
+ try {
5064
+ adapter = detectAdapter(root);
5065
+ } catch {
5066
+ return f;
5067
+ }
5068
+ if (adapter.kind !== "node") return f;
5069
+ const check2 = ssrExternalNotInDependencies(root);
5070
+ if (check2.kind === "list" && check2.missing.length > 0) {
5071
+ const moved = moveSsrExternalsToDependencies(root, check2.missing);
5072
+ if (moved.length > 0) {
5073
+ f.changed = true;
5074
+ f.details.push(`moved ${moved.join(", ")} from devDependencies to dependencies`);
5075
+ f.followUps.push(
5076
+ `${code(check2.file)}: moved ${moved.map(code).join(", ")} from devDependencies to dependencies because \`ssr.external\` lists ${moved.length === 1 ? "it" : "them"}. adapter-node 6 builds the server in one Vite pass and no longer bundles \`ssr.external\` imports, and the server installs production dependencies only. Keep ${moved.length === 1 ? "it" : "them"} in dependencies, or drop ${moved.length === 1 ? "it" : "them"} from \`ssr.external\` to have ${moved.length === 1 ? "it" : "them"} bundled.`
5077
+ );
5078
+ }
5079
+ } else if (check2.kind === "all") {
5080
+ f.followUps.push(
5081
+ `${code(check2.file)}: \`ssr.external: true\` does nothing under adapter-node 6, which bundles the whole server, dependencies included. Drop it, or list only the packages that must stay external, each in dependencies.`
5082
+ );
5083
+ }
5084
+ return f;
5085
+ }
4696
5086
  function bumpedHere(name) {
4697
5087
  return name === "vela" || name.startsWith("@sveltejs/") || name.startsWith("@velastack/") || name.startsWith("@types/") || FLOORS.some(([floor]) => floor === name) || EXACT_PINS.some(([pin]) => pin === name);
4698
5088
  }
4699
5089
  async function peersFixup(root, lookup) {
4700
5090
  const f = fixup("SvelteKit 2 peers");
4701
5091
  f.followUps = [];
4702
- const data = readJson(path23.join(root, "package.json")).data;
5092
+ const data = readJson(path25.join(root, "package.json")).data;
4703
5093
  const kit = depRange(data, "@sveltejs/kit") ?? "^3.0.0";
4704
5094
  const overrides = data.overrides ?? {};
4705
5095
  const overridden = (name) => {
@@ -4733,7 +5123,7 @@ async function peersFixup(root, lookup) {
4733
5123
  ...Object.keys(data.dependencies ?? {}),
4734
5124
  ...Object.keys(data.devDependencies ?? {})
4735
5125
  ].filter((name, i, all) => all.indexOf(name) === i);
4736
- const after = readJson(path23.join(root, "package.json")).data.overrides ?? {};
5126
+ const after = readJson(path25.join(root, "package.json")).data.overrides ?? {};
4737
5127
  for (const name of names) {
4738
5128
  const entry = after[name];
4739
5129
  if (bumpedHere(name) || typeof entry !== "object" || entry === null) continue;
@@ -4755,10 +5145,10 @@ function depRange(data, name) {
4755
5145
  var STALE_LOCK_ENTRY = /(^|\/)node_modules\/(@sveltejs\/[^/]+|sveltekit-superforms|sveltekit-flash-message|formsnap|@velastack\/[^/]+|sveltekit-negotiate)$/;
4756
5146
  function lockfileFixup(root) {
4757
5147
  const f = fixup("package-lock.json");
4758
- const lockPath = path23.join(root, "package-lock.json");
4759
- if (!fs25.existsSync(lockPath)) {
5148
+ const lockPath = path25.join(root, "package-lock.json");
5149
+ if (!fs27.existsSync(lockPath)) {
4760
5150
  for (const other of ["pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"]) {
4761
- if (fs25.existsSync(path23.join(root, other))) {
5151
+ if (fs27.existsSync(path25.join(root, other))) {
4762
5152
  f.warnings.push(
4763
5153
  `${other} still pins SvelteKit 2 packages; if the install fails, update @sveltejs/* with your package manager`
4764
5154
  );
@@ -4768,7 +5158,7 @@ function lockfileFixup(root) {
4768
5158
  }
4769
5159
  const { data, indent } = readJson(lockPath);
4770
5160
  const packages = data.packages;
4771
- const project = readJson(path23.join(root, "package.json")).data;
5161
+ const project = readJson(path25.join(root, "package.json")).data;
4772
5162
  const lockedKit = packages?.["node_modules/@sveltejs/kit"]?.version;
4773
5163
  const kit2Lock = lockedKit !== void 0 && (minVersion(lockedKit)?.major ?? 0) < 3;
4774
5164
  const removed = [];
@@ -4800,19 +5190,19 @@ function belowFloor(project, key, entry) {
4800
5190
  return Boolean(floor && locked && compareVersions(locked, floor) < 0);
4801
5191
  }
4802
5192
  function readJson(file) {
4803
- const text19 = fs25.readFileSync(file, "utf8");
5193
+ const text19 = fs27.readFileSync(file, "utf8");
4804
5194
  return {
4805
5195
  data: JSON.parse(text19),
4806
5196
  indent: text19.match(/^[{[]\s*\n([\t ]+)/)?.[1] ?? " "
4807
5197
  };
4808
5198
  }
4809
5199
  function writeJson(file, data, indent) {
4810
- fs25.writeFileSync(file, `${JSON.stringify(data, null, indent)}
5200
+ fs27.writeFileSync(file, `${JSON.stringify(data, null, indent)}
4811
5201
  `);
4812
5202
  }
4813
5203
  function collectFollowUps(root, sv) {
4814
5204
  const items = [];
4815
- const files = [...sourceFiles(path23.join(root, "src")), ...sourceFiles(path23.join(root, "test"))];
5205
+ const files = [...sourceFiles(path25.join(root, "src")), ...sourceFiles(path25.join(root, "test"))];
4816
5206
  for (const spread of sv.dropped) {
4817
5207
  items.push(
4818
5208
  `${code(spread.file)}: sv dropped ${code(spread.text)} when it moved the config into \`sveltekit({...})\` (it skips spread properties). Add it back there if it is still needed.`
@@ -4830,8 +5220,8 @@ function collectFollowUps(root, sv) {
4830
5220
  }
4831
5221
  }
4832
5222
  for (const file of files) {
4833
- const source = fs25.readFileSync(file, "utf8");
4834
- const rel = path23.relative(root, file).split(path23.sep).join("/");
5223
+ const source = fs27.readFileSync(file, "utf8");
5224
+ const rel = path25.relative(root, file).split(path25.sep).join("/");
4835
5225
  const lines = source.split("\n");
4836
5226
  const locals = envImports(source).filter((i) => !i.local.includes(".")).map((i) => i.local);
4837
5227
  if (locals.length > 0) {
@@ -4859,9 +5249,9 @@ function collectFollowUps(root, sv) {
4859
5249
  }
4860
5250
  });
4861
5251
  }
4862
- for (const file of textFiles(path23.join(root, "src"))) {
4863
- const rel = path23.relative(root, file).split(path23.sep).join("/");
4864
- const source = fs25.readFileSync(file, "utf8");
5252
+ for (const file of textFiles(path25.join(root, "src"))) {
5253
+ const rel = path25.relative(root, file).split(path25.sep).join("/");
5254
+ const source = fs27.readFileSync(file, "utf8");
4865
5255
  if (!source.includes("svelte.config.js")) continue;
4866
5256
  source.split("\n").forEach((line, i) => {
4867
5257
  if (!line.includes("svelte.config.js")) return;
@@ -4874,7 +5264,7 @@ function collectFollowUps(root, sv) {
4874
5264
  const vite = inspectViteSveltekit(root);
4875
5265
  if (vite?.inlineArg) {
4876
5266
  const config = vite.inlineArg.getText();
4877
- const rel = path23.basename(vite.filePath);
5267
+ const rel = path25.basename(vite.filePath);
4878
5268
  if (/\borigin\s*:\s*['"`]/.test(config)) {
4879
5269
  items.push(
4880
5270
  `\`${rel}\`: \`paths.origin\` is a literal. It is baked into the build, so every host serving this app gets that origin; leave it unset for a multi-host deploy (vela sets it from VELA_ORIGIN on single-host deploys).`
@@ -4890,24 +5280,25 @@ function collectFollowUps(root, sv) {
4890
5280
  }
4891
5281
  var BINARY_EXTENSIONS = /\.(?:png|jpe?g|gif|webp|avif|ico|bmp|tiff?|woff2?|ttf|otf|eot|pdf|zip|gz|tgz|mp[34]|webm|mov|wav|ogg|wasm|db|sqlite3?)$/i;
4892
5282
  function textFiles(dir) {
4893
- if (!fs25.existsSync(dir)) return [];
4894
- return fs25.globSync("**/*", {
5283
+ if (!fs27.existsSync(dir)) return [];
5284
+ return fs27.globSync("**/*", {
4895
5285
  cwd: dir,
4896
5286
  exclude: (name) => name === "node_modules" || name === ".svelte-kit"
4897
- }).filter((rel) => !BINARY_EXTENSIONS.test(rel)).map((rel) => path23.join(dir, rel)).filter((file) => {
4898
- const stat = fs25.statSync(file);
5287
+ }).filter((rel) => !BINARY_EXTENSIONS.test(rel)).map((rel) => path25.join(dir, rel)).filter((file) => {
5288
+ const stat = fs27.statSync(file);
4899
5289
  return stat.isFile() && stat.size < 2e6;
4900
5290
  });
4901
5291
  }
4902
5292
  var SV_FAILURE_ITEM = /sv's `[^`]+` task (could not parse it|failed)|: sv dropped `/;
4903
- function previousSvFollowUps(root) {
4904
- const file = path23.join(root, MIGRATION_TASKS_FILE);
4905
- if (!fs25.existsSync(file)) return [];
4906
- const content = fs25.readFileSync(file, "utf8");
5293
+ var SSR_EXTERNAL_ITEM = /: moved .+ from devDependencies to dependencies because `ssr\.external` lists /;
5294
+ function previousFollowUps(root, pattern) {
5295
+ const file = path25.join(root, MIGRATION_TASKS_FILE);
5296
+ if (!fs27.existsSync(file)) return [];
5297
+ const content = fs27.readFileSync(file, "utf8");
4907
5298
  const start = content.indexOf(FOLLOW_UPS_HEADING);
4908
5299
  if (start === -1) return [];
4909
5300
  const end = content.indexOf("\n## ", start + FOLLOW_UPS_HEADING.length);
4910
- return content.slice(start, end === -1 ? void 0 : end).split("\n").filter((line) => line.startsWith("- [") && SV_FAILURE_ITEM.test(line)).map((line) => line.replace(/^- \[[ x]\] /, ""));
5301
+ return content.slice(start, end === -1 ? void 0 : end).split("\n").filter((line) => line.startsWith("- [") && pattern.test(line)).map((line) => line.replace(/^- \[[ x]\] /, ""));
4911
5302
  }
4912
5303
  function code(text19) {
4913
5304
  const fence = text19.includes("`") ? "``" : "`";
@@ -4918,11 +5309,11 @@ function escape(text19) {
4918
5309
  return text19.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4919
5310
  }
4920
5311
  function writeFollowUps(root, items, generic) {
4921
- const file = path23.join(root, MIGRATION_TASKS_FILE);
4922
- const exists = fs25.existsSync(file);
5312
+ const file = path25.join(root, MIGRATION_TASKS_FILE);
5313
+ const exists = fs27.existsSync(file);
4923
5314
  const all = [...items, ...generic];
4924
5315
  if (!exists && items.length === 0) return;
4925
- const original = exists ? fs25.readFileSync(file, "utf8") : "# SvelteKit 3 migration tasks\n";
5316
+ const original = exists ? fs27.readFileSync(file, "utf8") : "# SvelteKit 3 migration tasks\n";
4926
5317
  let content = original;
4927
5318
  const start = content.indexOf(FOLLOW_UPS_HEADING);
4928
5319
  if (start !== -1) {
@@ -4944,17 +5335,17 @@ function writeFollowUps(root, items, generic) {
4944
5335
  ${body}` : `${content.slice(0, final)}${body}
4945
5336
  ${content.slice(final)}`;
4946
5337
  }
4947
- if (content !== original) fs25.writeFileSync(file, content);
5338
+ if (content !== original) fs27.writeFileSync(file, content);
4948
5339
  }
4949
5340
  function summarizeMigrationTasks(root) {
4950
- const file = path23.join(root, MIGRATION_TASKS_FILE);
5341
+ const file = path25.join(root, MIGRATION_TASKS_FILE);
4951
5342
  const markerComments = countMarkers(root);
4952
- if (!fs25.existsSync(file))
5343
+ if (!fs27.existsSync(file))
4953
5344
  return markerComments > 0 ? { sections: [], filesToReview: 0, markerComments } : null;
4954
5345
  const sections = [];
4955
5346
  let current = null;
4956
5347
  let inFiles = false;
4957
- for (const line of fs25.readFileSync(file, "utf8").split("\n")) {
5348
+ for (const line of fs27.readFileSync(file, "utf8").split("\n")) {
4958
5349
  if (line.startsWith("## ")) {
4959
5350
  current = null;
4960
5351
  inFiles = false;
@@ -4974,33 +5365,33 @@ function summarizeMigrationTasks(root) {
4974
5365
  }
4975
5366
  function countMarkers(root) {
4976
5367
  let count = 0;
4977
- const files = [...sourceFiles(path23.join(root, "src")), ...sourceFiles(path23.join(root, "test"))];
4978
- for (const entry of fs25.readdirSync(root, { withFileTypes: true })) {
5368
+ const files = [...sourceFiles(path25.join(root, "src")), ...sourceFiles(path25.join(root, "test"))];
5369
+ for (const entry of fs27.readdirSync(root, { withFileTypes: true })) {
4979
5370
  if (entry.isFile() && /\.(ts|js|mts|mjs)$/.test(entry.name))
4980
- files.push(path23.join(root, entry.name));
5371
+ files.push(path25.join(root, entry.name));
4981
5372
  }
4982
5373
  for (const file of files) {
4983
- count += fs25.readFileSync(file, "utf8").split(MIGRATION_TASK_MARKER).length - 1;
5374
+ count += fs27.readFileSync(file, "utf8").split(MIGRATION_TASK_MARKER).length - 1;
4984
5375
  }
4985
5376
  return count;
4986
5377
  }
4987
5378
  async function install(root) {
4988
- const agent = (await detect3({ cwd: root }))?.name ?? "npm";
5379
+ const agent = (await detect4({ cwd: root }))?.name ?? "npm";
4989
5380
  return installDependencies(agent, root, { exitOnFailure: false });
4990
5381
  }
4991
5382
  async function formatProject(root) {
4992
- const bin = path23.join(root, "node_modules", ".bin", "prettier");
4993
- if (!fs25.existsSync(bin)) return;
5383
+ const bin = path25.join(root, "node_modules", ".bin", "prettier");
5384
+ if (!fs27.existsSync(bin)) return;
4994
5385
  await x2(bin, ["--write", "--ignore-unknown", "."], {
4995
5386
  nodeOptions: { cwd: root, stdio: "ignore" }
4996
5387
  });
4997
5388
  }
4998
5389
  async function formatChanged(root, dirtyBefore) {
4999
- const bin = path23.join(root, "node_modules", ".bin", "prettier");
5390
+ const bin = path25.join(root, "node_modules", ".bin", "prettier");
5000
5391
  const changed = gitDirty(root);
5001
- if (!changed || !fs25.existsSync(bin)) return [];
5392
+ if (!changed || !fs27.existsSync(bin)) return [];
5002
5393
  const files = changed.filter(
5003
- (f) => !dirtyBefore.has(f) && fs25.existsSync(path23.join(root, f)) && fs25.statSync(path23.join(root, f)).isFile()
5394
+ (f) => !dirtyBefore.has(f) && fs27.existsSync(path25.join(root, f)) && fs27.statSync(path25.join(root, f)).isFile()
5004
5395
  );
5005
5396
  if (files.length === 0) return [];
5006
5397
  const result = await x2(bin, ["--write", "--ignore-unknown", ...files], {
@@ -5010,8 +5401,8 @@ async function formatChanged(root, dirtyBefore) {
5010
5401
  }
5011
5402
 
5012
5403
  // src/lib/kit3-template-support.ts
5013
- import fs26 from "node:fs";
5014
- import path24 from "node:path";
5404
+ import fs28 from "node:fs";
5405
+ import path26 from "node:path";
5015
5406
  var CMS = "@velastack/cms";
5016
5407
  var REPEATER_REMOVED_IN = { major: 0, minor: 5, patch: 0, prerelease: [] };
5017
5408
  var SOURCE_FILE = /\.(svelte|svx|md|[cm]?[jt]s)$/;
@@ -5038,11 +5429,11 @@ Pick another template, or create the SvelteKit 2 version with
5038
5429
  }
5039
5430
  function cmsRange(dir) {
5040
5431
  for (const file of ["package.template.json", "package.json"]) {
5041
- const pkgPath = path24.join(dir, file);
5042
- if (!fs26.existsSync(pkgPath)) continue;
5432
+ const pkgPath = path26.join(dir, file);
5433
+ if (!fs28.existsSync(pkgPath)) continue;
5043
5434
  let pkg;
5044
5435
  try {
5045
- pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf8"));
5436
+ pkg = JSON.parse(fs28.readFileSync(pkgPath, "utf8"));
5046
5437
  } catch {
5047
5438
  return void 0;
5048
5439
  }
@@ -5051,15 +5442,15 @@ function cmsRange(dir) {
5051
5442
  return void 0;
5052
5443
  }
5053
5444
  function findRepeaterImport(dir) {
5054
- const src = path24.join(dir, "src");
5055
- if (!fs26.existsSync(src)) return void 0;
5056
- const entries = fs26.readdirSync(src, { recursive: true, withFileTypes: true });
5445
+ const src = path26.join(dir, "src");
5446
+ if (!fs28.existsSync(src)) return void 0;
5447
+ const entries = fs28.readdirSync(src, { recursive: true, withFileTypes: true });
5057
5448
  for (const entry of entries) {
5058
5449
  if (!entry.isFile() || !SOURCE_FILE.test(entry.name)) continue;
5059
- const file = path24.join(entry.parentPath, entry.name);
5060
- const text19 = fs26.readFileSync(file, "utf8");
5450
+ const file = path26.join(entry.parentPath, entry.name);
5451
+ const text19 = fs28.readFileSync(file, "utf8");
5061
5452
  if (text19.includes("CmsRepeater") && REPEATER_IMPORT.test(text19)) {
5062
- return path24.relative(dir, file);
5453
+ return path26.relative(dir, file);
5063
5454
  }
5064
5455
  }
5065
5456
  return void 0;
@@ -5119,8 +5510,8 @@ var create = new Command3("create").description("scaffold a new velastack projec
5119
5510
  const listing = await listAllTemplates();
5120
5511
  const options = parseOptions(optionsSchema2(listing), rawOpts);
5121
5512
  const { directory, packageManager: packageManager2, installed: installed2, migrated, name, template, link: link2 } = await createProject2(projectPath, options, listing);
5122
- const relative = path25.relative(process13.cwd(), directory);
5123
- const pm = packageManager2 ?? (await detect4({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
5513
+ const relative = path27.relative(process13.cwd(), directory);
5514
+ const pm = packageManager2 ?? (await detect5({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
5124
5515
  const nextSteps = [];
5125
5516
  if (relative !== "") {
5126
5517
  const hasSpaces = relative.includes(" ");
@@ -5181,7 +5572,7 @@ async function createProject2(cwdArg, options, listing) {
5181
5572
  resolved.cleanup();
5182
5573
  }
5183
5574
  const { directory: projectPath, name, credentials, link: link2 } = scaffolded;
5184
- if (!fs27.existsSync(path25.join(projectPath, "package.json"))) {
5575
+ if (!fs29.existsSync(path27.join(projectPath, "package.json"))) {
5185
5576
  throw new Error(`Template ${template.name} is missing package.template.json`);
5186
5577
  }
5187
5578
  if (link2.linked) {
@@ -5240,7 +5631,7 @@ async function resolveCreatableTemplate(template) {
5240
5631
  async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
5241
5632
  let directory;
5242
5633
  if (cwdArg) {
5243
- directory = path25.resolve(cwdArg);
5634
+ directory = path27.resolve(cwdArg);
5244
5635
  } else {
5245
5636
  const answer = await p10.text({
5246
5637
  message: "Where would you like your project to be created?",
@@ -5248,16 +5639,16 @@ async function scaffoldProject(cwdArg, options, template, resolved, onCancel2) {
5248
5639
  defaultValue: "./"
5249
5640
  });
5250
5641
  if (p10.isCancel(answer)) onCancel2();
5251
- directory = path25.resolve(answer);
5642
+ directory = path27.resolve(answer);
5252
5643
  }
5253
- if (fs27.existsSync(directory) && fs27.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
5644
+ if (fs29.existsSync(directory) && fs29.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
5254
5645
  const force = await p10.confirm({
5255
5646
  message: "Directory not empty. Continue?",
5256
5647
  initialValue: false
5257
5648
  });
5258
5649
  if (p10.isCancel(force) || !force) onCancel2();
5259
5650
  }
5260
- const dirName = path25.basename(directory);
5651
+ const dirName = path27.basename(directory);
5261
5652
  const { name } = await p10.group(
5262
5653
  {
5263
5654
  name: () => {
@@ -5291,7 +5682,7 @@ async function migrateKit2Template(projectPath, templateName2) {
5291
5682
  try {
5292
5683
  result = await runKit3Migration(projectPath, { gitCheck: false, install: false, quiet: true });
5293
5684
  } catch (e) {
5294
- const relative = path25.relative(process13.cwd(), projectPath) || ".";
5685
+ const relative = path27.relative(process13.cwd(), projectPath) || ".";
5295
5686
  throw new Error(
5296
5687
  `Could not migrate template ${templateName2} to SvelteKit 3: ${e.message}
5297
5688
 
@@ -5302,11 +5693,11 @@ The project is in ${projectPath}. Finish the migration by hand with
5302
5693
  );
5303
5694
  }
5304
5695
  const tasks = result.tasks;
5305
- const tasksFile = path25.join(projectPath, MIGRATION_TASKS_FILE);
5306
- if (fs27.existsSync(tasksFile) && !tasks?.filesToReview && result.followUps.length === 0) {
5307
- fs27.rmSync(tasksFile);
5696
+ const tasksFile = path27.join(projectPath, MIGRATION_TASKS_FILE);
5697
+ if (fs29.existsSync(tasksFile) && !tasks?.filesToReview && result.followUps.length === 0) {
5698
+ fs29.rmSync(tasksFile);
5308
5699
  }
5309
- const left = fs27.existsSync(tasksFile);
5700
+ const left = fs29.existsSync(tasksFile);
5310
5701
  p10.log.success(
5311
5702
  `Migrated to SvelteKit 3${left ? `; ${MIGRATION_TASKS_FILE} lists what to check by hand` : ""}.`
5312
5703
  );
@@ -5400,7 +5791,7 @@ ${FREE_CMS_HINT}.`, "CMS");
5400
5791
  }
5401
5792
  function hasScript(directory, name) {
5402
5793
  try {
5403
- const pkg = JSON.parse(fs27.readFileSync(path25.join(directory, "package.json"), "utf8"));
5794
+ const pkg = JSON.parse(fs29.readFileSync(path27.join(directory, "package.json"), "utf8"));
5404
5795
  return typeof pkg.scripts?.[name] === "string";
5405
5796
  } catch {
5406
5797
  return false;
@@ -5415,7 +5806,7 @@ import { Command as Command4 } from "commander";
5415
5806
  import * as p16 from "@clack/prompts";
5416
5807
 
5417
5808
  // src/lib/pattern-runner.ts
5418
- import path26 from "node:path";
5809
+ import path28 from "node:path";
5419
5810
  import * as p11 from "@clack/prompts";
5420
5811
  import { bySlug as bySlug2 } from "@velastack/patterns";
5421
5812
 
@@ -5434,7 +5825,7 @@ Then run this again.`
5434
5825
 
5435
5826
  // src/lib/pattern-runner.ts
5436
5827
  function toRelative(root, filePath) {
5437
- return path26.isAbsolute(filePath) ? path26.relative(root, filePath) : filePath;
5828
+ return path28.isAbsolute(filePath) ? path28.relative(root, filePath) : filePath;
5438
5829
  }
5439
5830
  var isSuccess = (f) => (f.status ?? "success") === "success";
5440
5831
  async function runPattern(slug2, argv, input, report4, after) {
@@ -5516,10 +5907,10 @@ async function runPattern(slug2, argv, input, report4, after) {
5516
5907
  }
5517
5908
 
5518
5909
  // src/lib/form-ui.ts
5519
- import path27 from "node:path";
5910
+ import path29 from "node:path";
5520
5911
  var UIS = ["shadcn", "plain"];
5521
5912
  function detectFormInput(root) {
5522
- const pkg = readPackageJson(path27.join(root, "package.json"));
5913
+ const pkg = readPackageJson(path29.join(root, "package.json"));
5523
5914
  const hasDep = (name) => Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
5524
5915
  return {
5525
5916
  flash: hasDep("sveltekit-flash-message"),
@@ -5541,8 +5932,8 @@ function resolveFormInput(root, detectedUi, requested) {
5541
5932
  }
5542
5933
 
5543
5934
  // src/lib/ai-flow.ts
5544
- import fs28 from "node:fs";
5545
- import path28 from "node:path";
5935
+ import fs30 from "node:fs";
5936
+ import path30 from "node:path";
5546
5937
  import * as p15 from "@clack/prompts";
5547
5938
  import pc4 from "picocolors";
5548
5939
 
@@ -5817,15 +6208,15 @@ function specToArgv(spec) {
5817
6208
  return collectionSpecToArgv(spec);
5818
6209
  }
5819
6210
  function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
5820
- const dir = path28.join(
6211
+ const dir = path30.join(
5821
6212
  workspaceRootDir,
5822
6213
  hasBackend(workspaceRootDir) ? DATA_DIR : ".vela",
5823
6214
  "ai-form-layouts"
5824
6215
  );
5825
- fs28.mkdirSync(dir, { recursive: true });
5826
- const file = path28.join(dir, `${modelName}.json`);
5827
- fs28.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
5828
- return path28.relative(workspaceRootDir, file);
6216
+ fs30.mkdirSync(dir, { recursive: true });
6217
+ const file = path30.join(dir, `${modelName}.json`);
6218
+ fs30.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
6219
+ return path30.relative(workspaceRootDir, file);
5829
6220
  }
5830
6221
 
5831
6222
  // src/commands/generate/form.ts
@@ -6547,8 +6938,8 @@ import * as p21 from "@clack/prompts";
6547
6938
  import pc6 from "picocolors";
6548
6939
 
6549
6940
  // src/lib/deploy-config.ts
6550
- import fs29 from "node:fs";
6551
- import path29 from "node:path";
6941
+ import fs31 from "node:fs";
6942
+ import path31 from "node:path";
6552
6943
  import crypto from "node:crypto";
6553
6944
  import { pathToFileURL } from "node:url";
6554
6945
  var CONFIG_BASENAMES = [
@@ -6559,8 +6950,8 @@ var CONFIG_BASENAMES = [
6559
6950
  ];
6560
6951
  function findConfigFile(workspaceRootDir) {
6561
6952
  for (const name of CONFIG_BASENAMES) {
6562
- const file = path29.join(workspaceRootDir, name);
6563
- if (fs29.existsSync(file)) return file;
6953
+ const file = path31.join(workspaceRootDir, name);
6954
+ if (fs31.existsSync(file)) return file;
6564
6955
  }
6565
6956
  return null;
6566
6957
  }
@@ -6568,49 +6959,49 @@ async function loadDeployConfig(workspaceRootDir) {
6568
6959
  const file = findConfigFile(workspaceRootDir);
6569
6960
  if (!file) return {};
6570
6961
  if (file.endsWith(".json")) {
6571
- return JSON.parse(fs29.readFileSync(file, "utf8"));
6962
+ return JSON.parse(fs31.readFileSync(file, "utf8"));
6572
6963
  }
6573
6964
  const url = file.endsWith(".ts") ? await transpileToTemp(file) : pathToFileURL(file).href;
6574
6965
  try {
6575
6966
  const mod = await import(url);
6576
6967
  const config = mod.default;
6577
6968
  if (!config || typeof config !== "object") {
6578
- throw new Error(`${path29.basename(file)} must export a config object as its default export.`);
6969
+ throw new Error(`${path31.basename(file)} must export a config object as its default export.`);
6579
6970
  }
6580
6971
  return config;
6581
6972
  } finally {
6582
- if (url !== pathToFileURL(file).href) fs29.rmSync(new URL(url), { force: true });
6973
+ if (url !== pathToFileURL(file).href) fs31.rmSync(new URL(url), { force: true });
6583
6974
  }
6584
6975
  }
6585
6976
  async function transpileToTemp(file) {
6586
6977
  const { ts: ts2 } = await import("ts-morph");
6587
- const source = fs29.readFileSync(file, "utf8");
6978
+ const source = fs31.readFileSync(file, "utf8");
6588
6979
  const { outputText } = ts2.transpileModule(source, {
6589
6980
  compilerOptions: { module: ts2.ModuleKind.ESNext, target: ts2.ScriptTarget.ES2022 }
6590
6981
  });
6591
- const temp = path29.join(
6592
- path29.dirname(file),
6982
+ const temp = path31.join(
6983
+ path31.dirname(file),
6593
6984
  `.velastack.config.${crypto.randomBytes(4).toString("hex")}.mjs`
6594
6985
  );
6595
- fs29.writeFileSync(temp, outputText);
6986
+ fs31.writeFileSync(temp, outputText);
6596
6987
  return pathToFileURL(temp).href;
6597
6988
  }
6598
6989
  function projectFilePath(workspaceRootDir) {
6599
- return path29.join(workspaceRootDir, ".vela", "project.json");
6990
+ return path31.join(workspaceRootDir, ".vela", "project.json");
6600
6991
  }
6601
6992
  function readProjectFile(workspaceRootDir) {
6602
6993
  const file = projectFilePath(workspaceRootDir);
6603
- if (!fs29.existsSync(file)) return {};
6994
+ if (!fs31.existsSync(file)) return {};
6604
6995
  try {
6605
- return JSON.parse(fs29.readFileSync(file, "utf8"));
6996
+ return JSON.parse(fs31.readFileSync(file, "utf8"));
6606
6997
  } catch {
6607
6998
  return {};
6608
6999
  }
6609
7000
  }
6610
7001
  function writeProjectFile(workspaceRootDir, data) {
6611
7002
  const file = projectFilePath(workspaceRootDir);
6612
- fs29.mkdirSync(path29.dirname(file), { recursive: true });
6613
- fs29.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
7003
+ fs31.mkdirSync(path31.dirname(file), { recursive: true });
7004
+ fs31.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
6614
7005
  }
6615
7006
  function resolveAppIdentity(workspaceRootDir, config = {}) {
6616
7007
  const project = readProjectFile(workspaceRootDir);
@@ -6635,11 +7026,11 @@ function readAppIdentity(workspaceRootDir, config = {}) {
6635
7026
  }
6636
7027
  function defaultProjectName(workspaceRootDir) {
6637
7028
  try {
6638
- const pkg = readPackageJson(path29.join(workspaceRootDir, "package.json"));
7029
+ const pkg = readPackageJson(path31.join(workspaceRootDir, "package.json"));
6639
7030
  if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
6640
7031
  } catch {
6641
7032
  }
6642
- return path29.basename(workspaceRootDir);
7033
+ return path31.basename(workspaceRootDir);
6643
7034
  }
6644
7035
  function slug(value) {
6645
7036
  return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
@@ -6710,15 +7101,15 @@ function randomSuffix() {
6710
7101
  }
6711
7102
 
6712
7103
  // src/lib/artifact.ts
6713
- import fs31 from "node:fs";
6714
- import path31 from "node:path";
6715
- import { detect as detect5 } from "package-manager-detector";
7104
+ import fs33 from "node:fs";
7105
+ import path33 from "node:path";
7106
+ import { detect as detect6 } from "package-manager-detector";
6716
7107
  import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
6717
7108
 
6718
7109
  // src/lib/ssh.ts
6719
- import fs30 from "node:fs";
7110
+ import fs32 from "node:fs";
6720
7111
  import os4 from "node:os";
6721
- import path30 from "node:path";
7112
+ import path32 from "node:path";
6722
7113
  import crypto3 from "node:crypto";
6723
7114
  import process16 from "node:process";
6724
7115
  import { spawn as spawn3 } from "node:child_process";
@@ -6761,9 +7152,9 @@ var SshSession = class {
6761
7152
  }
6762
7153
  async open() {
6763
7154
  if (this.controlPath) return;
6764
- const dir = path30.join(os4.tmpdir(), "vela-ssh");
6765
- fs30.mkdirSync(dir, { recursive: true, mode: 448 });
6766
- const socket = path30.join(dir, `${crypto3.randomBytes(6).toString("hex")}.sock`);
7155
+ const dir = path32.join(os4.tmpdir(), "vela-ssh");
7156
+ fs32.mkdirSync(dir, { recursive: true, mode: 448 });
7157
+ const socket = path32.join(dir, `${crypto3.randomBytes(6).toString("hex")}.sock`);
6767
7158
  this.controlPath = socket;
6768
7159
  const args = [
6769
7160
  ...this.sshArgs(),
@@ -7034,7 +7425,7 @@ async function runBuild(cwd, buildCommand, env2) {
7034
7425
  throw new BuildError(`\`${buildCommand}\` exited ${result2.exitCode}.`);
7035
7426
  return;
7036
7427
  }
7037
- const pm = (await detect5({ cwd }))?.name ?? "npm";
7428
+ const pm = (await detect6({ cwd }))?.name ?? "npm";
7038
7429
  const resolved = resolveCommand4(pm, "run", ["build"]);
7039
7430
  if (!resolved) throw new BuildError(`Could not work out how to run a build with ${pm}.`);
7040
7431
  const result = await spawnCapture(resolved.command, resolved.args, {
@@ -7053,11 +7444,11 @@ function collectArtifact(cwd, config = {}) {
7053
7444
  const outputDir = config.outputDir ?? DEFAULT_OUTPUT_DIR;
7054
7445
  const entries = [];
7055
7446
  const add2 = (rel, remoteDir = "") => {
7056
- const localPath = path31.join(cwd, rel);
7057
- if (fs31.existsSync(localPath)) entries.push({ localPath, remoteDir });
7447
+ const localPath = path33.join(cwd, rel);
7448
+ if (fs33.existsSync(localPath)) entries.push({ localPath, remoteDir });
7058
7449
  };
7059
- const buildPath = path31.join(cwd, outputDir);
7060
- if (!fs31.existsSync(path31.join(buildPath, "index.js"))) {
7450
+ const buildPath = path33.join(cwd, outputDir);
7451
+ if (!fs33.existsSync(path33.join(buildPath, "index.js"))) {
7061
7452
  throw new BuildError(
7062
7453
  `No ${outputDir}/index.js to deploy.
7063
7454
 
@@ -7071,19 +7462,19 @@ matches where it writes), then deploy again.`
7071
7462
  for (const lockfile of [NPM_LOCKFILE, ...FOREIGN_LOCKFILES]) add2(lockfile);
7072
7463
  add2(".npmrc");
7073
7464
  add2(MIGRATIONS_DIR);
7074
- const hooks = path31.join(cwd, DATA_DIR, "hooks");
7075
- if (fs31.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
7465
+ const hooks = path33.join(cwd, DATA_DIR, "hooks");
7466
+ if (fs33.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
7076
7467
  for (const extra of config.include ?? []) add2(extra);
7077
7468
  return entries;
7078
7469
  }
7079
7470
  var NPM_LOCKFILE = "package-lock.json";
7080
7471
  var FOREIGN_LOCKFILES = ["pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb"];
7081
7472
  function hasLockfile(cwd) {
7082
- return fs31.existsSync(path31.join(cwd, NPM_LOCKFILE));
7473
+ return fs33.existsSync(path33.join(cwd, NPM_LOCKFILE));
7083
7474
  }
7084
7475
  function foreignLockfile(cwd) {
7085
7476
  if (hasLockfile(cwd)) return void 0;
7086
- return FOREIGN_LOCKFILES.find((name) => fs31.existsSync(path31.join(cwd, name)));
7477
+ return FOREIGN_LOCKFILES.find((name) => fs33.existsSync(path33.join(cwd, name)));
7087
7478
  }
7088
7479
  async function gitSha(cwd) {
7089
7480
  const result = await spawnCapture("git", ["rev-parse", "HEAD"], { cwd });
@@ -7122,8 +7513,8 @@ function sshOptionsFrom(options) {
7122
7513
 
7123
7514
  // src/lib/remote.ts
7124
7515
  import crypto4 from "node:crypto";
7125
- import fs32 from "node:fs";
7126
- import path32 from "node:path";
7516
+ import fs34 from "node:fs";
7517
+ import path34 from "node:path";
7127
7518
  import process17 from "node:process";
7128
7519
  var VELA_ROOT = "/var/lib/vela";
7129
7520
  var VELA_ETC = "/etc/vela";
@@ -7136,19 +7527,19 @@ function instanceHasBackend(state) {
7136
7527
  return state.backend ?? Boolean(state.pbPort);
7137
7528
  }
7138
7529
  function serverTemplatesDir() {
7139
- return path32.join(templatesDir(), "server");
7530
+ return path34.join(templatesDir(), "server");
7140
7531
  }
7141
7532
  var DIGEST_LENGTH = 12;
7142
7533
  function serverScriptsDigest(dir = serverTemplatesDir()) {
7143
7534
  const hash = crypto4.createHash("sha256");
7144
7535
  for (const file of listFiles(dir).sort()) {
7145
- hash.update(file).update("\0").update(fs32.readFileSync(path32.join(dir, file))).update("\0");
7536
+ hash.update(file).update("\0").update(fs34.readFileSync(path34.join(dir, file))).update("\0");
7146
7537
  }
7147
7538
  return hash.digest("hex").slice(0, DIGEST_LENGTH);
7148
7539
  }
7149
7540
  function listFiles(root, prefix = "") {
7150
7541
  const files = [];
7151
- for (const entry of fs32.readdirSync(path32.join(root, prefix), { withFileTypes: true })) {
7542
+ for (const entry of fs34.readdirSync(path34.join(root, prefix), { withFileTypes: true })) {
7152
7543
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
7153
7544
  if (entry.isDirectory()) files.push(...listFiles(root, rel));
7154
7545
  else if (entry.isFile()) files.push(rel);
@@ -7267,7 +7658,7 @@ var remotePaths = {
7267
7658
  };
7268
7659
 
7269
7660
  // src/lib/remote-env.ts
7270
- import fs33 from "node:fs";
7661
+ import fs35 from "node:fs";
7271
7662
  import dotenv from "dotenv";
7272
7663
  var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
7273
7664
  function isValidKey(key) {
@@ -7315,7 +7706,7 @@ function quote(value) {
7315
7706
  return `"${escaped}"`;
7316
7707
  }
7317
7708
  function readLocalEnvFile(file) {
7318
- const parsed = dotenv.parse(fs33.readFileSync(file));
7709
+ const parsed = dotenv.parse(fs35.readFileSync(file));
7319
7710
  const result = {};
7320
7711
  for (const [key, value] of Object.entries(parsed)) {
7321
7712
  if (isValidKey(key)) result[key] = value;
@@ -7641,17 +8032,17 @@ function envFilePath(workspaceRootDir) {
7641
8032
  import pc8 from "picocolors";
7642
8033
 
7643
8034
  // src/lib/local-env.ts
7644
- import fs34 from "node:fs";
8035
+ import fs36 from "node:fs";
7645
8036
  import * as p22 from "@clack/prompts";
7646
8037
  import pc7 from "picocolors";
7647
8038
  function readLocalEnv(envFile) {
7648
- if (!fs34.existsSync(envFile)) return {};
8039
+ if (!fs36.existsSync(envFile)) return {};
7649
8040
  return readLocalEnvFile(envFile);
7650
8041
  }
7651
8042
  function editLocalEnv(envFile, edit) {
7652
- const before = fs34.existsSync(envFile) ? fs34.readFileSync(envFile, "utf8") : "";
8043
+ const before = fs36.existsSync(envFile) ? fs36.readFileSync(envFile, "utf8") : "";
7653
8044
  const after = edit(before);
7654
- if (after !== before) fs34.writeFileSync(envFile, after);
8045
+ if (after !== before) fs36.writeFileSync(envFile, after);
7655
8046
  }
7656
8047
  function setLocalEnv(envFile, key, value) {
7657
8048
  editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
@@ -7788,8 +8179,8 @@ Set ${pc8.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc8.cyan("POCKETBASE_SUPERUS
7788
8179
  }
7789
8180
 
7790
8181
  // src/lib/s3-settings.ts
7791
- import fs35 from "node:fs";
7792
- import path33 from "node:path";
8182
+ import fs37 from "node:fs";
8183
+ import path35 from "node:path";
7793
8184
  var VIRTUAL_HOSTED = [/\.amazonaws\.com$/i, /\.r2\.cloudflarestorage\.com$/i];
7794
8185
  function defaultForcePathStyle(endpoint) {
7795
8186
  let host;
@@ -7827,18 +8218,18 @@ async function hasLocalUploads(session, instance, workspaceRootDir) {
7827
8218
  });
7828
8219
  return result.stdout.trim().length > 0;
7829
8220
  }
7830
- return hasFile(path33.join(workspaceRootDir, DATA_DIR, "storage"));
8221
+ return hasFile(path35.join(workspaceRootDir, DATA_DIR, "storage"));
7831
8222
  }
7832
8223
  function hasFile(dir) {
7833
8224
  let entries;
7834
8225
  try {
7835
- entries = fs35.readdirSync(dir, { withFileTypes: true });
8226
+ entries = fs37.readdirSync(dir, { withFileTypes: true });
7836
8227
  } catch {
7837
8228
  return false;
7838
8229
  }
7839
8230
  for (const entry of entries) {
7840
8231
  if (entry.isFile()) return true;
7841
- if (entry.isDirectory() && hasFile(path33.join(dir, entry.name))) return true;
8232
+ if (entry.isDirectory() && hasFile(path35.join(dir, entry.name))) return true;
7842
8233
  }
7843
8234
  return false;
7844
8235
  }
@@ -7893,367 +8284,124 @@ async function guardExistingUploads(ctx, options) {
7893
8284
  if (options.force) return;
7894
8285
  if (!await hasLocalUploads(ctx.session, ctx.instance, ctx.workspaceRootDir)) return;
7895
8286
  const from = ctx.session ? `${remotePaths.storage(ctx.instance)}/` : "data/storage/";
7896
- throw new Error(
7897
- `${ctx.targetName} already has uploaded files on disk.
7898
-
7899
- Turning on S3 changes where PocketBase reads from; it does not move anything,
7900
- so every one of those files would stop resolving.
7901
-
7902
- The layout is the same on both sides, so copying them across is a plain sync:
7903
-
7904
- ${pc9.cyan(`rclone copy ${from} <remote>:<bucket>/`)}
7905
-
7906
- Do that first, then re-run with ${pc9.cyan("--force")}.`
7907
- );
7908
- }
7909
- async function promptConfig(options, existing) {
7910
- const endpoint = options.endpoint ?? await text9("S3 endpoint URL", existing.endpoint || "https://s3.amazonaws.com");
7911
- const bucket = options.bucket ?? await text9("S3 bucket name", existing.bucket);
7912
- const region = options.region ?? await text9("S3 region", existing.region || "us-east-1");
7913
- const accessKey = options.accessKey ?? await text9("S3 access key", existing.accessKey);
7914
- const secret = options.secret ?? process19.env.VELA_S3_SECRET ?? await password6("S3 secret key");
7915
- const forcePathStyle = options.forcePathStyle ?? await confirm4(
7916
- "Address the bucket in the path? (MinIO, Ceph and most self-hosted gateways need this)",
7917
- defaultForcePathStyle(endpoint)
7918
- );
7919
- return { endpoint, bucket, region, accessKey, secret, forcePathStyle };
7920
- }
7921
- async function text9(message, initialValue = "") {
7922
- const value = await p23.text({
7923
- message,
7924
- initialValue,
7925
- validate: (input) => input?.trim() ? void 0 : `${message} is required`
7926
- });
7927
- if (p23.isCancel(value)) {
7928
- p23.cancel("Operation cancelled.");
7929
- process19.exit(0);
7930
- }
7931
- return value.trim();
7932
- }
7933
- async function password6(message) {
7934
- const value = await p23.password({
7935
- message,
7936
- validate: (input) => input ? void 0 : `${message} is required`
7937
- });
7938
- if (p23.isCancel(value)) {
7939
- p23.cancel("Operation cancelled.");
7940
- process19.exit(0);
7941
- }
7942
- return value;
7943
- }
7944
- async function confirm4(message, initialValue) {
7945
- const value = await p23.confirm({ message, initialValue });
7946
- if (p23.isCancel(value)) {
7947
- p23.cancel("Operation cancelled.");
7948
- process19.exit(0);
7949
- }
7950
- return value;
7951
- }
7952
-
7953
- // src/commands/enable/smtp.ts
7954
- import process20 from "node:process";
7955
- import { Command as Command23 } from "commander";
7956
- import * as p24 from "@clack/prompts";
7957
- var smtp = new Command23("smtp").description("configure SMTP for transactional email").configureHelp(helpConfig).action(
7958
- () => runCommand(async () => {
7959
- const { workspaceRootDir } = await getWorkspace();
7960
- const config = await p24.group(
7961
- {
7962
- host: () => p24.text({
7963
- message: "SMTP host",
7964
- placeholder: "smtp.example.com",
7965
- validate: (v12) => v12 ? void 0 : "Host is required"
7966
- }),
7967
- port: () => p24.text({
7968
- message: "SMTP port",
7969
- initialValue: "587",
7970
- validate: (v12) => {
7971
- if (!v12) return "Port is required";
7972
- const n = Number(v12);
7973
- if (!Number.isInteger(n) || n <= 0 || n > 65535) return "Invalid port";
7974
- return void 0;
7975
- }
7976
- }),
7977
- username: () => p24.text({ message: "SMTP username" }),
7978
- password: () => p24.password({ message: "SMTP password" })
7979
- },
7980
- {
7981
- onCancel: () => {
7982
- p24.cancel("Operation cancelled.");
7983
- process20.exit(0);
7984
- }
7985
- }
7986
- );
7987
- await withPocketbase(workspaceRootDir, async (pb) => {
7988
- await pb.settings.update({
7989
- smtp: {
7990
- enabled: true,
7991
- host: config.host,
7992
- port: parseInt(config.port, 10),
7993
- username: config.username ?? "",
7994
- password: config.password ?? ""
7995
- }
7996
- });
7997
- });
7998
- reportResult({
7999
- summary: "Enabled SMTP for transactional email.",
8000
- nextSteps: [
8001
- "PocketBase will now send auth/verification email via your SMTP server.",
8002
- "Send a test email from the PocketBase admin UI (Settings \u2192 Mail settings).",
8003
- "Run `vela disable smtp` to revert to the built-in fallback sender."
8004
- ]
8005
- });
8006
- }, "Failed to enable SMTP.")
8007
- );
8008
-
8009
- // src/commands/enable/cms.ts
8010
- import process21 from "node:process";
8011
- import { Command as Command24 } from "commander";
8012
- import * as p25 from "@clack/prompts";
8013
- import pc10 from "picocolors";
8014
-
8015
- // src/lib/adapter.ts
8016
- import fs36 from "node:fs";
8017
- import path34 from "node:path";
8018
- import {
8019
- SyntaxKind as SyntaxKind4
8020
- } from "ts-morph";
8021
- import { detect as detect6 } from "package-manager-detector";
8022
- var ADAPTER_NODE2 = "@sveltejs/adapter-node";
8023
- var ADAPTER_AUTO = "@sveltejs/adapter-auto";
8024
- var ADAPTER_STATIC2 = "@sveltejs/adapter-static";
8025
- var ADAPTER_NODE_RANGE = "^6.0.0";
8026
- var ADAPTER_SNIPPET = `import adapter from '${ADAPTER_NODE2}';
8027
-
8028
- // ...
8029
- adapter: adapter()`;
8030
- var AdapterError = class extends Error {
8031
- constructor(message, snippet = ADAPTER_SNIPPET) {
8032
- super(message);
8033
- this.snippet = snippet;
8034
- this.name = "AdapterError";
8035
- }
8036
- snippet;
8037
- };
8038
- function resolveKitTarget(root) {
8039
- const svelteConfig = findSvelteConfig(root);
8040
- if (svelteConfig) {
8041
- throw new AdapterError(
8042
- `${path34.basename(svelteConfig)} found: this looks like a SvelteKit 2 project, and
8043
- SvelteKit 3 reads its config only from sveltekit({...}) in vite.config.
8044
-
8045
- Migrate it first:`,
8046
- KIT3_MIGRATE_COMMAND
8047
- );
8048
- }
8049
- const vite = inspectViteSveltekit(root);
8050
- if (vite?.inlineArg) {
8051
- return {
8052
- sourceFile: vite.sourceFile,
8053
- filePath: vite.filePath,
8054
- kit: vite.inlineArg,
8055
- created: false,
8056
- originalText: vite.sourceFile.getFullText()
8057
- };
8058
- }
8059
- if (vite?.sveltekitCall) {
8060
- const name = path34.basename(vite.filePath);
8061
- if (vite.nonObjectArg) {
8062
- throw new AdapterError(`${name} passes sveltekit() something other than an object literal.`);
8063
- }
8064
- const originalText = vite.sourceFile.getFullText();
8065
- const kit = createSveltekitArg(vite);
8066
- if (!kit)
8067
- throw new AdapterError(`${name} has a sveltekit() call vela cannot add an argument to.`);
8068
- return {
8069
- sourceFile: vite.sourceFile,
8070
- filePath: vite.filePath,
8071
- kit,
8072
- created: true,
8073
- originalText
8074
- };
8075
- }
8076
- throw new AdapterError(`No vite.config with a sveltekit() plugin found in ${root}.`);
8077
- }
8078
- function classify(specifier) {
8079
- if (specifier === ADAPTER_NODE2) return "node";
8080
- if (specifier === ADAPTER_AUTO) return "auto";
8081
- if (specifier === ADAPTER_STATIC2) return "static";
8082
- return "other";
8083
- }
8084
- function importOf(sourceFile, identifier) {
8085
- return sourceFile.getImportDeclarations().find((decl) => decl.getDefaultImport()?.getText() === identifier);
8086
- }
8087
- function inspectAdapter(target) {
8088
- const base2 = { file: target.filePath };
8089
- const prop = target.kit.getProperty("adapter");
8090
- if (!prop) return { info: { ...base2, kind: "none" } };
8091
- if (prop.getKind() !== SyntaxKind4.PropertyAssignment) {
8092
- return { info: { ...base2, kind: "other" } };
8093
- }
8094
- const init = prop.asKindOrThrow(SyntaxKind4.PropertyAssignment).getInitializer();
8095
- if (!init || init.getKind() !== SyntaxKind4.CallExpression) {
8096
- return { info: { ...base2, kind: "other" } };
8097
- }
8098
- const callee = init.asKindOrThrow(SyntaxKind4.CallExpression).getExpression();
8099
- if (callee.getKind() !== SyntaxKind4.Identifier) {
8100
- return { info: { ...base2, kind: "other" } };
8101
- }
8102
- const importDecl = importOf(target.sourceFile, callee.getText());
8103
- if (!importDecl) return { info: { ...base2, kind: "other" } };
8104
- const specifier = importDecl.getModuleSpecifierValue();
8105
- return { info: { ...base2, kind: classify(specifier), specifier }, importDecl };
8106
- }
8107
- function detectAdapter(root) {
8108
- return inspectAdapter(resolveKitTarget(root)).info;
8109
- }
8110
- async function ensureNodeAdapter(root, { install: install2 = true } = {}) {
8111
- const target = resolveKitTarget(root);
8112
- const { info, importDecl } = inspectAdapter(target);
8113
- const name = path34.basename(target.filePath);
8114
- const outcome = {
8115
- previous: info.kind,
8116
- removedDeps: [],
8117
- packageJsonChanged: false
8118
- };
8119
- switch (info.kind) {
8120
- case "node":
8121
- break;
8122
- case "static":
8123
- throw new AdapterError(
8124
- `This project builds a static site with ${ADAPTER_STATIC2} (${name}).
8125
-
8126
- vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE2}. Switch
8127
- the adapter to deploy it here, or host the static output elsewhere.`
8128
- );
8129
- case "other":
8130
- throw new AdapterError(
8131
- `This project's adapter${info.specifier ? ` (${info.specifier})` : ""} in ${name} is not one
8132
- vela will change for you.
8133
-
8134
- vela deploy runs the app as a Node server, which needs ${ADAPTER_NODE2}:`
8135
- );
8136
- case "auto":
8137
- switchImport(target, importDecl);
8138
- outcome.configFile = name;
8139
- break;
8140
- case "none":
8141
- addAdapter(target);
8142
- outcome.configFile = name;
8143
- break;
8144
- }
8145
- if (outcome.configFile) saveTarget(target);
8146
- const pkgPath = path34.join(root, "package.json");
8147
- if (fs36.existsSync(pkgPath)) {
8148
- const pkg = readPackageJson(pkgPath);
8149
- const { changed, removed } = adoptNodeAdapter(pkg);
8150
- if (changed) {
8151
- writePackageJson(pkgPath, pkg);
8152
- outcome.packageJsonChanged = true;
8153
- outcome.removedDeps = removed;
8154
- }
8155
- }
8156
- if (outcome.packageJsonChanged && install2) {
8157
- outcome.installedWith = await installAdapterDependencies(root);
8158
- }
8159
- return outcome;
8160
- }
8161
- async function installAdapterDependencies(root) {
8162
- const agent = await packageManager(root);
8163
- if (!isInstalled(agent)) {
8164
- throw new AdapterError(
8165
- `${agent} is not installed, so ${ADAPTER_NODE2} couldn't be installed.
8166
-
8167
- The config and package.json are already updated: install ${agent}, run \`${agent} install\`, then deploy again.`,
8168
- ""
8169
- );
8170
- }
8171
- const ok = await installDependencies(agent, root, { exitOnFailure: false });
8172
- if (!ok) {
8173
- throw new AdapterError(
8174
- `Installing ${ADAPTER_NODE2} with ${agent} failed.
8175
-
8176
- The config and package.json are already updated: run \`${agent} install\`, then deploy again.`,
8177
- ""
8178
- );
8179
- }
8180
- return agent;
8181
- }
8182
- function switchImport(target, importDecl) {
8183
- importDecl.setModuleSpecifier(ADAPTER_NODE2);
8184
- const prop = target.kit.getPropertyOrThrow("adapter").asKindOrThrow(SyntaxKind4.PropertyAssignment);
8185
- const call = prop.getInitializerIfKindOrThrow(SyntaxKind4.CallExpression);
8186
- for (let i = call.getArguments().length - 1; i >= 0; i--) call.removeArgument(i);
8187
- dropAdapterAutoComments(target);
8188
- }
8189
- var ADAPTER_AUTO_COMMENT = /adapter-auto|svelte\.dev\/docs\/kit\/adapters|switch out the adapter/;
8190
- function dropAdapterAutoComments(target) {
8191
- const prop = target.kit.getPropertyOrThrow("adapter");
8192
- const ranges = prop.getLeadingCommentRanges();
8193
- if (ranges.length === 0 || !ranges.every((r) => ADAPTER_AUTO_COMMENT.test(r.getText()))) return;
8194
- const fullStart = prop.getFullStart();
8195
- const start = prop.getStart();
8196
- const trivia = target.sourceFile.getFullText().slice(fullStart, start);
8197
- const lastNewline = trivia.lastIndexOf("\n");
8198
- if (lastNewline === -1) return;
8199
- const indent = trivia.slice(lastNewline + 1);
8200
- target.sourceFile.replaceText([fullStart, start], `
8201
- ${indent}`);
8202
- }
8203
- function addAdapter(target) {
8204
- const taken = importOf(target.sourceFile, "adapter") ?? target.sourceFile.getVariableDeclaration("adapter");
8205
- if (taken) {
8206
- throw new AdapterError(
8207
- `${path34.basename(target.filePath)} already binds the name \`adapter\` to something that is not the SvelteKit adapter.`
8208
- );
8209
- }
8210
- target.sourceFile.addImportDeclaration({
8211
- defaultImport: "adapter",
8212
- moduleSpecifier: ADAPTER_NODE2
8213
- });
8214
- target.kit.addPropertyAssignment({ name: "adapter", initializer: "adapter()" });
8287
+ throw new Error(
8288
+ `${ctx.targetName} already has uploaded files on disk.
8289
+
8290
+ Turning on S3 changes where PocketBase reads from; it does not move anything,
8291
+ so every one of those files would stop resolving.
8292
+
8293
+ The layout is the same on both sides, so copying them across is a plain sync:
8294
+
8295
+ ${pc9.cyan(`rclone copy ${from} <remote>:<bucket>/`)}
8296
+
8297
+ Do that first, then re-run with ${pc9.cyan("--force")}.`
8298
+ );
8215
8299
  }
8216
- function saveTarget(target) {
8217
- if (target.created) formatLikeSource(target.sourceFile);
8218
- if (target.sourceFile.getFullText() === target.originalText) return;
8219
- target.sourceFile.saveSync();
8300
+ async function promptConfig(options, existing) {
8301
+ const endpoint = options.endpoint ?? await text9("S3 endpoint URL", existing.endpoint || "https://s3.amazonaws.com");
8302
+ const bucket = options.bucket ?? await text9("S3 bucket name", existing.bucket);
8303
+ const region = options.region ?? await text9("S3 region", existing.region || "us-east-1");
8304
+ const accessKey = options.accessKey ?? await text9("S3 access key", existing.accessKey);
8305
+ const secret = options.secret ?? process19.env.VELA_S3_SECRET ?? await password6("S3 secret key");
8306
+ const forcePathStyle = options.forcePathStyle ?? await confirm4(
8307
+ "Address the bucket in the path? (MinIO, Ceph and most self-hosted gateways need this)",
8308
+ defaultForcePathStyle(endpoint)
8309
+ );
8310
+ return { endpoint, bucket, region, accessKey, secret, forcePathStyle };
8220
8311
  }
8221
- function adoptNodeAdapter(pkg) {
8222
- const removed = [];
8223
- let changed = false;
8224
- for (const kind of ["dependencies", "devDependencies"]) {
8225
- const deps = pkg[kind];
8226
- if (deps && ADAPTER_AUTO in deps) {
8227
- delete deps[ADAPTER_AUTO];
8228
- removed.push(ADAPTER_AUTO);
8229
- changed = true;
8230
- }
8231
- }
8232
- if (!pkg.dependencies?.[ADAPTER_NODE2] && !pkg.devDependencies?.[ADAPTER_NODE2]) {
8233
- pkg.devDependencies = sortKeys({ ...pkg.devDependencies, [ADAPTER_NODE2]: ADAPTER_NODE_RANGE });
8234
- changed = true;
8312
+ async function text9(message, initialValue = "") {
8313
+ const value = await p23.text({
8314
+ message,
8315
+ initialValue,
8316
+ validate: (input) => input?.trim() ? void 0 : `${message} is required`
8317
+ });
8318
+ if (p23.isCancel(value)) {
8319
+ p23.cancel("Operation cancelled.");
8320
+ process19.exit(0);
8235
8321
  }
8236
- return { changed, removed: [...new Set(removed)] };
8322
+ return value.trim();
8237
8323
  }
8238
- function lockfileFor(agent) {
8239
- switch (agent) {
8240
- case "pnpm":
8241
- return "pnpm-lock.yaml";
8242
- case "yarn":
8243
- return "yarn.lock";
8244
- case "bun":
8245
- return "bun.lock";
8246
- case "deno":
8247
- return "deno.lock";
8248
- default:
8249
- return "package-lock.json";
8324
+ async function password6(message) {
8325
+ const value = await p23.password({
8326
+ message,
8327
+ validate: (input) => input ? void 0 : `${message} is required`
8328
+ });
8329
+ if (p23.isCancel(value)) {
8330
+ p23.cancel("Operation cancelled.");
8331
+ process19.exit(0);
8250
8332
  }
8333
+ return value;
8251
8334
  }
8252
- async function packageManager(root) {
8253
- return (await detect6({ cwd: root }))?.name ?? getUserAgent() ?? "npm";
8335
+ async function confirm4(message, initialValue) {
8336
+ const value = await p23.confirm({ message, initialValue });
8337
+ if (p23.isCancel(value)) {
8338
+ p23.cancel("Operation cancelled.");
8339
+ process19.exit(0);
8340
+ }
8341
+ return value;
8254
8342
  }
8255
8343
 
8344
+ // src/commands/enable/smtp.ts
8345
+ import process20 from "node:process";
8346
+ import { Command as Command23 } from "commander";
8347
+ import * as p24 from "@clack/prompts";
8348
+ var smtp = new Command23("smtp").description("configure SMTP for transactional email").configureHelp(helpConfig).action(
8349
+ () => runCommand(async () => {
8350
+ const { workspaceRootDir } = await getWorkspace();
8351
+ const config = await p24.group(
8352
+ {
8353
+ host: () => p24.text({
8354
+ message: "SMTP host",
8355
+ placeholder: "smtp.example.com",
8356
+ validate: (v12) => v12 ? void 0 : "Host is required"
8357
+ }),
8358
+ port: () => p24.text({
8359
+ message: "SMTP port",
8360
+ initialValue: "587",
8361
+ validate: (v12) => {
8362
+ if (!v12) return "Port is required";
8363
+ const n = Number(v12);
8364
+ if (!Number.isInteger(n) || n <= 0 || n > 65535) return "Invalid port";
8365
+ return void 0;
8366
+ }
8367
+ }),
8368
+ username: () => p24.text({ message: "SMTP username" }),
8369
+ password: () => p24.password({ message: "SMTP password" })
8370
+ },
8371
+ {
8372
+ onCancel: () => {
8373
+ p24.cancel("Operation cancelled.");
8374
+ process20.exit(0);
8375
+ }
8376
+ }
8377
+ );
8378
+ await withPocketbase(workspaceRootDir, async (pb) => {
8379
+ await pb.settings.update({
8380
+ smtp: {
8381
+ enabled: true,
8382
+ host: config.host,
8383
+ port: parseInt(config.port, 10),
8384
+ username: config.username ?? "",
8385
+ password: config.password ?? ""
8386
+ }
8387
+ });
8388
+ });
8389
+ reportResult({
8390
+ summary: "Enabled SMTP for transactional email.",
8391
+ nextSteps: [
8392
+ "PocketBase will now send auth/verification email via your SMTP server.",
8393
+ "Send a test email from the PocketBase admin UI (Settings \u2192 Mail settings).",
8394
+ "Run `vela disable smtp` to revert to the built-in fallback sender."
8395
+ ]
8396
+ });
8397
+ }, "Failed to enable SMTP.")
8398
+ );
8399
+
8256
8400
  // src/commands/enable/cms.ts
8401
+ import process21 from "node:process";
8402
+ import { Command as Command24 } from "commander";
8403
+ import * as p25 from "@clack/prompts";
8404
+ import pc10 from "picocolors";
8257
8405
  function resolveCmsBackend(facts) {
8258
8406
  if (facts.endpoint) return { kind: "hosted", endpoint: facts.endpoint, from: "flag" };
8259
8407
  if (facts.backend || facts.adapter === "node") return { kind: "self-hosted" };
@@ -9433,14 +9581,14 @@ var ui = new Command55("ui").description("generate ui components").configureHelp
9433
9581
  import { Command as Command58 } from "commander";
9434
9582
 
9435
9583
  // src/commands/legal/terms.ts
9436
- import path36 from "node:path";
9584
+ import path37 from "node:path";
9437
9585
  import { Command as Command56 } from "commander";
9438
9586
  import * as p38 from "@clack/prompts";
9439
9587
 
9440
9588
  // src/commands/legal/shared.ts
9441
9589
  import process26 from "node:process";
9442
- import fs37 from "node:fs";
9443
- import path35 from "node:path";
9590
+ import fs38 from "node:fs";
9591
+ import path36 from "node:path";
9444
9592
  import * as p37 from "@clack/prompts";
9445
9593
  function siteFields(site) {
9446
9594
  const url = site?.url && !isLocalUrl(site.url) ? site.url : void 0;
@@ -9722,16 +9870,16 @@ function writeLegalPage(root, dir, page) {
9722
9870
 
9723
9871
  ${html}`;
9724
9872
  }
9725
- const pagePath = path35.join(root, dir, "+page.svelte");
9726
- fs37.mkdirSync(path35.dirname(pagePath), { recursive: true });
9727
- fs37.writeFileSync(pagePath, html);
9873
+ const pagePath = path36.join(root, dir, "+page.svelte");
9874
+ fs38.mkdirSync(path36.dirname(pagePath), { recursive: true });
9875
+ fs38.writeFileSync(pagePath, html);
9728
9876
  const written = [pagePath];
9729
9877
  if (metaTags) {
9730
- const loaderPath = path35.join(root, dir, "+page.ts");
9731
- fs37.writeFileSync(loaderPath, pageMetaTagsLoader(page.title, page.description));
9878
+ const loaderPath = path36.join(root, dir, "+page.ts");
9879
+ fs38.writeFileSync(loaderPath, pageMetaTagsLoader(page.title, page.description));
9732
9880
  written.push(loaderPath);
9733
9881
  }
9734
- return written.map((file) => path35.relative(root, file));
9882
+ return written.map((file) => path36.relative(root, file));
9735
9883
  }
9736
9884
 
9737
9885
  // src/commands/legal/terms.ts
@@ -10128,7 +10276,7 @@ async function termsAction() {
10128
10276
  });
10129
10277
  const [relativeTermsPage, ...rest] = writeLegalPage(
10130
10278
  workspaceRootDir,
10131
- path36.join(publicRoutesDir, LEGAL_DIR, "terms"),
10279
+ path37.join(publicRoutesDir, LEGAL_DIR, "terms"),
10132
10280
  {
10133
10281
  html,
10134
10282
  title: "Terms of Service",
@@ -10148,7 +10296,7 @@ async function termsAction() {
10148
10296
  var terms = new Command56("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
10149
10297
 
10150
10298
  // src/commands/legal/privacy.ts
10151
- import path37 from "node:path";
10299
+ import path38 from "node:path";
10152
10300
  import { Command as Command57 } from "commander";
10153
10301
  import * as p39 from "@clack/prompts";
10154
10302
  var mapLabels = {
@@ -10864,7 +11012,7 @@ async function privacyAction() {
10864
11012
  });
10865
11013
  const [relativePrivacyPage, ...rest] = writeLegalPage(
10866
11014
  workspaceRootDir,
10867
- path37.join(publicRoutesDir, LEGAL_DIR, "privacy"),
11015
+ path38.join(publicRoutesDir, LEGAL_DIR, "privacy"),
10868
11016
  {
10869
11017
  html,
10870
11018
  title: "Privacy Policy",
@@ -10893,8 +11041,8 @@ import { Command as Command64 } from "commander";
10893
11041
  import { Command as Command59 } from "commander";
10894
11042
 
10895
11043
  // src/lib/data.ts
10896
- import fs38 from "node:fs";
10897
- import path38 from "node:path";
11044
+ import fs39 from "node:fs";
11045
+ import path39 from "node:path";
10898
11046
  import { ClientResponseError } from "pocketbase";
10899
11047
 
10900
11048
  // src/lib/collections.ts
@@ -10931,14 +11079,14 @@ function dependencyOrder(collections2, startingCollectionId) {
10931
11079
 
10932
11080
  // src/lib/data.ts
10933
11081
  function dataDir(cwd, kind) {
10934
- return path38.join(cwd, DATA_DIR, kind);
11082
+ return path39.join(cwd, DATA_DIR, kind);
10935
11083
  }
10936
11084
  function getDataFiles(cwd, kind) {
10937
11085
  const dir = dataDir(cwd, kind);
10938
- if (!fs38.existsSync(dir)) return [];
10939
- return fs38.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
11086
+ if (!fs39.existsSync(dir)) return [];
11087
+ return fs39.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
10940
11088
  collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
10941
- filePath: path38.join(dir, file)
11089
+ filePath: path39.join(dir, file)
10942
11090
  }));
10943
11091
  }
10944
11092
  function getSeedFiles(cwd) {
@@ -10948,7 +11096,7 @@ function getFixtureFiles(cwd) {
10948
11096
  return getDataFiles(cwd, "fixtures");
10949
11097
  }
10950
11098
  function readRecords(filePath) {
10951
- return JSON.parse(fs38.readFileSync(filePath, "utf8"));
11099
+ return JSON.parse(fs39.readFileSync(filePath, "utf8"));
10952
11100
  }
10953
11101
  function readSeedIds(cwd) {
10954
11102
  const ids = /* @__PURE__ */ new Map();
@@ -10985,7 +11133,7 @@ function describeError(e) {
10985
11133
  return e instanceof Error ? e.message : String(e);
10986
11134
  }
10987
11135
  function label3(cwd, filePath, count) {
10988
- return `${path38.relative(cwd, filePath)} (${count} records)`;
11136
+ return `${path39.relative(cwd, filePath)} (${count} records)`;
10989
11137
  }
10990
11138
  async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
10991
11139
  const records = readRecords(filePath);
@@ -10993,7 +11141,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
10993
11141
  try {
10994
11142
  await pb.collection(collectionName).create(record);
10995
11143
  } catch (e) {
10996
- throw new DataLoadError(kind, path38.relative(cwd, filePath), index, e);
11144
+ throw new DataLoadError(kind, path39.relative(cwd, filePath), index, e);
10997
11145
  }
10998
11146
  }
10999
11147
  return records.length;
@@ -11167,8 +11315,8 @@ var reset = new Command61("reset").description("clear and reload fixtures").conf
11167
11315
  );
11168
11316
 
11169
11317
  // src/commands/fixtures/generate.ts
11170
- import fs39 from "node:fs";
11171
- import path39 from "node:path";
11318
+ import fs40 from "node:fs";
11319
+ import path40 from "node:path";
11172
11320
  import { Command as Command62, InvalidArgumentError } from "commander";
11173
11321
  import * as p40 from "@clack/prompts";
11174
11322
  import { annotate } from "annotate-json-schema";
@@ -11205,9 +11353,9 @@ async function loadCollections(pb) {
11205
11353
  }
11206
11354
  async function generateFixtureFiles(pb, workspaceRootDir, opts) {
11207
11355
  const fixturesDir = dataDir(workspaceRootDir, "fixtures");
11208
- fs39.mkdirSync(fixturesDir, { recursive: true });
11209
- for (const file of fs39.readdirSync(fixturesDir)) {
11210
- if (file.endsWith(".json")) fs39.unlinkSync(path39.join(fixturesDir, file));
11356
+ fs40.mkdirSync(fixturesDir, { recursive: true });
11357
+ for (const file of fs40.readdirSync(fixturesDir)) {
11358
+ if (file.endsWith(".json")) fs40.unlinkSync(path40.join(fixturesDir, file));
11211
11359
  }
11212
11360
  if (opts.seed !== void 0) faker.seed(opts.seed);
11213
11361
  const generator = createGenerator({
@@ -11274,8 +11422,8 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
11274
11422
  items.push(record);
11275
11423
  }
11276
11424
  const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
11277
- fs39.writeFileSync(path39.join(fixturesDir, filename), JSON.stringify(items, null, 2));
11278
- writtenFiles.push(`${path39.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
11425
+ fs40.writeFileSync(path40.join(fixturesDir, filename), JSON.stringify(items, null, 2));
11426
+ writtenFiles.push(`${path40.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
11279
11427
  fileIndex++;
11280
11428
  }
11281
11429
  return { writtenFiles, warnings };
@@ -11422,8 +11570,8 @@ var load2 = new Command65("load").description("load seeds into the database").op
11422
11570
  );
11423
11571
 
11424
11572
  // src/commands/seeds/save.ts
11425
- import fs40 from "node:fs";
11426
- import path40 from "node:path";
11573
+ import fs41 from "node:fs";
11574
+ import path41 from "node:path";
11427
11575
  import { Command as Command66 } from "commander";
11428
11576
  var padZeros2 = (num, length) => num.toString().padStart(length, "0");
11429
11577
  function filterSystemFields(record, systemFieldNames) {
@@ -11443,10 +11591,10 @@ var save = new Command66("save").description("save the current data as seeds").o
11443
11591
  if (existing.length > 0 && !opts.force) {
11444
11592
  throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
11445
11593
  }
11446
- fs40.mkdirSync(seedsPath, { recursive: true });
11594
+ fs41.mkdirSync(seedsPath, { recursive: true });
11447
11595
  if (opts.force) {
11448
- for (const file of fs40.readdirSync(seedsPath)) {
11449
- if (file.endsWith(".json")) fs40.unlinkSync(path40.join(seedsPath, file));
11596
+ for (const file of fs41.readdirSync(seedsPath)) {
11597
+ if (file.endsWith(".json")) fs41.unlinkSync(path41.join(seedsPath, file));
11450
11598
  }
11451
11599
  }
11452
11600
  const saved = [];
@@ -11475,13 +11623,13 @@ var save = new Command66("save").description("save the current data as seeds").o
11475
11623
  const filtered = records.map(
11476
11624
  (r) => filterSystemFields(r, systemFieldNames)
11477
11625
  );
11478
- const relativeSeedPath = path40.join(
11626
+ const relativeSeedPath = path41.join(
11479
11627
  DATA_DIR,
11480
11628
  "seeds",
11481
11629
  `${padZeros2(count, 2)}-${collectionName}.json`
11482
11630
  );
11483
- const seedPath = path40.join(workspaceRootDir, relativeSeedPath);
11484
- fs40.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
11631
+ const seedPath = path41.join(workspaceRootDir, relativeSeedPath);
11632
+ fs41.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
11485
11633
  saved.push(`${relativeSeedPath} (${filtered.length} records)`);
11486
11634
  count++;
11487
11635
  }
@@ -11619,7 +11767,7 @@ import { Command as Command78 } from "commander";
11619
11767
  import { Command as Command72 } from "commander";
11620
11768
 
11621
11769
  // src/lib/migrate.ts
11622
- import path41 from "node:path";
11770
+ import path42 from "node:path";
11623
11771
  import process27 from "node:process";
11624
11772
  import { x as x3 } from "tinyexec";
11625
11773
  function migrateRoot() {
@@ -11633,9 +11781,9 @@ async function runPocketbaseMigrate(args) {
11633
11781
  binaryPath,
11634
11782
  [
11635
11783
  "--dir",
11636
- path41.join(cwd, DATA_DIR),
11784
+ path42.join(cwd, DATA_DIR),
11637
11785
  "--migrationsDir",
11638
- path41.join(cwd, MIGRATIONS_DIR),
11786
+ path42.join(cwd, MIGRATIONS_DIR),
11639
11787
  "migrate",
11640
11788
  ...args
11641
11789
  ],
@@ -11683,8 +11831,8 @@ var down = new Command73("down").alias("rollback").description("revert the last
11683
11831
  );
11684
11832
 
11685
11833
  // src/commands/migrate/create.ts
11686
- import fs41 from "node:fs";
11687
- import path42 from "node:path";
11834
+ import fs42 from "node:fs";
11835
+ import path43 from "node:path";
11688
11836
  import { Command as Command74 } from "commander";
11689
11837
  var create2 = new Command74("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
11690
11838
  (name) => runCommand(async () => {
@@ -11695,7 +11843,7 @@ var create2 = new Command74("create").alias("new").description("create a new bla
11695
11843
  const added = [...after].filter((f) => !before.has(f));
11696
11844
  reportResult({
11697
11845
  summary: `Created blank migration ${name}.`,
11698
- filesCreated: added.map((f) => path42.join(MIGRATIONS_DIR, f)),
11846
+ filesCreated: added.map((f) => path43.join(MIGRATIONS_DIR, f)),
11699
11847
  nextSteps: [
11700
11848
  `Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
11701
11849
  "Run `vela migrate up` to apply the migration once the handlers are written."
@@ -11704,14 +11852,14 @@ var create2 = new Command74("create").alias("new").description("create a new bla
11704
11852
  }, "Failed to create migration.")
11705
11853
  );
11706
11854
  function listMigrationFiles(cwd) {
11707
- const dir = path42.join(cwd, MIGRATIONS_DIR);
11708
- if (!fs41.existsSync(dir)) return /* @__PURE__ */ new Set();
11709
- return new Set(fs41.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
11855
+ const dir = path43.join(cwd, MIGRATIONS_DIR);
11856
+ if (!fs42.existsSync(dir)) return /* @__PURE__ */ new Set();
11857
+ return new Set(fs42.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
11710
11858
  }
11711
11859
 
11712
11860
  // src/commands/migrate/collections.ts
11713
- import fs42 from "node:fs";
11714
- import path43 from "node:path";
11861
+ import fs43 from "node:fs";
11862
+ import path44 from "node:path";
11715
11863
  import { Command as Command75 } from "commander";
11716
11864
  var collections = new Command75("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
11717
11865
  () => runCommand(async () => {
@@ -11728,7 +11876,7 @@ var collections = new Command75("collections").alias("snapshot").description("sn
11728
11876
  }
11729
11877
  reportResult({
11730
11878
  summary: "Snapshotted local collections into a new migration.",
11731
- filesCreated: added.map((f) => path43.join(MIGRATIONS_DIR, f)),
11879
+ filesCreated: added.map((f) => path44.join(MIGRATIONS_DIR, f)),
11732
11880
  nextSteps: [
11733
11881
  `Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
11734
11882
  "Commit the snapshot so teammates pick up the new schema.",
@@ -11738,9 +11886,9 @@ var collections = new Command75("collections").alias("snapshot").description("sn
11738
11886
  }, "Failed to snapshot collections.")
11739
11887
  );
11740
11888
  function listMigrationFiles2(cwd) {
11741
- const dir = path43.join(cwd, MIGRATIONS_DIR);
11742
- if (!fs42.existsSync(dir)) return /* @__PURE__ */ new Set();
11743
- return new Set(fs42.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
11889
+ const dir = path44.join(cwd, MIGRATIONS_DIR);
11890
+ if (!fs43.existsSync(dir)) return /* @__PURE__ */ new Set();
11891
+ return new Set(fs43.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
11744
11892
  }
11745
11893
 
11746
11894
  // src/commands/migrate/history-sync.ts
@@ -11756,14 +11904,14 @@ var historySync = new Command76("history-sync").description("drop _migrations ro
11756
11904
  );
11757
11905
 
11758
11906
  // src/commands/migrate/sveltekit-3.ts
11759
- import path44 from "node:path";
11907
+ import path45 from "node:path";
11760
11908
  import process28 from "node:process";
11761
11909
  import { Command as Command77 } from "commander";
11762
11910
  import * as p45 from "@clack/prompts";
11763
11911
  import pc15 from "picocolors";
11764
11912
  var sveltekit3 = new Command77("sveltekit-3").description("upgrade a SvelteKit 2 project to SvelteKit 3 (sv migrate, then the vela steps)").option("--cwd <path>", "the project to migrate (default: the current project)").option("--no-install", "skip installing dependencies").option("--force", "run even when the git working tree has uncommitted changes").option("--skip-sv", "only run the vela steps (sv has already been run)").configureHelp(helpConfig).action(
11765
11913
  (options) => runCommand(async () => {
11766
- const root = options.cwd ? path44.resolve(options.cwd) : findWorkspaceRoot() ?? process28.cwd();
11914
+ const root = options.cwd ? path45.resolve(options.cwd) : findWorkspaceRoot() ?? process28.cwd();
11767
11915
  p45.intro(pc15.bgCyan(pc15.black(" vela migrate sveltekit-3 ")));
11768
11916
  const result = await runKit3Migration(root, {
11769
11917
  install: options.install,
@@ -11780,7 +11928,7 @@ function printReport(root, result) {
11780
11928
  sections.push({ label: "Build output removed first", items: result.sv.cleared });
11781
11929
  }
11782
11930
  for (const fixup2 of changed) sections.push({ label: fixup2.name, items: fixup2.details });
11783
- const summary = result.mode === "repair" ? changed.length > 0 ? "Already on SvelteKit 3; brought the vela setup up to date." : "Already on SvelteKit 3; nothing left to change." : `Migrated ${path44.basename(root)} to SvelteKit 3.`;
11931
+ const summary = result.mode === "repair" ? changed.length > 0 ? "Already on SvelteKit 3; brought the vela setup up to date." : "Already on SvelteKit 3; nothing left to change." : `Migrated ${path45.basename(root)} to SvelteKit 3.`;
11784
11932
  reportResult({ summary, sections });
11785
11933
  const tasks = result.tasks;
11786
11934
  if (tasks && (tasks.sections.length > 0 || tasks.markerComments > 0)) {
@@ -11838,8 +11986,8 @@ function nextStepsFor(result) {
11838
11986
  var migrate = new Command78("migrate").description("manage database migrations (and `migrate sveltekit-3` to upgrade SvelteKit)").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync).addCommand(sveltekit3);
11839
11987
 
11840
11988
  // src/commands/dev.ts
11841
- import fs43 from "node:fs";
11842
- import path46 from "node:path";
11989
+ import fs44 from "node:fs";
11990
+ import path47 from "node:path";
11843
11991
  import process31 from "node:process";
11844
11992
  import { performance } from "node:perf_hooks";
11845
11993
  import { Command as Command79, InvalidArgumentError as InvalidArgumentError4 } from "commander";
@@ -11859,6 +12007,9 @@ function onTerminate(cleanup, proc = process29) {
11859
12007
  });
11860
12008
  }
11861
12009
  }
12010
+ function stopChild(child) {
12011
+ if (child?.pid && child.exitCode === null && child.signalCode === null) child.kill();
12012
+ }
11862
12013
 
11863
12014
  // src/lib/pocketbase-log-filter.ts
11864
12015
  import { Transform } from "node:stream";
@@ -11885,7 +12036,7 @@ function createPocketbaseLogFilter() {
11885
12036
  }
11886
12037
 
11887
12038
  // src/lib/vite.ts
11888
- import path45 from "node:path";
12039
+ import path46 from "node:path";
11889
12040
  import process30 from "node:process";
11890
12041
  import { createRequire as createRequire3 } from "node:module";
11891
12042
  import { pathToFileURL as pathToFileURL2 } from "node:url";
@@ -11905,7 +12056,7 @@ function viteVersionError(version) {
11905
12056
  }
11906
12057
  function resolveProjectVite(cwd) {
11907
12058
  try {
11908
- return createRequire3(path45.join(cwd, "package.json")).resolve("vite");
12059
+ return createRequire3(path46.join(cwd, "package.json")).resolve("vite");
11909
12060
  } catch {
11910
12061
  return null;
11911
12062
  }
@@ -11935,21 +12086,21 @@ var dev = new Command79("dev").description("start the development server").optio
11935
12086
  process31.env.VELA_DATA_DIR ??= localDataDir(cwd);
11936
12087
  const startTime = performance.now();
11937
12088
  const { createServer, version } = await loadVite(cwd);
11938
- const viteMetadataDir = path46.join(cwd, "node_modules", ".vite");
11939
- const viteMetadataFile = path46.join(viteMetadataDir, "_pocketbase_metadata.json");
12089
+ const viteMetadataDir = path47.join(cwd, "node_modules", ".vite");
12090
+ const viteMetadataFile = path47.join(viteMetadataDir, "_pocketbase_metadata.json");
11940
12091
  let pbProc;
11941
12092
  const backend3 = hasBackend(cwd);
11942
12093
  const needsStart = backend3 && !process31.env.POCKETBASE_URL;
11943
12094
  const cleanup = () => {
11944
12095
  if (pbProc?.pid) pbProc.kill();
11945
- if (fs43.existsSync(viteMetadataFile)) fs43.rmSync(viteMetadataFile);
12096
+ if (fs44.existsSync(viteMetadataFile)) fs44.rmSync(viteMetadataFile);
11946
12097
  };
11947
12098
  if (needsStart) {
11948
- const dataDir2 = path46.join(cwd, DATA_DIR);
12099
+ const dataDir2 = path47.join(cwd, DATA_DIR);
11949
12100
  const started = await startPocketbaseServe({
11950
12101
  dataDir: dataDir2,
11951
12102
  migrationsDir: MIGRATIONS_DIR,
11952
- hooksDir: path46.join(dataDir2, "hooks"),
12103
+ hooksDir: path47.join(dataDir2, "hooks"),
11953
12104
  dev: true,
11954
12105
  stdio: "pipe"
11955
12106
  });
@@ -11977,8 +12128,8 @@ var dev = new Command79("dev").description("start the development server").optio
11977
12128
  if (!backend3) return;
11978
12129
  const { address, port: vitePort } = server.httpServer.address();
11979
12130
  const viteHost = address === "::1" ? "localhost" : address;
11980
- await fs43.promises.mkdir(viteMetadataDir, { recursive: true });
11981
- await fs43.promises.writeFile(
12131
+ await fs44.promises.mkdir(viteMetadataDir, { recursive: true });
12132
+ await fs44.promises.writeFile(
11982
12133
  viteMetadataFile,
11983
12134
  JSON.stringify({
11984
12135
  pocketbaseUrl: process31.env.POCKETBASE_URL,
@@ -12023,18 +12174,18 @@ var dev = new Command79("dev").description("start the development server").optio
12023
12174
  });
12024
12175
  async function startWatchingTypes(cwd, pb) {
12025
12176
  const { processTypes } = await import("@velastack/pocketbase-codegen");
12026
- const typesDir = path46.resolve(cwd, ".svelte-kit", "types");
12027
- const pocketbaseDir = path46.join(typesDir, "pocketbase");
12028
- const pocketbaseTypes = path46.join(pocketbaseDir, "$types.d.ts");
12177
+ const typesDir = path47.resolve(cwd, ".svelte-kit", "types");
12178
+ const pocketbaseDir = path47.join(typesDir, "pocketbase");
12179
+ const pocketbaseTypes = path47.join(pocketbaseDir, "$types.d.ts");
12029
12180
  const regenerate = () => processTypes(pb, typesDir).catch(() => {
12030
12181
  });
12031
12182
  await regenerate();
12032
12183
  void (async () => {
12033
12184
  for (; ; ) {
12034
12185
  try {
12035
- await fs43.promises.mkdir(pocketbaseDir, { recursive: true });
12036
- for await (const event of fs43.promises.watch(pocketbaseDir)) {
12037
- if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs43.existsSync(pocketbaseTypes)) {
12186
+ await fs44.promises.mkdir(pocketbaseDir, { recursive: true });
12187
+ for await (const event of fs44.promises.watch(pocketbaseDir)) {
12188
+ if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs44.existsSync(pocketbaseTypes)) {
12038
12189
  setTimeout(regenerate, 100);
12039
12190
  }
12040
12191
  }
@@ -12046,8 +12197,8 @@ async function startWatchingTypes(cwd, pb) {
12046
12197
  }
12047
12198
 
12048
12199
  // src/commands/build.ts
12049
- import fs44 from "node:fs";
12050
- import path47 from "node:path";
12200
+ import fs45 from "node:fs";
12201
+ import path48 from "node:path";
12051
12202
  import process33 from "node:process";
12052
12203
  import { Command as Command80 } from "commander";
12053
12204
  import * as p46 from "@clack/prompts";
@@ -12089,45 +12240,60 @@ function splitHosts(value) {
12089
12240
  }
12090
12241
 
12091
12242
  // src/commands/build.ts
12092
- var PRERENDERED_DIR = path47.join(".svelte-kit", "output", "prerendered");
12243
+ var PRERENDERED_DIR = path48.join(".svelte-kit", "output", "prerendered");
12093
12244
  var build = new Command80("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
12094
12245
  const cwd = process33.cwd();
12095
12246
  warnIfKit2(findWorkspaceRoot(cwd) ?? cwd, (m) => p46.log.warn(m));
12247
+ warnIfSsrExternalMissing(findWorkspaceRoot(cwd) ?? cwd);
12096
12248
  applyBuildEnv(cwd);
12097
12249
  const origin = await originForBuild(cwd, options.target);
12098
12250
  if (origin) process33.env.VELA_ORIGIN = origin;
12099
12251
  let pbProc;
12100
12252
  const needsStart = hasBackend(cwd) && !process33.env.POCKETBASE_URL;
12253
+ let viteProc;
12101
12254
  const cleanup = () => {
12102
- if (pbProc?.pid) pbProc.kill();
12255
+ stopChild(pbProc);
12256
+ stopChild(viteProc);
12103
12257
  };
12258
+ onTerminate(cleanup);
12104
12259
  if (needsStart) {
12105
12260
  await ensureSuperuser(cwd);
12106
- const dataDir2 = path47.join(cwd, DATA_DIR);
12261
+ const dataDir2 = path48.join(cwd, DATA_DIR);
12107
12262
  const started = await startPocketbaseServe({
12108
12263
  dataDir: dataDir2,
12109
12264
  migrationsDir: MIGRATIONS_DIR,
12110
- hooksDir: path47.join(dataDir2, "hooks"),
12265
+ hooksDir: path48.join(dataDir2, "hooks"),
12111
12266
  dev: true
12112
12267
  });
12113
12268
  pbProc = started.proc;
12114
12269
  process33.env.POCKETBASE_URL = started.url;
12115
- onTerminate(cleanup);
12116
12270
  }
12117
12271
  try {
12118
12272
  const pm = (await detect7({ cwd }))?.name ?? "npm";
12119
12273
  const resolved = resolveCommand5(pm, "execute", ["vite", "build"]);
12120
12274
  const args = resolved.args.slice();
12121
12275
  if (pm === "npm") args.unshift("--yes");
12122
- await x4(resolved.command, args, {
12276
+ const vite = x4(resolved.command, args, {
12123
12277
  nodeOptions: { cwd, stdio: "inherit" },
12124
12278
  throwOnError: true
12125
12279
  });
12280
+ viteProc = vite.process;
12281
+ await vite;
12126
12282
  } finally {
12127
12283
  cleanup();
12128
12284
  }
12129
12285
  if (!origin) warnIfPrerendered(cwd);
12130
12286
  });
12287
+ function warnIfSsrExternalMissing(root) {
12288
+ try {
12289
+ if (detectAdapter(root).kind !== "node") return;
12290
+ } catch {
12291
+ return;
12292
+ }
12293
+ const check2 = ssrExternalNotInDependencies(root);
12294
+ const problem = ssrExternalProblem(check2) ?? ssrExternalAllNotice(check2);
12295
+ if (problem) p46.log.warn(problem);
12296
+ }
12131
12297
  async function originForBuild(cwd, target) {
12132
12298
  const workspaceRootDir = findWorkspaceRoot(cwd);
12133
12299
  if (!workspaceRootDir) return null;
@@ -12142,8 +12308,8 @@ async function originForBuild(cwd, target) {
12142
12308
  }
12143
12309
  }
12144
12310
  function warnIfPrerendered(cwd) {
12145
- const dir = path47.join(cwd, PRERENDERED_DIR);
12146
- if (!fs44.existsSync(dir) || fs44.readdirSync(dir).length === 0) return;
12311
+ const dir = path48.join(cwd, PRERENDERED_DIR);
12312
+ if (!fs45.existsSync(dir) || fs45.readdirSync(dir).length === 0) return;
12147
12313
  if (process33.env.VELA_ORIGIN === "") {
12148
12314
  p46.log.warn(
12149
12315
  `Prerendered pages were built with no origin, on purpose: this app is served on
@@ -12166,8 +12332,8 @@ Set one with ${pc18.cyan("vela deploy --domain example.com")}, or pass ${pc18.cy
12166
12332
  }
12167
12333
 
12168
12334
  // src/commands/preview.ts
12169
- import fs45 from "node:fs";
12170
- import path48 from "node:path";
12335
+ import fs46 from "node:fs";
12336
+ import path49 from "node:path";
12171
12337
  import process34 from "node:process";
12172
12338
  import { Command as Command81 } from "commander";
12173
12339
  import * as p47 from "@clack/prompts";
@@ -12175,7 +12341,7 @@ import pc19 from "picocolors";
12175
12341
  import { x as x5 } from "tinyexec";
12176
12342
  import { detect as detect8 } from "package-manager-detector";
12177
12343
  import { resolveCommand as resolveCommand6 } from "package-manager-detector/commands";
12178
- var ADAPTER_NODE_MODULE = path48.join("build", "adapter-node.js");
12344
+ var ADAPTER_NODE_MODULE = path49.join("build", "adapter-node.js");
12179
12345
  var preview = new Command81("preview").description("preview the built app").configureHelp(helpConfig).action(async () => {
12180
12346
  const cwd = process34.cwd();
12181
12347
  process34.env.VELA_DATA_DIR ??= localDataDir(cwd);
@@ -12183,30 +12349,34 @@ var preview = new Command81("preview").description("preview the built app").conf
12183
12349
  warnIfOriginBaked(cwd);
12184
12350
  let pbProc;
12185
12351
  const needsStart = hasBackend(cwd) && !process34.env.POCKETBASE_URL;
12352
+ let viteProc;
12186
12353
  const cleanup = () => {
12187
- if (pbProc?.pid) pbProc.kill();
12354
+ stopChild(pbProc);
12355
+ stopChild(viteProc);
12188
12356
  };
12357
+ onTerminate(cleanup);
12189
12358
  if (needsStart) {
12190
- const dataDir2 = path48.join(cwd, DATA_DIR);
12359
+ const dataDir2 = path49.join(cwd, DATA_DIR);
12191
12360
  const started = await startPocketbaseServe({
12192
12361
  dataDir: dataDir2,
12193
12362
  migrationsDir: MIGRATIONS_DIR,
12194
- hooksDir: path48.join(dataDir2, "hooks"),
12363
+ hooksDir: path49.join(dataDir2, "hooks"),
12195
12364
  dev: true
12196
12365
  });
12197
12366
  pbProc = started.proc;
12198
12367
  process34.env.POCKETBASE_URL = started.url;
12199
- onTerminate(cleanup);
12200
12368
  }
12201
12369
  try {
12202
12370
  const pm = (await detect8({ cwd }))?.name ?? "npm";
12203
12371
  const resolved = resolveCommand6(pm, "execute", ["vite", "preview"]);
12204
12372
  const args = resolved.args.slice();
12205
12373
  if (pm === "npm") args.unshift("--yes");
12206
- await x5(resolved.command, args, {
12374
+ const vite = x5(resolved.command, args, {
12207
12375
  nodeOptions: { cwd, stdio: "inherit" },
12208
12376
  throwOnError: true
12209
12377
  });
12378
+ viteProc = vite.process;
12379
+ await vite;
12210
12380
  } finally {
12211
12381
  cleanup();
12212
12382
  }
@@ -12224,7 +12394,7 @@ function bakedOrigin(source) {
12224
12394
  function warnIfOriginBaked(cwd) {
12225
12395
  let source;
12226
12396
  try {
12227
- source = fs45.readFileSync(path48.join(cwd, ADAPTER_NODE_MODULE), "utf8");
12397
+ source = fs46.readFileSync(path49.join(cwd, ADAPTER_NODE_MODULE), "utf8");
12228
12398
  } catch {
12229
12399
  return;
12230
12400
  }
@@ -12240,12 +12410,12 @@ set empty so no domain is baked in.`
12240
12410
  }
12241
12411
 
12242
12412
  // src/commands/sync.ts
12243
- import path49 from "node:path";
12413
+ import path50 from "node:path";
12244
12414
  import { Command as Command82 } from "commander";
12245
12415
  var sync = new Command82("sync").description("sync types from the database").configureHelp(helpConfig).action(
12246
12416
  () => runCommand(async () => {
12247
12417
  const { workspaceRootDir } = await getWorkspace();
12248
- const typesDir = path49.join(workspaceRootDir, ".svelte-kit", "types");
12418
+ const typesDir = path50.join(workspaceRootDir, ".svelte-kit", "types");
12249
12419
  const { processTypes } = await import("@velastack/pocketbase-codegen");
12250
12420
  await withPocketbase(workspaceRootDir, async (pb) => {
12251
12421
  await processTypes(pb, typesDir);
@@ -12312,8 +12482,8 @@ var provision = addSshOptions(
12312
12482
  );
12313
12483
 
12314
12484
  // src/commands/deploy.ts
12315
- import path51 from "node:path";
12316
- import fs47 from "node:fs";
12485
+ import path52 from "node:path";
12486
+ import fs48 from "node:fs";
12317
12487
  import process36 from "node:process";
12318
12488
  import { Command as Command84, Option as Option2 } from "commander";
12319
12489
  import * as p49 from "@clack/prompts";
@@ -12321,14 +12491,14 @@ import pc21 from "picocolors";
12321
12491
  import * as v10 from "valibot";
12322
12492
 
12323
12493
  // src/lib/pocketbase-settings.ts
12324
- import fs46 from "node:fs";
12325
- import path50 from "node:path";
12494
+ import fs47 from "node:fs";
12495
+ import path51 from "node:path";
12326
12496
  import process35 from "node:process";
12327
12497
  import PocketBase5 from "pocketbase";
12328
12498
  var COPIED_KEYS = ["senderName", "senderAddress"];
12329
12499
  async function readLocalMeta(cwd) {
12330
- const dataDir2 = path50.join(cwd, DATA_DIR);
12331
- if (!fs46.existsSync(dataDir2)) return null;
12500
+ const dataDir2 = path51.join(cwd, DATA_DIR);
12501
+ if (!fs47.existsSync(dataDir2)) return null;
12332
12502
  const email2 = process35.env.POCKETBASE_SUPERUSER_EMAIL;
12333
12503
  const password11 = process35.env.POCKETBASE_SUPERUSER_PASSWORD;
12334
12504
  if (!email2 || !password11) return null;
@@ -12337,7 +12507,7 @@ async function readLocalMeta(cwd) {
12337
12507
  const started = await startPocketbaseServe({
12338
12508
  dataDir: dataDir2,
12339
12509
  migrationsDir: MIGRATIONS_DIR,
12340
- hooksDir: path50.join(dataDir2, "hooks")
12510
+ hooksDir: path51.join(dataDir2, "hooks")
12341
12511
  });
12342
12512
  proc = started.proc;
12343
12513
  const pb = new PocketBase5(started.url);
@@ -12425,6 +12595,7 @@ ${pc21.cyan("package-lock.json")} (${pc21.dim("npm install --package-lock-only")
12425
12595
  );
12426
12596
  }
12427
12597
  }
12598
+ ssrExternalPreflight(findWorkspaceRoot() ?? process36.cwd());
12428
12599
  await withTarget(
12429
12600
  raw,
12430
12601
  {
@@ -12623,7 +12794,7 @@ ${pc21.cyan(err.snippet)}` : err.message);
12623
12794
  const has = current.kind === "auto" ? `is on ${ADAPTER_AUTO}` : "has no SvelteKit adapter configured";
12624
12795
  const confirmed = await p49.confirm({
12625
12796
  message: `This project ${has}, and vela deploy runs the app as a Node server.
12626
- Switch it to ${ADAPTER_NODE2}? This edits ${path51.basename(current.file)} and package.json.`
12797
+ Switch it to ${ADAPTER_NODE}? This edits ${path52.basename(current.file)} and package.json.`
12627
12798
  });
12628
12799
  if (p49.isCancel(confirmed) || !confirmed) {
12629
12800
  p49.cancel("Nothing was changed, and nothing was deployed.");
@@ -12636,8 +12807,8 @@ Switch it to ${ADAPTER_NODE2}? This edits ${path51.basename(current.file)} and p
12636
12807
  outcome.configFile,
12637
12808
  outcome.packageJsonChanged ? "package.json" : void 0
12638
12809
  ].filter((f) => Boolean(f));
12639
- const why = outcome.previous === "auto" ? `${ADAPTER_AUTO} builds nothing for a server of your own` : outcome.previous === "none" ? "No adapter was configured" : `${ADAPTER_NODE2} was configured but not in package.json`;
12640
- p49.log.step(`Switching the adapter to ${pc21.cyan(ADAPTER_NODE2)}`);
12810
+ const why = outcome.previous === "auto" ? `${ADAPTER_AUTO} builds nothing for a server of your own` : outcome.previous === "none" ? "No adapter was configured" : `${ADAPTER_NODE} was configured but not in package.json`;
12811
+ p49.log.step(`Switching the adapter to ${pc21.cyan(ADAPTER_NODE)}`);
12641
12812
  p49.log.info(
12642
12813
  `${why}, and vela deploy runs the app as a Node server.
12643
12814
 
@@ -12653,6 +12824,20 @@ Switch it to ${ADAPTER_NODE2}? This edits ${path51.basename(current.file)} and p
12653
12824
  }
12654
12825
  p49.log.warn(`Commit ${changed.join(", ")} so every deploy builds the same way.`);
12655
12826
  }
12827
+ function ssrExternalPreflight(root) {
12828
+ let adapter;
12829
+ try {
12830
+ adapter = detectAdapter(root);
12831
+ } catch {
12832
+ return;
12833
+ }
12834
+ if (adapter.kind !== "node") return;
12835
+ const check2 = ssrExternalNotInDependencies(root);
12836
+ const problem = ssrExternalProblem(check2);
12837
+ if (problem) throw new Error(problem);
12838
+ const notice = ssrExternalAllNotice(check2);
12839
+ if (notice) p49.log.warn(notice);
12840
+ }
12656
12841
  async function syncAppName(session, instance, appName, domain) {
12657
12842
  if (!appName && !domain) return;
12658
12843
  let result;
@@ -12790,7 +12975,7 @@ async function uploadRelease(session, instance, release, entries) {
12790
12975
  }
12791
12976
  function isDirectory(target) {
12792
12977
  try {
12793
- return fs47.statSync(target).isDirectory();
12978
+ return fs48.statSync(target).isDirectory();
12794
12979
  } catch {
12795
12980
  return false;
12796
12981
  }
@@ -12798,7 +12983,7 @@ function isDirectory(target) {
12798
12983
  async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
12799
12984
  const remote = await readRemoteEnv(session, instance);
12800
12985
  if (Object.keys(remote).length > 0) return;
12801
- if (!fs47.existsSync(path51.join(workspaceRootDir, ".env"))) return;
12986
+ if (!fs48.existsSync(path52.join(workspaceRootDir, ".env"))) return;
12802
12987
  p49.log.warn(
12803
12988
  `This app has no production environment variables yet.
12804
12989
 
@@ -12835,7 +13020,7 @@ async function serverTimeOrLocal(session) {
12835
13020
  }
12836
13021
 
12837
13022
  // src/commands/link.ts
12838
- import path52 from "node:path";
13023
+ import path53 from "node:path";
12839
13024
  import process37 from "node:process";
12840
13025
  import { Command as Command85 } from "commander";
12841
13026
  import * as p50 from "@clack/prompts";
@@ -12898,12 +13083,12 @@ async function promptProjectName(workspaceRootDir) {
12898
13083
  }
12899
13084
  function defaultProjectName2(workspaceRootDir) {
12900
13085
  try {
12901
- const pkg = readPackageJson(path52.join(workspaceRootDir, "package.json"));
13086
+ const pkg = readPackageJson(path53.join(workspaceRootDir, "package.json"));
12902
13087
  const name = pkg.name;
12903
13088
  if (typeof name === "string" && name.trim()) return name.trim();
12904
13089
  } catch {
12905
13090
  }
12906
- return path52.basename(workspaceRootDir);
13091
+ return path53.basename(workspaceRootDir);
12907
13092
  }
12908
13093
 
12909
13094
  // src/commands/env.ts
@@ -13034,8 +13219,8 @@ var envUnset = addTargetOptions(
13034
13219
  );
13035
13220
 
13036
13221
  // src/commands/env/import.ts
13037
- import fs48 from "node:fs";
13038
- import path53 from "node:path";
13222
+ import fs49 from "node:fs";
13223
+ import path54 from "node:path";
13039
13224
  import process39 from "node:process";
13040
13225
  import { Command as Command89 } from "commander";
13041
13226
  import * as p54 from "@clack/prompts";
@@ -13081,10 +13266,10 @@ var envImport = addTargetOptions(
13081
13266
  )
13082
13267
  );
13083
13268
  function resolve(file) {
13084
- return path53.resolve(process39.cwd(), file);
13269
+ return path54.resolve(process39.cwd(), file);
13085
13270
  }
13086
13271
  function read(resolved, shown) {
13087
- if (!fs48.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
13272
+ if (!fs49.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
13088
13273
  const incoming = readLocalEnvFile(resolved);
13089
13274
  if (Object.keys(incoming).length === 0) p54.log.info(`${shown} has no variables to import.`);
13090
13275
  return incoming;
@@ -13371,8 +13556,8 @@ var admin = new Command95("admin").description("manage admin panel logins").conf
13371
13556
  import { Command as Command101 } from "commander";
13372
13557
 
13373
13558
  // src/commands/backup/create.ts
13374
- import fs49 from "node:fs";
13375
- import path54 from "node:path";
13559
+ import fs50 from "node:fs";
13560
+ import path55 from "node:path";
13376
13561
  import { Command as Command96 } from "commander";
13377
13562
  import * as p58 from "@clack/prompts";
13378
13563
  import pc29 from "picocolors";
@@ -13526,12 +13711,12 @@ Your bucket's own versioning is what protects the uploaded files.`
13526
13711
  }, "Failed to create the backup.")
13527
13712
  );
13528
13713
  async function download(ctx, key, outputDir) {
13529
- const dir = path54.resolve(ctx.workspaceRootDir, outputDir);
13530
- fs49.mkdirSync(dir, { recursive: true });
13531
- const destination = path54.join(dir, key);
13714
+ const dir = path55.resolve(ctx.workspaceRootDir, outputDir);
13715
+ fs50.mkdirSync(dir, { recursive: true });
13716
+ const destination = path55.join(dir, key);
13532
13717
  if (!ctx.session) {
13533
- fs49.copyFileSync(path54.join(ctx.workspaceRootDir, "data", "backups", key), destination);
13534
- return path54.relative(ctx.workspaceRootDir, destination);
13718
+ fs50.copyFileSync(path55.join(ctx.workspaceRootDir, "data", "backups", key), destination);
13719
+ return path55.relative(ctx.workspaceRootDir, destination);
13535
13720
  }
13536
13721
  const spinner8 = p58.spinner();
13537
13722
  spinner8.start(`Downloading ${key}`);
@@ -13542,7 +13727,7 @@ async function download(ctx, key, outputDir) {
13542
13727
  throw error;
13543
13728
  }
13544
13729
  spinner8.stop(`Downloaded ${key}`);
13545
- return path54.relative(ctx.workspaceRootDir, destination);
13730
+ return path55.relative(ctx.workspaceRootDir, destination);
13546
13731
  }
13547
13732
 
13548
13733
  // src/commands/backup/list.ts
@@ -13576,8 +13761,8 @@ Take one with ${pc30.cyan("vela backup create")}.`
13576
13761
  );
13577
13762
 
13578
13763
  // src/commands/backup/download.ts
13579
- import fs50 from "node:fs";
13580
- import path55 from "node:path";
13764
+ import fs51 from "node:fs";
13765
+ import path56 from "node:path";
13581
13766
  import { Command as Command98 } from "commander";
13582
13767
  import * as p60 from "@clack/prompts";
13583
13768
  import pc31 from "picocolors";
@@ -13604,11 +13789,11 @@ Run ${pc31.cyan("vela backup list")} to see what it does have.`
13604
13789
  Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
13605
13790
  );
13606
13791
  }
13607
- const dir = path55.resolve(ctx.workspaceRootDir, options.output);
13608
- fs50.mkdirSync(dir, { recursive: true });
13609
- const destination = path55.join(dir, key);
13792
+ const dir = path56.resolve(ctx.workspaceRootDir, options.output);
13793
+ fs51.mkdirSync(dir, { recursive: true });
13794
+ const destination = path56.join(dir, key);
13610
13795
  if (!ctx.session) {
13611
- fs50.copyFileSync(path55.join(ctx.workspaceRootDir, "data", "backups", key), destination);
13796
+ fs51.copyFileSync(path56.join(ctx.workspaceRootDir, "data", "backups", key), destination);
13612
13797
  } else {
13613
13798
  const spinner8 = p60.spinner();
13614
13799
  spinner8.start(`Downloading ${key} (${formatBytes(found.size)})`);
@@ -13622,7 +13807,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
13622
13807
  }
13623
13808
  reportResult({
13624
13809
  summary: `Saved ${key} from ${ctx.targetName}.`,
13625
- filesCreated: [path55.relative(ctx.workspaceRootDir, destination)]
13810
+ filesCreated: [path56.relative(ctx.workspaceRootDir, destination)]
13626
13811
  });
13627
13812
  });
13628
13813
  }, "Failed to download the backup.")
@@ -13717,8 +13902,8 @@ Set one with ${pc33.cyan('vela backup schedule "0 3 * * *"')}.`
13717
13902
  var backup = new Command101("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
13718
13903
 
13719
13904
  // src/commands/restore.ts
13720
- import fs51 from "node:fs";
13721
- import path56 from "node:path";
13905
+ import fs52 from "node:fs";
13906
+ import path57 from "node:path";
13722
13907
  import process42 from "node:process";
13723
13908
  import { Command as Command102 } from "commander";
13724
13909
  import * as p63 from "@clack/prompts";
@@ -13748,7 +13933,7 @@ Run \`vela deploy\` first, then restore.`
13748
13933
  `${ctx.targetName} was deployed without a database, so there is nothing to restore.`
13749
13934
  );
13750
13935
  }
13751
- const local = source && fs51.existsSync(source) ? source : void 0;
13936
+ const local = source && fs52.existsSync(source) ? source : void 0;
13752
13937
  const key = local ? void 0 : await resolveKey(ctx, source);
13753
13938
  if (!options.yes) {
13754
13939
  await confirm14(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
@@ -13771,7 +13956,7 @@ Run \`vela deploy\` first, then restore.`
13771
13956
  });
13772
13957
  p63.log.success(
13773
13958
  `Restored ${pc34.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc34.cyan(
13774
- local ? path56.basename(local) : key
13959
+ local ? path57.basename(local) : key
13775
13960
  )}.`
13776
13961
  );
13777
13962
  if (result?.storageCarriedOver) {
@@ -13837,21 +14022,21 @@ Take one with ${pc34.cyan("vela backup create")}, or pass the path to an archive
13837
14022
  }
13838
14023
  async function stage(ctx, file) {
13839
14024
  const dir = remotePaths.restoreStage(ctx.instance);
13840
- const remote = `${dir}/${path56.basename(file)}`;
14025
+ const remote = `${dir}/${path57.basename(file)}`;
13841
14026
  const spinner8 = p63.spinner();
13842
- spinner8.start(`Uploading ${path56.basename(file)}`);
14027
+ spinner8.start(`Uploading ${path57.basename(file)}`);
13843
14028
  try {
13844
14029
  await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
13845
14030
  await ctx.session.upload([file], dir);
13846
14031
  } catch (error) {
13847
- spinner8.stop(`Could not upload ${path56.basename(file)}.`);
14032
+ spinner8.stop(`Could not upload ${path57.basename(file)}.`);
13848
14033
  throw error;
13849
14034
  }
13850
- spinner8.stop(`Uploaded ${path56.basename(file)}`);
14035
+ spinner8.stop(`Uploaded ${path57.basename(file)}`);
13851
14036
  return remote;
13852
14037
  }
13853
14038
  async function confirm14(appName, targetName, envTag, from) {
13854
- const what = `${pc34.cyan(`${appName} (${targetName})`)} from ${pc34.cyan(path56.basename(from))}`;
14039
+ const what = `${pc34.cyan(`${appName} (${targetName})`)} from ${pc34.cyan(path57.basename(from))}`;
13855
14040
  if (isProd(envTag)) {
13856
14041
  const answer = await p63.text({
13857
14042
  message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
@@ -13962,7 +14147,7 @@ Release and domain are shown from what this project recorded.`
13962
14147
  }
13963
14148
 
13964
14149
  // src/commands/test.ts
13965
- import path57 from "node:path";
14150
+ import path58 from "node:path";
13966
14151
  import process43 from "node:process";
13967
14152
  import { Command as Command104 } from "commander";
13968
14153
  import PocketBase6 from "pocketbase";
@@ -13970,21 +14155,21 @@ import pc36 from "picocolors";
13970
14155
  import { x as x6 } from "tinyexec";
13971
14156
  import { detect as detect9 } from "package-manager-detector";
13972
14157
  import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
13973
- import fs52 from "node:fs";
14158
+ import fs53 from "node:fs";
13974
14159
  var testServer = new Command104("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
13975
14160
  const cwd = process43.cwd();
13976
14161
  warnIfKit2(cwd, (m) => console.warn(pc36.yellow(`\u25B2 ${m}`)));
13977
14162
  const email2 = `test-${Math.random().toString(36).slice(2)}@example.com`;
13978
14163
  const password11 = "password";
13979
- const testDataDir = path57.join(cwd, "test-data");
13980
- fs52.rmSync(testDataDir, { recursive: true, force: true });
14164
+ const testDataDir = path58.join(cwd, "test-data");
14165
+ fs53.rmSync(testDataDir, { recursive: true, force: true });
13981
14166
  const { stop, url } = await launchPocketbase(cwd, {
13982
14167
  dir: testDataDir,
13983
- migrationsDir: path57.join(cwd, MIGRATIONS_DIR),
14168
+ migrationsDir: path58.join(cwd, MIGRATIONS_DIR),
13984
14169
  // The app's PocketBase hooks (slug generation, personal teams, …) are part
13985
14170
  // of its behaviour; the suite runs against the same server dev and build
13986
14171
  // start, so it loads them from the same place.
13987
- hooksDir: path57.join(cwd, DATA_DIR, "hooks"),
14172
+ hooksDir: path58.join(cwd, DATA_DIR, "hooks"),
13988
14173
  email: email2,
13989
14174
  password: password11
13990
14175
  });
@@ -14000,7 +14185,7 @@ var testServer = new Command104("test:server").description("run server tests").a
14000
14185
  if (cleanedUp) return;
14001
14186
  cleanedUp = true;
14002
14187
  stop();
14003
- fs52.rmSync(testDataDir, { recursive: true, force: true });
14188
+ fs53.rmSync(testDataDir, { recursive: true, force: true });
14004
14189
  };
14005
14190
  const cleanup = async () => {
14006
14191
  if (cleanedUp) return;
@@ -14109,8 +14294,8 @@ function stubPagesPlugin() {
14109
14294
  }
14110
14295
 
14111
14296
  // src/commands/routes.ts
14112
- import fs53 from "node:fs";
14113
- import path58 from "node:path";
14297
+ import fs54 from "node:fs";
14298
+ import path59 from "node:path";
14114
14299
  import { Command as Command105 } from "commander";
14115
14300
  var HTTP_METHODS = /* @__PURE__ */ new Set([
14116
14301
  "GET",
@@ -14124,30 +14309,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
14124
14309
  ]);
14125
14310
  var routes = new Command105("routes").description("list routes").configureHelp(helpConfig).action(async () => {
14126
14311
  const { workspaceRootDir, routesDir } = await getWorkspace();
14127
- const routesRoot = path58.join(workspaceRootDir, routesDir);
14312
+ const routesRoot = path59.join(workspaceRootDir, routesDir);
14128
14313
  const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
14129
14314
  found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
14130
14315
  printTable(found);
14131
14316
  });
14132
14317
  function walk(root, dir) {
14133
- const entries = fs53.readdirSync(dir, { withFileTypes: true });
14318
+ const entries = fs54.readdirSync(dir, { withFileTypes: true });
14134
14319
  const routes2 = [];
14135
14320
  const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
14136
14321
  if (hasLeaf) {
14137
- const id = "/" + path58.relative(root, dir).split(path58.sep).filter(Boolean).join("/");
14322
+ const id = "/" + path59.relative(root, dir).split(path59.sep).filter(Boolean).join("/");
14138
14323
  const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
14139
14324
  const methods = /* @__PURE__ */ new Set();
14140
14325
  for (const entry of entries) {
14141
14326
  if (!entry.isFile()) continue;
14142
14327
  if (entry.name.endsWith("+page.svelte")) methods.add("GET");
14143
14328
  if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
14144
- extractMethods(path58.join(dir, entry.name)).forEach((m) => methods.add(m));
14329
+ extractMethods(path59.join(dir, entry.name)).forEach((m) => methods.add(m));
14145
14330
  }
14146
14331
  }
14147
14332
  routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
14148
14333
  }
14149
14334
  for (const entry of entries) {
14150
- if (entry.isDirectory()) routes2.push(...walk(root, path58.join(dir, entry.name)));
14335
+ if (entry.isDirectory()) routes2.push(...walk(root, path59.join(dir, entry.name)));
14151
14336
  }
14152
14337
  return routes2;
14153
14338
  }
@@ -14156,7 +14341,7 @@ function isRouteFile(name) {
14156
14341
  }
14157
14342
  function extractMethods(file) {
14158
14343
  try {
14159
- const content = fs53.readFileSync(file, "utf8");
14344
+ const content = fs54.readFileSync(file, "utf8");
14160
14345
  const methods = [];
14161
14346
  const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
14162
14347
  let match;
@@ -14197,8 +14382,8 @@ function printTable(routes2) {
14197
14382
  }
14198
14383
 
14199
14384
  // src/commands/i18n.ts
14200
- import fs54 from "node:fs";
14201
- import path59 from "node:path";
14385
+ import fs55 from "node:fs";
14386
+ import path60 from "node:path";
14202
14387
  import process44 from "node:process";
14203
14388
  import { Command as Command106 } from "commander";
14204
14389
  import { x as x7 } from "tinyexec";
@@ -14207,7 +14392,7 @@ import { resolveCommand as resolveCommand8 } from "package-manager-detector/comm
14207
14392
  var WUCHALE_CONFIG_NAMES = ["js", "mjs", "ts", "mts"].map((ext) => `wuchale.config.${ext}`);
14208
14393
  async function runWuchale(extraArgs) {
14209
14394
  const cwd = findWorkspaceRoot() ?? process44.cwd();
14210
- if (!WUCHALE_CONFIG_NAMES.some((name) => fs54.existsSync(path59.join(cwd, name)))) {
14395
+ if (!WUCHALE_CONFIG_NAMES.some((name) => fs55.existsSync(path60.join(cwd, name)))) {
14211
14396
  throw new Error("No wuchale config found. Run `vela enable i18n` to set up i18n.");
14212
14397
  }
14213
14398
  const pm = (await detect10({ cwd }))?.name ?? "npm";
@@ -14335,7 +14520,7 @@ import pc39 from "picocolors";
14335
14520
 
14336
14521
  // src/lib/cms-backend.ts
14337
14522
  import { createRequire as createRequire4 } from "node:module";
14338
- import path60 from "node:path";
14523
+ import path61 from "node:path";
14339
14524
  import process46 from "node:process";
14340
14525
  import { pathToFileURL as pathToFileURL3 } from "node:url";
14341
14526
  import pc38 from "picocolors";
@@ -14343,7 +14528,7 @@ var DEFAULT_PROJECT = "default";
14343
14528
  async function loadBackendModule(root) {
14344
14529
  let entry;
14345
14530
  try {
14346
- entry = createRequire4(path60.join(root, "package.json")).resolve("@velastack/cms/backend");
14531
+ entry = createRequire4(path61.join(root, "package.json")).resolve("@velastack/cms/backend");
14347
14532
  } catch {
14348
14533
  throw new Error(
14349
14534
  `@velastack/cms is not installed in this project.
@@ -14361,8 +14546,8 @@ async function withCmsBackend(fn, cwd = process46.cwd()) {
14361
14546
  const { createCmsBackend } = await loadBackendModule(root);
14362
14547
  const dataDir2 = localDataDir(root);
14363
14548
  const backend3 = createCmsBackend({
14364
- dbPath: path60.join(dataDir2, "cms.sqlite"),
14365
- uploadDir: path60.join(dataDir2, "uploads")
14549
+ dbPath: path61.join(dataDir2, "cms.sqlite"),
14550
+ uploadDir: path61.join(dataDir2, "uploads")
14366
14551
  });
14367
14552
  try {
14368
14553
  return await fn(backend3);
@@ -14644,14 +14829,14 @@ var program = new Command117().name(package_default.name).description(package_de
14644
14829
  program.hook("preAction", (_thisCommand, actionCommand) => {
14645
14830
  const envRoot = findWorkspaceRoot() ?? process50.cwd();
14646
14831
  dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
14647
- const path61 = getCommandPath(actionCommand);
14648
- if (NO_BACKEND_COMMMANDS.has(path61)) return;
14649
- const top = path61.split(" ", 1)[0];
14832
+ const path62 = getCommandPath(actionCommand);
14833
+ if (NO_BACKEND_COMMMANDS.has(path62)) return;
14834
+ const top = path62.split(" ", 1)[0];
14650
14835
  if (NO_BACKEND_COMMMANDS.has(top)) return;
14651
14836
  if (!hasBackend()) {
14652
14837
  if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
14653
14838
  p72.log.error(
14654
- `${pc45.cyan(`vela ${path61}`)} needs a backend, and this project does not have one.
14839
+ `${pc45.cyan(`vela ${path62}`)} needs a backend, and this project does not have one.
14655
14840
 
14656
14841
  There is no PocketBase database here for it to talk to.
14657
14842
 
@@ -14661,7 +14846,7 @@ To add one, run ${pc45.cyan("vela enable backend")}.`
14661
14846
  p72.cancel("Operation failed.");
14662
14847
  process50.exit(1);
14663
14848
  }
14664
- if (SELF_CREDENTIALED_COMMANDS.has(path61)) return;
14849
+ if (SELF_CREDENTIALED_COMMANDS.has(path62)) return;
14665
14850
  if (!process50.env.POCKETBASE_SUPERUSER_EMAIL || !process50.env.POCKETBASE_SUPERUSER_PASSWORD) {
14666
14851
  p72.log.error(
14667
14852
  `PocketBase superuser credentials are required.