openship 0.6.7 → 0.6.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.
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-PPEBIY5F.js → chunk-5I3COAFH.js} +35 -12
  5. package/dist/{chunk-VQM6JHJB.js → chunk-5UXHT6ED.js} +9 -9
  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-BLEXTYRK.js → chunk-GNOMEMNI.js} +1 -1
  15. package/dist/{chunk-NRTJRNAE.js → chunk-IAMOUDHY.js} +138 -54
  16. package/dist/{chunk-CIJV43LH.js → chunk-MUWVC5R4.js} +161 -39
  17. package/dist/{chunk-ZPJ74LXE.js → chunk-NIYD7MD2.js} +197 -45
  18. package/dist/{chunk-FZ6QCF6B.js → chunk-NPSRGIHV.js} +2 -2
  19. package/dist/{chunk-2GWYYHOR.js → chunk-NRU2EBYZ.js} +2 -2
  20. package/dist/{chunk-J2XM3QSP.js → chunk-NUT6HKK6.js} +5 -5
  21. package/dist/{chunk-H3WT3A6R.js → chunk-P7RCYELG.js} +1 -1
  22. package/dist/{chunk-FYPFEDPZ.js → chunk-R5DC5PEF.js} +1 -1
  23. package/dist/{chunk-DDFUESPJ.js → chunk-RCMERVBL.js} +9 -9
  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-OMCZMMKR.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 +31643 -25553
  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-HQS7IR7H.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
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env sh
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
+ import { createRequire as __ospCreateRequire } from "node:module";
4
+ const require = __ospCreateRequire(import.meta.url);
5
+ import {
6
+ BareRuntime,
7
+ STATIC_RELEASE_BASE
8
+ } from "./chunk-ENKJ7XIF.js";
9
+ import "./chunk-5DJOB7IX.js";
10
+ import "./chunk-SK4FFCFR.js";
11
+ import "./chunk-AHJYP7DG.js";
12
+ import "./chunk-UAWY6X7V.js";
13
+ import "./chunk-R4VDPFLS.js";
14
+ import "./chunk-VAI5VOOI.js";
15
+ import "./chunk-TAZZZKYO.js";
16
+ import "./chunk-T6DVUX4F.js";
17
+ import "./chunk-T46BQOLY.js";
18
+ import "./chunk-GNOMEMNI.js";
19
+ import "./chunk-NPSRGIHV.js";
20
+ import "./chunk-P7RCYELG.js";
21
+ import "./chunk-BO6CY4V2.js";
22
+ import "./chunk-D6HU4VUZ.js";
23
+ import "./chunk-N5YZMO33.js";
24
+ import "./chunk-WEZFTL4V.js";
25
+ import "./chunk-PXKCZB2I.js";
26
+ export {
27
+ BareRuntime,
28
+ STATIC_RELEASE_BASE
29
+ };
@@ -7,12 +7,13 @@ import {
7
7
  createDockerBuildContext,
8
8
  missingContextDockerfileMessage,
9
9
  prepareSourceTree,
10
+ resolveDockerBuildArgs,
10
11
  resolveServiceDockerfile
11
- } from "./chunk-XWHWTHEL.js";
12
+ } from "./chunk-6GU6JSK6.js";
12
13
  import {
13
14
  isArtifactPathRef,
14
15
  removeManagedArtifact
15
- } from "./chunk-WU54BXFE.js";
16
+ } from "./chunk-SK4FFCFR.js";
16
17
  import {
17
18
  BuildCancelledError,
18
19
  BuildLogger,
@@ -33,7 +34,7 @@ import {
33
34
  sq,
34
35
  staticBuilderOutputPath,
35
36
  transferLocalDirectory
36
- } from "./chunk-H4FS5BED.js";
37
+ } from "./chunk-AHJYP7DG.js";
37
38
  import {
38
39
  DOCKER_DIAL_STDIO_COMMAND,
39
40
  attachDialStdioDiagnostics,
@@ -42,14 +43,14 @@ import {
42
43
  execSshCommand,
43
44
  openDockerDialStdioChannel,
44
45
  openSshUnixSocket
45
- } from "./chunk-5T4UVOM3.js";
46
+ } from "./chunk-TAZZZKYO.js";
46
47
  import {
47
48
  dirOf,
48
49
  ensureOwnedDir
49
- } from "./chunk-FZ6QCF6B.js";
50
+ } from "./chunk-NPSRGIHV.js";
50
51
  import {
51
52
  OPENSHIP_LABEL
52
- } from "./chunk-UWEV6XTS.js";
53
+ } from "./chunk-D6HU4VUZ.js";
53
54
  import {
54
55
  isRuntimeNotFoundError
55
56
  } from "./chunk-N5YZMO33.js";
@@ -63,7 +64,7 @@ import {
63
64
  registryForImage,
64
65
  safeErrorMessage,
65
66
  withTimeout
66
- } from "./chunk-2VSW6Q6C.js";
67
+ } from "./chunk-WEZFTL4V.js";
67
68
  import {
68
69
  __commonJS,
69
70
  __require,
@@ -4954,7 +4955,6 @@ import { join as join2 } from "path";
4954
4955
  import net2 from "net";
4955
4956
  var DEFAULT_REMOTE_DOCKER_SOCKET_PATH = "/var/run/docker.sock";
4956
4957
  var resolvedDockerSocketPathCache = /* @__PURE__ */ new WeakMap();
4957
- var STREAMLOCAL_PROBE_TIMEOUT_MS = 8e3;
4958
4958
  var STREAMLOCAL_DATA_VERIFY_TIMEOUT_MS = 3e3;
4959
4959
  var DIAL_STDIO_ANSWER_TIMEOUT_MS = 3e3;
4960
4960
  var VERIFY_BUFFER_CAP_BYTES = 8 * 1024 * 1024;
@@ -5280,12 +5280,12 @@ function createDockerSshBridge(opts) {
5280
5280
  try {
5281
5281
  probe = await withTimeout(
5282
5282
  openStreamlocalUpstream(opts),
5283
- STREAMLOCAL_PROBE_TIMEOUT_MS,
5284
- `streamlocal open timed out after ${STREAMLOCAL_PROBE_TIMEOUT_MS / 1e3}s`
5283
+ STREAMLOCAL_DATA_VERIFY_TIMEOUT_MS,
5284
+ `streamlocal open timed out after ${STREAMLOCAL_DATA_VERIFY_TIMEOUT_MS / 1e3}s`
5285
5285
  );
5286
5286
  const stream = probe;
5287
5287
  const flowed = await new Promise((resolve) => {
5288
- const timer = setTimeout(() => resolve(false), STREAMLOCAL_PROBE_TIMEOUT_MS);
5288
+ const timer = setTimeout(() => resolve(false), STREAMLOCAL_DATA_VERIFY_TIMEOUT_MS);
5289
5289
  const settle = (ok) => {
5290
5290
  clearTimeout(timer);
5291
5291
  resolve(ok);
@@ -5535,7 +5535,7 @@ function resolveDockerTransport(opts) {
5535
5535
  // ../../packages/adapters/src/runtime/docker.ts
5536
5536
  var isDockerNotFoundError = isRuntimeNotFoundError;
5537
5537
  function ownsBuiltImage(imageRef) {
5538
- return imageRef.startsWith("openship/");
5538
+ return /^openship\/[a-z0-9][a-z0-9._-]*:bld_[A-Za-z0-9_-]+$/.test(imageRef);
5539
5539
  }
5540
5540
  function clampShellWindow(value, fallback, min, max) {
5541
5541
  const n = Number.isFinite(value) ? Number(value) : fallback;
@@ -5603,14 +5603,7 @@ var IN_CONTAINER_EXEC_WATCHDOG = [
5603
5603
  ].join("\n");
5604
5604
  function buildInContainerExecCmd(command, timeoutMs) {
5605
5605
  const seconds = Math.max(1, Math.ceil(timeoutMs / 1e3));
5606
- return [
5607
- "sh",
5608
- "-c",
5609
- IN_CONTAINER_EXEC_WATCHDOG,
5610
- "openship-exec",
5611
- command,
5612
- String(seconds)
5613
- ];
5606
+ return ["sh", "-c", IN_CONTAINER_EXEC_WATCHDOG, "openship-exec", command, String(seconds)];
5614
5607
  }
5615
5608
  async function resolveExecExitCode(exec, label) {
5616
5609
  let info = await exec.inspect();
@@ -5745,7 +5738,7 @@ function packBuildContext(contextDir, entries, cancelSignal, ignoreContextPath)
5745
5738
  var DURATION_UNITS_NS = {
5746
5739
  ns: 1,
5747
5740
  us: 1e3,
5748
- "\xB5s": 1e3,
5741
+ \u00B5s: 1e3,
5749
5742
  ms: 1e6,
5750
5743
  s: 1e9,
5751
5744
  m: 6e10,
@@ -5853,7 +5846,7 @@ function firstNetworkIp(networks) {
5853
5846
  }
5854
5847
  function extractNetworkInfo(data) {
5855
5848
  let ip;
5856
- for (const net3 of Object.values(data.NetworkSettings.Networks ?? {})) {
5849
+ for (const net3 of Object.values(data.NetworkSettings?.Networks ?? {})) {
5857
5850
  if (net3.IPAddress) {
5858
5851
  ip = net3.IPAddress;
5859
5852
  break;
@@ -5861,14 +5854,31 @@ function extractNetworkInfo(data) {
5861
5854
  }
5862
5855
  const hostPortByContainerPort = {};
5863
5856
  let hostPort;
5864
- for (const [key, bindings] of Object.entries(data.NetworkSettings.Ports ?? {})) {
5865
- const bound = bindings?.[0]?.HostPort;
5866
- if (!bound) continue;
5867
- const parsed = parseInt(bound, 10);
5868
- if (!Number.isFinite(parsed)) continue;
5869
- const containerPort = parseInt(key.split("/")[0] ?? "", 10);
5870
- if (Number.isFinite(containerPort)) hostPortByContainerPort[containerPort] = parsed;
5871
- hostPort ??= parsed;
5857
+ const liveBindings = data.NetworkSettings?.Ports ?? {};
5858
+ const configuredBindings = data.HostConfig?.PortBindings ?? {};
5859
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(liveBindings), ...Object.keys(configuredBindings)])) {
5860
+ const [containerRaw, protocol = "tcp"] = key.split("/");
5861
+ if (protocol.toLowerCase() !== "tcp") continue;
5862
+ const containerPort = Number(containerRaw);
5863
+ if (!Number.isSafeInteger(containerPort) || containerPort < 1 || containerPort > 65535) {
5864
+ continue;
5865
+ }
5866
+ const live = liveBindings[key];
5867
+ const bindings = live && live.some((binding) => binding?.HostPort) ? live : configuredBindings[key];
5868
+ const candidates = (bindings ?? []).map((binding, index) => {
5869
+ const port = Number(binding?.HostPort);
5870
+ if (!Number.isSafeInteger(port) || port < 1 || port > 65535) return null;
5871
+ const ip2 = binding?.HostIp?.trim().replace(/^\[|\]$/g, "") ?? "";
5872
+ const priority = ip2 === "127.0.0.1" || ip2 === "::1" ? 3 : /^127(?:\.\d{1,3}){3}$/.test(ip2) ? 2 : ip2 && ip2 !== "0.0.0.0" && ip2 !== "::" ? 1 : 0;
5873
+ return { index, port, priority };
5874
+ }).filter(
5875
+ (candidate) => Boolean(candidate)
5876
+ ).sort((left, right) => right.priority - left.priority || left.index - right.index);
5877
+ const selected = candidates[0]?.port;
5878
+ if (selected !== void 0) {
5879
+ hostPortByContainerPort[containerPort] = selected;
5880
+ hostPort ??= selected;
5881
+ }
5872
5882
  }
5873
5883
  return {
5874
5884
  ip,
@@ -5923,6 +5933,7 @@ var DockerRuntime = class _DockerRuntime {
5923
5933
  name = "docker";
5924
5934
  capabilities = /* @__PURE__ */ new Set([
5925
5935
  "build",
5936
+ "prebuiltImage",
5926
5937
  "deploy",
5927
5938
  "multiServiceDeploy",
5928
5939
  "stop",
@@ -6235,10 +6246,8 @@ var DockerRuntime = class _DockerRuntime {
6235
6246
  const signal = opts?.signal;
6236
6247
  const executor = this.connectionOptions?.executor;
6237
6248
  if (!executor) throw new Error("SSH build path requires an executor on connectionOptions");
6238
- const buildArgs = Object.entries({
6239
- ...config.envVars,
6240
- NODE_ENV: "production"
6241
- }).filter(([k]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k)).map(([k, v]) => `--build-arg ${sq(`${k}=${v}`)}`).join(" ");
6249
+ const resolvedBuildArgs = resolveDockerBuildArgs(config);
6250
+ const buildArgs = Object.entries(resolvedBuildArgs).map(([k, v]) => `--build-arg ${sq(`${k}=${v}`)}`).join(" ");
6242
6251
  const labelArgs = Object.entries(
6243
6252
  this.labels({ projectId: config.projectId, sessionId: config.sessionId })
6244
6253
  ).map(([k, v]) => `--label ${sq(`${k}=${v}`)}`).join(" ");
@@ -6259,9 +6268,16 @@ var DockerRuntime = class _DockerRuntime {
6259
6268
  );
6260
6269
  }
6261
6270
  const buildCmd = `cd ${sq(remoteBuildDir)} && ${builderEnv}docker build${builderFlags} -t ${sq(tag)}${dockerfileFlag} ${labelArgs} ${buildArgs} .`;
6262
- log.log(`Running on remote: ${buildCmd}`);
6271
+ log.log(
6272
+ `Running Docker build on remote (${Object.keys(resolvedBuildArgs).length} build argument${Object.keys(resolvedBuildArgs).length === 1 ? "" : "s"}; values hidden).`
6273
+ );
6263
6274
  log.log("\u2500\u2500\u2500 docker build output \u2500\u2500\u2500");
6264
- this.emitDockerStep(log, "install", "running", "Running install inside container (docker build)");
6275
+ this.emitDockerStep(
6276
+ log,
6277
+ "install",
6278
+ "running",
6279
+ "Running install inside container (docker build)"
6280
+ );
6265
6281
  const { code } = await executor.streamExec(
6266
6282
  buildCmd,
6267
6283
  (entry) => {
@@ -6322,7 +6338,11 @@ var DockerRuntime = class _DockerRuntime {
6322
6338
  config.gitSsh
6323
6339
  );
6324
6340
  }
6325
- const { cloneUrl, gitEnv: GIT_ENV, credFlag: CRED } = assembleGitClone({
6341
+ const {
6342
+ cloneUrl,
6343
+ gitEnv: GIT_ENV,
6344
+ credFlag: CRED
6345
+ } = assembleGitClone({
6326
6346
  repoUrl: config.repoUrl,
6327
6347
  gitToken: config.gitToken,
6328
6348
  gitCredentialHelperPath: config.gitCredentialHelperPath,
@@ -6348,8 +6368,11 @@ var DockerRuntime = class _DockerRuntime {
6348
6368
  `${GIT_ENV} git ${CRED} clone --progress --depth 50 --branch ${sq(config.branch)} ${sq(cloneUrl)} ${dir} && cd ${dir} && git ${CRED} -c advice.detachedHead=false checkout ${sq(config.commitSha)}`
6349
6369
  );
6350
6370
  } catch {
6351
- log.log(`Commit ${config.commitSha} not in the shallow clone; unshallowing and retrying.
6352
- `, "warn");
6371
+ log.log(
6372
+ `Commit ${config.commitSha} not in the shallow clone; unshallowing and retrying.
6373
+ `,
6374
+ "warn"
6375
+ );
6353
6376
  await run(
6354
6377
  `cd ${dir} && ${GIT_ENV} git ${CRED} fetch --progress --unshallow && git ${CRED} -c advice.detachedHead=false checkout ${sq(config.commitSha)}`
6355
6378
  );
@@ -6500,10 +6523,7 @@ var DockerRuntime = class _DockerRuntime {
6500
6523
  t: tag,
6501
6524
  dockerfile: buildContext.dockerfileName,
6502
6525
  labels: this.labels({ projectId: config.projectId, sessionId: config.sessionId }),
6503
- buildargs: {
6504
- ...config.envVars,
6505
- NODE_ENV: "production"
6506
- },
6526
+ buildargs: resolveDockerBuildArgs(config),
6507
6527
  // Omitted entirely unless the project set a build cap — a self-hosted
6508
6528
  // build should be free to use the machine (a production build often
6509
6529
  // needs several GB). Opt-in only; see dockerBuildResourceLimits.
@@ -6517,7 +6537,9 @@ var DockerRuntime = class _DockerRuntime {
6517
6537
  log.log("Docker daemon finished streaming build output. Finalizing image...\n");
6518
6538
  } catch (err) {
6519
6539
  const contextErr = takeError();
6520
- throw contextErr ? new Error(`Failed to read Docker build context: ${safeErrorMessage(contextErr)}`, { cause: contextErr }) : err;
6540
+ throw contextErr ? new Error(`Failed to read Docker build context: ${safeErrorMessage(contextErr)}`, {
6541
+ cause: contextErr
6542
+ }) : err;
6521
6543
  } finally {
6522
6544
  await buildContext.cleanup();
6523
6545
  }
@@ -6566,9 +6588,11 @@ var DockerRuntime = class _DockerRuntime {
6566
6588
  }, 6e4);
6567
6589
  if (keepaliveTimer.unref) keepaliveTimer.unref();
6568
6590
  idleTimer = setTimeout(() => {
6569
- fail(new Error(
6570
- "Docker build produced no output for 30 minutes. This usually means the remote server cannot reach the package registry, has broken DNS, or the Docker daemon stalled during the build."
6571
- ));
6591
+ fail(
6592
+ new Error(
6593
+ "Docker build produced no output for 30 minutes. This usually means the remote server cannot reach the package registry, has broken DNS, or the Docker daemon stalled during the build."
6594
+ )
6595
+ );
6572
6596
  }, DOCKER_BUILD_IDLE_TIMEOUT_MS);
6573
6597
  if (idleTimer.unref) idleTimer.unref();
6574
6598
  };
@@ -6672,7 +6696,12 @@ var DockerRuntime = class _DockerRuntime {
6672
6696
  log.log(`Image ${tag} is ready.
6673
6697
  `);
6674
6698
  log.step("build", "completed", `Finalizing image ${tag}`);
6675
- return { sessionId: config.sessionId, status: "deploying", imageRef: tag, durationMs: Date.now() - startTime };
6699
+ return {
6700
+ sessionId: config.sessionId,
6701
+ status: "deploying",
6702
+ imageRef: tag,
6703
+ durationMs: Date.now() - startTime
6704
+ };
6676
6705
  }
6677
6706
  this.emitDockerStep(log, "clone", "running", "Preparing Docker build context...");
6678
6707
  const buildContext = await createDockerBuildContext(config, {
@@ -6683,12 +6712,7 @@ var DockerRuntime = class _DockerRuntime {
6683
6712
  try {
6684
6713
  const sizeBytes = await this.estimateContextSize(buildContext.contextDir);
6685
6714
  const sizeMB = (sizeBytes / 1024 / 1024).toFixed(1);
6686
- this.emitDockerStep(
6687
- log,
6688
- "clone",
6689
- "completed",
6690
- `Docker build context ready (${sizeMB} MB)`
6691
- );
6715
+ this.emitDockerStep(log, "clone", "completed", `Docker build context ready (${sizeMB} MB)`);
6692
6716
  } catch {
6693
6717
  this.emitDockerStep(log, "clone", "completed", "Docker build context ready");
6694
6718
  }
@@ -6734,7 +6758,75 @@ var DockerRuntime = class _DockerRuntime {
6734
6758
  if (abort.signal.aborted || err instanceof BuildCancelledError) return cancelled();
6735
6759
  const msg = safeErrorMessage(err);
6736
6760
  log.step("build", "failed", `Docker build failed: ${msg}`);
6737
- return { sessionId: config.sessionId, status: "failed", durationMs: Date.now() - startTime, errorMessage: `Docker build failed: ${msg}` };
6761
+ return {
6762
+ sessionId: config.sessionId,
6763
+ status: "failed",
6764
+ durationMs: Date.now() - startTime,
6765
+ errorMessage: `Docker build failed: ${msg}`
6766
+ };
6767
+ } finally {
6768
+ releaseDockerBuild(config.sessionId, abort);
6769
+ }
6770
+ }
6771
+ /**
6772
+ * Acquire a registry image without ever treating it as a Dockerfile builder.
6773
+ *
6774
+ * The returned digest is preferred over the requested tag so a later deploy
6775
+ * runs exactly the bytes acquired here even if a mutable tag moves between
6776
+ * prepare and deploy. The image is deliberately non-owned: it came from a
6777
+ * registry and may be shared by unrelated containers on the target daemon, so
6778
+ * deployment cleanup must never remove it as if Openship had built it.
6779
+ */
6780
+ async prepareImage(config, logger) {
6781
+ const log = logger ?? new BuildLogger();
6782
+ const startTime = Date.now();
6783
+ const abort = registerDockerBuild(config.sessionId);
6784
+ const cancelled = () => {
6785
+ log.step("build", "failed", "Image pull cancelled");
6786
+ return {
6787
+ sessionId: config.sessionId,
6788
+ status: "cancelled",
6789
+ durationMs: Date.now() - startTime,
6790
+ artifactOwned: false
6791
+ };
6792
+ };
6793
+ try {
6794
+ if (abort.signal.aborted) return cancelled();
6795
+ const requestedRef = config.imageRef.trim();
6796
+ if (!requestedRef) throw new Error("Prebuilt image reference is required");
6797
+ log.step("build", "running", `Pulling prebuilt image ${requestedRef}`);
6798
+ try {
6799
+ await this.ensureDockerFeature(log);
6800
+ } catch (featureErr) {
6801
+ throw new Error(this.formatDockerConnectivityError(featureErr));
6802
+ }
6803
+ await this.pullImage(requestedRef, { force: config.forcePull });
6804
+ if (abort.signal.aborted) return cancelled();
6805
+ const deployRef = await this.resolveImageDigest(requestedRef).catch(() => void 0) ?? requestedRef;
6806
+ log.log(
6807
+ deployRef === requestedRef ? `Image ${requestedRef} is ready.
6808
+ ` : `Image ${requestedRef} is ready as ${deployRef}.
6809
+ `
6810
+ );
6811
+ log.step("build", "completed", `Prebuilt image ${deployRef} is ready`);
6812
+ return {
6813
+ sessionId: config.sessionId,
6814
+ status: "deploying",
6815
+ imageRef: deployRef,
6816
+ durationMs: Date.now() - startTime,
6817
+ artifactOwned: false
6818
+ };
6819
+ } catch (err) {
6820
+ if (abort.signal.aborted) return cancelled();
6821
+ const message = safeErrorMessage(err);
6822
+ log.step("build", "failed", `Image pull failed: ${message}`);
6823
+ return {
6824
+ sessionId: config.sessionId,
6825
+ status: "failed",
6826
+ durationMs: Date.now() - startTime,
6827
+ errorMessage: `Image pull failed: ${message}`,
6828
+ artifactOwned: false
6829
+ };
6738
6830
  } finally {
6739
6831
  releaseDockerBuild(config.sessionId, abort);
6740
6832
  }
@@ -6883,9 +6975,9 @@ var DockerRuntime = class _DockerRuntime {
6883
6975
  async pruneBuildFilesFromDocRoot(config, hostOutDir, sshExecutor, log) {
6884
6976
  if (staticBuilderOutputPath(config) !== builderContextRoot(config)) return;
6885
6977
  if (sshExecutor) {
6886
- const globs = _DockerRuntime.DOC_ROOT_EXCLUDED.map(
6887
- (name) => `${sq(hostOutDir)}/${name}`
6888
- ).join(" ");
6978
+ const globs = _DockerRuntime.DOC_ROOT_EXCLUDED.map((name) => `${sq(hostOutDir)}/${name}`).join(
6979
+ " "
6980
+ );
6889
6981
  await sshExecutor.exec(`rm -rf ${globs}`).catch(() => {
6890
6982
  });
6891
6983
  log.log(`Excluded build files from the published output (${hostOutDir}).
@@ -7007,7 +7099,9 @@ var DockerRuntime = class _DockerRuntime {
7007
7099
  `static extract failed copying ${docRoot} out of the build container (exit ${status.StatusCode})${logs ? `: ${logs.slice(-500)}` : ""}`
7008
7100
  );
7009
7101
  }
7010
- const entries = (await readdir(hostOutDir).catch(() => [])).filter((e) => e !== probe);
7102
+ const entries = (await readdir(hostOutDir).catch(() => [])).filter(
7103
+ (e) => e !== probe
7104
+ );
7011
7105
  this.assertDocRootFilled(entries.length === 0, docRoot);
7012
7106
  return true;
7013
7107
  } finally {
@@ -7250,11 +7344,7 @@ var DockerRuntime = class _DockerRuntime {
7250
7344
  signal,
7251
7345
  ignoreContextPath
7252
7346
  );
7253
- const builder = this.selectDockerodeBuilder(
7254
- spec.config,
7255
- requiresBuildKit,
7256
- spec.logger
7257
- );
7347
+ const builder = this.selectDockerodeBuilder(spec.config, requiresBuildKit, spec.logger);
7258
7348
  try {
7259
7349
  const stream = await this.docker.buildImage(body, {
7260
7350
  t: tag,
@@ -7263,7 +7353,7 @@ var DockerRuntime = class _DockerRuntime {
7263
7353
  projectId: spec.config.projectId,
7264
7354
  sessionId: spec.config.sessionId
7265
7355
  }),
7266
- buildargs: { ...spec.config.envVars, NODE_ENV: "production" },
7356
+ buildargs: resolveDockerBuildArgs(spec.config),
7267
7357
  ...dockerBuildResourceLimits(spec.config.resources),
7268
7358
  forcerm: true,
7269
7359
  ...builder.options,
@@ -7272,7 +7362,10 @@ var DockerRuntime = class _DockerRuntime {
7272
7362
  await this.streamDockerodeBuild(stream, spec.logger, builder.trace);
7273
7363
  } catch (err) {
7274
7364
  const contextErr = takeError();
7275
- throw contextErr ? new Error(`Failed to read Docker build context: ${safeErrorMessage(contextErr)}`, { cause: contextErr }) : err;
7365
+ throw contextErr ? new Error(
7366
+ `Failed to read Docker build context: ${safeErrorMessage(contextErr)}`,
7367
+ { cause: contextErr }
7368
+ ) : err;
7276
7369
  }
7277
7370
  }
7278
7371
  if (isCancelled(spec.config.sessionId)) {
@@ -7666,7 +7759,9 @@ var DockerRuntime = class _DockerRuntime {
7666
7759
  * the ones that survive `container.remove()` and would otherwise leak.
7667
7760
  * Anonymous volumes are auto-removed with `{ v: true }` and don't need to
7668
7761
  * be enumerated. Bind mounts and tmpfs are skipped (the user manages them
7669
- * outside our control). Returns [] if the container is already gone.
7762
+ * outside our control). Returns [] only if the container is already gone;
7763
+ * transport and permission failures propagate so an explicit volume wipe
7764
+ * never destroys the last copy of its mount inventory.
7670
7765
  */
7671
7766
  async inspectNamedVolumes(containerId) {
7672
7767
  try {
@@ -7674,16 +7769,18 @@ var DockerRuntime = class _DockerRuntime {
7674
7769
  const data = await container.inspect();
7675
7770
  const mounts = data.Mounts ?? [];
7676
7771
  return mounts.filter((m) => m.Type === "volume" && typeof m.Name === "string" && m.Name.length > 0).map((m) => m.Name);
7677
- } catch {
7678
- return [];
7772
+ } catch (err) {
7773
+ if (isDockerNotFoundError(err)) return [];
7774
+ throw err;
7679
7775
  }
7680
7776
  }
7681
- /** Remove a named volume by name. Best-effort - already-gone is fine. */
7777
+ /** Remove a named volume by name. Already-gone is idempotent success. */
7682
7778
  async removeVolume(name) {
7683
7779
  try {
7684
7780
  const volume = this.docker.getVolume(name);
7685
7781
  await volume.remove({ force: true });
7686
- } catch {
7782
+ } catch (err) {
7783
+ if (!isDockerNotFoundError(err)) throw err;
7687
7784
  }
7688
7785
  }
7689
7786
  // ── Docker discovery (label-agnostic) ────────────────────────────────────
@@ -7897,7 +7994,8 @@ var DockerRuntime = class _DockerRuntime {
7897
7994
  const executor = this.transport.kind === "ssh" ? this.connectionOptions?.executor : null;
7898
7995
  if (executor?.execWithInput) {
7899
7996
  const { code, stderr, stdout } = await executor.execWithInput(`docker load`, body);
7900
- if (code !== 0) throw new Error(`docker load exited ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`);
7997
+ if (code !== 0)
7998
+ throw new Error(`docker load exited ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`);
7901
7999
  return parseLoadedImageRef(stdout);
7902
8000
  }
7903
8001
  const stream = await this.docker.loadImage(body);
@@ -8155,7 +8253,11 @@ var DockerRuntime = class _DockerRuntime {
8155
8253
  });
8156
8254
  stream.on("end", () => {
8157
8255
  if (buffer && !destroyed) {
8158
- onLog({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), message: buffer, level: parseLogLevel(buffer) });
8256
+ onLog({
8257
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
8258
+ message: buffer,
8259
+ level: parseLogLevel(buffer)
8260
+ });
8159
8261
  buffer = "";
8160
8262
  }
8161
8263
  });
@@ -8370,15 +8472,9 @@ var DockerRuntime = class _DockerRuntime {
8370
8472
  async inContainerExecutor(containerId) {
8371
8473
  return {
8372
8474
  exec: async (command, opts) => {
8373
- const { exitCode, stdout, stderr } = await this.execInContainer(
8374
- containerId,
8375
- command,
8376
- opts
8377
- );
8475
+ const { exitCode, stdout, stderr } = await this.execInContainer(containerId, command, opts);
8378
8476
  if (exitCode !== 0) {
8379
- throw new Error(
8380
- stdout.trim() || stderr.trim() || `exec exited with code ${exitCode}`
8381
- );
8477
+ throw new Error(stdout.trim() || stderr.trim() || `exec exited with code ${exitCode}`);
8382
8478
  }
8383
8479
  return stdout;
8384
8480
  }
@@ -8482,7 +8578,8 @@ var DockerRuntime = class _DockerRuntime {
8482
8578
  for (const m of c.Mounts ?? []) {
8483
8579
  if (m.Type !== "volume" || !m.Name || !named.has(m.Name)) continue;
8484
8580
  if (owner === config.projectId) ownNames.add(m.Name);
8485
- else if (!foreign.has(m.Name)) foreign.set(m.Name, c.Names?.[0]?.replace(/^\//, "") ?? owner);
8581
+ else if (!foreign.has(m.Name))
8582
+ foreign.set(m.Name, c.Names?.[0]?.replace(/^\//, "") ?? owner);
8486
8583
  }
8487
8584
  }
8488
8585
  for (const [name, other] of foreign) {
@@ -8602,21 +8699,20 @@ var DockerRuntime = class _DockerRuntime {
8602
8699
  } catch (err) {
8603
8700
  const msg = err?.message ?? "";
8604
8701
  if (!/already exists|already connected/i.test(msg)) {
8605
- console.warn(
8606
- `[docker] link-connect failed for ${c.Id.slice(0, 12)} \u2192 ${name}: ${msg}`
8607
- );
8702
+ console.warn(`[docker] link-connect failed for ${c.Id.slice(0, 12)} \u2192 ${name}: ${msg}`);
8608
8703
  }
8609
8704
  }
8610
8705
  }
8611
8706
  }
8612
8707
  }
8613
- /** Remove a project network (best-effort). */
8708
+ /** Remove a project network. Already-gone is idempotent success. */
8614
8709
  async removeNetwork(slug) {
8615
8710
  const networkName = `openship-${slug}`;
8616
8711
  try {
8617
8712
  const network = this.docker.getNetwork(networkName);
8618
8713
  await network.remove();
8619
- } catch {
8714
+ } catch (err) {
8715
+ if (!isDockerNotFoundError(err)) throw err;
8620
8716
  }
8621
8717
  }
8622
8718
  /**
@@ -6,13 +6,13 @@ import {
6
6
  detectBuildKillHint,
7
7
  runBuildPipeline,
8
8
  transferLocalDirectory
9
- } from "./chunk-H4FS5BED.js";
9
+ } from "./chunk-AHJYP7DG.js";
10
10
  import {
11
11
  LocalExecutor
12
- } from "./chunk-E2X26PXR.js";
12
+ } from "./chunk-T6DVUX4F.js";
13
13
  import {
14
14
  wrapLocalBuildCommand
15
- } from "./chunk-H3WT3A6R.js";
15
+ } from "./chunk-P7RCYELG.js";
16
16
 
17
17
  // ../../packages/adapters/src/runtime/local-build.ts
18
18
  var LOCAL_BUILD_DIR = "/tmp/openship/.builds";