openship 0.6.7 → 0.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/bare-FA66N7GC.js +29 -0
  2. package/dist/{chunk-LHFXSC36.js → chunk-3MP6ACKM.js} +183 -87
  3. package/dist/{chunk-MEE6OZFP.js → chunk-5DJOB7IX.js} +3 -3
  4. package/dist/{chunk-VQM6JHJB.js → chunk-5UXHT6ED.js} +9 -9
  5. package/dist/{chunk-PPEBIY5F.js → chunk-634DDFT5.js} +35 -12
  6. package/dist/{chunk-XWHWTHEL.js → chunk-6GU6JSK6.js} +21 -2
  7. package/dist/{chunk-QHMDCYZ3.js → chunk-7PEXM2UI.js} +213 -45
  8. package/dist/{chunk-RDXT4BQB.js → chunk-7YBWXEM6.js} +4 -4
  9. package/dist/{chunk-H4FS5BED.js → chunk-AHJYP7DG.js} +13 -11
  10. package/dist/{chunk-VSTFHUCV.js → chunk-BO6CY4V2.js} +109 -23
  11. package/dist/{chunk-J3K6XABC.js → chunk-D3OEMXYP.js} +3 -3
  12. package/dist/{chunk-UWEV6XTS.js → chunk-D6HU4VUZ.js} +1 -1
  13. package/dist/{chunk-S6B2Z3OO.js → chunk-ENKJ7XIF.js} +21 -11
  14. package/dist/{chunk-DDFUESPJ.js → chunk-FCGJN5Q5.js} +9 -9
  15. package/dist/{chunk-BLEXTYRK.js → chunk-GNOMEMNI.js} +1 -1
  16. package/dist/{chunk-NRTJRNAE.js → chunk-IAMOUDHY.js} +138 -54
  17. package/dist/{chunk-CIJV43LH.js → chunk-MUWVC5R4.js} +161 -39
  18. package/dist/{chunk-ZPJ74LXE.js → chunk-NIYD7MD2.js} +197 -45
  19. package/dist/{chunk-FZ6QCF6B.js → chunk-NPSRGIHV.js} +2 -2
  20. package/dist/{chunk-2GWYYHOR.js → chunk-NRU2EBYZ.js} +2 -2
  21. package/dist/{chunk-J2XM3QSP.js → chunk-NUT6HKK6.js} +5 -5
  22. package/dist/{chunk-H3WT3A6R.js → chunk-P7RCYELG.js} +1 -1
  23. package/dist/{chunk-FYPFEDPZ.js → chunk-R5DC5PEF.js} +1 -1
  24. package/dist/{chunk-RXQBD4ZY.js → chunk-RHLNVZMS.js} +2 -2
  25. package/dist/{chunk-WU54BXFE.js → chunk-SK4FFCFR.js} +1 -1
  26. package/dist/{chunk-PVP4RGWT.js → chunk-T46BQOLY.js} +3 -3
  27. package/dist/{chunk-E2X26PXR.js → chunk-T6DVUX4F.js} +1 -1
  28. package/dist/{chunk-5T4UVOM3.js → chunk-TAZZZKYO.js} +1 -1
  29. package/dist/{chunk-GGIAIGUL.js → chunk-UAWY6X7V.js} +34 -12
  30. package/dist/{chunk-2ANV5ZQ5.js → chunk-VAI5VOOI.js} +1 -1
  31. package/dist/{chunk-2VSW6Q6C.js → chunk-WEZFTL4V.js} +655 -62
  32. package/dist/{chunk-GIPJNNI5.js → chunk-X53JXRS4.js} +3 -3
  33. package/dist/{cloud-KRTZ2IL5.js → cloud-2CRDKOWQ.js} +1 -1
  34. package/dist/cloud-REV3DPJH.js +42 -0
  35. package/dist/{detect-G4DR3U2N.js → detect-BBFT5GEU.js} +4 -4
  36. package/dist/{docker-YOVPCIB4.js → docker-EG3QSE6I.js} +10 -10
  37. package/dist/{docker-edge-executor-QFXD3337.js → docker-edge-executor-E5TOTLMR.js} +7 -7
  38. package/dist/edge-import-YJVJUGYC.js +56 -0
  39. package/dist/{edge-preflight-MXERVAMG.js → edge-preflight-QUW4BM7N.js} +13 -13
  40. package/dist/{ensure-container-edge-F4JUNQIK.js → ensure-container-edge-FOEFQ3PI.js} +13 -11
  41. package/dist/{executor-CVPAYYHR.js → executor-NTWDJ3DB.js} +6 -6
  42. package/dist/host-channel-preflight-OI2TRHSG.js +54 -0
  43. package/dist/index.js +158 -72
  44. package/dist/{local-executor-ODC6RANU.js → local-executor-OQ2GRN7K.js} +3 -3
  45. package/dist/{nginx-KLFF43TC.js → nginx-4U4C2XUS.js} +9 -9
  46. package/dist/{noop-NJ72F46T.js → noop-CLLJHCPL.js} +1 -1
  47. package/dist/{openresty-lua-VKWUV4GB.js → openresty-lua-LLWT5XQW.js} +7 -5
  48. package/dist/{privilege-7D3SSOL3.js → privilege-MNDVMDST.js} +5 -5
  49. package/dist/server/index.js +31801 -25560
  50. package/dist/server/migrations/0109_service_build_args.sql +9 -0
  51. package/dist/server/migrations/0110_service_deployment_host_ports.sql +18 -0
  52. package/dist/server/migrations/0111_host_port_claim.sql +381 -0
  53. package/dist/server/migrations/0112_backup_run_execution_lease.sql +12 -0
  54. package/dist/server/migrations/0113_docker_migration_execution_lease.sql +11 -0
  55. package/dist/server/migrations/0114_build_session_execution_lease_index.sql +6 -0
  56. package/dist/server/migrations/0115_orphan_target_key.sql +3 -0
  57. package/dist/server/migrations/0116_domain_ssl_challenge.sql +2 -0
  58. package/dist/server/migrations/meta/_journal.json +56 -0
  59. package/dist/{setup-I5AJC6NJ.js → setup-IFIMPQZJ.js} +12 -12
  60. package/dist/{ssh-client-625VWGKP.js → ssh-client-2XWZCMGI.js} +2 -2
  61. package/dist/up-RC5ZQIAD.js +61 -0
  62. package/package.json +1 -1
  63. package/dist/bare-7QD623QV.js +0 -29
  64. package/dist/cloud-KNNABE3O.js +0 -40
  65. package/dist/edge-import-CRFVSR6P.js +0 -56
  66. package/dist/host-channel-preflight-QTDNGLCK.js +0 -54
  67. package/dist/up-QXTOOVXC.js +0 -61
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  stop,
27
27
  upCommand,
28
28
  writeCliInstall
29
- } from "./chunk-DDFUESPJ.js";
29
+ } from "./chunk-FCGJN5Q5.js";
30
30
  import {
31
31
  composeDown,
32
32
  composeInternalToken,
@@ -60,7 +60,7 @@ import {
60
60
  sourceBuildDir,
61
61
  storedApiPort,
62
62
  storedDashboardPort
63
- } from "./chunk-PPEBIY5F.js";
63
+ } from "./chunk-634DDFT5.js";
64
64
  import {
65
65
  bootstrapAdmin,
66
66
  detectPublicIp,
@@ -71,10 +71,10 @@ import {
71
71
  internalTokenRejectedProblem,
72
72
  waitDashboard,
73
73
  waitHealthy
74
- } from "./chunk-RDXT4BQB.js";
74
+ } from "./chunk-7YBWXEM6.js";
75
75
  import {
76
76
  startUnitHint
77
- } from "./chunk-VQM6JHJB.js";
77
+ } from "./chunk-5UXHT6ED.js";
78
78
  import "./chunk-QWHBRY2K.js";
79
79
  import {
80
80
  completeHostEdge,
@@ -85,13 +85,13 @@ import {
85
85
  renderEdgeConflict,
86
86
  repairEdgeConflict,
87
87
  rollbackHostEdge
88
- } from "./chunk-J2XM3QSP.js";
88
+ } from "./chunk-NUT6HKK6.js";
89
89
  import {
90
90
  DATA_DIR,
91
91
  LOG_DIR,
92
92
  OS_DIR
93
93
  } from "./chunk-ELGRMZOW.js";
94
- import "./chunk-FYPFEDPZ.js";
94
+ import "./chunk-R5DC5PEF.js";
95
95
  import "./chunk-ONKEYSMY.js";
96
96
  import "./chunk-XZYFZ6A5.js";
97
97
  import "./chunk-PDW4L3NV.js";
@@ -100,38 +100,38 @@ import "./chunk-42WQABXM.js";
100
100
  import "./chunk-DRK3MEDS.js";
101
101
  import "./chunk-3NQQXMDR.js";
102
102
  import "./chunk-ZWLDLTJP.js";
103
- import "./chunk-J3K6XABC.js";
104
- import "./chunk-CIJV43LH.js";
103
+ import "./chunk-D3OEMXYP.js";
104
+ import "./chunk-MUWVC5R4.js";
105
105
  import {
106
106
  detectInstalledProxy,
107
107
  scanImportableSites
108
- } from "./chunk-ZPJ74LXE.js";
109
- import "./chunk-NRTJRNAE.js";
110
- import "./chunk-QHMDCYZ3.js";
108
+ } from "./chunk-NIYD7MD2.js";
109
+ import "./chunk-IAMOUDHY.js";
110
+ import "./chunk-7PEXM2UI.js";
111
111
  import "./chunk-I3DPMTSF.js";
112
112
  import "./chunk-WNWQBB7F.js";
113
- import "./chunk-2GWYYHOR.js";
114
- import "./chunk-RXQBD4ZY.js";
115
- import "./chunk-LHFXSC36.js";
116
- import "./chunk-XWHWTHEL.js";
117
- import "./chunk-S6B2Z3OO.js";
118
- import "./chunk-MEE6OZFP.js";
119
- import "./chunk-WU54BXFE.js";
120
- import "./chunk-H4FS5BED.js";
121
- import "./chunk-GGIAIGUL.js";
113
+ import "./chunk-NRU2EBYZ.js";
114
+ import "./chunk-RHLNVZMS.js";
115
+ import "./chunk-3MP6ACKM.js";
116
+ import "./chunk-6GU6JSK6.js";
117
+ import "./chunk-ENKJ7XIF.js";
118
+ import "./chunk-5DJOB7IX.js";
119
+ import "./chunk-SK4FFCFR.js";
120
+ import "./chunk-AHJYP7DG.js";
121
+ import "./chunk-UAWY6X7V.js";
122
122
  import "./chunk-R4VDPFLS.js";
123
- import "./chunk-2ANV5ZQ5.js";
124
- import "./chunk-5T4UVOM3.js";
123
+ import "./chunk-VAI5VOOI.js";
124
+ import "./chunk-TAZZZKYO.js";
125
125
  import {
126
126
  LocalExecutor
127
- } from "./chunk-E2X26PXR.js";
128
- import "./chunk-PVP4RGWT.js";
129
- import "./chunk-BLEXTYRK.js";
130
- import "./chunk-FZ6QCF6B.js";
131
- import "./chunk-H3WT3A6R.js";
132
- import "./chunk-GIPJNNI5.js";
133
- import "./chunk-VSTFHUCV.js";
134
- import "./chunk-UWEV6XTS.js";
127
+ } from "./chunk-T6DVUX4F.js";
128
+ import "./chunk-T46BQOLY.js";
129
+ import "./chunk-GNOMEMNI.js";
130
+ import "./chunk-NPSRGIHV.js";
131
+ import "./chunk-P7RCYELG.js";
132
+ import "./chunk-X53JXRS4.js";
133
+ import "./chunk-BO6CY4V2.js";
134
+ import "./chunk-D6HU4VUZ.js";
135
135
  import "./chunk-N5YZMO33.js";
136
136
  import {
137
137
  CLOUD_DASHBOARD_URL,
@@ -142,15 +142,19 @@ import {
142
142
  buildMailImageRef,
143
143
  cliInstallCommand,
144
144
  commandToArgv,
145
+ composeBuildIssues,
145
146
  composeMountIssues,
146
147
  composeMountToSpec,
147
148
  composePortToSpec,
148
149
  isValidEmail,
149
150
  parseComposeNamespace,
150
151
  parseOpenshipConfigJson,
152
+ renderReleaseImage,
151
153
  resolveCliUpdatePlan,
152
- summarizeHostChannelCause
153
- } from "./chunk-2VSW6Q6C.js";
154
+ summarizeHostChannelCause,
155
+ validateReleaseRepository,
156
+ validateReleaseVersionUrl
157
+ } from "./chunk-WEZFTL4V.js";
154
158
  import "./chunk-PXKCZB2I.js";
155
159
 
156
160
  // src/index.ts
@@ -309,7 +313,7 @@ function getDashboardUrl(name) {
309
313
  }
310
314
 
311
315
  // src/lib/api-client.ts
312
- var USER_AGENT = `openship-cli/${true ? "0.6.7" : "dev"}`;
316
+ var USER_AGENT = `openship-cli/${true ? "0.6.9" : "dev"}`;
313
317
  function getApiUrl2() {
314
318
  return `${getApiUrl()}/api`;
315
319
  }
@@ -1105,7 +1109,7 @@ function dockerNameRunning(nameFilter) {
1105
1109
  return r.stdout.trim().length > 0;
1106
1110
  }
1107
1111
  async function hostControlCheck(api) {
1108
- const { checkHostChannel } = await import("./host-channel-preflight-QTDNGLCK.js");
1112
+ const { checkHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
1109
1113
  return hostControlRow(await checkHostChannel().catch(() => null), api);
1110
1114
  }
1111
1115
  var NEVER_PROVISIONED_DETAIL = `never provisioned \u2014 run \`${HOST_CHANNEL_PROVISION_COMMAND}\``;
@@ -1510,7 +1514,7 @@ async function interactiveDoctor() {
1510
1514
  continue;
1511
1515
  }
1512
1516
  if (action2 === "host-control") {
1513
- const { verifyHostChannel } = await import("./host-channel-preflight-QTDNGLCK.js");
1517
+ const { verifyHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
1514
1518
  const report3 = await verifyHostChannel().catch(() => null);
1515
1519
  if (report3?.status === "fixed") log2.success("Host control is reachable now.");
1516
1520
  else if (report3?.status === "ok") log2.success("Host control was already reachable.");
@@ -2195,7 +2199,10 @@ function printProject(project) {
2195
2199
  ["name", project.name],
2196
2200
  ["slug", project.slug],
2197
2201
  ["framework", project.framework],
2198
- ["gitRepo", project.gitOwner && project.gitRepo ? `${project.gitOwner}/${project.gitRepo}` : null],
2202
+ [
2203
+ "gitRepo",
2204
+ project.gitOwner && project.gitRepo ? `${project.gitOwner}/${project.gitRepo}` : null
2205
+ ],
2199
2206
  ["gitBranch", project.gitBranch],
2200
2207
  ["autoDeploy", project.autoDeploy],
2201
2208
  ["status", project.status]
@@ -2207,6 +2214,46 @@ function printProject(project) {
2207
2214
  }
2208
2215
  }
2209
2216
  var ENVIRONMENTS = ["production", "preview", "development"];
2217
+ function releaseImageSourceFromOptions(opts) {
2218
+ const imageTemplate = opts.imageTemplate.trim();
2219
+ const repo = opts.githubRepo?.trim() || void 0;
2220
+ const versionUrl = opts.versionUrl?.trim() || void 0;
2221
+ const pinnedVersion = opts.pin?.trim() || void 0;
2222
+ const validationTag = pinnedVersion ?? "v1.2.3";
2223
+ renderReleaseImage(imageTemplate, {
2224
+ version: validationTag.replace(/^v/i, ""),
2225
+ tag: validationTag
2226
+ });
2227
+ if (repo && versionUrl) {
2228
+ throw new Error("--github-repo cannot be combined with --version-url.");
2229
+ }
2230
+ if (repo) {
2231
+ const invalidRepo = validateReleaseRepository(repo);
2232
+ if (invalidRepo)
2233
+ throw new Error(invalidRepo.replace("GitHub release repository", "--github-repo"));
2234
+ return {
2235
+ artifactKind: "image",
2236
+ mode: "github",
2237
+ imageTemplate,
2238
+ repo,
2239
+ ...pinnedVersion ? { pinnedVersion } : {}
2240
+ };
2241
+ }
2242
+ if (!versionUrl && !pinnedVersion) {
2243
+ throw new Error("Pass --github-repo, --version-url, or --pin.");
2244
+ }
2245
+ if (versionUrl) {
2246
+ const invalidUrl = validateReleaseVersionUrl(versionUrl);
2247
+ if (invalidUrl) throw new Error(invalidUrl.replace("Release version URL", "--version-url"));
2248
+ }
2249
+ return {
2250
+ artifactKind: "image",
2251
+ mode: "url",
2252
+ imageTemplate,
2253
+ ...versionUrl ? { versionUrl } : {},
2254
+ ...pinnedVersion ? { pinnedVersion } : {}
2255
+ };
2256
+ }
2210
2257
  var listCmd2 = new Command14("list").alias("ls").description("List projects in the active organization").action(
2211
2258
  action(async () => {
2212
2259
  const rows = [];
@@ -2230,10 +2277,27 @@ var getCmd = new Command14("get").description("Show a single project").argument(
2230
2277
  printProject(data);
2231
2278
  })
2232
2279
  );
2233
- var createCmd = new Command14("create").description("Create a project").requiredOption("--name <name>", "Project name").option("--slug <slug>", "Free-subdomain slug (slug.opsh.io)").option("--git-owner <owner>", "GitHub owner/org").option("--git-repo <repo>", "GitHub repository name").option("--git-branch <branch>", "Git branch to deploy").option("--framework <framework>", "Stack/framework id").option("--local-path <path>", "Local source path").option("--port <port>", "Container port", (v) => Number(v)).option(
2234
- "--type <type>",
2235
- "Project type: app | docker | services | monorepo"
2236
- ).action(
2280
+ var releaseImageCmd = new Command14("release-image").description("Track and deploy a versioned prebuilt container image").argument("<id>", "Project ID").requiredOption(
2281
+ "--image-template <reference>",
2282
+ "Image reference with {tag} or {version}, e.g. ghcr.io/acme/api:{tag}"
2283
+ ).option("--github-repo <owner/repo>", "Resolve versions from GitHub Releases").option("--version-url <https-url>", "HTTPS endpoint returning a version or tag").option("--pin <version>", "Deploy a fixed version instead of the discovered latest release").action(
2284
+ action(async (id, opts) => {
2285
+ const source = releaseImageSourceFromOptions(opts);
2286
+ const result = await apiRequest(
2287
+ `/projects/${encodeURIComponent(id)}/release-image-source`,
2288
+ { method: "PUT", body: JSON.stringify(source) }
2289
+ );
2290
+ if (isJsonMode()) {
2291
+ printJson(result.data);
2292
+ return;
2293
+ }
2294
+ const upstream = source.mode === "github" ? `GitHub Releases (${source.repo})` : source.versionUrl ? `version URL (${source.versionUrl})` : `pinned version (${source.pinnedVersion})`;
2295
+ ok(`
2296
+ Project ${id} now deploys ${source.imageTemplate} from ${upstream}
2297
+ `);
2298
+ })
2299
+ );
2300
+ var createCmd = new Command14("create").description("Create a project").requiredOption("--name <name>", "Project name").option("--slug <slug>", "Free-subdomain slug (slug.opsh.io)").option("--git-owner <owner>", "GitHub owner/org").option("--git-repo <repo>", "GitHub repository name").option("--git-branch <branch>", "Git branch to deploy").option("--framework <framework>", "Stack/framework id").option("--local-path <path>", "Local source path").option("--port <port>", "Container port", (v) => Number(v)).option("--type <type>", "Project type: app | docker | services | monorepo").action(
2237
2301
  action(async (opts) => {
2238
2302
  const body = { name: opts.name };
2239
2303
  if (opts.slug) body.slug = opts.slug;
@@ -2547,7 +2611,9 @@ var logsCmd = new Command14("logs").description("Show or stream runtime (contain
2547
2611
  for (const entry of data) printLogEntry(entry);
2548
2612
  return;
2549
2613
  }
2550
- for await (const ev of sseRequest(`/projects/${encodeURIComponent(id)}/logs/stream${tailQs}`)) {
2614
+ for await (const ev of sseRequest(
2615
+ `/projects/${encodeURIComponent(id)}/logs/stream${tailQs}`
2616
+ )) {
2551
2617
  if (ev.event === "error") {
2552
2618
  const parsed = safeParse(ev.data);
2553
2619
  err(` ${parsed?.error ?? ev.data}`);
@@ -2612,6 +2678,7 @@ function printLogEntry(entry) {
2612
2678
  var projectCommand = new Command14("project").alias("projects").description("Manage Openship projects");
2613
2679
  projectCommand.addCommand(listCmd2);
2614
2680
  projectCommand.addCommand(getCmd);
2681
+ projectCommand.addCommand(releaseImageCmd);
2615
2682
  projectCommand.addCommand(createCmd);
2616
2683
  projectCommand.addCommand(deleteCmd);
2617
2684
  projectCommand.addCommand(envCmd);
@@ -2752,10 +2819,7 @@ var getCmd2 = stackCommand("get").description("Show one service's configuration"
2752
2819
  fail(e);
2753
2820
  }
2754
2821
  });
2755
- var createCmd2 = stackCommand("create").description("Add a service to a stack").argument("<name>", "Service name (unique within the stack)").option("--image <image>", "Container image (e.g. postgres:16)").option("--build <context>", "Build context path (relative to repo root)").option("--dockerfile <path>", "Dockerfile path (relative to build context)").option("--port <mapping>", "Port mapping, e.g. 8080:80 (repeatable)", collect, []).option("--depends-on <service>", "Service this depends on (repeatable)", collect, []).option("--env <KEY=VALUE>", "Compose environment default (repeatable)", collect, []).option("--command <command>", "Override the container command").option(
2756
- "--restart <policy>",
2757
- "Restart policy: no | always | on-failure | unless-stopped"
2758
- ).option("--expose", "Expose the service publicly through managed routing").option("--exposed-port <port>", "Container port to expose publicly").option("--domain <label>", "Free subdomain label (with --expose)").action(async (name, opts) => {
2822
+ var createCmd2 = stackCommand("create").description("Add a service to a stack").argument("<name>", "Service name (unique within the stack)").option("--image <image>", "Container image (e.g. postgres:16)").option("--build <context>", "Build context path (relative to repo root)").option("--dockerfile <path>", "Dockerfile path (relative to build context)").option("--port <mapping>", "Port mapping, e.g. 8080:80 (repeatable)", collect, []).option("--depends-on <service>", "Service this depends on (repeatable)", collect, []).option("--env <KEY=VALUE>", "Compose environment default (repeatable)", collect, []).option("--command <command>", "Override the container command").option("--restart <policy>", "Restart policy: no | always | on-failure | unless-stopped").option("--expose", "Expose the service publicly through managed routing").option("--exposed-port <port>", "Container port to expose publicly").option("--domain <label>", "Free subdomain label (with --expose)").action(async (name, opts) => {
2759
2823
  requireAuth();
2760
2824
  try {
2761
2825
  const projectId = await resolveProject(opts.project);
@@ -2859,6 +2923,17 @@ function mapDependsOn(deps) {
2859
2923
  if (deps && typeof deps === "object") return Object.keys(deps);
2860
2924
  return [];
2861
2925
  }
2926
+ function mapBuildArgs(raw) {
2927
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
2928
+ const args = {};
2929
+ for (const [key, value] of Object.entries(raw)) {
2930
+ if (value === null || value === void 0) args[key] = null;
2931
+ else if (["string", "number", "boolean"].includes(typeof value)) {
2932
+ args[key] = String(value);
2933
+ }
2934
+ }
2935
+ return Object.keys(args).length > 0 ? args : void 0;
2936
+ }
2862
2937
  function mapNamespaces(name, d) {
2863
2938
  const advanced = {};
2864
2939
  const errors = [];
@@ -2878,12 +2953,17 @@ function mapComposeService(name, def, baseDir, errors) {
2878
2953
  const svc = { name };
2879
2954
  if (typeof d.image === "string") svc.image = d.image;
2880
2955
  const build = d.build;
2956
+ for (const issue of composeBuildIssues(build, { allowAbsoluteContext: true })) {
2957
+ if (issue.blocking) errors.push(` ${name}: ${issue.reason}`);
2958
+ }
2881
2959
  if (typeof build === "string") {
2882
2960
  svc.build = relativizeContext(build, baseDir);
2883
2961
  } else if (build && typeof build === "object") {
2884
2962
  const b = build;
2885
2963
  svc.build = relativizeContext(typeof b.context === "string" ? b.context : ".", baseDir);
2886
2964
  if (typeof b.dockerfile === "string") svc.dockerfile = b.dockerfile;
2965
+ const buildArgs = mapBuildArgs(b.args);
2966
+ if (buildArgs) svc.buildArgs = buildArgs;
2887
2967
  }
2888
2968
  const ports = mapPorts(d.ports);
2889
2969
  if (ports.length) svc.ports = ports;
@@ -2901,17 +2981,21 @@ function mapComposeService(name, def, baseDir, errors) {
2901
2981
  if (typeof d.restart === "string") svc.restart = d.restart;
2902
2982
  const { advanced, errors: namespaceErrors } = mapNamespaces(name, d);
2903
2983
  errors.push(...namespaceErrors);
2984
+ if (build && typeof build === "object" && Object.hasOwn(build, "args")) {
2985
+ advanced.buildArgTemplateKeys = [];
2986
+ }
2904
2987
  if (Object.keys(advanced).length > 0) svc.advanced = advanced;
2905
2988
  return svc;
2906
2989
  }
2907
- var syncCmd = stackCommand("sync").description("Sync a stack's services from a docker-compose file (services not in the file are removed)").argument("<compose-file>", "Path to docker-compose.yml / compose.yaml").option("-y, --yes", "Skip the confirmation prompt").action(async (composeFile, opts) => {
2990
+ var syncCmd = stackCommand("sync").description(
2991
+ "Sync a stack's services from a docker-compose file (services not in the file are removed)"
2992
+ ).argument("<compose-file>", "Path to docker-compose.yml / compose.yaml").option("-y, --yes", "Skip the confirmation prompt").action(async (composeFile, opts) => {
2908
2993
  requireAuth();
2909
2994
  const abs = path.resolve(composeFile);
2910
- const proc = spawnSync2(
2911
- "docker",
2912
- ["compose", "-f", abs, "config", "--format", "json"],
2913
- { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
2914
- );
2995
+ const proc = spawnSync2("docker", ["compose", "-f", abs, "config", "--format", "json"], {
2996
+ encoding: "utf8",
2997
+ maxBuffer: 64 * 1024 * 1024
2998
+ });
2915
2999
  if (proc.error) {
2916
3000
  if (proc.error.code === "ENOENT") {
2917
3001
  err(" `docker` not found. `service sync` uses Docker Compose to parse the file.");
@@ -3085,10 +3169,11 @@ var envGetCmd = stackCommand("get").description("List a service's environment va
3085
3169
  fail(e);
3086
3170
  }
3087
3171
  });
3088
- var envSetCmd = stackCommand("set").description("Set a service's environment variables for one environment").argument("<service>", "Service name or id").argument("<pairs...>", "KEY=VALUE pairs").option("-e, --env <environment>", "Environment: production | preview | development", "production").option("--secret", "Mark the provided variables as secret").option(
3089
- "--replace",
3090
- "Replace ALL variables for this environment with only the given pairs"
3091
- ).action(async (service, pairs, opts) => {
3172
+ var envSetCmd = stackCommand("set").description("Set a service's environment variables for one environment").argument("<service>", "Service name or id").argument("<pairs...>", "KEY=VALUE pairs").option(
3173
+ "-e, --env <environment>",
3174
+ "Environment: production | preview | development",
3175
+ "production"
3176
+ ).option("--secret", "Mark the provided variables as secret").option("--replace", "Replace ALL variables for this environment with only the given pairs").action(async (service, pairs, opts) => {
3092
3177
  requireAuth();
3093
3178
  try {
3094
3179
  const projectId = await resolveProject(opts.project);
@@ -3152,9 +3237,7 @@ var logsCmd2 = stackCommand("logs").description("Show or stream a service's runt
3152
3237
  const svc = await resolveService(projectId, service);
3153
3238
  const tail = opts.tail ? `?tail=${encodeURIComponent(opts.tail)}` : "";
3154
3239
  if (!opts.follow) {
3155
- const res = await apiRequest(
3156
- `/projects/${projectId}/services/${svc.id}/logs${tail}`
3157
- );
3240
+ const res = await apiRequest(`/projects/${projectId}/services/${svc.id}/logs${tail}`);
3158
3241
  const entries = res.data ?? [];
3159
3242
  if (isJsonMode()) {
3160
3243
  printJson(entries);
@@ -3163,14 +3246,17 @@ var logsCmd2 = stackCommand("logs").description("Show or stream a service's runt
3163
3246
  for (const e of entries) printLogEntry2(e);
3164
3247
  return;
3165
3248
  }
3166
- for await (const ev of sseRequest(`/projects/${projectId}/services/${svc.id}/logs/stream${tail}`)) {
3249
+ for await (const ev of sseRequest(
3250
+ `/projects/${projectId}/services/${svc.id}/logs/stream${tail}`
3251
+ )) {
3167
3252
  if (ev.event === "error") {
3168
3253
  const parsed = safeParse2(ev.data);
3169
3254
  throw new ApiError(parsed?.error || "Log stream error", 0, parsed);
3170
3255
  }
3171
3256
  if (ev.event === "log") {
3172
3257
  const parsed = safeParse2(ev.data);
3173
- if (parsed) printLogEntry2(parsed);
3258
+ if (parsed)
3259
+ printLogEntry2(parsed);
3174
3260
  }
3175
3261
  }
3176
3262
  } catch (e) {
@@ -3499,7 +3585,7 @@ async function runRepair2(mode) {
3499
3585
  requireLinux();
3500
3586
  const sp = spin2(mode === "migrate" ? "Migrating the existing proxy's sites into the edge\u2026" : "Taking over :80/:443\u2026");
3501
3587
  try {
3502
- const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-MXERVAMG.js");
3588
+ const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-QUW4BM7N.js");
3503
3589
  sp?.stop();
3504
3590
  const res = await repairEdgeConflict2(mode, apiPort(), onLog);
3505
3591
  reportRepair(res);
@@ -3648,7 +3734,7 @@ async function panelStatus() {
3648
3734
  async function panelRepair(mode) {
3649
3735
  const sp = spin2(mode === "migrate" ? "Migrating the existing proxy's sites\u2026" : "Taking over :80/:443\u2026");
3650
3736
  try {
3651
- const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-MXERVAMG.js");
3737
+ const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-QUW4BM7N.js");
3652
3738
  sp?.stop();
3653
3739
  const res = await repairEdgeConflict2(mode, apiPort(), onLog);
3654
3740
  renderRepair(res);
@@ -4490,7 +4576,7 @@ function printMonitoringNextSteps() {
4490
4576
  info(" openship edge analytics -p <project> per-domain analytics");
4491
4577
  }
4492
4578
  async function runMonitoringInstall(opts) {
4493
- const up = await import("./up-QXTOOVXC.js");
4579
+ const up = await import("./up-RC5ZQIAD.js");
4494
4580
  let adminName = opts.adminName;
4495
4581
  let adminEmail = opts.adminEmail;
4496
4582
  let adminPassword = opts.adminPassword;
@@ -6647,7 +6733,7 @@ function applyOnlyArgv(selfArgs, json) {
6647
6733
  // src/commands/update.ts
6648
6734
  async function verifyHostChannelAfterUpdate() {
6649
6735
  if (isJsonMode()) return;
6650
- const { verifyHostChannel } = await import("./host-channel-preflight-QTDNGLCK.js");
6736
+ const { verifyHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
6651
6737
  await verifyHostChannel().catch(() => {
6652
6738
  });
6653
6739
  }
@@ -6724,7 +6810,7 @@ async function runSourceUpdate(source, opts) {
6724
6810
  }
6725
6811
  var REINSTALL_HINT = "curl -fsSL https://get.openship.io | sh";
6726
6812
  async function runTarballUpdate(install, opts) {
6727
- const current = "0.6.7";
6813
+ const current = "0.6.9";
6728
6814
  let latest;
6729
6815
  try {
6730
6816
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -6808,7 +6894,7 @@ var updateCommand = new Command26("update").description("Update the Openship CLI
6808
6894
  if (source) return runSourceUpdate(source, opts);
6809
6895
  const cliInstall = readCliInstall();
6810
6896
  if (cliInstall?.method === "tarball") return runTarballUpdate(cliInstall, opts);
6811
- const current = "0.6.7";
6897
+ const current = "0.6.9";
6812
6898
  let latest;
6813
6899
  try {
6814
6900
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -7416,7 +7502,7 @@ async function runWizard() {
7416
7502
  }
7417
7503
  }
7418
7504
  }
7419
- const uiTag = `v${"0.6.7"}`;
7505
+ const uiTag = `v${"0.6.9"}`;
7420
7506
  if (method === "bare") {
7421
7507
  const dl = spinner4();
7422
7508
  dl.start("Pulling the Openship dist from GitHub");
@@ -7476,7 +7562,7 @@ async function runWizard() {
7476
7562
  const dashboardPort = String(ports.dashboard);
7477
7563
  const moved = portMoveNotice(ports, composeTrustedOriginUrls());
7478
7564
  if (moved.length) log5.info(moved.join("\n"));
7479
- if (!pinnedImagesReady({ version: "0.6.7" })) {
7565
+ if (!pinnedImagesReady({ version: "0.6.9" })) {
7480
7566
  cancel4("The pinned Openship image tag isn't in the registry yet \u2014 nothing on this box was changed.");
7481
7567
  process.exit(1);
7482
7568
  }
@@ -7500,7 +7586,7 @@ async function runWizard() {
7500
7586
  dashboardPort,
7501
7587
  publicUrl,
7502
7588
  trustProxy: behindProxy,
7503
- version: "0.6.7",
7589
+ version: "0.6.9",
7504
7590
  noHostControl: !allowHostControl
7505
7591
  });
7506
7592
  if (!fetched.ok) {
@@ -7529,7 +7615,7 @@ async function runWizard() {
7529
7615
  dashboardPort,
7530
7616
  publicUrl,
7531
7617
  trustProxy: behindProxy,
7532
- version: "0.6.7",
7618
+ version: "0.6.9",
7533
7619
  noHostControl: !allowHostControl
7534
7620
  });
7535
7621
  if (!up.ok) {
@@ -7630,7 +7716,7 @@ async function runWizard() {
7630
7716
  if (result.liveUrl) liveUrl2 = result.liveUrl;
7631
7717
  else if (!result.domainRegistered) liveUrl2 = `http://localhost:${started.dashPort}`;
7632
7718
  for (const w of result.warnings) log5.warn(w);
7633
- const { verifyHostChannel } = await import("./host-channel-preflight-QTDNGLCK.js");
7719
+ const { verifyHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
7634
7720
  await verifyHostChannel().catch(() => {
7635
7721
  });
7636
7722
  finishSetup({
@@ -7909,7 +7995,7 @@ function attachCompletion(program2) {
7909
7995
 
7910
7996
  // src/index.ts
7911
7997
  var program = new Command28();
7912
- program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.6.7").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
7998
+ program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.6.9").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
7913
7999
  if (thisCommand.opts().json) setJsonMode(true);
7914
8000
  }).action(async () => {
7915
8001
  const installed = serviceStatus().installed || readInstallMethod() === "compose";
@@ -4,9 +4,9 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  LocalExecutor
7
- } from "./chunk-E2X26PXR.js";
8
- import "./chunk-H3WT3A6R.js";
9
- import "./chunk-2VSW6Q6C.js";
7
+ } from "./chunk-T6DVUX4F.js";
8
+ import "./chunk-P7RCYELG.js";
9
+ import "./chunk-WEZFTL4V.js";
10
10
  import "./chunk-PXKCZB2I.js";
11
11
  export {
12
12
  LocalExecutor
@@ -14,18 +14,18 @@ import {
14
14
  renderProxyOptions,
15
15
  renderProxyTlsOptions,
16
16
  summarizeCertbotFailure
17
- } from "./chunk-NRTJRNAE.js";
18
- import "./chunk-QHMDCYZ3.js";
17
+ } from "./chunk-IAMOUDHY.js";
18
+ import "./chunk-7PEXM2UI.js";
19
19
  import "./chunk-I3DPMTSF.js";
20
20
  import "./chunk-R4VDPFLS.js";
21
- import "./chunk-BLEXTYRK.js";
22
- import "./chunk-FZ6QCF6B.js";
23
- import "./chunk-H3WT3A6R.js";
24
- import "./chunk-GIPJNNI5.js";
25
- import "./chunk-VSTFHUCV.js";
26
- import "./chunk-UWEV6XTS.js";
21
+ import "./chunk-GNOMEMNI.js";
22
+ import "./chunk-NPSRGIHV.js";
23
+ import "./chunk-P7RCYELG.js";
24
+ import "./chunk-X53JXRS4.js";
25
+ import "./chunk-BO6CY4V2.js";
26
+ import "./chunk-D6HU4VUZ.js";
27
27
  import "./chunk-N5YZMO33.js";
28
- import "./chunk-2VSW6Q6C.js";
28
+ import "./chunk-WEZFTL4V.js";
29
29
  import "./chunk-PXKCZB2I.js";
30
30
  export {
31
31
  MANAGED_STATIC_BASE,
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  NoopInfraProvider
7
- } from "./chunk-RXQBD4ZY.js";
7
+ } from "./chunk-RHLNVZMS.js";
8
8
  import "./chunk-PXKCZB2I.js";
9
9
  export {
10
10
  NoopInfraProvider
@@ -40,12 +40,14 @@ import {
40
40
  ensureOpenRestyConfig,
41
41
  luaSourceAvailable,
42
42
  parseNginxVersion
43
- } from "./chunk-QHMDCYZ3.js";
44
- import "./chunk-BLEXTYRK.js";
45
- import "./chunk-FZ6QCF6B.js";
46
- import "./chunk-H3WT3A6R.js";
43
+ } from "./chunk-7PEXM2UI.js";
44
+ import "./chunk-GNOMEMNI.js";
45
+ import "./chunk-NPSRGIHV.js";
46
+ import "./chunk-P7RCYELG.js";
47
+ import "./chunk-BO6CY4V2.js";
48
+ import "./chunk-D6HU4VUZ.js";
47
49
  import "./chunk-N5YZMO33.js";
48
- import "./chunk-2VSW6Q6C.js";
50
+ import "./chunk-WEZFTL4V.js";
49
51
  import "./chunk-PXKCZB2I.js";
50
52
  export {
51
53
  ACME_CHALLENGE_LOCATION,
@@ -6,12 +6,12 @@ import {
6
6
  privilegedExecutor,
7
7
  rootChecked,
8
8
  rootOrDegrade
9
- } from "./chunk-PVP4RGWT.js";
10
- import "./chunk-BLEXTYRK.js";
11
- import "./chunk-FZ6QCF6B.js";
12
- import "./chunk-H3WT3A6R.js";
9
+ } from "./chunk-T46BQOLY.js";
10
+ import "./chunk-GNOMEMNI.js";
11
+ import "./chunk-NPSRGIHV.js";
12
+ import "./chunk-P7RCYELG.js";
13
13
  import "./chunk-N5YZMO33.js";
14
- import "./chunk-2VSW6Q6C.js";
14
+ import "./chunk-WEZFTL4V.js";
15
15
  import "./chunk-PXKCZB2I.js";
16
16
  export {
17
17
  privilegedExecutor,