openship 0.4.7 → 0.4.8

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.
@@ -9,7 +9,7 @@ import {
9
9
  import "./chunk-MZ2WEHHY.js";
10
10
  import "./chunk-L2VOGB2X.js";
11
11
  import "./chunk-4Z5QO7N6.js";
12
- import "./chunk-4TJC4JZQ.js";
12
+ import "./chunk-XPPZ7B2J.js";
13
13
  import "./chunk-OXWDY22G.js";
14
14
  import "./chunk-RPHRPFEH.js";
15
15
  import "./chunk-TYVME3XD.js";
@@ -59,21 +59,39 @@ function sq(value) {
59
59
  function isOurEdgeContainer(name, image) {
60
60
  return /openship-edge/i.test(`${name ?? ""} ${image ?? ""}`);
61
61
  }
62
- async function edgeIsServing(executor, port = 80) {
63
- const running = await tryExec(
64
- executor,
65
- `docker inspect -f '{{.State.Running}}' ${sq(EDGE_CONTAINER_NAME)} 2>/dev/null`
66
- );
67
- if ((running ?? "").trim() !== "true") return false;
68
- const probe = await tryExec(
62
+ function vhostLog(message, level = "info") {
63
+ return { timestamp: (/* @__PURE__ */ new Date()).toISOString(), message, level };
64
+ }
65
+ async function sanitizeEdgeVhosts(executor, sitesDir, onLog) {
66
+ const script = [
67
+ `for f in ${sq(sitesDir)}/*.conf; do`,
68
+ ` [ -f "$f" ] || continue;`,
69
+ // A real server_name is anything that isn't the `_` wildcard.
70
+ ` if ! grep -qE '^[[:space:]]*server_name[[:space:]]+[^_;[:space:]]' "$f"; then`,
71
+ ` echo "dropped-catchall $f"; rm -f "$f"; continue;`,
72
+ ` fi;`,
73
+ ` if grep -qE '[[:space:]]default_server' "$f"; then`,
74
+ ` sed -E 's/([[:space:]]listen[^;]*)[[:space:]]+default_server/\\1/g' "$f" > "$f.osh" && mv "$f.osh" "$f" && echo "unset-default $f";`,
75
+ ` fi;`,
76
+ `done`
77
+ ].join(" ");
78
+ const out = await executor.exec(script).catch(() => "");
79
+ for (const line of out.split("\n").map((l) => l.trim()).filter(Boolean)) {
80
+ const [action, file] = [line.slice(0, line.indexOf(" ")), line.slice(line.indexOf(" ") + 1)];
81
+ if (action === "dropped-catchall") {
82
+ onLog(vhostLog(`Dropped catch-all vhost ${file} \u2014 the edge image provides it.`, "warn"));
83
+ } else if (action === "unset-default") {
84
+ onLog(vhostLog(`Removed default_server from ${file} \u2014 the edge image owns it.`, "warn"));
85
+ }
86
+ }
87
+ }
88
+ async function edgeIsBroken(executor) {
89
+ const status = await tryExec(
69
90
  executor,
70
- containerShell(`wget -q -O /dev/null -T 3 http://127.0.0.1:${port}/ >/dev/null 2>&1; echo $?`)
91
+ `docker inspect -f '{{.State.Status}}' ${sq(EDGE_CONTAINER_NAME)} 2>/dev/null`
71
92
  );
72
- const code = (probe ?? "").trim().split("\n").pop() ?? "1";
73
- return code === "0" || code === "8";
74
- }
75
- function containerShell(command) {
76
- return `docker exec ${sq(EDGE_CONTAINER_NAME)} sh -c ${sq(command)}`;
93
+ const state = (status ?? "").trim();
94
+ return state === "restarting" || state === "exited" || state === "dead";
77
95
  }
78
96
  async function edgeCrashReason(executor) {
79
97
  const logs = await tryExec(
@@ -86,7 +104,7 @@ function edgeFailureReason(containerLog) {
86
104
  const lines = containerLog.split("\n").map((l) => l.trim()).filter(Boolean);
87
105
  const emerg = lines.find((l) => l.includes("[emerg]"));
88
106
  if (emerg) return emerg.replace(/^.*\[emerg\]\s*\d*#\d*:\s*/, "");
89
- return lines.at(-1) ?? null;
107
+ return null;
90
108
  }
91
109
  var EDGE_CONTAINER_NAME = "openship-edge";
92
110
  async function ourEdgeContainerRunning(executor) {
@@ -268,7 +286,8 @@ export {
268
286
  classifyProxy,
269
287
  sq,
270
288
  isOurEdgeContainer,
271
- edgeIsServing,
289
+ sanitizeEdgeVhosts,
290
+ edgeIsBroken,
272
291
  edgeCrashReason,
273
292
  edgeFailureReason,
274
293
  EDGE_CONTAINER_NAME,
@@ -5,7 +5,7 @@ const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  checkGit,
7
7
  installGit
8
- } from "./chunk-UXWAVM4C.js";
8
+ } from "./chunk-SLTYVHU7.js";
9
9
  import {
10
10
  createDockerBuildContext,
11
11
  normalizeDockerRelativePath,
@@ -101,10 +101,10 @@ import {
101
101
  } from "./chunk-W73X43R7.js";
102
102
  import {
103
103
  CloudRuntime
104
- } from "./chunk-XFCDYZUQ.js";
104
+ } from "./chunk-5NYUCONN.js";
105
105
  import {
106
106
  systemCatalog
107
- } from "./chunk-UXWAVM4C.js";
107
+ } from "./chunk-SLTYVHU7.js";
108
108
  import {
109
109
  AwsCrc32,
110
110
  __awaiter,
@@ -149,8 +149,9 @@ import {
149
149
  import {
150
150
  EDGE_CONTAINER_NAME,
151
151
  edgeCrashReason,
152
- invalidateEdgeContainer
153
- } from "./chunk-R5BHFFAV.js";
152
+ invalidateEdgeContainer,
153
+ sanitizeEdgeVhosts
154
+ } from "./chunk-2D3I5G6P.js";
154
155
  import {
155
156
  EDGE_CONTAINER_MOUNTS,
156
157
  EDGE_HOST_STATE_DIR
@@ -13234,7 +13235,7 @@ function renderEnv(opts, host, cfg) {
13234
13235
  // (hides the local row). Written explicitly so the policy is visible in .env.
13235
13236
  `OPENSHIP_HOST_CONTROL=${cfg.hostControl ? "true" : "false"}`,
13236
13237
  `OPENSHIP_IMAGE_REGISTRY=${cfg.registry}`,
13237
- `OPENSHIP_VERSION=${opts.version || (true ? "0.4.7" : "latest")}`,
13238
+ `OPENSHIP_VERSION=${opts.version || (true ? "0.4.8" : "latest")}`,
13238
13239
  `POSTGRES_PASSWORD=${keepSecret(prev, "POSTGRES_PASSWORD")}`,
13239
13240
  `BETTER_AUTH_SECRET=${keepSecret(prev, "BETTER_AUTH_SECRET")}`,
13240
13241
  `INTERNAL_TOKEN=${keepSecret(prev, "INTERNAL_TOKEN")}`,
@@ -13307,7 +13308,14 @@ function compose(args, opts) {
13307
13308
  });
13308
13309
  return r2.status ?? 1;
13309
13310
  }
13310
- function composeUp(opts) {
13311
+ function composePrefetch(opts) {
13312
+ const { buildDir } = materialize(opts);
13313
+ if (buildDir) {
13314
+ return compose(["pull", "postgres", "redis"], { withBuildOverride: true }) === 0 && compose(["build"], { withBuildOverride: true }) === 0;
13315
+ }
13316
+ return compose(["pull"]) === 0;
13317
+ }
13318
+ async function composeUp(opts) {
13311
13319
  const { buildDir, cfg, envChanged } = materialize(opts);
13312
13320
  const apiPort = cfg.apiPort;
13313
13321
  const dashPort = cfg.dashPort;
@@ -13323,12 +13331,20 @@ function composeUp(opts) {
13323
13331
  if (dbVolumeExists(project)) {
13324
13332
  reconcileDbPassword(env.POSTGRES_USER || "openship", env.POSTGRES_PASSWORD ?? "");
13325
13333
  }
13334
+ await sanitizeEdgeVhosts(
13335
+ new LocalExecutor(),
13336
+ EDGE_SITES_HOST_DIR,
13337
+ (l2) => console.log(` ${l2.message}`)
13338
+ ).catch(() => {
13339
+ });
13326
13340
  if (buildDir) {
13327
- if (compose(["pull", "postgres", "redis"], { withBuildOverride: true }) !== 0) {
13328
- return { ok: false, apiPort, dashPort };
13329
- }
13330
- if (compose(["build"], { withBuildOverride: true }) !== 0) {
13331
- return { ok: false, apiPort, dashPort };
13341
+ if (!opts.alreadyFetched) {
13342
+ if (compose(["pull", "postgres", "redis"], { withBuildOverride: true }) !== 0) {
13343
+ return { ok: false, apiPort, dashPort };
13344
+ }
13345
+ if (compose(["build"], { withBuildOverride: true }) !== 0) {
13346
+ return { ok: false, apiPort, dashPort };
13347
+ }
13332
13348
  }
13333
13349
  if (up({ withBuildOverride: true }) !== 0) {
13334
13350
  return { ok: false, apiPort, dashPort };
@@ -13337,7 +13353,9 @@ function composeUp(opts) {
13337
13353
  writeInstallMethod("compose");
13338
13354
  return { ok: true, apiPort, dashPort };
13339
13355
  }
13340
- if (compose(["pull"]) !== 0) return { ok: false, apiPort, dashPort };
13356
+ if (!opts.alreadyFetched && compose(["pull"]) !== 0) {
13357
+ return { ok: false, apiPort, dashPort };
13358
+ }
13341
13359
  if (up() !== 0) return { ok: false, apiPort, dashPort };
13342
13360
  onEdgeContainerChanged();
13343
13361
  writeInstallMethod("compose");
@@ -13366,9 +13384,9 @@ function composeUninstall(opts = {}) {
13366
13384
  }
13367
13385
  return { ok, removedImages };
13368
13386
  }
13369
- function composeUpdate(version) {
13387
+ async function composeUpdate(version) {
13370
13388
  if (!existsSync3(COMPOSE_FILE)) return false;
13371
- return composeUp(version ? { version } : {}).ok;
13389
+ return (await composeUp(version ? { version } : {})).ok;
13372
13390
  }
13373
13391
  function composePs() {
13374
13392
  return compose(["ps"]);
@@ -13488,6 +13506,7 @@ export {
13488
13506
  composeIsViableDefault,
13489
13507
  ensureDocker,
13490
13508
  sourceBuildDir,
13509
+ composePrefetch,
13491
13510
  composeUp,
13492
13511
  composeDown,
13493
13512
  composeUninstall,
@@ -6,7 +6,7 @@ import {
6
6
  COMPONENT_INSTALLERS,
7
7
  checkAll,
8
8
  checkComponents
9
- } from "./chunk-UXWAVM4C.js";
9
+ } from "./chunk-SLTYVHU7.js";
10
10
 
11
11
  // ../../packages/adapters/src/system/state.ts
12
12
  var DEFAULT_STATE_PATH = "/etc/openship/setup-state.json";
@@ -31,9 +31,10 @@ import {
31
31
  ourLuaOnHost,
32
32
  probeEdge,
33
33
  resolveOurEdgeContainer,
34
+ sanitizeEdgeVhosts,
34
35
  sq as sq2,
35
36
  stopTargetsForStatus
36
- } from "./chunk-R5BHFFAV.js";
37
+ } from "./chunk-2D3I5G6P.js";
37
38
  import {
38
39
  waitForPortListening
39
40
  } from "./chunk-ILFETZOM.js";
@@ -1842,7 +1843,7 @@ async function runningImage(executor, container) {
1842
1843
  return out.trim() || null;
1843
1844
  }
1844
1845
  async function containerEdgeProvider(executor, container, opts) {
1845
- const { NginxProvider: Provider } = await import("./nginx-XWJAOGS4.js");
1846
+ const { NginxProvider: Provider } = await import("./nginx-3L4SIBJA.js");
1846
1847
  return new Provider({
1847
1848
  ...opts,
1848
1849
  // Vhosts go to the BIND-MOUNTED HOST dir (so every host-side reader — the
@@ -1857,7 +1858,7 @@ async function containerEdgeProvider(executor, container, opts) {
1857
1858
  }
1858
1859
  async function localContainerEdgeProvider(container, opts) {
1859
1860
  const { DockerEdgeExecutor } = await import("./docker-edge-executor-VHW3JPJS.js");
1860
- const { NginxProvider: Provider } = await import("./nginx-XWJAOGS4.js");
1861
+ const { NginxProvider: Provider } = await import("./nginx-3L4SIBJA.js");
1861
1862
  return new Provider({
1862
1863
  ...opts,
1863
1864
  paths: OPENRESTY_DEFAULT_PATHS,
@@ -1867,6 +1868,18 @@ async function localContainerEdgeProvider(container, opts) {
1867
1868
  pinPaths: true
1868
1869
  });
1869
1870
  }
1871
+ async function startEdgeContainer(executor, container, image, onLog) {
1872
+ await sanitizeEdgeVhosts(executor, EDGE_HOST_PATHS.sitesDir, onLog).catch(() => {
1873
+ });
1874
+ await executor.exec(`docker rm -f ${sq(container)} 2>/dev/null || true`).catch(() => {
1875
+ });
1876
+ const run = await executor.streamExec(
1877
+ buildEdgeRunCommand(container, image),
1878
+ onLog
1879
+ );
1880
+ invalidateEdgeContainer(executor);
1881
+ return run.code === 0;
1882
+ }
1870
1883
  function buildEdgeRunCommand(container, image) {
1871
1884
  const mounts = EDGE_CONTAINER_MOUNTS.map(
1872
1885
  // `:z` relabels for SELinux-enforcing hosts; a no-op elsewhere.
@@ -1890,14 +1903,7 @@ async function swapEdgeImage(executor, container, from, to, opts) {
1890
1903
  return { swapped: false, edgeDown: false };
1891
1904
  }
1892
1905
  const start = async (image) => {
1893
- await executor.exec(`docker rm -f ${sq(container)} 2>/dev/null || true`).catch(() => {
1894
- });
1895
- const run = await executor.streamExec(
1896
- buildEdgeRunCommand(container, image),
1897
- onLog
1898
- );
1899
- invalidateEdgeContainer(executor);
1900
- if (run.code !== 0) return false;
1906
+ if (!await startEdgeContainer(executor, container, image, onLog)) return false;
1901
1907
  const listening = await waitForPortListening(executor, 80, {
1902
1908
  timeoutMs: opts.verifyTimeoutMs ?? 3e4
1903
1909
  });
@@ -1920,29 +1926,6 @@ async function listDir(executor, dir) {
1920
1926
  out.split("\n").map((l) => l.trim()).filter(Boolean)
1921
1927
  );
1922
1928
  }
1923
- async function sanitizeCarriedVhosts(executor, sitesDir, onLog) {
1924
- const script = [
1925
- `for f in ${sq(sitesDir)}/*.conf; do`,
1926
- ` [ -f "$f" ] || continue;`,
1927
- // A real server_name is anything that isn't the `_` wildcard.
1928
- ` if ! grep -qE '^[[:space:]]*server_name[[:space:]]+[^_;[:space:]]' "$f"; then`,
1929
- ` echo "dropped-catchall $f"; rm -f "$f"; continue;`,
1930
- ` fi;`,
1931
- ` if grep -qE '[[:space:]]default_server' "$f"; then`,
1932
- ` sed -i -E 's/([[:space:]]listen[^;]*)[[:space:]]+default_server/\\1/g' "$f" && echo "unset-default $f";`,
1933
- ` fi;`,
1934
- `done`
1935
- ].join(" ");
1936
- const out = await executor.exec(script).catch(() => "");
1937
- for (const line of out.split("\n").map((l) => l.trim()).filter(Boolean)) {
1938
- const [action, file] = [line.slice(0, line.indexOf(" ")), line.slice(line.indexOf(" ") + 1)];
1939
- if (action === "dropped-catchall") {
1940
- onLog(log4(`Dropped the bare edge's catch-all ${file} \u2014 the edge image provides it.`, "warn"));
1941
- } else if (action === "unset-default") {
1942
- onLog(log4(`Removed default_server from ${file} \u2014 the edge image owns it.`, "warn"));
1943
- }
1944
- }
1945
- }
1946
1929
  async function ensureContainerEdge(executor, opts) {
1947
1930
  const { onLog } = opts;
1948
1931
  const container = opts.container?.trim() || EDGE_CONTAINER_NAME;
@@ -1989,7 +1972,6 @@ async function ensureContainerEdge(executor, opts) {
1989
1972
  beforeCarry = await listDir(executor, sitesTarget);
1990
1973
  await executor.exec(`cp -a ${sq(`${barePaths.sitesDir}/.`)} ${sq(`${sitesTarget}/`)} 2>/dev/null || true`).catch(() => {
1991
1974
  });
1992
- await sanitizeCarriedVhosts(executor, sitesTarget, onLog);
1993
1975
  }
1994
1976
  }
1995
1977
  const restoreBare = async () => {
@@ -2015,15 +1997,10 @@ async function ensureContainerEdge(executor, opts) {
2015
1997
  await executor.exec("systemctl reset-failed openresty 2>/dev/null || true").catch(() => {
2016
1998
  });
2017
1999
  }
2018
- await executor.exec(`docker rm -f ${sq(container)} 2>/dev/null || true`).catch(() => {
2019
- });
2020
2000
  onLog(log4("Starting the edge container..."));
2021
- const run = await executor.streamExec(
2022
- buildEdgeRunCommand(container, image),
2023
- onLog
2024
- );
2025
- invalidateEdgeContainer(executor);
2026
- if (run.code !== 0) throw new Error("the edge container failed to start");
2001
+ if (!await startEdgeContainer(executor, container, image, onLog)) {
2002
+ throw new Error("the edge container failed to start");
2003
+ }
2027
2004
  await executor.exec(containerCommand(container, "openresty -t"));
2028
2005
  const listening = await waitForPortListening(executor, 80, {
2029
2006
  timeoutMs: opts.verifyTimeoutMs ?? 3e4
@@ -30,7 +30,7 @@ import {
30
30
  } from "./chunk-6APULWSU.js";
31
31
 
32
32
  // ../../packages/adapters/src/system/executor.ts
33
- import { readFileSync } from "fs";
33
+ import { existsSync, readFileSync } from "fs";
34
34
 
35
35
  // ../../packages/adapters/src/system/ssh-executor.ts
36
36
  import { createReadStream } from "fs";
@@ -1508,6 +1508,18 @@ function createExecutor(ssh) {
1508
1508
  function hostControlDisabled() {
1509
1509
  return process.env.OPENSHIP_HOST_CONTROL?.trim().toLowerCase() === "false";
1510
1510
  }
1511
+ function runningInContainer() {
1512
+ if (process.env.OPENSHIP_IN_CONTAINER?.trim().toLowerCase() === "true") return true;
1513
+ try {
1514
+ if (existsSync("/.dockerenv")) return true;
1515
+ } catch {
1516
+ }
1517
+ try {
1518
+ return /\b(docker|containerd|podman|kubepods)\b/.test(readFileSync("/proc/1/cgroup", "utf8"));
1519
+ } catch {
1520
+ return false;
1521
+ }
1522
+ }
1511
1523
  function createHostExecutor() {
1512
1524
  if (hostControlDisabled()) {
1513
1525
  throw new Error(
@@ -1515,7 +1527,14 @@ function createHostExecutor() {
1515
1527
  );
1516
1528
  }
1517
1529
  const host = process.env.OPENSHIP_HOST_SSH_HOST?.trim();
1518
- if (!host) return localExecutor;
1530
+ if (!host) {
1531
+ if (runningInContainer()) {
1532
+ throw new Error(
1533
+ "This operation targets the HOST machine, but no host channel is configured (OPENSHIP_HOST_SSH_HOST is unset) and Openship is running in a container \u2014 so it would have run inside the container instead, against the wrong filesystem. Re-run `openship up` to provision the host channel."
1534
+ );
1535
+ }
1536
+ return localExecutor;
1537
+ }
1519
1538
  const keyPath = process.env.OPENSHIP_HOST_SSH_KEY?.trim();
1520
1539
  const portRaw = Number(process.env.OPENSHIP_HOST_SSH_PORT || "22");
1521
1540
  const port = Number.isInteger(portRaw) && portRaw > 0 && portRaw < 65536 ? portRaw : 22;
@@ -6,19 +6,19 @@ import {
6
6
  CloudRuntime,
7
7
  PAGE_CONTAINER_PREFIX,
8
8
  provisionCloudWorkspace
9
- } from "./chunk-XFCDYZUQ.js";
10
- import "./chunk-UXWAVM4C.js";
9
+ } from "./chunk-5NYUCONN.js";
10
+ import "./chunk-SLTYVHU7.js";
11
11
  import "./chunk-V6AN6XLZ.js";
12
12
  import "./chunk-MZ2WEHHY.js";
13
13
  import "./chunk-L2VOGB2X.js";
14
14
  import "./chunk-4Z5QO7N6.js";
15
- import "./chunk-4TJC4JZQ.js";
15
+ import "./chunk-XPPZ7B2J.js";
16
16
  import "./chunk-OXWDY22G.js";
17
17
  import "./chunk-RPHRPFEH.js";
18
18
  import "./chunk-TYVME3XD.js";
19
19
  import "./chunk-FXTBHTWY.js";
20
20
  import "./chunk-FPRHYBY2.js";
21
- import "./chunk-R5BHFFAV.js";
21
+ import "./chunk-2D3I5G6P.js";
22
22
  import "./chunk-ILFETZOM.js";
23
23
  import "./chunk-VFINNTUL.js";
24
24
  import "./chunk-6APULWSU.js";
@@ -9,7 +9,7 @@ import {
9
9
  classifyProxy,
10
10
  edgeCrashReason,
11
11
  edgeFailureReason,
12
- edgeIsServing,
12
+ edgeIsBroken,
13
13
  freeEdgeTargets,
14
14
  invalidateEdgeContainer,
15
15
  isOurEdgeContainer,
@@ -17,9 +17,10 @@ import {
17
17
  ourLuaOnHost,
18
18
  probeEdge,
19
19
  resolveOurEdgeContainer,
20
+ sanitizeEdgeVhosts,
20
21
  sq,
21
22
  stopTargetsForStatus
22
- } from "./chunk-R5BHFFAV.js";
23
+ } from "./chunk-2D3I5G6P.js";
23
24
  import "./chunk-ILFETZOM.js";
24
25
  import "./chunk-VFINNTUL.js";
25
26
  import "./chunk-6APULWSU.js";
@@ -31,7 +32,7 @@ export {
31
32
  classifyProxy,
32
33
  edgeCrashReason,
33
34
  edgeFailureReason,
34
- edgeIsServing,
35
+ edgeIsBroken,
35
36
  freeEdgeTargets,
36
37
  invalidateEdgeContainer,
37
38
  isOurEdgeContainer,
@@ -39,6 +40,7 @@ export {
39
40
  ourLuaOnHost,
40
41
  probeEdge,
41
42
  resolveOurEdgeContainer,
43
+ sanitizeEdgeVhosts,
42
44
  sq,
43
45
  stopTargetsForStatus
44
46
  };
@@ -5,7 +5,7 @@ const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  importMigratedSites,
7
7
  waitForApiHealth
8
- } from "./chunk-IMBD5PZ5.js";
8
+ } from "./chunk-BBHX7T4R.js";
9
9
  import "./chunk-FRNAR33O.js";
10
10
  import "./chunk-EI575GHN.js";
11
11
  import "./chunk-6APIPIJY.js";
@@ -14,12 +14,12 @@ import "./chunk-OWED2GRM.js";
14
14
  import "./chunk-VWPEKOH6.js";
15
15
  import "./chunk-W73X43R7.js";
16
16
  import "./chunk-TGIINPVM.js";
17
- import "./chunk-XFCDYZUQ.js";
17
+ import "./chunk-5NYUCONN.js";
18
18
  import "./chunk-AVIB7CT7.js";
19
19
  import "./chunk-5MZ624VX.js";
20
20
  import "./chunk-Q2CIRAOK.js";
21
- import "./chunk-IPYPMI3S.js";
22
- import "./chunk-UXWAVM4C.js";
21
+ import "./chunk-GKHUSZCD.js";
22
+ import "./chunk-SLTYVHU7.js";
23
23
  import "./chunk-O6ZZF52V.js";
24
24
  import "./chunk-JYGD5WSN.js";
25
25
  import "./chunk-SJIFLLX4.js";
@@ -28,13 +28,13 @@ import "./chunk-VDMQJHPI.js";
28
28
  import "./chunk-MZ2WEHHY.js";
29
29
  import "./chunk-L2VOGB2X.js";
30
30
  import "./chunk-4Z5QO7N6.js";
31
- import "./chunk-4TJC4JZQ.js";
31
+ import "./chunk-XPPZ7B2J.js";
32
32
  import "./chunk-OXWDY22G.js";
33
33
  import "./chunk-RPHRPFEH.js";
34
34
  import "./chunk-TYVME3XD.js";
35
35
  import "./chunk-FXTBHTWY.js";
36
36
  import "./chunk-FPRHYBY2.js";
37
- import "./chunk-R5BHFFAV.js";
37
+ import "./chunk-2D3I5G6P.js";
38
38
  import "./chunk-ILFETZOM.js";
39
39
  import "./chunk-VFINNTUL.js";
40
40
  import "./chunk-6APULWSU.js";
@@ -10,12 +10,12 @@ import {
10
10
  localContainerEdgeProvider,
11
11
  resolveEdgeImage,
12
12
  setDefaultEdgeImage
13
- } from "./chunk-UXWAVM4C.js";
13
+ } from "./chunk-SLTYVHU7.js";
14
14
  import "./chunk-L2VOGB2X.js";
15
15
  import "./chunk-RPHRPFEH.js";
16
16
  import "./chunk-FXTBHTWY.js";
17
17
  import "./chunk-FPRHYBY2.js";
18
- import "./chunk-R5BHFFAV.js";
18
+ import "./chunk-2D3I5G6P.js";
19
19
  import "./chunk-ILFETZOM.js";
20
20
  import "./chunk-VFINNTUL.js";
21
21
  import "./chunk-6APULWSU.js";
@@ -8,7 +8,7 @@ import {
8
8
  createExecutor,
9
9
  createHostExecutor,
10
10
  hostControlDisabled
11
- } from "./chunk-4TJC4JZQ.js";
11
+ } from "./chunk-XPPZ7B2J.js";
12
12
  import "./chunk-OXWDY22G.js";
13
13
  import "./chunk-RPHRPFEH.js";
14
14
  import {
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  composeDown,
9
9
  composeInternalToken,
10
10
  composeIsViableDefault,
11
+ composePrefetch,
11
12
  composePs,
12
13
  composeRestart,
13
14
  composeRunning,
@@ -25,7 +26,7 @@ import {
25
26
  remoteSha,
26
27
  shortSha,
27
28
  sourceBuildDir
28
- } from "./chunk-IMBD5PZ5.js";
29
+ } from "./chunk-BBHX7T4R.js";
29
30
  import "./chunk-FRNAR33O.js";
30
31
  import "./chunk-EI575GHN.js";
31
32
  import "./chunk-6APIPIJY.js";
@@ -34,11 +35,11 @@ import "./chunk-OWED2GRM.js";
34
35
  import "./chunk-VWPEKOH6.js";
35
36
  import "./chunk-W73X43R7.js";
36
37
  import "./chunk-TGIINPVM.js";
37
- import "./chunk-XFCDYZUQ.js";
38
+ import "./chunk-5NYUCONN.js";
38
39
  import "./chunk-AVIB7CT7.js";
39
40
  import "./chunk-5MZ624VX.js";
40
41
  import "./chunk-Q2CIRAOK.js";
41
- import "./chunk-IPYPMI3S.js";
42
+ import "./chunk-GKHUSZCD.js";
42
43
  import {
43
44
  beginEdgeTakeover,
44
45
  collectProxyCerts,
@@ -51,7 +52,7 @@ import {
51
52
  recoverInterruptedTakeover,
52
53
  rollbackEdgeTakeover,
53
54
  scanImportableSites
54
- } from "./chunk-UXWAVM4C.js";
55
+ } from "./chunk-SLTYVHU7.js";
55
56
  import "./chunk-O6ZZF52V.js";
56
57
  import "./chunk-JYGD5WSN.js";
57
58
  import "./chunk-SJIFLLX4.js";
@@ -60,7 +61,7 @@ import "./chunk-VDMQJHPI.js";
60
61
  import "./chunk-MZ2WEHHY.js";
61
62
  import "./chunk-L2VOGB2X.js";
62
63
  import "./chunk-4Z5QO7N6.js";
63
- import "./chunk-4TJC4JZQ.js";
64
+ import "./chunk-XPPZ7B2J.js";
64
65
  import "./chunk-OXWDY22G.js";
65
66
  import "./chunk-RPHRPFEH.js";
66
67
  import {
@@ -70,9 +71,9 @@ import "./chunk-FXTBHTWY.js";
70
71
  import "./chunk-FPRHYBY2.js";
71
72
  import {
72
73
  edgeCrashReason,
73
- edgeIsServing,
74
+ edgeIsBroken,
74
75
  ourEdgeContainerRunning
75
- } from "./chunk-R5BHFFAV.js";
76
+ } from "./chunk-2D3I5G6P.js";
76
77
  import "./chunk-ILFETZOM.js";
77
78
  import "./chunk-VFINNTUL.js";
78
79
  import {
@@ -1683,6 +1684,25 @@ async function runCompose(opts) {
1683
1684
  );
1684
1685
  process.exit(1);
1685
1686
  }
1687
+ const publicUrl = effectivePublicUrl(opts.publicUrl);
1688
+ const prefetch = ora(
1689
+ sourceBuildDir() ? "Building images before touching :80/:443\u2026" : "Pulling images before touching :80/:443\u2026"
1690
+ ).start();
1691
+ const fetched = composePrefetch({
1692
+ apiPort: opts.port,
1693
+ dashboardPort: opts.dashboardPort,
1694
+ publicUrl,
1695
+ trustProxy: opts.trustProxy,
1696
+ noHostControl: opts.hostControl === false ? true : void 0
1697
+ });
1698
+ if (!fetched) {
1699
+ prefetch.fail("Couldn't fetch the stack's images \u2014 nothing was changed on this box.");
1700
+ console.error(
1701
+ chalk6.dim("\n Your current proxy is untouched and still serving. Fix the pull/build error above and re-run.\n")
1702
+ );
1703
+ process.exit(1);
1704
+ }
1705
+ prefetch.succeed("Images ready \u2014 nothing on :80/:443 has changed yet.");
1686
1706
  let edgePlan;
1687
1707
  try {
1688
1708
  edgePlan = await planAndApplyHostEdge({ edge: opts.edge });
@@ -1700,12 +1720,13 @@ async function runCompose(opts) {
1700
1720
  );
1701
1721
  process.exit(1);
1702
1722
  }
1703
- const publicUrl = effectivePublicUrl(opts.publicUrl);
1704
1723
  const fromSource = sourceBuildDir();
1705
1724
  const spinner5 = ora(
1706
1725
  fromSource ? `Building Openship from ${fromSource} and starting the stack\u2026` : "Starting Openship via Docker Compose\u2026"
1707
1726
  ).start();
1708
- const res = composeUp({
1727
+ const res = await composeUp({
1728
+ // Prefetched above, before the preflight stopped anything.
1729
+ alreadyFetched: true,
1709
1730
  apiPort: opts.port,
1710
1731
  dashboardPort: opts.dashboardPort,
1711
1732
  publicUrl,
@@ -1724,11 +1745,11 @@ async function runCompose(opts) {
1724
1745
  process.exit(1);
1725
1746
  }
1726
1747
  spinner5.succeed("Openship is running via Docker Compose.");
1727
- if (edgePlan.action && !await edgeIsServing(new LocalExecutor())) {
1748
+ if (edgePlan.action && await edgeIsBroken(new LocalExecutor())) {
1728
1749
  const reason = await edgeCrashReason(new LocalExecutor());
1729
1750
  console.error(
1730
1751
  chalk6.red(`
1731
- Openship's edge is not serving :80${reason ? ` \u2014 ${reason}` : "."}`)
1752
+ Openship's edge container is not running${reason ? ` \u2014 ${reason}` : "."}`)
1732
1753
  );
1733
1754
  const restored = await rollbackHostEdge();
1734
1755
  console.error(
@@ -1996,7 +2017,7 @@ async function runForeground(opts, source) {
1996
2017
  const uiSpinner = ora("Preparing the dashboard\u2026").start();
1997
2018
  try {
1998
2019
  const bundle = await ensureDashboard({
1999
- tag: source ? "local" : opts.uiVersion || `v${"0.4.7"}`,
2020
+ tag: source ? "local" : opts.uiVersion || `v${"0.4.8"}`,
2000
2021
  onProgress: (received, total) => {
2001
2022
  if (total) {
2002
2023
  uiSpinner.text = `Downloading dashboard\u2026 ${Math.round(received / total * 100)}%`;
@@ -6605,7 +6626,7 @@ function detectPackageManager2(override) {
6605
6626
  var updateCommand = new Command26("update").description("Update the Openship CLI + bundled server to the latest release").option("--check", "Only report the current + latest version; don't install").option("--via <manager>", "Package manager to update with: bun | npm").option("--rebuild", "From-source installs: rebuild even if already at the remote tip").action(async (opts) => {
6606
6627
  const source = readSourceInstall();
6607
6628
  if (source) return runSourceUpdate(source, opts);
6608
- const current = "0.4.7";
6629
+ const current = "0.4.8";
6609
6630
  let latest;
6610
6631
  try {
6611
6632
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -6640,7 +6661,7 @@ var updateCommand = new Command26("update").description("Update the Openship CLI
6640
6661
  return;
6641
6662
  }
6642
6663
  if (readInstallMethod() === "compose") {
6643
- const applied = composeUpdate(latest);
6664
+ const applied = await composeUpdate(latest);
6644
6665
  if (isJsonMode()) {
6645
6666
  printJson({ updated: true, from: current, to: latest, via: pm, method: "compose", applied });
6646
6667
  } else if (applied) {
@@ -7172,7 +7193,7 @@ async function runWizard() {
7172
7193
  }
7173
7194
  }
7174
7195
  }
7175
- const uiTag = `v${"0.4.7"}`;
7196
+ const uiTag = `v${"0.4.8"}`;
7176
7197
  if (method === "bare") {
7177
7198
  const dl = spinner4();
7178
7199
  dl.start("Pulling the Openship dist from GitHub");
@@ -7226,6 +7247,18 @@ async function runWizard() {
7226
7247
  }
7227
7248
  }
7228
7249
  if (method === "compose") {
7250
+ log5.step(
7251
+ sourceBuildDir() ? "Building the Openship images before touching :80/:443 (first run takes a few minutes)\u2026" : "Pulling images before touching :80/:443\u2026"
7252
+ );
7253
+ if (!composePrefetch({
7254
+ publicUrl,
7255
+ trustProxy: behindProxy,
7256
+ version: "0.4.8",
7257
+ noHostControl: !allowHostControl
7258
+ })) {
7259
+ cancel4("Couldn't fetch the Openship images \u2014 nothing on this box was changed.");
7260
+ process.exit(1);
7261
+ }
7229
7262
  const edgePlan = await planAndApplyHostEdge({});
7230
7263
  if (!edgePlan.proceed) {
7231
7264
  cancel4("Left the existing proxy on 80/443 running \u2014 re-run and choose migrate/takeover when ready.");
@@ -7234,13 +7267,13 @@ async function runWizard() {
7234
7267
  edgeAction = edgePlan.action;
7235
7268
  migratedSites = edgePlan.sites;
7236
7269
  migratedCertPems = edgePlan.certPems;
7237
- log5.step(
7238
- sourceBuildDir() ? "Building the Openship images from your source checkout (first run takes a few minutes)\u2026" : "Pulling images and starting the Docker Compose stack\u2026"
7239
- );
7240
- const up = composeUp({
7270
+ log5.step("Starting the Docker Compose stack\u2026");
7271
+ const up = await composeUp({
7272
+ // Prefetched above, before the preflight stopped anything.
7273
+ alreadyFetched: true,
7241
7274
  publicUrl,
7242
7275
  trustProxy: behindProxy,
7243
- version: "0.4.7",
7276
+ version: "0.4.8",
7244
7277
  noHostControl: !allowHostControl
7245
7278
  });
7246
7279
  if (!up.ok) {
@@ -7577,7 +7610,7 @@ ${chalk20.dim("Dashboard".padEnd(11))}${dashUrl}
7577
7610
 
7578
7611
  // src/index.ts
7579
7612
  var program = new Command28();
7580
- program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.4.7").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
7613
+ program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.4.8").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
7581
7614
  if (thisCommand.opts().json) setJsonMode(true);
7582
7615
  }).action(async () => {
7583
7616
  const installed = serviceStatus().installed || readInstallMethod() === "compose";
@@ -10,7 +10,7 @@ import {
10
10
  summarizeCertbotFailure
11
11
  } from "./chunk-FXTBHTWY.js";
12
12
  import "./chunk-FPRHYBY2.js";
13
- import "./chunk-R5BHFFAV.js";
13
+ import "./chunk-2D3I5G6P.js";
14
14
  import "./chunk-ILFETZOM.js";
15
15
  import "./chunk-VFINNTUL.js";
16
16
  import "./chunk-6APULWSU.js";
@@ -25764,7 +25764,7 @@ __export(exports_executor, {
25764
25764
  SshExecutor: () => SshExecutor,
25765
25765
  LocalExecutor: () => LocalExecutor
25766
25766
  });
25767
- import { readFileSync } from "node:fs";
25767
+ import { existsSync, readFileSync } from "node:fs";
25768
25768
  function createExecutor(ssh) {
25769
25769
  if (ssh) {
25770
25770
  if (ssh.useSystemSsh)
@@ -25776,13 +25776,30 @@ function createExecutor(ssh) {
25776
25776
  function hostControlDisabled() {
25777
25777
  return process.env.OPENSHIP_HOST_CONTROL?.trim().toLowerCase() === "false";
25778
25778
  }
25779
+ function runningInContainer() {
25780
+ if (process.env.OPENSHIP_IN_CONTAINER?.trim().toLowerCase() === "true")
25781
+ return true;
25782
+ try {
25783
+ if (existsSync("/.dockerenv"))
25784
+ return true;
25785
+ } catch {}
25786
+ try {
25787
+ return /\b(docker|containerd|podman|kubepods)\b/.test(readFileSync("/proc/1/cgroup", "utf8"));
25788
+ } catch {
25789
+ return false;
25790
+ }
25791
+ }
25779
25792
  function createHostExecutor() {
25780
25793
  if (hostControlDisabled()) {
25781
25794
  throw new Error("Host control is disabled on this instance (OPENSHIP_HOST_CONTROL=false). " + "Re-run `openship up` without --no-host-control to allow host operations.");
25782
25795
  }
25783
25796
  const host = process.env.OPENSHIP_HOST_SSH_HOST?.trim();
25784
- if (!host)
25797
+ if (!host) {
25798
+ if (runningInContainer()) {
25799
+ throw new Error("This operation targets the HOST machine, but no host channel is configured " + "(OPENSHIP_HOST_SSH_HOST is unset) and Openship is running in a container — " + "so it would have run inside the container instead, against the wrong " + "filesystem. Re-run `openship up` to provision the host channel.");
25800
+ }
25785
25801
  return localExecutor;
25802
+ }
25786
25803
  const keyPath = process.env.OPENSHIP_HOST_SSH_KEY?.trim();
25787
25804
  const portRaw = Number(process.env.OPENSHIP_HOST_SSH_PORT || "22");
25788
25805
  const port = Number.isInteger(portRaw) && portRaw > 0 && portRaw < 65536 ? portRaw : 22;
@@ -29081,7 +29098,7 @@ __export(exports_openresty_lua, {
29081
29098
  ACME_CHALLENGE_LOCATION: () => ACME_CHALLENGE_LOCATION
29082
29099
  });
29083
29100
  import { createHash } from "node:crypto";
29084
- import { existsSync, readFileSync as readFileSync2 } from "node:fs";
29101
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
29085
29102
  import { dirname as dirname4, join as join10 } from "node:path";
29086
29103
  import { fileURLToPath } from "node:url";
29087
29104
  async function detectOpenRestyPaths(executor) {
@@ -29164,11 +29181,11 @@ http {
29164
29181
  `;
29165
29182
  }
29166
29183
  function luaSourceAvailable() {
29167
- return VHOST_REFERENCED_LUA.every((f) => EMBEDDED_LUA[f] !== undefined || existsSync(join10(LUA_SRC_DIR, f)));
29184
+ return VHOST_REFERENCED_LUA.every((f) => EMBEDDED_LUA[f] !== undefined || existsSync2(join10(LUA_SRC_DIR, f)));
29168
29185
  }
29169
29186
  function readLua(filename) {
29170
29187
  const onDisk = join10(LUA_SRC_DIR, filename);
29171
- if (existsSync(onDisk))
29188
+ if (existsSync2(onDisk))
29172
29189
  return readFileSync2(onDisk, "utf-8");
29173
29190
  const embedded = EMBEDDED_LUA[filename];
29174
29191
  if (embedded !== undefined)
@@ -29368,6 +29385,7 @@ var exports_detect = {};
29368
29385
  __export(exports_detect, {
29369
29386
  stopTargetsForStatus: () => stopTargetsForStatus,
29370
29387
  sq: () => sq3,
29388
+ sanitizeEdgeVhosts: () => sanitizeEdgeVhosts,
29371
29389
  resolveOurEdgeContainer: () => resolveOurEdgeContainer,
29372
29390
  probeEdge: () => probeEdge,
29373
29391
  ourLuaOnHost: () => ourLuaOnHost,
@@ -29375,7 +29393,7 @@ __export(exports_detect, {
29375
29393
  isOurEdgeContainer: () => isOurEdgeContainer,
29376
29394
  invalidateEdgeContainer: () => invalidateEdgeContainer,
29377
29395
  freeEdgeTargets: () => freeEdgeTargets,
29378
- edgeIsServing: () => edgeIsServing,
29396
+ edgeIsBroken: () => edgeIsBroken,
29379
29397
  edgeFailureReason: () => edgeFailureReason,
29380
29398
  edgeCrashReason: () => edgeCrashReason,
29381
29399
  classifyProxy: () => classifyProxy,
@@ -29414,17 +29432,36 @@ function sq3(value) {
29414
29432
  function isOurEdgeContainer(name2, image) {
29415
29433
  return /openship-edge/i.test(`${name2 ?? ""} ${image ?? ""}`);
29416
29434
  }
29417
- async function edgeIsServing(executor, port = 80) {
29418
- const running = await tryExec3(executor, `docker inspect -f '{{.State.Running}}' ${sq3(EDGE_CONTAINER_NAME)} 2>/dev/null`);
29419
- if ((running ?? "").trim() !== "true")
29420
- return false;
29421
- const probe = await tryExec3(executor, containerShell(`wget -q -O /dev/null -T 3 http://127.0.0.1:${port}/ >/dev/null 2>&1; echo $?`));
29422
- const code = (probe ?? "").trim().split(`
29423
- `).pop() ?? "1";
29424
- return code === "0" || code === "8";
29435
+ function vhostLog(message, level = "info") {
29436
+ return { timestamp: new Date().toISOString(), message, level };
29425
29437
  }
29426
- function containerShell(command) {
29427
- return `docker exec ${sq3(EDGE_CONTAINER_NAME)} sh -c ${sq3(command)}`;
29438
+ async function sanitizeEdgeVhosts(executor, sitesDir, onLog) {
29439
+ const script = [
29440
+ `for f in ${sq3(sitesDir)}/*.conf; do`,
29441
+ ` [ -f "$f" ] || continue;`,
29442
+ ` if ! grep -qE '^[[:space:]]*server_name[[:space:]]+[^_;[:space:]]' "$f"; then`,
29443
+ ` echo "dropped-catchall $f"; rm -f "$f"; continue;`,
29444
+ ` fi;`,
29445
+ ` if grep -qE '[[:space:]]default_server' "$f"; then`,
29446
+ ` sed -E 's/([[:space:]]listen[^;]*)[[:space:]]+default_server/\\1/g' "$f" > "$f.osh" && mv "$f.osh" "$f" && echo "unset-default $f";`,
29447
+ ` fi;`,
29448
+ `done`
29449
+ ].join(" ");
29450
+ const out2 = await executor.exec(script).catch(() => "");
29451
+ for (const line of out2.split(`
29452
+ `).map((l) => l.trim()).filter(Boolean)) {
29453
+ const [action, file3] = [line.slice(0, line.indexOf(" ")), line.slice(line.indexOf(" ") + 1)];
29454
+ if (action === "dropped-catchall") {
29455
+ onLog(vhostLog(`Dropped catch-all vhost ${file3} — the edge image provides it.`, "warn"));
29456
+ } else if (action === "unset-default") {
29457
+ onLog(vhostLog(`Removed default_server from ${file3} — the edge image owns it.`, "warn"));
29458
+ }
29459
+ }
29460
+ }
29461
+ async function edgeIsBroken(executor) {
29462
+ const status = await tryExec3(executor, `docker inspect -f '{{.State.Status}}' ${sq3(EDGE_CONTAINER_NAME)} 2>/dev/null`);
29463
+ const state = (status ?? "").trim();
29464
+ return state === "restarting" || state === "exited" || state === "dead";
29428
29465
  }
29429
29466
  async function edgeCrashReason(executor) {
29430
29467
  const logs = await tryExec3(executor, `docker logs --tail 40 ${sq3(EDGE_CONTAINER_NAME)} 2>&1`);
@@ -29436,7 +29473,7 @@ function edgeFailureReason(containerLog) {
29436
29473
  const emerg = lines.find((l) => l.includes("[emerg]"));
29437
29474
  if (emerg)
29438
29475
  return emerg.replace(/^.*\[emerg\]\s*\d*#\d*:\s*/, "");
29439
- return lines.at(-1) ?? null;
29476
+ return null;
29440
29477
  }
29441
29478
  async function ourEdgeContainerRunning(executor) {
29442
29479
  return Boolean(await resolveOurEdgeContainer(executor));
@@ -32342,6 +32379,13 @@ async function localContainerEdgeProvider(container, opts) {
32342
32379
  pinPaths: true
32343
32380
  });
32344
32381
  }
32382
+ async function startEdgeContainer(executor, container, image, onLog) {
32383
+ await sanitizeEdgeVhosts(executor, EDGE_HOST_PATHS.sitesDir, onLog).catch(() => {});
32384
+ await executor.exec(`docker rm -f ${sq2(container)} 2>/dev/null || true`).catch(() => {});
32385
+ const run2 = await executor.streamExec(buildEdgeRunCommand(container, image), onLog);
32386
+ invalidateEdgeContainer(executor);
32387
+ return run2.code === 0;
32388
+ }
32345
32389
  function buildEdgeRunCommand(container, image) {
32346
32390
  const mounts = EDGE_CONTAINER_MOUNTS.map((m) => `-v ${sq2(`${m.host}:${m.container}:z`)}`).join(" ");
32347
32391
  return [
@@ -32362,10 +32406,7 @@ async function swapEdgeImage(executor, container, from, to, opts) {
32362
32406
  return { swapped: false, edgeDown: false };
32363
32407
  }
32364
32408
  const start2 = async (image) => {
32365
- await executor.exec(`docker rm -f ${sq2(container)} 2>/dev/null || true`).catch(() => {});
32366
- const run2 = await executor.streamExec(buildEdgeRunCommand(container, image), onLog);
32367
- invalidateEdgeContainer(executor);
32368
- if (run2.code !== 0)
32409
+ if (!await startEdgeContainer(executor, container, image, onLog))
32369
32410
  return false;
32370
32411
  const listening = await waitForPortListening(executor, 80, {
32371
32412
  timeoutMs: opts.verifyTimeoutMs ?? 30000
@@ -32388,29 +32429,6 @@ async function listDir(executor, dir) {
32388
32429
  return new Set(out2.split(`
32389
32430
  `).map((l) => l.trim()).filter(Boolean));
32390
32431
  }
32391
- async function sanitizeCarriedVhosts(executor, sitesDir, onLog) {
32392
- const script = [
32393
- `for f in ${sq2(sitesDir)}/*.conf; do`,
32394
- ` [ -f "$f" ] || continue;`,
32395
- ` if ! grep -qE '^[[:space:]]*server_name[[:space:]]+[^_;[:space:]]' "$f"; then`,
32396
- ` echo "dropped-catchall $f"; rm -f "$f"; continue;`,
32397
- ` fi;`,
32398
- ` if grep -qE '[[:space:]]default_server' "$f"; then`,
32399
- ` sed -i -E 's/([[:space:]]listen[^;]*)[[:space:]]+default_server/\\1/g' "$f" && echo "unset-default $f";`,
32400
- ` fi;`,
32401
- `done`
32402
- ].join(" ");
32403
- const out2 = await executor.exec(script).catch(() => "");
32404
- for (const line of out2.split(`
32405
- `).map((l) => l.trim()).filter(Boolean)) {
32406
- const [action, file3] = [line.slice(0, line.indexOf(" ")), line.slice(line.indexOf(" ") + 1)];
32407
- if (action === "dropped-catchall") {
32408
- onLog(log2(`Dropped the bare edge's catch-all ${file3} — the edge image provides it.`, "warn"));
32409
- } else if (action === "unset-default") {
32410
- onLog(log2(`Removed default_server from ${file3} — the edge image owns it.`, "warn"));
32411
- }
32412
- }
32413
- }
32414
32432
  async function ensureContainerEdge(executor, opts) {
32415
32433
  const { onLog } = opts;
32416
32434
  const container = opts.container?.trim() || EDGE_CONTAINER_NAME;
@@ -32451,7 +32469,6 @@ async function ensureContainerEdge(executor, opts) {
32451
32469
  onLog(log2(`Carrying vhosts from ${barePaths.sitesDir}...`));
32452
32470
  beforeCarry = await listDir(executor, sitesTarget);
32453
32471
  await executor.exec(`cp -a ${sq2(`${barePaths.sitesDir}/.`)} ${sq2(`${sitesTarget}/`)} 2>/dev/null || true`).catch(() => {});
32454
- await sanitizeCarriedVhosts(executor, sitesTarget, onLog);
32455
32472
  }
32456
32473
  }
32457
32474
  const restoreBare = async () => {
@@ -32474,12 +32491,10 @@ async function ensureContainerEdge(executor, opts) {
32474
32491
  await executor.exec("systemctl disable --now openresty 2>/dev/null || true").catch(() => {});
32475
32492
  await executor.exec("systemctl reset-failed openresty 2>/dev/null || true").catch(() => {});
32476
32493
  }
32477
- await executor.exec(`docker rm -f ${sq2(container)} 2>/dev/null || true`).catch(() => {});
32478
32494
  onLog(log2("Starting the edge container..."));
32479
- const run2 = await executor.streamExec(buildEdgeRunCommand(container, image), onLog);
32480
- invalidateEdgeContainer(executor);
32481
- if (run2.code !== 0)
32495
+ if (!await startEdgeContainer(executor, container, image, onLog)) {
32482
32496
  throw new Error("the edge container failed to start");
32497
+ }
32483
32498
  await executor.exec(containerCommand(container, "openresty -t"));
32484
32499
  const listening = await waitForPortListening(executor, 80, {
32485
32500
  timeoutMs: opts.verifyTimeoutMs ?? 30000
@@ -99515,7 +99530,7 @@ var init_migrator3 = __esm(() => {
99515
99530
  });
99516
99531
 
99517
99532
  // ../../packages/db/src/client.ts
99518
- import { mkdirSync as mkdirSync2, existsSync as existsSync3, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
99533
+ import { mkdirSync as mkdirSync2, existsSync as existsSync4, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
99519
99534
  import { resolve as resolve5, dirname as dirname8, join as join18 } from "path";
99520
99535
  import { fileURLToPath as fileURLToPath2 } from "url";
99521
99536
  function getDriver() {
@@ -99590,7 +99605,7 @@ async function createPgClient(url2) {
99590
99605
  }
99591
99606
  function clearStalePgliteControlFile(dataDir) {
99592
99607
  const controlPath = join18(dataDir, "postmaster.pid");
99593
- if (!existsSync3(controlPath))
99608
+ if (!existsSync4(controlPath))
99594
99609
  return;
99595
99610
  try {
99596
99611
  unlinkSync2(controlPath);
@@ -99619,7 +99634,7 @@ async function createPgliteClient() {
99619
99634
  return memDb;
99620
99635
  }
99621
99636
  const dataDir = resolvePgliteDataDir();
99622
- if (!existsSync3(dataDir)) {
99637
+ if (!existsSync4(dataDir)) {
99623
99638
  mkdirSync2(dataDir, { recursive: true });
99624
99639
  }
99625
99640
  await acquirePgliteLock(dataDir, { waitMs: 30000, pollMs: 250 });
@@ -191546,7 +191561,7 @@ var package_default;
191546
191561
  var init_package = __esm(() => {
191547
191562
  package_default = {
191548
191563
  name: "@repo/api",
191549
- version: "0.4.7",
191564
+ version: "0.4.8",
191550
191565
  license: "Apache-2.0",
191551
191566
  private: true,
191552
191567
  type: "module",
@@ -246625,7 +246640,7 @@ var init_safe_fetch = __esm(() => {
246625
246640
 
246626
246641
  // ../api/src/lib/release-download.ts
246627
246642
  import { createHash as createHash11 } from "node:crypto";
246628
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, renameSync, rmSync } from "node:fs";
246643
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, renameSync, rmSync } from "node:fs";
246629
246644
  import { readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
246630
246645
  import { join as join20, resolve as resolve8 } from "node:path";
246631
246646
  import { spawn as spawn5 } from "node:child_process";
@@ -246639,7 +246654,7 @@ async function fetchAndExtractRelease(input) {
246639
246654
  const external4 = Boolean(input.assetUrl);
246640
246655
  const envOverride = input.envOverride ?? (input.asset ? envOverrideFor(input.asset) : "OPENSHIP_RELEASE_DIST_PATH");
246641
246656
  const targetDir = resolve8(cacheDir, tag2);
246642
- if (existsSync4(targetDir)) {
246657
+ if (existsSync5(targetDir)) {
246643
246658
  return { path: targetDir, downloaded: false };
246644
246659
  }
246645
246660
  let assetUrl;
@@ -246697,7 +246712,7 @@ async function fetchAndExtractRelease(input) {
246697
246712
  try {
246698
246713
  renameSync(scratchDir, targetDir);
246699
246714
  } catch (err2) {
246700
- if (existsSync4(targetDir)) {
246715
+ if (existsSync5(targetDir)) {
246701
246716
  rmSync(scratchDir, { recursive: true, force: true });
246702
246717
  return { path: targetDir, downloaded: true };
246703
246718
  }
@@ -246709,7 +246724,7 @@ async function fetchAndExtractRelease(input) {
246709
246724
  }
246710
246725
  return { path: targetDir, downloaded: true };
246711
246726
  } catch (err2) {
246712
- if (existsSync4(scratchDir)) {
246727
+ if (existsSync5(scratchDir)) {
246713
246728
  rmSync(scratchDir, { recursive: true, force: true });
246714
246729
  }
246715
246730
  throw err2;
@@ -247000,7 +247015,7 @@ var init_release_download = __esm(() => {
247000
247015
  });
247001
247016
 
247002
247017
  // ../api/src/lib/release-resolver.ts
247003
- import { existsSync as existsSync5 } from "node:fs";
247018
+ import { existsSync as existsSync6 } from "node:fs";
247004
247019
  import { homedir as homedir4 } from "node:os";
247005
247020
  import { join as join21, resolve as resolve9 } from "node:path";
247006
247021
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -247020,17 +247035,17 @@ async function resolveReleaseDist(spec) {
247020
247035
  const raw2 = process.env[spec.envOverride];
247021
247036
  if (raw2) {
247022
247037
  const dir = spec.envOverrideSubdir ? resolve9(raw2, spec.envOverrideSubdir) : resolve9(raw2);
247023
- if (existsSync5(dir))
247038
+ if (existsSync6(dir))
247024
247039
  return { dir, version: version5, origin: "env" };
247025
247040
  throw new ReleaseDistMissingError(spec.name, dir);
247026
247041
  }
247027
247042
  }
247028
- if (spec.repoLocalPath && existsSync5(spec.repoLocalPath)) {
247043
+ if (spec.repoLocalPath && existsSync6(spec.repoLocalPath)) {
247029
247044
  return { dir: spec.repoLocalPath, version: version5, origin: "repo-local" };
247030
247045
  }
247031
247046
  const cacheDir = join21(spec.dataDir ?? computeDataDir(), `${spec.name}-dist`);
247032
247047
  const cachedTarget = join21(cacheDir, tag2);
247033
- if (existsSync5(cachedTarget))
247048
+ if (existsSync6(cachedTarget))
247034
247049
  return { dir: cachedTarget, version: version5, origin: "cache-hit" };
247035
247050
  const src = spec.source;
247036
247051
  try {
@@ -247065,13 +247080,13 @@ function resolveReleaseDistOrNull(spec) {
247065
247080
  const raw2 = process.env[spec.envOverride];
247066
247081
  if (raw2) {
247067
247082
  const dir = spec.envOverrideSubdir ? resolve9(raw2, spec.envOverrideSubdir) : resolve9(raw2);
247068
- return existsSync5(dir) ? dir : null;
247083
+ return existsSync6(dir) ? dir : null;
247069
247084
  }
247070
247085
  }
247071
- if (spec.repoLocalPath && existsSync5(spec.repoLocalPath))
247086
+ if (spec.repoLocalPath && existsSync6(spec.repoLocalPath))
247072
247087
  return spec.repoLocalPath;
247073
247088
  const cached6 = join21(spec.dataDir ?? computeDataDir(), `${spec.name}-dist`, `v${version5}`);
247074
- return existsSync5(cached6) ? cached6 : null;
247089
+ return existsSync6(cached6) ? cached6 : null;
247075
247090
  }
247076
247091
  function subst(s4, version5, tag2) {
247077
247092
  return s4.replaceAll("{version}", version5).replaceAll("{tag}", tag2);
@@ -278351,7 +278366,7 @@ var require_lib5 = __commonJS((exports) => {
278351
278366
 
278352
278367
  // ../api/src/lib/geo-ip.ts
278353
278368
  import { isIP } from "node:net";
278354
- import { existsSync as existsSync7 } from "node:fs";
278369
+ import { existsSync as existsSync8 } from "node:fs";
278355
278370
  import { mkdir as mkdir2, writeFile as writeFile5 } from "node:fs/promises";
278356
278371
  import { homedir as homedir7 } from "node:os";
278357
278372
  import { dirname as dirname9, join as join25 } from "node:path";
@@ -278373,7 +278388,7 @@ function candidatePaths() {
278373
278388
  async function resolveDbPath() {
278374
278389
  for (const p4 of candidatePaths()) {
278375
278390
  try {
278376
- if (existsSync7(p4))
278391
+ if (existsSync8(p4))
278377
278392
  return p4;
278378
278393
  } catch {}
278379
278394
  }
@@ -297113,7 +297128,7 @@ await __promiseAll([
297113
297128
  init_github_access(),
297114
297129
  init_rollback()
297115
297130
  ]);
297116
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
297131
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
297117
297132
  async function assertGitHubAccessForDeployment(ctx2, deploymentId, organizationId) {
297118
297133
  const dep = await getDeployment(deploymentId, organizationId);
297119
297134
  const project2 = await repos.project.findById(dep.projectId);
@@ -297273,7 +297288,7 @@ async function skipPortCheck(deploymentId, organizationId, target) {
297273
297288
  }
297274
297289
  function readInstanceLog(tail) {
297275
297290
  const path2 = process.env.OPENSHIP_INSTANCE_LOG;
297276
- if (!path2 || !existsSync6(path2))
297291
+ if (!path2 || !existsSync7(path2))
297277
297292
  return [];
297278
297293
  let text3;
297279
297294
  try {
@@ -4,13 +4,13 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  SystemManager
7
- } from "./chunk-IPYPMI3S.js";
8
- import "./chunk-UXWAVM4C.js";
7
+ } from "./chunk-GKHUSZCD.js";
8
+ import "./chunk-SLTYVHU7.js";
9
9
  import "./chunk-L2VOGB2X.js";
10
10
  import "./chunk-RPHRPFEH.js";
11
11
  import "./chunk-FXTBHTWY.js";
12
12
  import "./chunk-FPRHYBY2.js";
13
- import "./chunk-R5BHFFAV.js";
13
+ import "./chunk-2D3I5G6P.js";
14
14
  import "./chunk-ILFETZOM.js";
15
15
  import "./chunk-VFINNTUL.js";
16
16
  import "./chunk-6APULWSU.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openship",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "Openship CLI - deploy, manage, and open your Openship platform from the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {