openship 0.6.7 → 0.6.9

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.
Files changed (67) hide show
  1. package/dist/bare-FA66N7GC.js +29 -0
  2. package/dist/{chunk-LHFXSC36.js → chunk-3MP6ACKM.js} +183 -87
  3. package/dist/{chunk-MEE6OZFP.js → chunk-5DJOB7IX.js} +3 -3
  4. package/dist/{chunk-VQM6JHJB.js → chunk-5UXHT6ED.js} +9 -9
  5. package/dist/{chunk-PPEBIY5F.js → chunk-634DDFT5.js} +35 -12
  6. package/dist/{chunk-XWHWTHEL.js → chunk-6GU6JSK6.js} +21 -2
  7. package/dist/{chunk-QHMDCYZ3.js → chunk-7PEXM2UI.js} +213 -45
  8. package/dist/{chunk-RDXT4BQB.js → chunk-7YBWXEM6.js} +4 -4
  9. package/dist/{chunk-H4FS5BED.js → chunk-AHJYP7DG.js} +13 -11
  10. package/dist/{chunk-VSTFHUCV.js → chunk-BO6CY4V2.js} +109 -23
  11. package/dist/{chunk-J3K6XABC.js → chunk-D3OEMXYP.js} +3 -3
  12. package/dist/{chunk-UWEV6XTS.js → chunk-D6HU4VUZ.js} +1 -1
  13. package/dist/{chunk-S6B2Z3OO.js → chunk-ENKJ7XIF.js} +21 -11
  14. package/dist/{chunk-DDFUESPJ.js → chunk-FCGJN5Q5.js} +9 -9
  15. package/dist/{chunk-BLEXTYRK.js → chunk-GNOMEMNI.js} +1 -1
  16. package/dist/{chunk-NRTJRNAE.js → chunk-IAMOUDHY.js} +138 -54
  17. package/dist/{chunk-CIJV43LH.js → chunk-MUWVC5R4.js} +161 -39
  18. package/dist/{chunk-ZPJ74LXE.js → chunk-NIYD7MD2.js} +197 -45
  19. package/dist/{chunk-FZ6QCF6B.js → chunk-NPSRGIHV.js} +2 -2
  20. package/dist/{chunk-2GWYYHOR.js → chunk-NRU2EBYZ.js} +2 -2
  21. package/dist/{chunk-J2XM3QSP.js → chunk-NUT6HKK6.js} +5 -5
  22. package/dist/{chunk-H3WT3A6R.js → chunk-P7RCYELG.js} +1 -1
  23. package/dist/{chunk-FYPFEDPZ.js → chunk-R5DC5PEF.js} +1 -1
  24. package/dist/{chunk-RXQBD4ZY.js → chunk-RHLNVZMS.js} +2 -2
  25. package/dist/{chunk-WU54BXFE.js → chunk-SK4FFCFR.js} +1 -1
  26. package/dist/{chunk-PVP4RGWT.js → chunk-T46BQOLY.js} +3 -3
  27. package/dist/{chunk-E2X26PXR.js → chunk-T6DVUX4F.js} +1 -1
  28. package/dist/{chunk-5T4UVOM3.js → chunk-TAZZZKYO.js} +1 -1
  29. package/dist/{chunk-GGIAIGUL.js → chunk-UAWY6X7V.js} +34 -12
  30. package/dist/{chunk-2ANV5ZQ5.js → chunk-VAI5VOOI.js} +1 -1
  31. package/dist/{chunk-2VSW6Q6C.js → chunk-WEZFTL4V.js} +655 -62
  32. package/dist/{chunk-GIPJNNI5.js → chunk-X53JXRS4.js} +3 -3
  33. package/dist/{cloud-KRTZ2IL5.js → cloud-2CRDKOWQ.js} +1 -1
  34. package/dist/cloud-REV3DPJH.js +42 -0
  35. package/dist/{detect-G4DR3U2N.js → detect-BBFT5GEU.js} +4 -4
  36. package/dist/{docker-YOVPCIB4.js → docker-EG3QSE6I.js} +10 -10
  37. package/dist/{docker-edge-executor-QFXD3337.js → docker-edge-executor-E5TOTLMR.js} +7 -7
  38. package/dist/edge-import-YJVJUGYC.js +56 -0
  39. package/dist/{edge-preflight-MXERVAMG.js → edge-preflight-QUW4BM7N.js} +13 -13
  40. package/dist/{ensure-container-edge-F4JUNQIK.js → ensure-container-edge-FOEFQ3PI.js} +13 -11
  41. package/dist/{executor-CVPAYYHR.js → executor-NTWDJ3DB.js} +6 -6
  42. package/dist/host-channel-preflight-OI2TRHSG.js +54 -0
  43. package/dist/index.js +158 -72
  44. package/dist/{local-executor-ODC6RANU.js → local-executor-OQ2GRN7K.js} +3 -3
  45. package/dist/{nginx-KLFF43TC.js → nginx-4U4C2XUS.js} +9 -9
  46. package/dist/{noop-NJ72F46T.js → noop-CLLJHCPL.js} +1 -1
  47. package/dist/{openresty-lua-VKWUV4GB.js → openresty-lua-LLWT5XQW.js} +7 -5
  48. package/dist/{privilege-7D3SSOL3.js → privilege-MNDVMDST.js} +5 -5
  49. package/dist/server/index.js +31801 -25560
  50. package/dist/server/migrations/0109_service_build_args.sql +9 -0
  51. package/dist/server/migrations/0110_service_deployment_host_ports.sql +18 -0
  52. package/dist/server/migrations/0111_host_port_claim.sql +381 -0
  53. package/dist/server/migrations/0112_backup_run_execution_lease.sql +12 -0
  54. package/dist/server/migrations/0113_docker_migration_execution_lease.sql +11 -0
  55. package/dist/server/migrations/0114_build_session_execution_lease_index.sql +6 -0
  56. package/dist/server/migrations/0115_orphan_target_key.sql +3 -0
  57. package/dist/server/migrations/0116_domain_ssl_challenge.sql +2 -0
  58. package/dist/server/migrations/meta/_journal.json +56 -0
  59. package/dist/{setup-I5AJC6NJ.js → setup-IFIMPQZJ.js} +12 -12
  60. package/dist/{ssh-client-625VWGKP.js → ssh-client-2XWZCMGI.js} +2 -2
  61. package/dist/up-RC5ZQIAD.js +61 -0
  62. package/package.json +1 -1
  63. package/dist/bare-7QD623QV.js +0 -29
  64. package/dist/cloud-KNNABE3O.js +0 -40
  65. package/dist/edge-import-CRFVSR6P.js +0 -56
  66. package/dist/host-channel-preflight-QTDNGLCK.js +0 -54
  67. package/dist/up-QXTOOVXC.js +0 -61
@@ -9,31 +9,32 @@ import {
9
9
  readDeclaredPair,
10
10
  readMaybeInContainer,
11
11
  validateCertFor
12
- } from "./chunk-NRTJRNAE.js";
12
+ } from "./chunk-IAMOUDHY.js";
13
13
  import {
14
14
  EDGE_CHALLENGE_HOST_DIR,
15
15
  EDGE_CONTAINER_MOUNTS,
16
16
  EDGE_HOST_PATHS,
17
17
  OPENRESTY_DEFAULT_PATHS
18
- } from "./chunk-QHMDCYZ3.js";
18
+ } from "./chunk-7PEXM2UI.js";
19
19
  import {
20
20
  privilegedExecutor,
21
21
  rootChecked,
22
22
  rootOrDegrade
23
- } from "./chunk-PVP4RGWT.js";
23
+ } from "./chunk-T46BQOLY.js";
24
24
  import {
25
25
  envOps,
26
26
  opScript
27
- } from "./chunk-BLEXTYRK.js";
27
+ } from "./chunk-GNOMEMNI.js";
28
28
  import {
29
29
  resolveEnvironment
30
- } from "./chunk-FZ6QCF6B.js";
30
+ } from "./chunk-NPSRGIHV.js";
31
31
  import {
32
32
  sq
33
- } from "./chunk-H3WT3A6R.js";
33
+ } from "./chunk-P7RCYELG.js";
34
34
  import {
35
35
  EdgeConflictError,
36
36
  EdgeMigrateRequested,
37
+ detectEdgeContainer,
37
38
  edgeCrashReason,
38
39
  edgeFailureReason,
39
40
  edgeIsBroken,
@@ -44,16 +45,16 @@ import {
44
45
  sanitizeEdgeVhosts,
45
46
  sq as sq2,
46
47
  stopTargetsForStatus
47
- } from "./chunk-GIPJNNI5.js";
48
+ } from "./chunk-X53JXRS4.js";
48
49
  import {
49
50
  waitForPortListening
50
- } from "./chunk-VSTFHUCV.js";
51
+ } from "./chunk-BO6CY4V2.js";
51
52
  import {
52
53
  EDGE_CONTAINER_NAME,
53
54
  probeExec,
54
55
  tryExec,
55
56
  withReason
56
- } from "./chunk-UWEV6XTS.js";
57
+ } from "./chunk-D6HU4VUZ.js";
57
58
  import {
58
59
  formatDuration,
59
60
  systemDebug
@@ -64,11 +65,12 @@ import {
64
65
  answered,
65
66
  buildEdgeImageRef,
66
67
  compareSemver,
68
+ isLoopbackHost,
67
69
  parseProxyValue,
68
70
  safeErrorMessage,
69
71
  sanitizeProxySettings,
70
72
  shellQuote
71
- } from "./chunk-2VSW6Q6C.js";
73
+ } from "./chunk-WEZFTL4V.js";
72
74
 
73
75
  // ../../packages/adapters/src/system/managed-image.ts
74
76
  import { posix } from "path";
@@ -425,8 +427,9 @@ function parseUpstreams(config) {
425
427
  let m;
426
428
  while ((m = re.exec(config)) !== null) {
427
429
  const name = m[1];
428
- const server = m[2].match(/(?:^|[\s;{])server\s+([^;\s]+)/);
429
- if (name && server?.[1]) map.set(name, server[1].trim());
430
+ const body = m[2] ?? "";
431
+ const targets = [...body.matchAll(/(?:^|[\s;{])server\s+([^;\s]+)/g)].map((server) => server[1]?.trim()).filter((target) => Boolean(target));
432
+ if (name && targets.length > 0) map.set(name, targets);
430
433
  }
431
434
  return map;
432
435
  }
@@ -439,14 +442,55 @@ function resolveProxyTarget(proxyPass, upstreams) {
439
442
  const scheme = m[1];
440
443
  const authority = m[2];
441
444
  const host = authority.replace(/:\d+$/, "");
442
- if (upstreams.has(host)) return { url: `${scheme}${upstreams.get(host)}` };
445
+ const declaredUpstream = upstreams.get(authority);
446
+ if (declaredUpstream?.[0]) return { url: `${scheme}${declaredUpstream[0]}` };
443
447
  const isIp = /^\d{1,3}(\.\d{1,3}){3}$/.test(host);
444
448
  if (host === "localhost" || host === "ip6-localhost") {
445
449
  return { url: raw.replace(/^(https?:\/\/)[^/:]+/i, "$1127.0.0.1") };
446
450
  }
447
- if (isIp || host.includes(".")) return { url: raw };
451
+ if (isIp || host.includes(".") || host.startsWith("[") && host.endsWith("]")) {
452
+ return { url: raw };
453
+ }
448
454
  return { reason: `proxy_pass host "${host}" is an undeclared upstream \u2014 not migratable` };
449
455
  }
456
+ function strictLoopbackUpstreamPorts(config) {
457
+ const normalized = stripComments(config);
458
+ const upstreams = parseUpstreams(normalized);
459
+ const ports = /* @__PURE__ */ new Set();
460
+ for (const match of normalized.matchAll(/(?:^|[;{}\s])proxy_pass\s+([^;]+);/g)) {
461
+ const raw = match[1]?.trim();
462
+ if (!raw) continue;
463
+ const resolved = resolveProxyTarget(raw, upstreams);
464
+ if ("reason" in resolved) {
465
+ if (/\/\/unix:/i.test(raw)) continue;
466
+ throw new Error(`Cannot inventory Openship edge routes: ${resolved.reason}`);
467
+ }
468
+ const authority = raw.match(/^https?:\/\/([^/]+)/i)?.[1];
469
+ const scheme = raw.match(/^(https?:\/\/)/i)?.[1];
470
+ const targets = authority && scheme && upstreams.has(authority) ? upstreams.get(authority).map((target) => `${scheme}${target}`) : [resolved.url];
471
+ for (const target of targets) {
472
+ let url;
473
+ try {
474
+ url = new URL(target);
475
+ } catch {
476
+ throw new Error(`Cannot inventory Openship edge routes: invalid proxy_pass "${raw}"`);
477
+ }
478
+ if (!isLoopbackHost(url.hostname)) continue;
479
+ const port = url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80;
480
+ if (!Number.isSafeInteger(port) || port < 1 || port > 65535) {
481
+ throw new Error(`Cannot inventory Openship edge routes: invalid loopback port in "${raw}"`);
482
+ }
483
+ ports.add(port);
484
+ }
485
+ }
486
+ return ports;
487
+ }
488
+ function parseStrictEdgeConfig(raw) {
489
+ return {
490
+ ...parseNginxConfig(raw),
491
+ loopbackUpstreamPorts: strictLoopbackUpstreamPorts(raw)
492
+ };
493
+ }
450
494
  function locationBlocks(serverBody) {
451
495
  const out = [];
452
496
  const re = /(?:^|[\s;}])location\s+([^{]+?)\s*\{/g;
@@ -538,7 +582,9 @@ function resolveStaticRoot(root, prefix) {
538
582
  }
539
583
  function parseServer(body, source, upstreams, prefix) {
540
584
  const warnings = [];
541
- const names = firstDirective(body, "server_name")?.split(/\s+/).filter((n) => n && n !== "_" && !n.startsWith("~") && !LOOPBACK_SERVER_NAMES.has(n.toLowerCase())) ?? [];
585
+ const names = firstDirective(body, "server_name")?.split(/\s+/).filter(
586
+ (n) => n && n !== "_" && !n.startsWith("~") && !LOOPBACK_SERVER_NAMES.has(n.toLowerCase())
587
+ ) ?? [];
542
588
  const listens = [...body.matchAll(/(?:^|[;{\s])listen\s+([^;]+);/g)].map((m) => m[1]);
543
589
  const ssl = listens.some((l) => /\bssl\b/.test(l) || /\b443\b/.test(l));
544
590
  const root = firstDirective(body, "root");
@@ -634,6 +680,35 @@ async function scanOpenshipEdge(executor) {
634
680
  const fromContainer = await tryExec(executor, containerCommand(container, cat));
635
681
  return parseNginxConfig(fromContainer ?? "");
636
682
  }
683
+ async function scanOpenshipEdgeStrict(executor, knownContainer) {
684
+ const detected = await detectEdgeContainer(executor);
685
+ if (!detected) {
686
+ const bareConfig = await dumpResolvedConfig(executor, ["openresty"]);
687
+ if (bareConfig) return parseStrictEdgeConfig(bareConfig);
688
+ throw new Error(
689
+ "Cannot read Openship edge routes: neither Docker nor bare OpenResty inventory is available"
690
+ );
691
+ }
692
+ if (!detected.exists) {
693
+ const bareConfig = await dumpResolvedConfig(executor, ["openresty"]);
694
+ if (bareConfig) return parseStrictEdgeConfig(bareConfig);
695
+ throw new Error(
696
+ "Cannot read Openship edge routes: no running Openship edge or bare OpenResty inventory is available"
697
+ );
698
+ }
699
+ if (!detected.running) {
700
+ throw new Error("Cannot read Openship edge routes: the edge container is not running");
701
+ }
702
+ const container = knownContainer ?? detected.name;
703
+ if (!container) throw new Error("Cannot read Openship edge routes: container identity missing");
704
+ const fromContainer = await executor.exec(
705
+ containerCommand(container, "openresty -T 2>/dev/null")
706
+ );
707
+ if (!fromContainer.trim() || !/server\s*\{/.test(fromContainer)) {
708
+ throw new Error("Cannot read Openship edge routes: active OpenResty config dump was empty");
709
+ }
710
+ return parseStrictEdgeConfig(fromContainer);
711
+ }
637
712
 
638
713
  // ../../packages/adapters/src/system/proxy/import/caddy.ts
639
714
  var CADDYFILE_PATHS = ["/etc/caddy/Caddyfile", "/etc/Caddyfile"];
@@ -1613,6 +1688,24 @@ function makeApi(exec, kind, ours, container) {
1613
1688
  }));
1614
1689
  return scan;
1615
1690
  };
1691
+ let strictLoopbackPorts = null;
1692
+ const listLoopbackUpstreamPortsStrict = (opts = {}) => {
1693
+ if (!ours) {
1694
+ return Promise.reject(
1695
+ new Error("Strict loopback upstream inventory is only available for the Openship edge")
1696
+ );
1697
+ }
1698
+ if (opts.refresh || !strictLoopbackPorts) {
1699
+ const nextScan = scanOpenshipEdgeStrict(exec, container).then(
1700
+ ({ loopbackUpstreamPorts }) => loopbackUpstreamPorts
1701
+ );
1702
+ strictLoopbackPorts = nextScan;
1703
+ void nextScan.catch(() => {
1704
+ if (strictLoopbackPorts === nextScan) strictLoopbackPorts = null;
1705
+ });
1706
+ }
1707
+ return strictLoopbackPorts;
1708
+ };
1616
1709
  const siteFor = async (host) => {
1617
1710
  const target = host.toLowerCase();
1618
1711
  const { sites } = await listSites();
@@ -1644,6 +1737,7 @@ function makeApi(exec, kind, ours, container) {
1644
1737
  ours,
1645
1738
  container,
1646
1739
  listSites,
1740
+ listLoopbackUpstreamPortsStrict,
1647
1741
  sitesByPort: async () => buildProxyRouteIndex((await listSites()).sites),
1648
1742
  siteFor,
1649
1743
  certFor: async (host) => (await certCandidateFor(host)).cert,
@@ -2310,7 +2404,7 @@ function edgeHostExecutor(executor) {
2310
2404
  });
2311
2405
  }
2312
2406
  async function containerEdgeProvider(executor, container, opts) {
2313
- const { NginxProvider: Provider } = await import("./nginx-KLFF43TC.js");
2407
+ const { NginxProvider: Provider } = await import("./nginx-4U4C2XUS.js");
2314
2408
  return new Provider({
2315
2409
  ...opts,
2316
2410
  // Vhosts go to the BIND-MOUNTED HOST dir (so every host-side reader — the
@@ -2334,8 +2428,8 @@ async function containerEdgeProvider(executor, container, opts) {
2334
2428
  });
2335
2429
  }
2336
2430
  async function localContainerEdgeProvider(container, opts) {
2337
- const { DockerEdgeExecutor } = await import("./docker-edge-executor-QFXD3337.js");
2338
- const { NginxProvider: Provider } = await import("./nginx-KLFF43TC.js");
2431
+ const { DockerEdgeExecutor } = await import("./docker-edge-executor-E5TOTLMR.js");
2432
+ const { NginxProvider: Provider } = await import("./nginx-4U4C2XUS.js");
2339
2433
  return new Provider({
2340
2434
  ...opts,
2341
2435
  paths: OPENRESTY_DEFAULT_PATHS,
@@ -2356,20 +2450,40 @@ async function localContainerEdgeProvider(container, opts) {
2356
2450
  containerEdge: true
2357
2451
  });
2358
2452
  }
2359
- async function startEdgeContainer(executor, container, image, onLog) {
2453
+ async function startEdgeContainer(executor, container, image, onLog, mounts) {
2360
2454
  await sanitizeEdgeVhosts(executor, EDGE_HOST_PATHS.sitesDir, onLog).catch(() => {
2361
2455
  });
2362
2456
  await executor.exec(`docker rm -f ${sq(container)} 2>/dev/null || true`).catch(() => {
2363
2457
  });
2364
2458
  const run = await executor.streamExec(
2365
- buildEdgeRunCommand(container, image),
2459
+ buildEdgeRunCommand(container, image, mounts),
2366
2460
  onLog
2367
2461
  );
2368
2462
  invalidateEdgeContainer(executor);
2369
2463
  return run.code === 0;
2370
2464
  }
2371
- function buildEdgeRunCommand(container, image) {
2372
- const mounts = EDGE_CONTAINER_MOUNTS.map(
2465
+ async function resolveEdgeContainerMounts(executor) {
2466
+ return Promise.all(
2467
+ EDGE_CONTAINER_MOUNTS.map(async (mount) => {
2468
+ let host;
2469
+ try {
2470
+ host = (await executor.exec(`cd ${sq(mount.host)} && pwd -P`)).trim();
2471
+ } catch (err) {
2472
+ throw new Error(
2473
+ `Could not resolve edge bind-mount source ${mount.host} on the target host: ${safeErrorMessage(err)}`
2474
+ );
2475
+ }
2476
+ if (!host.startsWith("/") || host.includes("\n")) {
2477
+ throw new Error(
2478
+ `Could not resolve edge bind-mount source ${mount.host} on the target host: expected one absolute path, received ${JSON.stringify(host)}.`
2479
+ );
2480
+ }
2481
+ return { host, container: mount.container };
2482
+ })
2483
+ );
2484
+ }
2485
+ function buildEdgeRunCommand(container, image, edgeMounts = EDGE_CONTAINER_MOUNTS) {
2486
+ const mounts = edgeMounts.map(
2373
2487
  // `:z` relabels for SELinux-enforcing hosts; a no-op elsewhere.
2374
2488
  (m) => `-v ${sq(`${m.host}:${m.container}:z`)}`
2375
2489
  ).join(" ");
@@ -2382,10 +2496,27 @@ function buildEdgeRunCommand(container, image) {
2382
2496
  sq(image)
2383
2497
  ].join(" ");
2384
2498
  }
2385
- function makeEdgeStart(executor, container, opts) {
2499
+ async function edgeContainerMountsMatch(executor, container, expected) {
2500
+ let raw;
2501
+ try {
2502
+ raw = await executor.exec(
2503
+ `docker inspect -f '{{range .HostConfig.Binds}}{{println .}}{{end}}' ${sq(container)}`
2504
+ );
2505
+ } catch {
2506
+ return null;
2507
+ }
2508
+ const actual = /* @__PURE__ */ new Map();
2509
+ for (const line of raw.split("\n")) {
2510
+ const [source, destination] = line.trim().split(":");
2511
+ if (!source || !destination) continue;
2512
+ actual.set(destination, source);
2513
+ }
2514
+ return expected.every((mount) => actual.get(mount.container) === mount.host);
2515
+ }
2516
+ function makeEdgeStart(executor, container, opts, mounts) {
2386
2517
  const { onLog } = opts;
2387
2518
  return async (image) => {
2388
- if (!await startEdgeContainer(executor, container, image, onLog)) return false;
2519
+ if (!await startEdgeContainer(executor, container, image, onLog, mounts)) return false;
2389
2520
  const verdict = await verifyEdgeServing(executor, container, {
2390
2521
  timeoutMs: opts.verifyTimeoutMs ?? 3e4
2391
2522
  });
@@ -2420,6 +2551,17 @@ async function ensureContainerEdge(executor, opts) {
2420
2551
  const { onLog } = opts;
2421
2552
  const container = opts.container?.trim() || EDGE_CONTAINER_NAME;
2422
2553
  const image = resolveEdgeImage(opts.image);
2554
+ let resolvedMounts = null;
2555
+ const targetMounts = async (checked) => {
2556
+ if (resolvedMounts) return resolvedMounts;
2557
+ const host = checked ?? await rootOrDegrade(executor, {
2558
+ purpose: "Resolving the edge's bind-mount sources",
2559
+ consequence: "Docker may mount a different host directory than Openship writes.",
2560
+ report: (message) => onLog(log5(message, "warn"))
2561
+ });
2562
+ resolvedMounts = await resolveEdgeContainerMounts(host);
2563
+ return resolvedMounts;
2564
+ };
2423
2565
  const existing = await resolveOurEdgeContainer(executor, { fresh: true });
2424
2566
  if (existing) {
2425
2567
  const verdict = await verifyEdgeServing(executor, existing);
@@ -2427,27 +2569,35 @@ async function ensureContainerEdge(executor, opts) {
2427
2569
  onLog(log5(`The edge container exists but isn't serving: ${verdict.reason}`, "warn"));
2428
2570
  onLog(log5("Recreating it...", "warn"));
2429
2571
  } else {
2430
- const current = await containerImageRef(executor, existing);
2431
- const stale = current != null && current !== image;
2432
- if (stale) {
2433
- const start = makeEdgeStart(executor, existing, opts);
2434
- const swap = await swapManagedImage(executor, {
2435
- kind: "edge",
2436
- from: current ?? image,
2437
- to: image,
2438
- label: "edge",
2439
- onLog,
2440
- start
2441
- });
2442
- return {
2443
- container: existing,
2444
- image,
2445
- converted: false,
2446
- updated: swap.swapped,
2447
- edgeDown: swap.down
2448
- };
2572
+ const mounts2 = await targetMounts();
2573
+ const mountsMatch = await edgeContainerMountsMatch(executor, existing, mounts2);
2574
+ if (mountsMatch === false) {
2575
+ onLog(
2576
+ log5("The edge container uses stale or non-canonical bind mounts; recreating it...", "warn")
2577
+ );
2578
+ } else {
2579
+ const current = await containerImageRef(executor, existing);
2580
+ const stale = current != null && current !== image;
2581
+ if (stale) {
2582
+ const start = makeEdgeStart(executor, existing, opts, mounts2);
2583
+ const swap = await swapManagedImage(executor, {
2584
+ kind: "edge",
2585
+ from: current ?? image,
2586
+ to: image,
2587
+ label: "edge",
2588
+ onLog,
2589
+ start
2590
+ });
2591
+ return {
2592
+ container: existing,
2593
+ image,
2594
+ converted: false,
2595
+ updated: swap.swapped,
2596
+ edgeDown: swap.down
2597
+ };
2598
+ }
2599
+ return { container: existing, image, converted: false };
2449
2600
  }
2450
- return { container: existing, image, converted: false };
2451
2601
  }
2452
2602
  }
2453
2603
  if (!await dockerAvailable(executor)) {
@@ -2482,10 +2632,11 @@ async function ensureContainerEdge(executor, opts) {
2482
2632
  );
2483
2633
  });
2484
2634
  }
2635
+ const mounts = await targetMounts(hostState);
2485
2636
  const clear = await ensureEdgeClear(executor, opts.config, onLog);
2486
2637
  try {
2487
2638
  onLog(log5("Starting the edge container..."));
2488
- if (!await startEdgeContainer(executor, container, image, onLog)) {
2639
+ if (!await startEdgeContainer(executor, container, image, onLog, mounts)) {
2489
2640
  throw new Error("the edge container failed to start");
2490
2641
  }
2491
2642
  const verdict = await verifyEdgeServing(executor, container, {
@@ -2535,6 +2686,7 @@ export {
2535
2686
  resolveEdgeImage,
2536
2687
  containerEdgeProvider,
2537
2688
  localContainerEdgeProvider,
2689
+ resolveEdgeContainerMounts,
2538
2690
  buildEdgeRunCommand,
2539
2691
  verifyEdgeServing,
2540
2692
  ensureContainerEdge,
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  sq
7
- } from "./chunk-H3WT3A6R.js";
7
+ } from "./chunk-P7RCYELG.js";
8
8
  import {
9
9
  formatDuration,
10
10
  isRemoteConnectionError,
@@ -17,7 +17,7 @@ import {
17
17
  parseSystemArch,
18
18
  parseSystemOs,
19
19
  safeErrorMessage
20
- } from "./chunk-2VSW6Q6C.js";
20
+ } from "./chunk-WEZFTL4V.js";
21
21
 
22
22
  // ../../packages/adapters/src/system/elevated-executor.ts
23
23
  import { randomBytes } from "crypto";
@@ -13,11 +13,11 @@ var CloudInfraProvider = class {
13
13
  async registerRoute(route) {
14
14
  void route;
15
15
  }
16
- async removeRoute(domain) {
16
+ async removeRoute(domain, _opts) {
17
17
  void domain;
18
18
  }
19
19
  // ── SSL ──────────────────────────────────────────────────────────────
20
- async provisionCert(domain) {
20
+ async provisionCert(domain, _opts) {
21
21
  return { domain, expiresAt: "", issuer: "oblien", verified: false };
22
22
  }
23
23
  async renewCert(domain) {
@@ -19,16 +19,16 @@ import {
19
19
  rollbackEdgeTakeover,
20
20
  scanImportableSites,
21
21
  unreachableStaticRoots
22
- } from "./chunk-ZPJ74LXE.js";
22
+ } from "./chunk-NIYD7MD2.js";
23
23
  import {
24
24
  LocalExecutor
25
- } from "./chunk-E2X26PXR.js";
25
+ } from "./chunk-T6DVUX4F.js";
26
26
  import {
27
27
  ourEdgeContainerRunning
28
- } from "./chunk-GIPJNNI5.js";
28
+ } from "./chunk-X53JXRS4.js";
29
29
  import {
30
30
  isOurEdgeContainer
31
- } from "./chunk-UWEV6XTS.js";
31
+ } from "./chunk-D6HU4VUZ.js";
32
32
 
33
33
  // src/lib/edge-preflight.ts
34
34
  import { spawnSync } from "child_process";
@@ -243,7 +243,7 @@ async function repairEdgeConflict(mode, apiPort, onLog) {
243
243
  }
244
244
  spawnSync("docker", ["restart", "openship-edge"], { stdio: "ignore" });
245
245
  if (mode === "migrate" && scan.sites.length > 0) {
246
- const { importMigratedSites } = await import("./edge-import-CRFVSR6P.js");
246
+ const { importMigratedSites } = await import("./edge-import-YJVJUGYC.js");
247
247
  const outcome = await importMigratedSites(apiPort, scan.sites, certPems);
248
248
  if (outcome.registered.length === 0) {
249
249
  return {
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  shellQuote
7
- } from "./chunk-2VSW6Q6C.js";
7
+ } from "./chunk-WEZFTL4V.js";
8
8
 
9
9
  // ../../packages/adapters/src/system/local-shell.ts
10
10
  import { execFile } from "child_process";
@@ -7,7 +7,7 @@ import {
7
7
  COMPONENT_INSTALLERS,
8
8
  checkAll,
9
9
  checkComponents
10
- } from "./chunk-ZPJ74LXE.js";
10
+ } from "./chunk-NIYD7MD2.js";
11
11
 
12
12
  // ../../packages/adapters/src/system/state.ts
13
13
  var DEFAULT_STATE_PATH = "/etc/openship/setup-state.json";
@@ -7,9 +7,9 @@ const require = __ospCreateRequire(import.meta.url);
7
7
  var NoopInfraProvider = class {
8
8
  async registerRoute(_route) {
9
9
  }
10
- async removeRoute(_domain) {
10
+ async removeRoute(_domain, _opts) {
11
11
  }
12
- async provisionCert(domain) {
12
+ async provisionCert(domain, _opts) {
13
13
  return { domain, expiresAt: "", issuer: "none", verified: false };
14
14
  }
15
15
  async renewCert(domain) {
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  sq
7
- } from "./chunk-H3WT3A6R.js";
7
+ } from "./chunk-P7RCYELG.js";
8
8
 
9
9
  // ../../packages/adapters/src/runtime/managed-artifact.ts
10
10
  var MANAGED_ARTIFACT_BASE = "/opt/openship";
@@ -4,15 +4,15 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  hostRefusal
7
- } from "./chunk-BLEXTYRK.js";
7
+ } from "./chunk-GNOMEMNI.js";
8
8
  import {
9
9
  elevatedExecutor,
10
10
  resolveEnvironment
11
- } from "./chunk-FZ6QCF6B.js";
11
+ } from "./chunk-NPSRGIHV.js";
12
12
  import {
13
13
  answered,
14
14
  refused
15
- } from "./chunk-2VSW6Q6C.js";
15
+ } from "./chunk-WEZFTL4V.js";
16
16
 
17
17
  // ../../packages/adapters/src/system/privilege.ts
18
18
  function rootChecked(executor, why) {
@@ -8,7 +8,7 @@ import {
8
8
  getLocalShellPath,
9
9
  logEntry,
10
10
  sq
11
- } from "./chunk-H3WT3A6R.js";
11
+ } from "./chunk-P7RCYELG.js";
12
12
 
13
13
  // ../../packages/adapters/src/system/local-executor.ts
14
14
  import { exec, spawn } from "child_process";
@@ -12,7 +12,7 @@ import {
12
12
  HOST_CHANNEL_ROW_CREDENTIALS_UNUSED,
13
13
  hostFirewallRule,
14
14
  safeErrorMessage
15
- } from "./chunk-2VSW6Q6C.js";
15
+ } from "./chunk-WEZFTL4V.js";
16
16
 
17
17
  // ../../packages/adapters/src/system/ssh-client.ts
18
18
  import { Client } from "ssh2";