openship 0.6.5 → 0.6.6

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 (54) hide show
  1. package/dist/{bare-XQIPDO4R.js → bare-OXJVW3AK.js} +11 -10
  2. package/dist/{chunk-WE7BXW6L.js → chunk-2YM3NI2E.js} +2 -2
  3. package/dist/{chunk-RFWJE7ZN.js → chunk-4I2BM2DT.js} +3 -3
  4. package/dist/{chunk-QLX7NBEA.js → chunk-5DMWSTOM.js} +78 -1836
  5. package/dist/{chunk-VDESJSG6.js → chunk-77QDF6UD.js} +135 -21
  6. package/dist/{chunk-7334NSJL.js → chunk-A4GXYE4L.js} +67 -31
  7. package/dist/{chunk-HPXP6LXZ.js → chunk-CBLD2HS5.js} +3 -3
  8. package/dist/{chunk-6JELW75A.js → chunk-FE7ZZQSE.js} +3 -3
  9. package/dist/{chunk-XVOBL7BC.js → chunk-HKRQXPTI.js} +1 -1
  10. package/dist/{chunk-GRTXMUHA.js → chunk-LFE5KQ7Y.js} +11 -11
  11. package/dist/{chunk-TM2IQPYU.js → chunk-LH2PLRQO.js} +2 -2
  12. package/dist/{chunk-LFCSC4IU.js → chunk-LUKYPVJ4.js} +3 -3
  13. package/dist/{chunk-VHMOQL5Y.js → chunk-MLYSEZQB.js} +115 -19
  14. package/dist/{chunk-7S4USQYF.js → chunk-NK5N5LXN.js} +50 -122
  15. package/dist/{chunk-3ZAGC5NT.js → chunk-OBPKYXQL.js} +17 -6
  16. package/dist/{chunk-5OUWIPOB.js → chunk-PCPVTH6M.js} +12 -84
  17. package/dist/chunk-Q7WGTQQ5.js +88 -0
  18. package/dist/{chunk-VLQ3UIVO.js → chunk-QVW76WDL.js} +52 -26
  19. package/dist/{chunk-PZRRL5PC.js → chunk-RSR7PFIQ.js} +14 -3
  20. package/dist/{chunk-A7EWM2KA.js → chunk-SM26HDS2.js} +1 -1
  21. package/dist/{chunk-LEYSL46B.js → chunk-UJ6JZM65.js} +3426 -632
  22. package/dist/{chunk-WFRXYWK2.js → chunk-UVNMQM7W.js} +1 -1
  23. package/dist/chunk-VTGPEC6B.js +308 -0
  24. package/dist/chunk-WVAML4H6.js +2145 -0
  25. package/dist/{chunk-MSZUCNPV.js → chunk-YIMOCZBZ.js} +1 -1
  26. package/dist/{chunk-EZPPTWJQ.js → chunk-YMMQRE5J.js} +1 -1
  27. package/dist/{cloud-3DODOWTR.js → cloud-75VIT4KV.js} +16 -15
  28. package/dist/{detect-P4CIQBRH.js → detect-OIE5V3VZ.js} +3 -3
  29. package/dist/{docker-3K2NEBD6.js → docker-VTR2GK5Y.js} +7 -6
  30. package/dist/{docker-edge-executor-YZZ6P7IC.js → docker-edge-executor-22IBXNYJ.js} +4 -4
  31. package/dist/{edge-import-MCJNVTZ2.js → edge-import-WJUB4M7F.js} +23 -22
  32. package/dist/{edge-preflight-ES6FH4JK.js → edge-preflight-GBNCPNVU.js} +10 -10
  33. package/dist/{ensure-container-edge-YPITNH45.js → ensure-container-edge-KPI2CVXJ.js} +9 -9
  34. package/dist/{executor-DZGX55K2.js → executor-7LXXZPBR.js} +6 -3
  35. package/dist/{host-channel-preflight-MUXE3KZU.js → host-channel-preflight-KE6OONYK.js} +23 -22
  36. package/dist/index.js +95 -84
  37. package/dist/{nginx-NSAHWGJV.js → nginx-KUFMLMAC.js} +9 -7
  38. package/dist/{openresty-lua-DR4D3EZ6.js → openresty-lua-ATTH35BE.js} +6 -4
  39. package/dist/{privilege-YTVI4SKF.js → privilege-I4W3ZNZK.js} +4 -4
  40. package/dist/server/engine/samples/amavisd/amavisd.conf +25 -0
  41. package/dist/server/engine/samples/postfix/master.cf +14 -0
  42. package/dist/server/index.js +35002 -27533
  43. package/dist/server/migrations/0105_mail_inbound_rules.sql +80 -0
  44. package/dist/server/migrations/0106_mcp_call_tracking.sql +23 -0
  45. package/dist/server/migrations/0107_build_minute_metering_indexes.sql +20 -0
  46. package/dist/server/migrations/0108_credential.sql +68 -0
  47. package/dist/server/migrations/meta/_journal.json +28 -0
  48. package/dist/{setup-WUUZURHS.js → setup-XGLGUUFW.js} +10 -10
  49. package/dist/ssh-client-JBMA7SN4.js +28 -0
  50. package/dist/{up-XEO3SR6Z.js → up-K4BV7466.js} +26 -27
  51. package/package.json +1 -1
  52. package/dist/chunk-6HOA5JT7.js +0 -124
  53. package/dist/chunk-XRNRT37W.js +0 -316
  54. /package/dist/{dist-es-ZP5QDSJ3.js → dist-es-AXFRS7PS.js} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  resolveDockerfileCandidates,
10
10
  resolveServiceDockerfile,
11
11
  staticBuilderOutputPath
12
- } from "./chunk-LFCSC4IU.js";
12
+ } from "./chunk-LUKYPVJ4.js";
13
13
  import {
14
14
  BuildCancelledError,
15
15
  BuildLogger,
@@ -20,7 +20,7 @@ import {
20
20
  shellGitSshWriter,
21
21
  sq,
22
22
  transferLocalDirectory
23
- } from "./chunk-TM2IQPYU.js";
23
+ } from "./chunk-LH2PLRQO.js";
24
24
  import {
25
25
  DOCKER_DIAL_STDIO_COMMAND,
26
26
  attachDialStdioDiagnostics,
@@ -29,11 +29,11 @@ import {
29
29
  execSshCommand,
30
30
  openDockerDialStdioChannel,
31
31
  openSshUnixSocket
32
- } from "./chunk-5OUWIPOB.js";
32
+ } from "./chunk-PCPVTH6M.js";
33
33
  import {
34
34
  dirOf,
35
35
  ensureOwnedDir
36
- } from "./chunk-WFRXYWK2.js";
36
+ } from "./chunk-UVNMQM7W.js";
37
37
  import {
38
38
  formatCpuCores,
39
39
  formatMemoryMb,
@@ -41,9 +41,11 @@ import {
41
41
  hasMemoryLimit,
42
42
  isRuntimeNotFoundError,
43
43
  ownsNetworkEndpoint,
44
+ registryConfigKeys,
45
+ registryForImage,
44
46
  safeErrorMessage,
45
47
  withTimeout
46
- } from "./chunk-LEYSL46B.js";
48
+ } from "./chunk-UJ6JZM65.js";
47
49
  import {
48
50
  __commonJS,
49
51
  __require,
@@ -313,7 +315,7 @@ var require_buffer_list = __commonJS({
313
315
  }
314
316
  }, {
315
317
  key: "join",
316
- value: function join2(s) {
318
+ value: function join3(s) {
317
319
  if (this.length === 0) return "";
318
320
  var p = this.head;
319
321
  var ret = "" + p.data;
@@ -4608,6 +4610,82 @@ import Dockerode from "dockerode";
4608
4610
  import { createGzip } from "zlib";
4609
4611
  import { PassThrough, Writable } from "stream";
4610
4612
 
4613
+ // ../../packages/adapters/src/runtime/docker-auth.ts
4614
+ import { readFile } from "fs/promises";
4615
+ import { homedir } from "os";
4616
+ import { join } from "path";
4617
+ function firstPresent(values, keys) {
4618
+ if (!values) return void 0;
4619
+ for (const key of keys) {
4620
+ if (Object.hasOwn(values, key)) return { key, value: values[key] };
4621
+ }
4622
+ return void 0;
4623
+ }
4624
+ function dockerConfigJsonFor(auth) {
4625
+ const a = auth;
4626
+ const registry = a.serveraddress?.trim();
4627
+ if (!registry) return null;
4628
+ if (a.identitytoken) {
4629
+ return JSON.stringify({ auths: { [registry]: { identitytoken: a.identitytoken } } });
4630
+ }
4631
+ if (!a.username || !a.password) return null;
4632
+ const encoded = Buffer.from(`${a.username}:${a.password}`).toString("base64");
4633
+ return JSON.stringify({ auths: { [registry]: { auth: encoded } } });
4634
+ }
4635
+ function toAuthConfig(entry, serveraddress) {
4636
+ if (entry.identitytoken) {
4637
+ return { identitytoken: entry.identitytoken, serveraddress };
4638
+ }
4639
+ if (entry.username && entry.password) {
4640
+ return { username: entry.username, password: entry.password, serveraddress };
4641
+ }
4642
+ if (!entry.auth) return void 0;
4643
+ let decoded;
4644
+ try {
4645
+ decoded = Buffer.from(entry.auth, "base64").toString("utf8");
4646
+ } catch {
4647
+ return void 0;
4648
+ }
4649
+ const separator = decoded.indexOf(":");
4650
+ if (separator < 1) return void 0;
4651
+ return {
4652
+ username: decoded.slice(0, separator),
4653
+ password: decoded.slice(separator + 1),
4654
+ serveraddress
4655
+ };
4656
+ }
4657
+ var DockerCredentialHelperError = class extends Error {
4658
+ constructor(registry) {
4659
+ super(
4660
+ `Openship can't read the credentials for ${registry}: they are stored in a Docker credential helper, which is not available inside the Openship container. Add the credentials inline to the Docker config (docker logout ${registry}, remove the credential helper for it, then docker login ${registry}), or use a public image.`
4661
+ );
4662
+ this.name = "DockerCredentialHelperError";
4663
+ }
4664
+ };
4665
+ async function resolveDockerAuth(ref) {
4666
+ const registry = registryForImage(ref);
4667
+ const configPath = join(
4668
+ process.env.DOCKER_CONFIG || join(homedir(), ".docker"),
4669
+ "config.json"
4670
+ );
4671
+ let config;
4672
+ try {
4673
+ config = JSON.parse(await readFile(configPath, "utf8"));
4674
+ } catch {
4675
+ return void 0;
4676
+ }
4677
+ if (!config || typeof config !== "object") return void 0;
4678
+ const keys = registryConfigKeys(registry);
4679
+ const inline = firstPresent(config.auths, keys);
4680
+ const usable = inline ? toAuthConfig(inline.value, inline.key) : void 0;
4681
+ if (usable) return usable;
4682
+ const helperForRegistry = firstPresent(config.credHelpers, keys);
4683
+ if (helperForRegistry || config.credsStore && inline) {
4684
+ throw new DockerCredentialHelperError(registry);
4685
+ }
4686
+ return void 0;
4687
+ }
4688
+
4611
4689
  // ../../packages/adapters/src/runtime/source-tarball.ts
4612
4690
  function githubTarballUrl(repoUrl, ref) {
4613
4691
  if (!repoUrl || !ref) return null;
@@ -4792,6 +4870,9 @@ function resolveComposeCmd(config) {
4792
4870
  if (config.commandArgv != null) return config.commandArgv;
4793
4871
  return config.command ? ["sh", "-c", config.command] : void 0;
4794
4872
  }
4873
+ function resolveComposeEntrypoint(advanced) {
4874
+ return advanced?.entrypoint ?? void 0;
4875
+ }
4795
4876
 
4796
4877
  // ../../packages/adapters/src/runtime/resource-limits.ts
4797
4878
  function dockerResourceLimits(resources) {
@@ -4843,8 +4924,8 @@ function describeResourceLimits(resources) {
4843
4924
  // ../../packages/adapters/src/runtime/docker-transport.ts
4844
4925
  import { createHash } from "crypto";
4845
4926
  import { readFileSync } from "fs";
4846
- import { homedir } from "os";
4847
- import { join } from "path";
4927
+ import { homedir as homedir2 } from "os";
4928
+ import { join as join2 } from "path";
4848
4929
 
4849
4930
  // ../../packages/adapters/src/runtime/docker-ssh-agent.ts
4850
4931
  import net2 from "net";
@@ -5317,7 +5398,7 @@ function createDockerSshBridge(opts) {
5317
5398
  var DEFAULT_DOCKER_SOCKET_PATH = "/var/run/docker.sock";
5318
5399
  var contextSocketCache = /* @__PURE__ */ new Map();
5319
5400
  function resolveDockerContextSocket(env) {
5320
- const configDir = env.DOCKER_CONFIG?.trim() || join(homedir(), ".docker");
5401
+ const configDir = env.DOCKER_CONFIG?.trim() || join2(homedir2(), ".docker");
5321
5402
  let name = env.DOCKER_CONTEXT?.trim();
5322
5403
  const cacheKey = `${configDir}\0${name ?? ""}`;
5323
5404
  const cached = contextSocketCache.get(cacheKey);
@@ -5325,13 +5406,13 @@ function resolveDockerContextSocket(env) {
5325
5406
  let socket = null;
5326
5407
  try {
5327
5408
  if (!name) {
5328
- const config = JSON.parse(readFileSync(join(configDir, "config.json"), "utf8"));
5409
+ const config = JSON.parse(readFileSync(join2(configDir, "config.json"), "utf8"));
5329
5410
  name = typeof config.currentContext === "string" ? config.currentContext.trim() : "";
5330
5411
  }
5331
5412
  if (name && name !== "default") {
5332
5413
  const digest = createHash("sha256").update(name).digest("hex");
5333
5414
  const meta = JSON.parse(
5334
- readFileSync(join(configDir, "contexts", "meta", digest, "meta.json"), "utf8")
5415
+ readFileSync(join2(configDir, "contexts", "meta", digest, "meta.json"), "utf8")
5335
5416
  );
5336
5417
  const host = meta.Endpoints?.docker?.Host;
5337
5418
  if (typeof host === "string" && host.startsWith("unix://")) {
@@ -5933,7 +6014,7 @@ var DockerRuntime = class _DockerRuntime {
5933
6014
  */
5934
6015
  async estimateContextSize(dir) {
5935
6016
  const { stat, readdir } = await import("fs/promises");
5936
- const { join: join2 } = await import("path");
6017
+ const { join: join3 } = await import("path");
5937
6018
  let total = 0;
5938
6019
  const stack = [dir];
5939
6020
  while (stack.length) {
@@ -5945,7 +6026,7 @@ var DockerRuntime = class _DockerRuntime {
5945
6026
  continue;
5946
6027
  }
5947
6028
  for (const entry of entries) {
5948
- const full = join2(current, entry.name);
6029
+ const full = join3(current, entry.name);
5949
6030
  if (entry.isDirectory()) {
5950
6031
  stack.push(full);
5951
6032
  } else if (entry.isFile()) {
@@ -6663,12 +6744,12 @@ var DockerRuntime = class _DockerRuntime {
6663
6744
  */
6664
6745
  async extractDocRootViaBindMount(tag, docRoot, hostOutDir) {
6665
6746
  const { mkdir, readdir, writeFile, rm } = await import("fs/promises");
6666
- const { join: join2 } = await import("path");
6747
+ const { join: join3 } = await import("path");
6667
6748
  const { randomBytes } = await import("crypto");
6668
6749
  await mkdir(hostOutDir, { recursive: true });
6669
6750
  const OUT = "/__openship_out";
6670
6751
  const probe = `.openship-extract-probe-${randomBytes(6).toString("hex")}`;
6671
- await writeFile(join2(hostOutDir, probe), "probe");
6752
+ await writeFile(join3(hostOutDir, probe), "probe");
6672
6753
  const container = await this.docker.createContainer({
6673
6754
  Image: tag,
6674
6755
  // Override the ENTRYPOINT: builder base images (node, bun) ship a
@@ -6708,7 +6789,7 @@ var DockerRuntime = class _DockerRuntime {
6708
6789
  } finally {
6709
6790
  await container.remove({ force: true }).catch(() => {
6710
6791
  });
6711
- await rm(join2(hostOutDir, probe), { force: true }).catch(() => {
6792
+ await rm(join3(hostOutDir, probe), { force: true }).catch(() => {
6712
6793
  });
6713
6794
  }
6714
6795
  }
@@ -7425,13 +7506,39 @@ var DockerRuntime = class _DockerRuntime {
7425
7506
  }
7426
7507
  const executor = this.connectionOptions?.executor;
7427
7508
  if (executor) {
7428
- await executor.exec(`docker pull ${sq(ref)}`, { timeout: 10 * 6e4 });
7509
+ const timeout = 10 * 6e4;
7510
+ const auth = await this.connectionOptions?.resolveRegistryAuth?.(ref);
7511
+ const config = auth ? dockerConfigJsonFor(auth) : null;
7512
+ if (!config) {
7513
+ await executor.exec(`docker pull ${sq(ref)}`, { timeout });
7514
+ return;
7515
+ }
7516
+ const dir = `/tmp/openship-pull-${crypto.randomUUID()}`;
7517
+ try {
7518
+ await executor.exec(`mkdir -m 700 ${sq(dir)}`);
7519
+ await executor.writeFile(`${dir}/config.json`, config);
7520
+ await executor.exec(`chmod 600 ${sq(dir)}/config.json`);
7521
+ await executor.exec(
7522
+ `DOCKER_CONFIG=${sq(dir)} docker pull ${sq(ref)}; rc=$?; rm -rf ${sq(dir)}; exit $rc`,
7523
+ { timeout }
7524
+ );
7525
+ } finally {
7526
+ await executor.exec(`rm -rf ${sq(dir)}`).catch(() => {
7527
+ });
7528
+ }
7429
7529
  return;
7430
7530
  }
7431
- const stream = await this.docker.pull(ref);
7432
- await new Promise((resolve, reject) => {
7433
- this.docker.modem.followProgress(stream, (err) => err ? reject(err) : resolve());
7434
- });
7531
+ const authconfig = this.connectionOptions?.resolveRegistryAuth ? await this.connectionOptions.resolveRegistryAuth(ref) : await resolveDockerAuth(ref);
7532
+ try {
7533
+ const stream = await this.docker.pull(ref, authconfig ? { authconfig } : {});
7534
+ await new Promise((resolve, reject) => {
7535
+ this.docker.modem.followProgress(stream, (err) => err ? reject(err) : resolve());
7536
+ });
7537
+ } catch (err) {
7538
+ throw new Error(
7539
+ `Failed to pull ${ref} from ${registryForImage(ref)}: ${safeErrorMessage(err)}`
7540
+ );
7541
+ }
7435
7542
  }
7436
7543
  /** Is this image tag present on THIS daemon? Distinguishes a locally-built
7437
7544
  * image (must be transferred cross-server) from a registry tag (the target
@@ -8217,6 +8324,7 @@ var DockerRuntime = class _DockerRuntime {
8217
8324
  ...Object.entries(config.environment).map(([k, v]) => `${k}=${v}`)
8218
8325
  ];
8219
8326
  const cmd = resolveComposeCmd(config);
8327
+ const entrypoint = resolveComposeEntrypoint(config.advanced);
8220
8328
  const sharedNetwork = config.namespaces?.network;
8221
8329
  const sharesNetns = !!sharedNetwork && sharedNetwork !== "none";
8222
8330
  const ownsProjectEndpoint = ownsNetworkEndpoint(sharedNetwork);
@@ -8282,6 +8390,12 @@ var DockerRuntime = class _DockerRuntime {
8282
8390
  name: containerName,
8283
8391
  Image: config.image,
8284
8392
  Cmd: cmd,
8393
+ // Entrypoint (#575). SPREAD rather than assigned, because `undefined` and `[]`
8394
+ // must reach Docker differently: absent leaves the image's own ENTRYPOINT
8395
+ // alone, while `Entrypoint: []` clears it. Assigning `undefined` would send the
8396
+ // key, and the same conditional-spread shape is why `toStopConfig` returns an
8397
+ // object instead of nullable fields.
8398
+ ...entrypoint === void 0 ? {} : { Entrypoint: entrypoint },
8285
8399
  Env: env,
8286
8400
  // Docker rejects an explicit hostname when the network namespace is another
8287
8401
  // container's — that container owns the UTS identity too.
@@ -9,12 +9,28 @@ import {
9
9
  readDeclaredPair,
10
10
  readMaybeInContainer,
11
11
  validateCertFor
12
- } from "./chunk-VLQ3UIVO.js";
12
+ } from "./chunk-QVW76WDL.js";
13
+ import {
14
+ EDGE_CHALLENGE_HOST_DIR,
15
+ EDGE_CONTAINER_MOUNTS,
16
+ EDGE_HOST_PATHS,
17
+ OPENRESTY_DEFAULT_PATHS
18
+ } from "./chunk-RSR7PFIQ.js";
13
19
  import {
14
20
  privilegedExecutor,
15
21
  rootChecked,
16
22
  rootOrDegrade
17
- } from "./chunk-RFWJE7ZN.js";
23
+ } from "./chunk-4I2BM2DT.js";
24
+ import {
25
+ envOps,
26
+ opScript
27
+ } from "./chunk-YMMQRE5J.js";
28
+ import {
29
+ resolveEnvironment
30
+ } from "./chunk-UVNMQM7W.js";
31
+ import {
32
+ sq
33
+ } from "./chunk-ZFJXPCQP.js";
18
34
  import {
19
35
  EDGE_CONTAINER_NAME,
20
36
  EdgeConflictError,
@@ -29,29 +45,13 @@ import {
29
45
  sanitizeEdgeVhosts,
30
46
  sq as sq2,
31
47
  stopTargetsForStatus
32
- } from "./chunk-WE7BXW6L.js";
48
+ } from "./chunk-2YM3NI2E.js";
33
49
  import {
34
50
  probeExec,
35
51
  tryExec,
36
52
  waitForPortListening,
37
53
  withReason
38
- } from "./chunk-A7EWM2KA.js";
39
- import {
40
- EDGE_CHALLENGE_HOST_DIR,
41
- EDGE_CONTAINER_MOUNTS,
42
- EDGE_HOST_PATHS,
43
- OPENRESTY_DEFAULT_PATHS
44
- } from "./chunk-PZRRL5PC.js";
45
- import {
46
- envOps,
47
- opScript
48
- } from "./chunk-EZPPTWJQ.js";
49
- import {
50
- resolveEnvironment
51
- } from "./chunk-WFRXYWK2.js";
52
- import {
53
- sq
54
- } from "./chunk-ZFJXPCQP.js";
54
+ } from "./chunk-SM26HDS2.js";
55
55
  import {
56
56
  AppError,
57
57
  PROXY_DIRECTIVES,
@@ -63,7 +63,7 @@ import {
63
63
  safeErrorMessage,
64
64
  sanitizeProxySettings,
65
65
  systemDebug
66
- } from "./chunk-LEYSL46B.js";
66
+ } from "./chunk-UJ6JZM65.js";
67
67
 
68
68
  // ../../packages/adapters/src/system/managed-image.ts
69
69
  import { posix } from "path";
@@ -396,6 +396,14 @@ async function dumpResolvedConfig(executor, bins) {
396
396
  }
397
397
  return null;
398
398
  }
399
+ async function nginxPrefix(executor, bins) {
400
+ for (const bin of bins) {
401
+ const out = await tryExec(executor, `${bin} -V 2>&1`);
402
+ const prefix = out?.match(/--prefix=(\S+)/)?.[1];
403
+ if (prefix) return prefix;
404
+ }
405
+ return null;
406
+ }
399
407
  async function loadNginxConfig(executor) {
400
408
  const dumped = await dumpResolvedConfig(executor, ["nginx", "openresty"]);
401
409
  if (dumped) return dumped;
@@ -511,9 +519,24 @@ function parseProxyDirectives(body) {
511
519
  ...Object.keys(raw).length > 0 ? { raw } : {}
512
520
  };
513
521
  }
514
- function parseServer(body, source, upstreams) {
522
+ var LOOPBACK_SERVER_NAMES = /* @__PURE__ */ new Set([
523
+ "localhost",
524
+ "localhost.localdomain",
525
+ "ip6-localhost",
526
+ "ip6-loopback"
527
+ ]);
528
+ function resolveStaticRoot(root, prefix) {
529
+ if (root.startsWith("/")) return { root };
530
+ if (!prefix) {
531
+ return {
532
+ reason: `static root "${root}" is relative to nginx's compiled prefix, which this host didn't report`
533
+ };
534
+ }
535
+ return { root: `${prefix.replace(/\/+$/, "")}/${root}` };
536
+ }
537
+ function parseServer(body, source, upstreams, prefix) {
515
538
  const warnings = [];
516
- const names = firstDirective(body, "server_name")?.split(/\s+/).filter((n) => n && n !== "_" && !n.startsWith("~")) ?? [];
539
+ const names = firstDirective(body, "server_name")?.split(/\s+/).filter((n) => n && n !== "_" && !n.startsWith("~") && !LOOPBACK_SERVER_NAMES.has(n.toLowerCase())) ?? [];
517
540
  const listens = [...body.matchAll(/(?:^|[;{\s])listen\s+([^;]+);/g)].map((m) => m[1]);
518
541
  const ssl = listens.some((l) => /\bssl\b/.test(l) || /\b443\b/.test(l));
519
542
  const root = firstDirective(body, "root");
@@ -540,7 +563,12 @@ function parseServer(body, source, upstreams) {
540
563
  } else if (isHttpsUpgradeForSelf(body, names)) {
541
564
  return { warnings: [] };
542
565
  } else if (root && !isAcmeWebrootOnly(body)) {
543
- target = { kind: "static", root: root.replace(/;$/, "") };
566
+ const resolved2 = resolveStaticRoot(root.replace(/;$/, ""), prefix);
567
+ if ("reason" in resolved2) {
568
+ warnings.push(`nginx: ${names[0]} \u2014 ${resolved2.reason} (skipped)`);
569
+ return { warnings };
570
+ }
571
+ target = { kind: "static", root: resolved2.root };
544
572
  } else if (root) {
545
573
  return { warnings: [] };
546
574
  } else {
@@ -555,7 +583,7 @@ function parseServer(body, source, upstreams) {
555
583
  if (tunables.raw) site.proxyRaw = tunables.raw;
556
584
  return { site, warnings };
557
585
  }
558
- function parseNginxConfig(raw) {
586
+ function parseNginxConfig(raw, prefix) {
559
587
  const warnings = [];
560
588
  const sites = [];
561
589
  if (!raw.trim()) {
@@ -568,7 +596,7 @@ function parseNginxConfig(raw) {
568
596
  warnings.push("nginx: no server blocks found");
569
597
  }
570
598
  for (const body of blocks) {
571
- const { site, warnings: blockWarnings } = parseServer(body, "nginx", upstreams);
599
+ const { site, warnings: blockWarnings } = parseServer(body, "nginx", upstreams, prefix);
572
600
  warnings.push(...blockWarnings);
573
601
  if (site) sites.push(site);
574
602
  }
@@ -580,7 +608,10 @@ function parseNginxConfig(raw) {
580
608
  return { proxy: "nginx", sites: kept, warnings };
581
609
  }
582
610
  async function scanNginx(executor) {
583
- return parseNginxConfig(await loadNginxConfig(executor));
611
+ const raw = await loadNginxConfig(executor);
612
+ const relativeRoot = /(?:^|[;{\s])root\s+[^/;\s]/.test(raw);
613
+ const prefix = relativeRoot ? await nginxPrefix(executor, ["nginx", "openresty"]) : null;
614
+ return parseNginxConfig(raw, prefix ?? void 0);
584
615
  }
585
616
  var OUR_EDGE_SITE_GLOBS = [
586
617
  `${EDGE_HOST_PATHS.sitesDir}/*.conf`,
@@ -2277,7 +2308,7 @@ function edgeHostExecutor(executor) {
2277
2308
  });
2278
2309
  }
2279
2310
  async function containerEdgeProvider(executor, container, opts) {
2280
- const { NginxProvider: Provider } = await import("./nginx-NSAHWGJV.js");
2311
+ const { NginxProvider: Provider } = await import("./nginx-KUFMLMAC.js");
2281
2312
  return new Provider({
2282
2313
  ...opts,
2283
2314
  // Vhosts go to the BIND-MOUNTED HOST dir (so every host-side reader — the
@@ -2301,8 +2332,8 @@ async function containerEdgeProvider(executor, container, opts) {
2301
2332
  });
2302
2333
  }
2303
2334
  async function localContainerEdgeProvider(container, opts) {
2304
- const { DockerEdgeExecutor } = await import("./docker-edge-executor-YZZ6P7IC.js");
2305
- const { NginxProvider: Provider } = await import("./nginx-NSAHWGJV.js");
2335
+ const { DockerEdgeExecutor } = await import("./docker-edge-executor-22IBXNYJ.js");
2336
+ const { NginxProvider: Provider } = await import("./nginx-KUFMLMAC.js");
2306
2337
  return new Provider({
2307
2338
  ...opts,
2308
2339
  paths: OPENRESTY_DEFAULT_PATHS,
@@ -2434,8 +2465,13 @@ async function ensureContainerEdge(executor, opts) {
2434
2465
  );
2435
2466
  }
2436
2467
  }
2468
+ const hostState = await rootOrDegrade(executor, {
2469
+ purpose: "Creating the edge's state directories",
2470
+ consequence: "Docker will create them empty, so vhosts and certificates may not persist.",
2471
+ report: (message) => onLog(log5(message, "warn"))
2472
+ });
2437
2473
  for (const mount of EDGE_CONTAINER_MOUNTS) {
2438
- await executor.exec(`mkdir -p ${sq(mount.host)}`).catch((err) => {
2474
+ await hostState.exec(`mkdir -p ${sq(mount.host)}`).catch((err) => {
2439
2475
  onLog(
2440
2476
  log5(
2441
2477
  `Could not create the edge state directory ${mount.host}: ${safeErrorMessage(err)}. Docker will create it empty, so vhosts and certificates may not persist.`,
@@ -19,13 +19,13 @@ import {
19
19
  rollbackEdgeTakeover,
20
20
  scanImportableSites,
21
21
  unreachableStaticRoots
22
- } from "./chunk-7334NSJL.js";
22
+ } from "./chunk-A4GXYE4L.js";
23
23
  import {
24
24
  LocalExecutor
25
25
  } from "./chunk-6FH4AXVY.js";
26
26
  import {
27
27
  ourEdgeContainerRunning
28
- } from "./chunk-WE7BXW6L.js";
28
+ } from "./chunk-2YM3NI2E.js";
29
29
 
30
30
  // src/lib/edge-preflight.ts
31
31
  import { spawnSync } from "child_process";
@@ -240,7 +240,7 @@ async function repairEdgeConflict(mode, apiPort, onLog) {
240
240
  }
241
241
  spawnSync("docker", ["restart", "openship-edge"], { stdio: "ignore" });
242
242
  if (mode === "migrate" && scan.sites.length > 0) {
243
- const { importMigratedSites } = await import("./edge-import-MCJNVTZ2.js");
243
+ const { importMigratedSites } = await import("./edge-import-WJUB4M7F.js");
244
244
  const outcome = await importMigratedSites(apiPort, scan.sites, certPems);
245
245
  if (outcome.registered.length === 0) {
246
246
  return {
@@ -9,13 +9,13 @@ import {
9
9
  import {
10
10
  LocalExecutor
11
11
  } from "./chunk-6FH4AXVY.js";
12
- import {
13
- edgeFailureReason
14
- } from "./chunk-WE7BXW6L.js";
15
12
  import {
16
13
  logEntry,
17
14
  sq
18
15
  } from "./chunk-ZFJXPCQP.js";
16
+ import {
17
+ edgeFailureReason
18
+ } from "./chunk-2YM3NI2E.js";
19
19
 
20
20
  // ../../packages/adapters/src/system/docker-edge-executor.ts
21
21
  import Dockerode from "dockerode";
@@ -7,7 +7,7 @@ import {
7
7
  COMPONENT_INSTALLERS,
8
8
  checkAll,
9
9
  checkComponents
10
- } from "./chunk-7334NSJL.js";
10
+ } from "./chunk-A4GXYE4L.js";
11
11
 
12
12
  // ../../packages/adapters/src/system/state.ts
13
13
  var DEFAULT_STATE_PATH = "/etc/openship/setup-state.json";
@@ -7,7 +7,7 @@ import {
7
7
  resolveProjectDir,
8
8
  resolveStaticOutputPath,
9
9
  runLocalBuild
10
- } from "./chunk-MSZUCNPV.js";
10
+ } from "./chunk-YIMOCZBZ.js";
11
11
  import {
12
12
  BuildCancelledError,
13
13
  BuildLogger,
@@ -17,32 +17,32 @@ import {
17
17
  runBuildPipeline,
18
18
  sq,
19
19
  transferLocalDirectory
20
- } from "./chunk-TM2IQPYU.js";
20
+ } from "./chunk-LH2PLRQO.js";
21
21
  import {
22
22
  LocalExecutor
23
23
  } from "./chunk-6FH4AXVY.js";
24
24
  import {
25
25
  privilegedExecutor
26
- } from "./chunk-RFWJE7ZN.js";
27
- import {
28
- probeExec,
29
- probeListeningPort,
30
- withReason
31
- } from "./chunk-A7EWM2KA.js";
26
+ } from "./chunk-4I2BM2DT.js";
32
27
  import {
33
28
  HOST_STATE_DIR,
34
29
  envOps,
35
30
  hostRefusal,
36
31
  opScript
37
- } from "./chunk-EZPPTWJQ.js";
32
+ } from "./chunk-YMMQRE5J.js";
38
33
  import {
39
34
  ensureOwnedDir,
40
35
  resolveEnvironment
41
- } from "./chunk-WFRXYWK2.js";
36
+ } from "./chunk-UVNMQM7W.js";
42
37
  import {
43
38
  sq as sq2,
44
39
  wrapLocalBuildCommand
45
40
  } from "./chunk-ZFJXPCQP.js";
41
+ import {
42
+ probeExec,
43
+ probeListeningPort,
44
+ withReason
45
+ } from "./chunk-SM26HDS2.js";
46
46
  import {
47
47
  DeployError,
48
48
  LANGUAGES,
@@ -59,7 +59,7 @@ import {
59
59
  safeErrorMessage,
60
60
  shellQuote,
61
61
  systemDebug
62
- } from "./chunk-LEYSL46B.js";
62
+ } from "./chunk-UJ6JZM65.js";
63
63
 
64
64
  // ../../packages/adapters/src/system/remote-journal.ts
65
65
  var OPSH_RUN_VERSION = 1;
@@ -5,12 +5,12 @@ const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  getTarCreateEnv,
7
7
  prepareSourceTarArgs
8
- } from "./chunk-5OUWIPOB.js";
8
+ } from "./chunk-Q7WGTQQ5.js";
9
9
  import {
10
10
  TRANSFER_EXCLUDES,
11
11
  packageManagerEnsureCommand,
12
12
  safeErrorMessage
13
- } from "./chunk-LEYSL46B.js";
13
+ } from "./chunk-UJ6JZM65.js";
14
14
 
15
15
  // ../../packages/adapters/src/runtime/git-clone.ts
16
16
  function sq(value) {
@@ -7,14 +7,14 @@ import {
7
7
  localGitSshWriter,
8
8
  materializeGitSsh,
9
9
  sq
10
- } from "./chunk-TM2IQPYU.js";
10
+ } from "./chunk-LH2PLRQO.js";
11
11
  import {
12
12
  getTarCreateEnv,
13
13
  prepareSourceTarArgs
14
- } from "./chunk-5OUWIPOB.js";
14
+ } from "./chunk-Q7WGTQQ5.js";
15
15
  import {
16
16
  packageManagerEnsureCommand
17
- } from "./chunk-LEYSL46B.js";
17
+ } from "./chunk-UJ6JZM65.js";
18
18
  import {
19
19
  __commonJS,
20
20
  __toESM