openship 0.4.8 → 0.6.0

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 (112) hide show
  1. package/README.md +27 -1
  2. package/dist/bare-FSUAM5V5.js +23 -0
  3. package/dist/{bowser-O3AEA6AN.js → bowser-HNOTPGJO.js} +2 -2
  4. package/dist/{chunk-5MZ624VX.js → chunk-2GWYYHOR.js} +1 -1
  5. package/dist/chunk-3FYIXVX5.js +8051 -0
  6. package/dist/{chunk-ILFETZOM.js → chunk-3LDWWY7U.js} +21 -1
  7. package/dist/{chunk-W73X43R7.js → chunk-3NQQXMDR.js} +3 -3
  8. package/dist/{chunk-OWED2GRM.js → chunk-42WQABXM.js} +2 -2
  9. package/dist/{chunk-TYVME3XD.js → chunk-6FH4AXVY.js} +20 -3
  10. package/dist/{chunk-OXWDY22G.js → chunk-6ODUBKUB.js} +3 -3
  11. package/dist/{chunk-DYPH4HCI.js → chunk-AO252K7Z.js} +1 -1
  12. package/dist/{chunk-XPPZ7B2J.js → chunk-B3CE2OMR.js} +14 -12
  13. package/dist/{chunk-IXCHURVK.js → chunk-DOD2BXHQ.js} +4 -4
  14. package/dist/{chunk-VWPEKOH6.js → chunk-DRK3MEDS.js} +3 -3
  15. package/dist/{chunk-V6AN6XLZ.js → chunk-EMXI4UCU.js} +125 -47
  16. package/dist/{chunk-GKHUSZCD.js → chunk-EP2TNALB.js} +2 -2
  17. package/dist/{chunk-SLTYVHU7.js → chunk-GUQ3QCJ7.js} +942 -519
  18. package/dist/chunk-I3DPMTSF.js +29 -0
  19. package/dist/{chunk-L2VOGB2X.js → chunk-IW2UKBVF.js} +3 -3
  20. package/dist/{chunk-VDMQJHPI.js → chunk-IXM5245F.js} +228 -13
  21. package/dist/{chunk-MZ2WEHHY.js → chunk-JIMUYEKN.js} +4 -4
  22. package/dist/chunk-OGY63DGD.js +705 -0
  23. package/dist/{chunk-O6ZZF52V.js → chunk-ONKEYSMY.js} +2 -2
  24. package/dist/{chunk-6APULWSU.js → chunk-OTLSJYAC.js} +1744 -118
  25. package/dist/{chunk-EI575GHN.js → chunk-PDW4L3NV.js} +3 -3
  26. package/dist/{chunk-5NYUCONN.js → chunk-PSZSKEPA.js} +33 -51
  27. package/dist/{chunk-KI2EY3WB.js → chunk-PXKCZB2I.js} +1 -1
  28. package/dist/{chunk-FXTBHTWY.js → chunk-QEH4QUBX.js} +649 -85
  29. package/dist/{chunk-6APIPIJY.js → chunk-QWHBRY2K.js} +5 -5
  30. package/dist/{chunk-6B5YCFFV.js → chunk-RVER2EOO.js} +5 -5
  31. package/dist/{chunk-Q2CIRAOK.js → chunk-RXQBD4ZY.js} +1 -1
  32. package/dist/{chunk-TGIINPVM.js → chunk-TWJCLD4W.js} +60 -10
  33. package/dist/{chunk-4Z5QO7N6.js → chunk-VDDMADOF.js} +3 -3
  34. package/dist/{chunk-BBHX7T4R.js → chunk-VE2YOK4I.js} +991 -254
  35. package/dist/{chunk-2D3I5G6P.js → chunk-VZ2ZHPS2.js} +73 -43
  36. package/dist/{chunk-AVIB7CT7.js → chunk-WNWQBB7F.js} +2 -2
  37. package/dist/{chunk-FRNAR33O.js → chunk-XZYFZ6A5.js} +3 -3
  38. package/dist/{chunk-RPHRPFEH.js → chunk-ZCFVHA25.js} +1 -1
  39. package/dist/{chunk-FPRHYBY2.js → chunk-ZFJXPCQP.js} +1 -1
  40. package/dist/{chunk-JYGD5WSN.js → chunk-ZWLDLTJP.js} +1 -1
  41. package/dist/cloud-E5M6VMCG.js +31 -0
  42. package/dist/{cloud-7QYOGF7F.js → cloud-KRTZ2IL5.js} +3 -3
  43. package/dist/{detect-AZLOHUFX.js → detect-ALF4GXRX.js} +7 -8
  44. package/dist/{dist-IQJ6H6UZ.js → dist-BM6NPWIH.js} +3 -3
  45. package/dist/{dist-es-X3B5QYKB.js → dist-es-2YRDXMUU.js} +6 -6
  46. package/dist/{dist-es-OSNJBLXB.js → dist-es-CCVZEFRZ.js} +5 -5
  47. package/dist/{dist-es-VNKHQVIB.js → dist-es-IOH6G4GM.js} +4 -4
  48. package/dist/{dist-es-RYHIPOTN.js → dist-es-JGBPABJI.js} +14 -14
  49. package/dist/{dist-es-JSTDUS7Q.js → dist-es-KWSMDPIP.js} +6 -6
  50. package/dist/{dist-es-5DY7K32L.js → dist-es-UYDDOVZ3.js} +6 -6
  51. package/dist/{dist-es-WV4AMOII.js → dist-es-XUOR4NQN.js} +8 -8
  52. package/dist/docker-QECQJ5P4.js +32 -0
  53. package/dist/docker-edge-executor-62N64MGS.js +17 -0
  54. package/dist/edge-import-CQWHN2Q3.js +48 -0
  55. package/dist/ensure-container-edge-MJVXJQG5.js +32 -0
  56. package/dist/{event-streams-EHRAKL75.js → event-streams-TR4GAC53.js} +4 -4
  57. package/dist/{executor-XJ6RP4Q2.js → executor-JELARVKC.js} +8 -8
  58. package/dist/index.js +1209 -560
  59. package/dist/{loadSso-46FQRIZS.js → loadSso-UGF4JMRK.js} +10 -10
  60. package/dist/{local-executor-V7U5VOZW.js → local-executor-WOFZD72X.js} +4 -4
  61. package/dist/nginx-AXGNWRKZ.js +31 -0
  62. package/dist/node-entry.js +4 -0
  63. package/dist/{noop-FMMFG2EZ.js → noop-NJ72F46T.js} +3 -3
  64. package/dist/openresty-lua-IE4P5YQX.js +81 -0
  65. package/dist/server/index.js +116248 -94749
  66. package/dist/server/lua/geo_country.lua +31 -6
  67. package/dist/server/lua/maxminddb.lua +403 -0
  68. package/dist/server/lua/mgmt_api.lua +431 -68
  69. package/dist/server/lua/pipe_log.lua +10 -4
  70. package/dist/server/lua/site_logger.lua +220 -12
  71. package/dist/server/migrations/0073_project_volumes_object_storage.sql +3 -0
  72. package/dist/server/migrations/0074_project_compose_path.sql +1 -0
  73. package/dist/server/migrations/0075_service_command_argv.sql +1 -0
  74. package/dist/server/migrations/0076_rollback_retention.sql +17 -0
  75. package/dist/server/migrations/0077_domain_redirect.sql +13 -0
  76. package/dist/server/migrations/0078_grant_source_scope.sql +30 -0
  77. package/dist/server/migrations/0079_project_readiness.sql +18 -0
  78. package/dist/server/migrations/0080_deployment_error_classification.sql +26 -0
  79. package/dist/server/migrations/0081_project_readiness_repair.sql +34 -0
  80. package/dist/server/migrations/0082_edge_target_verification.sql +39 -0
  81. package/dist/server/migrations/0083_service_incident.sql +84 -0
  82. package/dist/server/migrations/0084_analytics_daily_rollup.sql +72 -0
  83. package/dist/server/migrations/0085_resource_usage.sql +68 -0
  84. package/dist/server/migrations/0086_remote_infra_updates.sql +41 -0
  85. package/dist/server/migrations/0087_server_container_version_columns.sql +17 -0
  86. package/dist/server/migrations/0088_audit_source_and_settings.sql +27 -0
  87. package/dist/server/migrations/0089_auto_scan_infra.sql +7 -0
  88. package/dist/server/migrations/0090_project_collect_paths.sql +18 -0
  89. package/dist/server/migrations/0091_project_server_id.sql +26 -0
  90. package/dist/server/migrations/0092_project_internal_alias.sql +13 -0
  91. package/dist/server/migrations/0093_service_incident_org_index.sql +13 -0
  92. package/dist/server/migrations/0094_backup_restore_meta.sql +15 -0
  93. package/dist/server/migrations/0095_backup_restore_cancel.sql +19 -0
  94. package/dist/server/migrations/0096_backup_policy_retention_defaults.sql +20 -0
  95. package/dist/server/migrations/0097_update_status_upstream_only.sql +35 -0
  96. package/dist/server/migrations/meta/_journal.json +175 -0
  97. package/dist/setup-FA4PW4NU.js +21 -0
  98. package/dist/{signin-ITOPKKUB.js → signin-3M3UPB6K.js} +10 -10
  99. package/dist/{sso-oidc-NON2PD7Y.js → sso-oidc-3VDIYOEJ.js} +10 -10
  100. package/dist/{sts-HHFFSAY2.js → sts-B3WIYLXR.js} +9 -9
  101. package/package.json +6 -3
  102. package/dist/bare-JY5Y5ELU.js +0 -23
  103. package/dist/chunk-SJIFLLX4.js +0 -2931
  104. package/dist/chunk-VFINNTUL.js +0 -362
  105. package/dist/cloud-KYWY3RP4.js +0 -30
  106. package/dist/docker-LODK5Y2S.js +0 -16
  107. package/dist/docker-edge-executor-VHW3JPJS.js +0 -13
  108. package/dist/edge-import-ABUDKKJI.js +0 -45
  109. package/dist/ensure-container-edge-SW6HENSG.js +0 -31
  110. package/dist/nginx-3L4SIBJA.js +0 -24
  111. package/dist/openresty-lua-4WLGDSER.js +0 -42
  112. package/dist/setup-NU6T2PDU.js +0 -20
@@ -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
+
6
+ // ../../packages/adapters/src/system/edge-exec-error.ts
7
+ var EDGE_DOWN_MARKER = "the edge container is not running";
8
+ function isEdgeDownFailure(text) {
9
+ return /is restarting, wait until the container is running/i.test(text) || /container .* is not running/i.test(text) || /\bis not running\b/i.test(text) || /No such container/i.test(text) || /container .* is paused/i.test(text) || /invalid PID number/i.test(text);
10
+ }
11
+ function explainEdgeDown(opts) {
12
+ const { container, status, reason } = opts;
13
+ const state = status?.trim() ? ` (${status.trim()})` : "";
14
+ const crashLooping = status?.trim() === "restarting";
15
+ const consequence = crashLooping ? `it is crash-looping, so nothing that runs through the edge on this server can work \u2014 certificate issuance, config reloads and route changes all go through it` : `nothing that runs through the edge on this server can work until it is up \u2014 certificate issuance, config reloads and route changes all go through it`;
16
+ const cause = reason?.trim() ? `OpenResty is refusing to start: ${reason.trim().replace(/\s+/g, " ")}. Fix that, then \`docker start ${container}\` and retry.` : `Run \`docker logs --tail 40 ${container}\` on the server for the reason, then retry.`;
17
+ return `${EDGE_DOWN_MARKER} ("${container}")${state} \u2014 ${consequence}. ${cause}`;
18
+ }
19
+ function edgeDownExplanation(text) {
20
+ if (!text) return null;
21
+ const line = text.split("\n").map((l) => l.trim()).find((l) => l.includes(EDGE_DOWN_MARKER));
22
+ return line || null;
23
+ }
24
+
25
+ export {
26
+ isEdgeDownFailure,
27
+ explainEdgeDown,
28
+ edgeDownExplanation
29
+ };
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v bun || command -v node)" "$0" "$@"
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
3
  import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  formatDuration,
7
7
  isRemoteConnectionError,
8
8
  systemDebug
9
- } from "./chunk-RPHRPFEH.js";
9
+ } from "./chunk-ZCFVHA25.js";
10
10
  import {
11
11
  safeErrorMessage
12
- } from "./chunk-6APULWSU.js";
12
+ } from "./chunk-OTLSJYAC.js";
13
13
 
14
14
  // ../../packages/adapters/src/system/environment.ts
15
15
  var profileCache = /* @__PURE__ */ new WeakMap();
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v bun || command -v node)" "$0" "$@"
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
3
  import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
@@ -7,10 +7,10 @@ import {
7
7
  resolveProjectDir,
8
8
  resolveStaticOutputPath,
9
9
  runLocalBuild
10
- } from "./chunk-MZ2WEHHY.js";
10
+ } from "./chunk-JIMUYEKN.js";
11
11
  import {
12
12
  resolveEnvironment
13
- } from "./chunk-L2VOGB2X.js";
13
+ } from "./chunk-IW2UKBVF.js";
14
14
  import {
15
15
  BuildCancelledError,
16
16
  BuildLogger,
@@ -19,32 +19,33 @@ import {
19
19
  runBuildPipeline,
20
20
  sq,
21
21
  transferLocalDirectory
22
- } from "./chunk-4Z5QO7N6.js";
22
+ } from "./chunk-VDDMADOF.js";
23
23
  import {
24
24
  formatDuration,
25
25
  isRemoteConnectionError,
26
26
  isRetryableRemoteConnectionError,
27
27
  systemDebug
28
- } from "./chunk-RPHRPFEH.js";
28
+ } from "./chunk-ZCFVHA25.js";
29
29
  import {
30
30
  LocalExecutor
31
- } from "./chunk-TYVME3XD.js";
31
+ } from "./chunk-6FH4AXVY.js";
32
+ import {
33
+ probeListeningPort
34
+ } from "./chunk-3LDWWY7U.js";
32
35
  import {
33
36
  sq as sq2,
34
37
  wrapLocalBuildCommand
35
- } from "./chunk-FPRHYBY2.js";
36
- import {
37
- probeListeningPort
38
- } from "./chunk-ILFETZOM.js";
38
+ } from "./chunk-ZFJXPCQP.js";
39
39
  import {
40
40
  DeployError,
41
41
  LANGUAGES,
42
42
  STACKS,
43
+ appVolumeTargets,
43
44
  buildOutputTransferExcludes,
44
45
  missingOutputDirectoryMessage,
45
46
  packageManagerEnsureCommand,
46
47
  safeErrorMessage
47
- } from "./chunk-6APULWSU.js";
48
+ } from "./chunk-OTLSJYAC.js";
48
49
 
49
50
  // ../../packages/adapters/src/system/remote-journal.ts
50
51
  var OPSH_RUN_VERSION = 1;
@@ -996,6 +997,101 @@ async function installTools(executor, toolNames, onLog, requiredVersions) {
996
997
  return results;
997
998
  }
998
999
 
1000
+ // ../../packages/adapters/src/runtime/supervisor/usage.ts
1001
+ var SAMPLE_MS = 250;
1002
+ var ZERO_USAGE = {
1003
+ cpuPercent: 0,
1004
+ memoryMb: 0,
1005
+ diskMb: 0,
1006
+ networkRxBytes: 0,
1007
+ networkTxBytes: 0
1008
+ };
1009
+ function buildProbe(pid, cgroupCandidates) {
1010
+ const p = sq(String(pid));
1011
+ const cgList = cgroupCandidates.map(sq).join(" ");
1012
+ return [
1013
+ `P=${p}`,
1014
+ // Locate a readable cgroup v2 dir for this unit, if any.
1015
+ `CG=""`,
1016
+ `for c in ${cgList}; do if [ -r "$c/cpu.stat" ]; then CG="$c"; break; fi; done`,
1017
+ // ── cgroup v2 ──
1018
+ `if [ -n "$CG" ]; then`,
1019
+ ` C1=$(awk '/^usage_usec/{print $2}' "$CG/cpu.stat" 2>/dev/null)`,
1020
+ ` sleep ${(SAMPLE_MS / 1e3).toFixed(3)}`,
1021
+ ` C2=$(awk '/^usage_usec/{print $2}' "$CG/cpu.stat" 2>/dev/null)`,
1022
+ ` M=$(cat "$CG/memory.current" 2>/dev/null)`,
1023
+ // io.stat is "<maj:min> rbytes=N wbytes=N rios=N wios=N" per device — summed
1024
+ // across devices. Read and write are kept apart so the parser adds each once.
1025
+ ` R=$(awk '{for(i=1;i<=NF;i++){split($i,kv,"=");if(kv[1]=="rbytes")r+=kv[2]}}END{print r+0}' "$CG/io.stat" 2>/dev/null)`,
1026
+ ` W=$(awk '{for(i=1;i<=NF;i++){split($i,kv,"=");if(kv[1]=="wbytes")w+=kv[2]}}END{print w+0}' "$CG/io.stat" 2>/dev/null)`,
1027
+ ` echo "cgroup \${C1:-0} \${C2:-0} \${M:-0} \${R:-0} \${W:-0}"`,
1028
+ // ── /proc/<pid> ──
1029
+ `elif [ -r "/proc/$P/stat" ]; then`,
1030
+ // utime (14) + stime (15) in clock ticks. comm can contain spaces, so cut
1031
+ // everything up to the closing paren before counting fields.
1032
+ ` T=$(getconf CLK_TCK 2>/dev/null || echo 100)`,
1033
+ ` C1=$(sed 's/.*) //' "/proc/$P/stat" 2>/dev/null | awk -v t="$T" '{print int((($12+$13)/t)*1000000)}')`,
1034
+ ` sleep ${(SAMPLE_MS / 1e3).toFixed(3)}`,
1035
+ ` C2=$(sed 's/.*) //' "/proc/$P/stat" 2>/dev/null | awk -v t="$T" '{print int((($12+$13)/t)*1000000)}')`,
1036
+ ` M=$(awk '/^VmRSS:/{print $2*1024}' "/proc/$P/status" 2>/dev/null)`,
1037
+ ` R=$(awk '/^read_bytes:/{print $2}' "/proc/$P/io" 2>/dev/null)`,
1038
+ ` W=$(awk '/^write_bytes:/{print $2}' "/proc/$P/io" 2>/dev/null)`,
1039
+ ` echo "proc \${C1:-0} \${C2:-0} \${M:-0} \${R:-0} \${W:-0}"`,
1040
+ // ── ps (macOS / no procfs) ──
1041
+ `else`,
1042
+ // ps %cpu is a LIFETIME average, not a rate — reported as-is and flagged by the
1043
+ // `ps` source so the parser doesn't pretend it's an instantaneous sample.
1044
+ ` X=$(ps -o rss=,%cpu= -p "$P" 2>/dev/null | awk '{print ($1*1024)" "$2}')`,
1045
+ ` echo "ps \${X:-0 0}"`,
1046
+ `fi`
1047
+ ].join("; ");
1048
+ }
1049
+ function parseProbe(out) {
1050
+ const parts = out.trim().split(/\s+/);
1051
+ const source = parts[0];
1052
+ const n = (i) => {
1053
+ const v = Number(parts[i]);
1054
+ return Number.isFinite(v) && v >= 0 ? v : 0;
1055
+ };
1056
+ let cpuPercent;
1057
+ let memoryMb;
1058
+ let diskMb = 0;
1059
+ if (source === "ps") {
1060
+ if (parts.length < 3) return { ...ZERO_USAGE, source: "none" };
1061
+ memoryMb = n(1) / (1024 * 1024);
1062
+ cpuPercent = n(2);
1063
+ } else if (source === "cgroup" || source === "proc") {
1064
+ if (parts.length < 6) return { ...ZERO_USAGE, source: "none" };
1065
+ const deltaUsec = Math.max(0, n(2) - n(1));
1066
+ cpuPercent = deltaUsec / (SAMPLE_MS * 1e3) * 100;
1067
+ memoryMb = n(3) / (1024 * 1024);
1068
+ diskMb = (n(4) + n(5)) / (1024 * 1024);
1069
+ } else {
1070
+ return { ...ZERO_USAGE, source: "none" };
1071
+ }
1072
+ return {
1073
+ cpuPercent: Math.round(cpuPercent * 100) / 100,
1074
+ memoryMb: Math.round(memoryMb * 100) / 100,
1075
+ diskMb: Math.round(diskMb * 100) / 100,
1076
+ // Per-process network accounting needs eBPF or a per-unit netns, neither of
1077
+ // which a bare deploy has. Zero here means "not measured", and the dashboard
1078
+ // shows network only for container runtimes.
1079
+ networkRxBytes: 0,
1080
+ networkTxBytes: 0,
1081
+ source
1082
+ };
1083
+ }
1084
+ async function sampleBareUsage(executor, pid, cgroupCandidates = []) {
1085
+ if (!Number.isInteger(pid) || pid <= 0) return { ...ZERO_USAGE };
1086
+ try {
1087
+ const out = await executor.exec(buildProbe(pid, cgroupCandidates));
1088
+ const { source: _source, ...usage } = parseProbe(out);
1089
+ return usage;
1090
+ } catch {
1091
+ return { ...ZERO_USAGE };
1092
+ }
1093
+ }
1094
+
999
1095
  // ../../packages/adapters/src/runtime/supervisor/systemd.ts
1000
1096
  var UNIT_PREFIX = "openship";
1001
1097
  function escapeSystemdEnvValue(value) {
@@ -1146,6 +1242,33 @@ ${hint}` : "Process exited immediately after start (no output captured)";
1146
1242
  return false;
1147
1243
  }
1148
1244
  }
1245
+ /**
1246
+ * Usage for the unit. Prefers the unit's cgroup, which accounts for the whole
1247
+ * process tree — a `npm start` that forks the real server would otherwise report
1248
+ * only the wrapper's near-zero usage.
1249
+ *
1250
+ * `MainPID` is fetched as the fallback identity (and as the liveness check) for a
1251
+ * host without a readable cgroup; the probe picks the tier itself. `--value` is
1252
+ * used so a stopped unit yields "0" rather than a `MainPID=0` line to parse.
1253
+ */
1254
+ async getUsage(deploymentId) {
1255
+ const unitName = this.unitName(deploymentId);
1256
+ try {
1257
+ const out = await this.executor.exec(
1258
+ `systemctl show ${sq(unitName)} -p MainPID --value 2>/dev/null || true`
1259
+ );
1260
+ const pid = Number.parseInt(out.trim(), 10);
1261
+ if (!Number.isFinite(pid) || pid <= 0) return { ...ZERO_USAGE };
1262
+ return sampleBareUsage(this.executor, pid, [
1263
+ // Where systemd places a unit started from /etc/systemd/system. The delegate
1264
+ // path appears when the unit sets Delegate=yes; harmless to probe either way.
1265
+ `/sys/fs/cgroup/system.slice/${unitName}`,
1266
+ `/sys/fs/cgroup/system.slice/${unitName}/init.scope`
1267
+ ]);
1268
+ } catch {
1269
+ return { ...ZERO_USAGE };
1270
+ }
1271
+ }
1149
1272
  async getLogs(deploymentId, tail) {
1150
1273
  const unitName = this.unitName(deploymentId);
1151
1274
  const tailArg = tail ? `-n ${tail}` : `-n 200`;
@@ -1325,6 +1448,19 @@ ${hint}` : "Process exited immediately after spawn (no output captured)";
1325
1448
  if (!pid) return false;
1326
1449
  return this.isAlive(pid);
1327
1450
  }
1451
+ /**
1452
+ * Usage for the tracked process.
1453
+ *
1454
+ * No cgroup candidates: nohup does not create one (that's the documented
1455
+ * limitation above), so the probe uses /proc on Linux and `ps` on macOS. Both
1456
+ * measure the LEADER only — a start command that forks will under-report, which
1457
+ * is the same tradeoff as this supervisor's lack of restart and reboot handling.
1458
+ */
1459
+ async getUsage(deploymentId) {
1460
+ const pid = await this.readPid(deploymentId);
1461
+ if (!pid) return { ...ZERO_USAGE };
1462
+ return sampleBareUsage(this.executor, pid);
1463
+ }
1328
1464
  async getLogs(deploymentId, tail) {
1329
1465
  const logPath = this.logFile(deploymentId);
1330
1466
  try {
@@ -1385,6 +1521,10 @@ async function probeSystemd(executor) {
1385
1521
  }
1386
1522
 
1387
1523
  // ../../packages/adapters/src/runtime/bare.ts
1524
+ function parentPath(path) {
1525
+ const idx = path.replace(/\/+$/, "").lastIndexOf("/");
1526
+ return idx > 0 ? path.slice(0, idx) : "/";
1527
+ }
1388
1528
  var DEFAULT_WORK_DIR = "/opt/openship";
1389
1529
  var DEFAULT_BUILD_TIMEOUT = 10 * 60 * 1e3;
1390
1530
  var STATIC_RELEASE_BASE = "/opt/openship/static";
@@ -1399,8 +1539,17 @@ var BareRuntime = class {
1399
1539
  "destroy",
1400
1540
  "runtimeLogs",
1401
1541
  "streamLogs",
1542
+ // Real measurements now (cgroup → /proc → ps, via the supervisor), so this can
1543
+ // finally be declared. It was absent while getUsage returned a zeros stub — but
1544
+ // nothing checked, so callers rendered those zeros as data. Anything reading
1545
+ // usage should gate on supports("usage") rather than trust the numbers.
1546
+ // Network is the one gap: per-process rx/tx needs eBPF or a netns, so it stays 0.
1547
+ "usage",
1402
1548
  "containerIp",
1403
1549
  "rollback",
1550
+ // The release dir + supervisor unit survive a redeploy, so restoring a
1551
+ // past release really is an in-place unit swap (see makeActive).
1552
+ "unitRestore",
1404
1553
  "inContainerExec"
1405
1554
  ]);
1406
1555
  workDir;
@@ -1466,6 +1615,60 @@ var BareRuntime = class {
1466
1615
  releaseDir(deploymentId) {
1467
1616
  return `${this.workDir}/releases/${deploymentId}`;
1468
1617
  }
1618
+ /** Per-project directory holding the paths that must survive a release swap.
1619
+ * The `shared/` half of the Capistrano layout `releases/` already implements. */
1620
+ sharedDir(projectId) {
1621
+ return `${this.workDir}/shared/${projectId}`;
1622
+ }
1623
+ /**
1624
+ * Repoint the release's persistent paths at `shared/`, so a redeploy doesn't
1625
+ * take the app's data with the old release.
1626
+ *
1627
+ * Docker gets this from a volume; bare has no mount to hang it on, so the
1628
+ * equivalent is the deploy convention: keep the state outside the release tree
1629
+ * and symlink it in. The first release that ships the path SEEDS the shared
1630
+ * copy from it — frameworks ship a skeleton there (Laravel's `storage/` has
1631
+ * `framework/cache`, `framework/sessions`, …) and an app handed an empty
1632
+ * directory instead would fail on write.
1633
+ *
1634
+ * Best-effort per path: a box without the shared dir writable is a storage
1635
+ * problem to report, not a reason to fail an otherwise good release.
1636
+ */
1637
+ async linkPersistentPaths(releaseDir, projectId, volumes, log) {
1638
+ const targets = appVolumeTargets(volumes ?? []);
1639
+ if (targets.length === 0) return;
1640
+ const shared = this.sharedDir(projectId);
1641
+ for (const relative of targets) {
1642
+ const sharedPath = `${shared}/${relative}`;
1643
+ const releasePath = `${releaseDir}/${relative}`;
1644
+ try {
1645
+ if (!await this.executor.exists(sharedPath)) {
1646
+ await this.executor.mkdir(parentPath(sharedPath));
1647
+ if (await this.executor.exists(releasePath)) {
1648
+ await this.executor.exec(`cp -a ${sq(releasePath)} ${sq(sharedPath)}`);
1649
+ } else {
1650
+ await this.executor.mkdir(sharedPath);
1651
+ }
1652
+ }
1653
+ await this.executor.rm(releasePath);
1654
+ await this.executor.mkdir(parentPath(releasePath));
1655
+ await this.executor.exec(`ln -sfn ${sq(sharedPath)} ${sq(releasePath)}`);
1656
+ log?.({
1657
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1658
+ message: `Persistent path ${relative} \u2192 ${sharedPath}
1659
+ `,
1660
+ level: "info"
1661
+ });
1662
+ } catch (err) {
1663
+ log?.({
1664
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1665
+ message: `Could not persist ${relative}: ${safeErrorMessage(err)}
1666
+ `,
1667
+ level: "warn"
1668
+ });
1669
+ }
1670
+ }
1671
+ }
1469
1672
  async promoteBuildArtifact(artifactPath, deploymentId, previousDeploymentId) {
1470
1673
  const releaseDir = this.releaseDir(deploymentId);
1471
1674
  if (artifactPath === releaseDir) return releaseDir;
@@ -1727,6 +1930,7 @@ var BareRuntime = class {
1727
1930
  config.deploymentId,
1728
1931
  config.previousDeploymentId
1729
1932
  ) : stagedDir;
1933
+ await this.linkPersistentPaths(workDir, config.projectId, config.volumes, _onLog);
1730
1934
  const sv = await this.supervisor();
1731
1935
  const env = {
1732
1936
  ...Object.fromEntries(
@@ -1887,8 +2091,19 @@ var BareRuntime = class {
1887
2091
  const sv = await this.supervisor();
1888
2092
  return sv.streamLogs(containerId, onLog, opts);
1889
2093
  }
1890
- async getUsage(_containerId) {
1891
- return { cpuPercent: 0, memoryMb: 0, diskMb: 0, networkRxBytes: 0, networkTxBytes: 0 };
2094
+ /**
2095
+ * CPU / memory / disk-IO for the deployment's process.
2096
+ *
2097
+ * `containerId` is the DEPLOYMENT id here, not a docker container id — that's the
2098
+ * bare runtime's convention throughout (it's what the supervisor keys units and
2099
+ * PID files on).
2100
+ *
2101
+ * The supervisor owns the measurement because the identity differs: systemd has a
2102
+ * unit and a cgroup, nohup has a PID file. Both land on the same probe.
2103
+ */
2104
+ async getUsage(containerId) {
2105
+ const sv = await this.supervisor();
2106
+ return sv.getUsage(containerId);
1892
2107
  }
1893
2108
  // ── Network ────────────────────────────────────────────────────────────
1894
2109
  async getContainerIp(_containerId) {
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env sh
2
- ":" //# ; exec "$(command -v bun || command -v node)" "$0" "$@"
2
+ ":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
3
3
  import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  detectBuildKillHint,
7
7
  runBuildPipeline,
8
8
  transferLocalDirectory
9
- } from "./chunk-4Z5QO7N6.js";
9
+ } from "./chunk-VDDMADOF.js";
10
10
  import {
11
11
  LocalExecutor
12
- } from "./chunk-TYVME3XD.js";
12
+ } from "./chunk-6FH4AXVY.js";
13
13
  import {
14
14
  wrapLocalBuildCommand
15
- } from "./chunk-FPRHYBY2.js";
15
+ } from "./chunk-ZFJXPCQP.js";
16
16
 
17
17
  // ../../packages/adapters/src/runtime/local-build.ts
18
18
  var LOCAL_BUILD_DIR = "/tmp/openship/.builds";