@serfab/cadre-host 0.7.1

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 (300) hide show
  1. package/README.md +101 -0
  2. package/dist/auth/duration.d.ts +1 -0
  3. package/dist/auth/duration.js +32 -0
  4. package/dist/auth/duration.js.map +1 -0
  5. package/dist/auth/index.d.ts +9 -0
  6. package/dist/auth/index.js +8 -0
  7. package/dist/auth/index.js.map +1 -0
  8. package/dist/auth/trust-circle-store.d.ts +26 -0
  9. package/dist/auth/trust-circle-store.js +129 -0
  10. package/dist/auth/trust-circle-store.js.map +1 -0
  11. package/dist/auth/trust-circle.d.ts +91 -0
  12. package/dist/auth/trust-circle.js +230 -0
  13. package/dist/auth/trust-circle.js.map +1 -0
  14. package/dist/auth/types.d.ts +81 -0
  15. package/dist/auth/types.js +24 -0
  16. package/dist/auth/types.js.map +1 -0
  17. package/dist/bin/host.d.ts +13 -0
  18. package/dist/bin/host.js +826 -0
  19. package/dist/bin/host.js.map +1 -0
  20. package/dist/index.d.ts +32 -0
  21. package/dist/index.js +27 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/installer/browser.d.ts +14 -0
  24. package/dist/installer/browser.js +35 -0
  25. package/dist/installer/browser.js.map +1 -0
  26. package/dist/installer/config.d.ts +43 -0
  27. package/dist/installer/config.js +113 -0
  28. package/dist/installer/config.js.map +1 -0
  29. package/dist/installer/identity.d.ts +23 -0
  30. package/dist/installer/identity.js +36 -0
  31. package/dist/installer/identity.js.map +1 -0
  32. package/dist/installer/index.d.ts +83 -0
  33. package/dist/installer/index.js +204 -0
  34. package/dist/installer/index.js.map +1 -0
  35. package/dist/installer/paths.d.ts +33 -0
  36. package/dist/installer/paths.js +84 -0
  37. package/dist/installer/paths.js.map +1 -0
  38. package/dist/installer/platform.d.ts +9 -0
  39. package/dist/installer/platform.js +21 -0
  40. package/dist/installer/platform.js.map +1 -0
  41. package/dist/installer/service-host/index.d.ts +11 -0
  42. package/dist/installer/service-host/index.js +16 -0
  43. package/dist/installer/service-host/index.js.map +1 -0
  44. package/dist/installer/service-host/launchd.d.ts +16 -0
  45. package/dist/installer/service-host/launchd.js +79 -0
  46. package/dist/installer/service-host/launchd.js.map +1 -0
  47. package/dist/installer/service-host/nssm.d.ts +20 -0
  48. package/dist/installer/service-host/nssm.js +88 -0
  49. package/dist/installer/service-host/nssm.js.map +1 -0
  50. package/dist/installer/service-host/systemd.d.ts +16 -0
  51. package/dist/installer/service-host/systemd.js +78 -0
  52. package/dist/installer/service-host/systemd.js.map +1 -0
  53. package/dist/installer/service-host/template.d.ts +6 -0
  54. package/dist/installer/service-host/template.js +20 -0
  55. package/dist/installer/service-host/template.js.map +1 -0
  56. package/dist/installer/service-host/types.d.ts +40 -0
  57. package/dist/installer/service-host/types.js +6 -0
  58. package/dist/installer/service-host/types.js.map +1 -0
  59. package/dist/installer/wizard.d.ts +31 -0
  60. package/dist/installer/wizard.js +67 -0
  61. package/dist/installer/wizard.js.map +1 -0
  62. package/dist/nat/address-resolver.d.ts +22 -0
  63. package/dist/nat/address-resolver.js +31 -0
  64. package/dist/nat/address-resolver.js.map +1 -0
  65. package/dist/nat/ddns/duckdns.d.ts +12 -0
  66. package/dist/nat/ddns/duckdns.js +57 -0
  67. package/dist/nat/ddns/duckdns.js.map +1 -0
  68. package/dist/nat/ddns/index.d.ts +30 -0
  69. package/dist/nat/ddns/index.js +21 -0
  70. package/dist/nat/ddns/index.js.map +1 -0
  71. package/dist/nat/ddns/updater.d.ts +68 -0
  72. package/dist/nat/ddns/updater.js +194 -0
  73. package/dist/nat/ddns/updater.js.map +1 -0
  74. package/dist/nat/external-ip.d.ts +62 -0
  75. package/dist/nat/external-ip.js +114 -0
  76. package/dist/nat/external-ip.js.map +1 -0
  77. package/dist/nat/index.d.ts +22 -0
  78. package/dist/nat/index.js +16 -0
  79. package/dist/nat/index.js.map +1 -0
  80. package/dist/nat/nat-service.d.ts +101 -0
  81. package/dist/nat/nat-service.js +284 -0
  82. package/dist/nat/nat-service.js.map +1 -0
  83. package/dist/nat/nat-store.d.ts +19 -0
  84. package/dist/nat/nat-store.js +136 -0
  85. package/dist/nat/nat-store.js.map +1 -0
  86. package/dist/nat/port-mapper.d.ts +98 -0
  87. package/dist/nat/port-mapper.js +226 -0
  88. package/dist/nat/port-mapper.js.map +1 -0
  89. package/dist/nat/reachability.d.ts +19 -0
  90. package/dist/nat/reachability.js +29 -0
  91. package/dist/nat/reachability.js.map +1 -0
  92. package/dist/nat/secrets/file-store.d.ts +23 -0
  93. package/dist/nat/secrets/file-store.js +102 -0
  94. package/dist/nat/secrets/file-store.js.map +1 -0
  95. package/dist/nat/secrets/index.d.ts +36 -0
  96. package/dist/nat/secrets/index.js +56 -0
  97. package/dist/nat/secrets/index.js.map +1 -0
  98. package/dist/nat/secrets/keytar-store.d.ts +18 -0
  99. package/dist/nat/secrets/keytar-store.js +52 -0
  100. package/dist/nat/secrets/keytar-store.js.map +1 -0
  101. package/dist/nat/types.d.ts +120 -0
  102. package/dist/nat/types.js +24 -0
  103. package/dist/nat/types.js.map +1 -0
  104. package/dist/orchestrator/host-process-orchestrator.d.ts +87 -0
  105. package/dist/orchestrator/host-process-orchestrator.js +557 -0
  106. package/dist/orchestrator/host-process-orchestrator.js.map +1 -0
  107. package/dist/orchestrator/index.d.ts +3 -0
  108. package/dist/orchestrator/index.js +2 -0
  109. package/dist/orchestrator/index.js.map +1 -0
  110. package/dist/orchestrator/log-rotator.d.ts +25 -0
  111. package/dist/orchestrator/log-rotator.js +56 -0
  112. package/dist/orchestrator/log-rotator.js.map +1 -0
  113. package/dist/orchestrator/pid-liveness.d.ts +11 -0
  114. package/dist/orchestrator/pid-liveness.js +26 -0
  115. package/dist/orchestrator/pid-liveness.js.map +1 -0
  116. package/dist/orchestrator/port-allocator.d.ts +16 -0
  117. package/dist/orchestrator/port-allocator.js +38 -0
  118. package/dist/orchestrator/port-allocator.js.map +1 -0
  119. package/dist/orchestrator/state-store.d.ts +32 -0
  120. package/dist/orchestrator/state-store.js +44 -0
  121. package/dist/orchestrator/state-store.js.map +1 -0
  122. package/dist/orchestrator/types.d.ts +85 -0
  123. package/dist/orchestrator/types.js +31 -0
  124. package/dist/orchestrator/types.js.map +1 -0
  125. package/dist/server/error-handler.d.ts +26 -0
  126. package/dist/server/error-handler.js +95 -0
  127. package/dist/server/error-handler.js.map +1 -0
  128. package/dist/server/events/bus.d.ts +17 -0
  129. package/dist/server/events/bus.js +36 -0
  130. package/dist/server/events/bus.js.map +1 -0
  131. package/dist/server/events/sse-route.d.ts +22 -0
  132. package/dist/server/events/sse-route.js +65 -0
  133. package/dist/server/events/sse-route.js.map +1 -0
  134. package/dist/server/events/types.d.ts +25 -0
  135. package/dist/server/events/types.js +8 -0
  136. package/dist/server/events/types.js.map +1 -0
  137. package/dist/server/index.d.ts +67 -0
  138. package/dist/server/index.js +149 -0
  139. package/dist/server/index.js.map +1 -0
  140. package/dist/server/origin-guard.d.ts +24 -0
  141. package/dist/server/origin-guard.js +72 -0
  142. package/dist/server/origin-guard.js.map +1 -0
  143. package/dist/server/routes/nat.d.ts +16 -0
  144. package/dist/server/routes/nat.js +42 -0
  145. package/dist/server/routes/nat.js.map +1 -0
  146. package/dist/server/routes/nodes.d.ts +23 -0
  147. package/dist/server/routes/nodes.js +128 -0
  148. package/dist/server/routes/nodes.js.map +1 -0
  149. package/dist/server/routes/settings.d.ts +26 -0
  150. package/dist/server/routes/settings.js +97 -0
  151. package/dist/server/routes/settings.js.map +1 -0
  152. package/dist/server/routes/status.d.ts +42 -0
  153. package/dist/server/routes/status.js +76 -0
  154. package/dist/server/routes/status.js.map +1 -0
  155. package/dist/server/routes/trust-circle.d.ts +17 -0
  156. package/dist/server/routes/trust-circle.js +35 -0
  157. package/dist/server/routes/trust-circle.js.map +1 -0
  158. package/dist/server/routes/update.d.ts +16 -0
  159. package/dist/server/routes/update.js +29 -0
  160. package/dist/server/routes/update.js.map +1 -0
  161. package/dist/server/server.d.ts +40 -0
  162. package/dist/server/server.js +90 -0
  163. package/dist/server/server.js.map +1 -0
  164. package/dist/server/settings-store.d.ts +24 -0
  165. package/dist/server/settings-store.js +27 -0
  166. package/dist/server/settings-store.js.map +1 -0
  167. package/dist/server/static.d.ts +25 -0
  168. package/dist/server/static.js +177 -0
  169. package/dist/server/static.js.map +1 -0
  170. package/dist/ui/assets/index-BwU5mJGF.css +1 -0
  171. package/dist/ui/assets/index-C9uChk2P.js +14 -0
  172. package/dist/ui/assets/index-C9uChk2P.js.map +1 -0
  173. package/dist/ui/index.html +14 -0
  174. package/dist/update/apply.d.ts +37 -0
  175. package/dist/update/apply.js +102 -0
  176. package/dist/update/apply.js.map +1 -0
  177. package/dist/update/index.d.ts +101 -0
  178. package/dist/update/index.js +228 -0
  179. package/dist/update/index.js.map +1 -0
  180. package/dist/update/manifest.d.ts +48 -0
  181. package/dist/update/manifest.js +152 -0
  182. package/dist/update/manifest.js.map +1 -0
  183. package/dist/update/release-key.d.ts +24 -0
  184. package/dist/update/release-key.js +52 -0
  185. package/dist/update/release-key.js.map +1 -0
  186. package/dist/update/store.d.ts +22 -0
  187. package/dist/update/store.js +81 -0
  188. package/dist/update/store.js.map +1 -0
  189. package/dist/update/types.d.ts +90 -0
  190. package/dist/update/types.js +22 -0
  191. package/dist/update/types.js.map +1 -0
  192. package/dist/update/version.d.ts +18 -0
  193. package/dist/update/version.js +76 -0
  194. package/dist/update/version.js.map +1 -0
  195. package/package.json +80 -0
  196. package/service/README.md +86 -0
  197. package/service/cadre-host.service.tmpl +16 -0
  198. package/service/com.serfab.cadre-host.plist.tmpl +35 -0
  199. package/service/install-service.ps1 +98 -0
  200. package/service/uninstall-service.ps1 +19 -0
  201. package/src/__tests__/cli-invite.smoke.test.ts +187 -0
  202. package/src/__tests__/cli-nat.smoke.test.ts +207 -0
  203. package/src/__tests__/cli.smoke.test.ts +41 -0
  204. package/src/__tests__/orchestrator.test.ts +570 -0
  205. package/src/auth/__tests__/duration.test.ts +28 -0
  206. package/src/auth/__tests__/trust-circle-integration.test.ts +128 -0
  207. package/src/auth/__tests__/trust-circle-store.test.ts +115 -0
  208. package/src/auth/__tests__/trust-circle.test.ts +334 -0
  209. package/src/auth/duration.ts +33 -0
  210. package/src/auth/index.ts +19 -0
  211. package/src/auth/trust-circle-store.ts +155 -0
  212. package/src/auth/trust-circle.ts +304 -0
  213. package/src/auth/types.ts +96 -0
  214. package/src/bin/host.ts +905 -0
  215. package/src/index.ts +167 -0
  216. package/src/installer/__tests__/config.test.ts +86 -0
  217. package/src/installer/__tests__/identity.test.ts +34 -0
  218. package/src/installer/__tests__/installer.smoke.test.ts +124 -0
  219. package/src/installer/__tests__/paths.test.ts +47 -0
  220. package/src/installer/__tests__/service-host.test.ts +62 -0
  221. package/src/installer/__tests__/wizard.test.ts +60 -0
  222. package/src/installer/browser.ts +42 -0
  223. package/src/installer/config.ts +153 -0
  224. package/src/installer/identity.ts +49 -0
  225. package/src/installer/index.ts +303 -0
  226. package/src/installer/paths.ts +109 -0
  227. package/src/installer/platform.ts +27 -0
  228. package/src/installer/service-host/index.ts +21 -0
  229. package/src/installer/service-host/launchd.ts +90 -0
  230. package/src/installer/service-host/nssm.ts +100 -0
  231. package/src/installer/service-host/systemd.ts +88 -0
  232. package/src/installer/service-host/template.ts +21 -0
  233. package/src/installer/service-host/types.ts +48 -0
  234. package/src/installer/wizard.ts +92 -0
  235. package/src/nat/__tests__/address-resolver.test.ts +82 -0
  236. package/src/nat/__tests__/ddns-duckdns.test.ts +83 -0
  237. package/src/nat/__tests__/ddns-updater.test.ts +253 -0
  238. package/src/nat/__tests__/external-ip.test.ts +124 -0
  239. package/src/nat/__tests__/nat-service.test.ts +305 -0
  240. package/src/nat/__tests__/nat-store.test.ts +93 -0
  241. package/src/nat/__tests__/port-mapper.test.ts +191 -0
  242. package/src/nat/__tests__/reachability.test.ts +24 -0
  243. package/src/nat/__tests__/secrets.test.ts +156 -0
  244. package/src/nat/address-resolver.ts +51 -0
  245. package/src/nat/ddns/duckdns.ts +76 -0
  246. package/src/nat/ddns/index.ts +55 -0
  247. package/src/nat/ddns/updater.ts +243 -0
  248. package/src/nat/external-ip.ts +154 -0
  249. package/src/nat/index.ts +71 -0
  250. package/src/nat/nat-service.ts +375 -0
  251. package/src/nat/nat-store.ts +154 -0
  252. package/src/nat/port-mapper.ts +329 -0
  253. package/src/nat/reachability.ts +34 -0
  254. package/src/nat/secrets/file-store.ts +130 -0
  255. package/src/nat/secrets/index.ts +82 -0
  256. package/src/nat/secrets/keytar-store.ts +67 -0
  257. package/src/nat/types.ts +157 -0
  258. package/src/orchestrator/host-process-orchestrator.ts +626 -0
  259. package/src/orchestrator/index.ts +3 -0
  260. package/src/orchestrator/log-rotator.ts +53 -0
  261. package/src/orchestrator/pid-liveness.ts +24 -0
  262. package/src/orchestrator/port-allocator.ts +43 -0
  263. package/src/orchestrator/state-store.ts +72 -0
  264. package/src/orchestrator/types.ts +95 -0
  265. package/src/server/__tests__/bus.test.ts +38 -0
  266. package/src/server/__tests__/error-handler.test.ts +96 -0
  267. package/src/server/__tests__/nodes-route.test.ts +179 -0
  268. package/src/server/__tests__/origin-guard.test.ts +72 -0
  269. package/src/server/__tests__/publishers.test.ts +216 -0
  270. package/src/server/__tests__/server.smoke.test.ts +178 -0
  271. package/src/server/__tests__/settings-route.test.ts +177 -0
  272. package/src/server/__tests__/sse-route.test.ts +119 -0
  273. package/src/server/__tests__/status-route.test.ts +113 -0
  274. package/src/server/error-handler.ts +108 -0
  275. package/src/server/events/bus.ts +42 -0
  276. package/src/server/events/sse-route.ts +81 -0
  277. package/src/server/events/types.ts +22 -0
  278. package/src/server/index.ts +209 -0
  279. package/src/server/origin-guard.ts +84 -0
  280. package/src/server/routes/nat.ts +63 -0
  281. package/src/server/routes/nodes.ts +147 -0
  282. package/src/server/routes/settings.ts +115 -0
  283. package/src/server/routes/status.ts +108 -0
  284. package/src/server/routes/trust-circle.ts +49 -0
  285. package/src/server/routes/update.ts +43 -0
  286. package/src/server/server.ts +122 -0
  287. package/src/server/settings-store.ts +37 -0
  288. package/src/server/static.ts +191 -0
  289. package/src/update/__tests__/apply.test.ts +101 -0
  290. package/src/update/__tests__/manifest.test.ts +93 -0
  291. package/src/update/__tests__/store.test.ts +81 -0
  292. package/src/update/__tests__/update-service.integration.test.ts +221 -0
  293. package/src/update/__tests__/version.test.ts +31 -0
  294. package/src/update/apply.ts +148 -0
  295. package/src/update/index.ts +303 -0
  296. package/src/update/manifest.ts +172 -0
  297. package/src/update/release-key.ts +55 -0
  298. package/src/update/store.ts +101 -0
  299. package/src/update/types.ts +109 -0
  300. package/src/update/version.ts +80 -0
@@ -0,0 +1,557 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { createRequire } from 'node:module';
3
+ import { randomBytes } from 'node:crypto';
4
+ import { existsSync, readFileSync, rmSync, writeFileSync, mkdirSync, statSync, openSync, readSync, closeSync, } from 'node:fs';
5
+ import { join, resolve as resolvePath } from 'node:path';
6
+ import debug from 'debug';
7
+ import pidusage from 'pidusage';
8
+ import { defaultLogPath, rotateOnDisk } from './log-rotator.js';
9
+ import { PortAllocator } from './port-allocator.js';
10
+ import { StateStore } from './state-store.js';
11
+ import { isPidAlive } from './pid-liveness.js';
12
+ import { decodeDockerId, encodeDockerId, } from './types.js';
13
+ const log = debug('cadre:host:orchestrator');
14
+ const DEFAULTS = {
15
+ portRangeStart: 10000,
16
+ portRangeEnd: 20000,
17
+ stopTimeoutMs: 10000,
18
+ logMaxBytes: 10 * 1024 * 1024,
19
+ logMaxFiles: 5,
20
+ };
21
+ const STARTUP_TOKEN_FILE = '.startup-token';
22
+ const CONFIG_FILE = 'cadre.json';
23
+ const LIVENESS_POLL_MS = 100;
24
+ /**
25
+ * Runs cadre nodes as plain Node child processes on the host.
26
+ *
27
+ * Each container gets its own workdir under `rootDir`. Handles are mirrored
28
+ * to `<rootDir>/state.json` so cadre-host can re-attach after a restart.
29
+ *
30
+ * ## Child stdio: direct-fd inheritance
31
+ *
32
+ * Spawned children inherit a file descriptor opened on `<workdir>/node.log`
33
+ * directly as their stdout and stderr. The orchestrator closes its own copy
34
+ * of the fd immediately after spawn, so the child's write path no longer
35
+ * touches any handle owned by this process. This is what lets children
36
+ * survive — and keep logging through — an orchestrator restart. Were the
37
+ * orchestrator instead piping stdout/stderr through an in-process Writable,
38
+ * a parent exit would deliver SIGPIPE to the child (POSIX) or fail its
39
+ * writes with EPIPE (Windows), silently breaking the documented "init()
40
+ * re-attach" flow.
41
+ *
42
+ * ## Log rotation: spawn-time only
43
+ *
44
+ * Because the child holds a stable fd open against the inode, the
45
+ * orchestrator cannot safely rename `node.log` while the child is running.
46
+ * Rotation therefore happens only at spawn time, when no live child is
47
+ * attached to the workdir (`createContainer` is the single producer per
48
+ * workdir). If `node.log` already exceeds `logMaxBytes`, the rotation
49
+ * cascade runs against the on-disk paths before the fresh fd is opened.
50
+ * A child whose log grows past `logMaxBytes` mid-run will keep appending
51
+ * to the active file until it (or its successor) is restarted; v1 traffic
52
+ * is low enough that this is acceptable.
53
+ */
54
+ export class HostProcessOrchestrator {
55
+ constructor(cfg) {
56
+ this.cfg = cfg;
57
+ this.handles = new Map();
58
+ /** State-change listeners — invoked when a handle's alive state changes. */
59
+ this.stateListeners = new Set();
60
+ this.rootDir = resolvePath(cfg.rootDir);
61
+ mkdirSync(this.rootDir, { recursive: true });
62
+ this.portAllocator = new PortAllocator(cfg.portRange?.start ?? DEFAULTS.portRangeStart, cfg.portRange?.end ?? DEFAULTS.portRangeEnd);
63
+ this.stateStore = new StateStore(this.rootDir);
64
+ this.stopTimeoutMs = cfg.stopTimeoutMs ?? DEFAULTS.stopTimeoutMs;
65
+ this.logMaxBytes = cfg.logMaxBytes ?? DEFAULTS.logMaxBytes;
66
+ this.logMaxFiles = cfg.logMaxFiles ?? DEFAULTS.logMaxFiles;
67
+ this.defaultMemoryLimit = cfg.defaultResources?.memoryLimit;
68
+ this.cliEntrypoint = cfg.spawn?.entrypoint ?? resolveCadreCliBin();
69
+ log('HostProcessOrchestrator rootDir=%s cli=%s', this.rootDir, this.cliEntrypoint);
70
+ }
71
+ /**
72
+ * Read persisted state and re-attach to surviving children. Not part of
73
+ * `Orchestrator` — call once before handing the instance to a container
74
+ * service.
75
+ */
76
+ async init() {
77
+ const state = this.stateStore.load();
78
+ for (const persisted of state.handles) {
79
+ const alive = isPidAlive(persisted.pid) && tokenMatches(persisted.workdir, persisted.startupToken);
80
+ const handle = {
81
+ containerId: persisted.containerId,
82
+ dockerId: persisted.dockerId,
83
+ pid: persisted.pid,
84
+ startupToken: persisted.startupToken,
85
+ workdir: persisted.workdir,
86
+ ports: persisted.ports,
87
+ spawnedAt: persisted.spawnedAt,
88
+ partyId: persisted.partyId,
89
+ profile: persisted.profile,
90
+ alive,
91
+ };
92
+ this.handles.set(handle.dockerId, handle);
93
+ // Always reserve ports — even for dead handles, until the caller cleans them up
94
+ this.portAllocator.markUsed(persisted.ports.health);
95
+ this.portAllocator.markUsed(persisted.ports.metrics);
96
+ this.portAllocator.markUsed(persisted.ports.p2p);
97
+ }
98
+ log('init: re-attached %d handles', state.handles.length);
99
+ }
100
+ /**
101
+ * Snapshot of currently-known managed nodes. Used by the local UI's
102
+ * `/api/nodes` route.
103
+ */
104
+ listNodes() {
105
+ return [...this.handles.values()].map((h) => toNodeInfo(h));
106
+ }
107
+ /**
108
+ * Look up a single managed node by either containerId (friendly id) or
109
+ * dockerId (opaque `pid:token`). Returns undefined when neither matches.
110
+ */
111
+ getNode(idOrDockerId) {
112
+ const direct = this.handles.get(idOrDockerId);
113
+ if (direct)
114
+ return toNodeInfo(direct);
115
+ for (const h of this.handles.values()) {
116
+ if (h.containerId === idOrDockerId)
117
+ return toNodeInfo(h);
118
+ }
119
+ return undefined;
120
+ }
121
+ /**
122
+ * Resolve the opaque dockerId for a friendly containerId so callers can
123
+ * pass it into stopContainer / getLogs / getStats.
124
+ */
125
+ resolveDockerId(idOrDockerId) {
126
+ if (this.handles.has(idOrDockerId))
127
+ return idOrDockerId;
128
+ for (const h of this.handles.values()) {
129
+ if (h.containerId === idOrDockerId)
130
+ return h.dockerId;
131
+ }
132
+ return undefined;
133
+ }
134
+ /**
135
+ * Register a state-change listener. Invoked when a handle's `alive`
136
+ * transitions (child exit, manual stop). Returns an unsubscribe fn.
137
+ */
138
+ onStateChange(listener) {
139
+ this.stateListeners.add(listener);
140
+ return () => { this.stateListeners.delete(listener); };
141
+ }
142
+ /** Handles that init() found dead (PID gone or token mismatch). */
143
+ listDeadHandles() {
144
+ const dead = [];
145
+ for (const h of this.handles.values()) {
146
+ if (!h.alive) {
147
+ dead.push(this.toPersisted(h));
148
+ }
149
+ }
150
+ return dead;
151
+ }
152
+ async createContainer(request) {
153
+ const healthPort = this.portAllocator.allocate();
154
+ const metricsPort = this.portAllocator.allocate();
155
+ const p2pPort = this.portAllocator.allocate();
156
+ const workdir = join(this.rootDir, request.containerId);
157
+ mkdirSync(workdir, { recursive: true });
158
+ mkdirSync(join(workdir, 'storage'), { recursive: true });
159
+ const token = randomBytes(16).toString('hex');
160
+ const tokenPath = join(workdir, STARTUP_TOKEN_FILE);
161
+ // Ensure stale token from a previous container with the same id is cleared.
162
+ if (existsSync(tokenPath)) {
163
+ try {
164
+ rmSync(tokenPath);
165
+ }
166
+ catch { /* ignore */ }
167
+ }
168
+ const configPath = join(workdir, CONFIG_FILE);
169
+ writeFileSync(configPath, JSON.stringify(this.buildChildConfig(request, workdir), null, 2), 'utf8');
170
+ const memoryLimit = request.resources?.memoryLimit ?? this.defaultMemoryLimit;
171
+ const heapBytes = parseMemoryLimit(memoryLimit);
172
+ const heapMB = heapBytes !== undefined ? Math.max(64, Math.floor(heapBytes / (1024 * 1024))) : undefined;
173
+ const env = {
174
+ ...process.env,
175
+ CADRE_STARTUP_TOKEN: token,
176
+ CADRE_HEALTH_PORT: String(healthPort),
177
+ CADRE_METRICS_PORT: String(metricsPort),
178
+ CADRE_LISTEN_ADDRS: `/ip4/0.0.0.0/tcp/${p2pPort}`,
179
+ };
180
+ if (heapMB !== undefined) {
181
+ env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --max-old-space-size=${heapMB}`.trim();
182
+ }
183
+ // Rotate the on-disk log files BEFORE opening the fd — once the child
184
+ // is running it holds the inode open and any later rename would leave
185
+ // it writing to the rotated file. See class docstring.
186
+ const logPath = defaultLogPath(workdir);
187
+ maybeRotateAtSpawn(logPath, this.logMaxBytes, this.logMaxFiles);
188
+ const logFd = openSync(logPath, 'a');
189
+ let child;
190
+ try {
191
+ child = spawn(process.execPath, [
192
+ this.cliEntrypoint,
193
+ 'start',
194
+ '-c', configPath,
195
+ '--health-port', String(healthPort),
196
+ '--metrics-port', String(metricsPort),
197
+ '--startup-token-file', tokenPath,
198
+ ], {
199
+ cwd: workdir,
200
+ detached: true,
201
+ // Inherit the log fd directly. OS duplicates it into the child;
202
+ // closing our copy below is safe and severs the parent's only
203
+ // tie to the child's write path.
204
+ stdio: ['ignore', logFd, logFd],
205
+ env,
206
+ });
207
+ }
208
+ catch (err) {
209
+ // Synchronous spawn failure — release the fd and the reserved ports
210
+ // before propagating, so a bad-args bug doesn't leak resources.
211
+ closeSync(logFd);
212
+ this.portAllocator.release(healthPort);
213
+ this.portAllocator.release(metricsPort);
214
+ this.portAllocator.release(p2pPort);
215
+ throw err;
216
+ }
217
+ // Always release the parent's copy of the fd — the child has its own.
218
+ closeSync(logFd);
219
+ if (!child.pid) {
220
+ // Spawn returned without a pid — release reservations and report.
221
+ this.portAllocator.release(healthPort);
222
+ this.portAllocator.release(metricsPort);
223
+ this.portAllocator.release(p2pPort);
224
+ throw new Error(`Failed to spawn child for container ${request.containerId}`);
225
+ }
226
+ child.unref();
227
+ const dockerId = encodeDockerId(child.pid, token);
228
+ const handle = {
229
+ containerId: request.containerId,
230
+ dockerId,
231
+ pid: child.pid,
232
+ startupToken: token,
233
+ workdir,
234
+ ports: { health: healthPort, metrics: metricsPort, p2p: p2pPort },
235
+ spawnedAt: new Date().toISOString(),
236
+ partyId: request.partyId,
237
+ profile: request.profile,
238
+ child,
239
+ alive: true,
240
+ };
241
+ child.once('exit', () => {
242
+ const h = this.handles.get(dockerId);
243
+ if (h && h.alive) {
244
+ h.alive = false;
245
+ this.emitStateChange(h);
246
+ }
247
+ });
248
+ this.handles.set(dockerId, handle);
249
+ this.persist();
250
+ this.emitStateChange(handle);
251
+ log('created container %s -> pid %d ports=%j', request.containerId, child.pid, handle.ports);
252
+ return {
253
+ dockerId,
254
+ healthEndpoint: `http://localhost:${healthPort}/health`,
255
+ metricsEndpoint: `http://localhost:${metricsPort}/metrics`,
256
+ p2pPort,
257
+ };
258
+ }
259
+ async stopContainer(dockerId) {
260
+ const handle = this.requireHandle(dockerId);
261
+ if (!isPidAlive(handle.pid)) {
262
+ handle.alive = false;
263
+ this.persist();
264
+ return;
265
+ }
266
+ // Capture the exit event before we send signals so we can await full
267
+ // teardown — important on Windows where cwd handles release lazily.
268
+ const exitPromise = handle.child
269
+ ? new Promise((resolve) => handle.child.once('exit', () => resolve()))
270
+ : Promise.resolve();
271
+ log('SIGTERM container %s (pid=%d)', handle.containerId, handle.pid);
272
+ try {
273
+ process.kill(handle.pid, 'SIGTERM');
274
+ }
275
+ catch (err) {
276
+ const code = err.code;
277
+ if (code !== 'ESRCH') {
278
+ throw err;
279
+ }
280
+ }
281
+ const deadline = Date.now() + this.stopTimeoutMs;
282
+ while (Date.now() < deadline) {
283
+ if (!isPidAlive(handle.pid))
284
+ break;
285
+ await sleep(LIVENESS_POLL_MS);
286
+ }
287
+ if (isPidAlive(handle.pid)) {
288
+ log('SIGKILL container %s (pid=%d)', handle.containerId, handle.pid);
289
+ try {
290
+ process.kill(handle.pid, 'SIGKILL');
291
+ }
292
+ catch (err) {
293
+ const code = err.code;
294
+ if (code !== 'ESRCH') {
295
+ throw err;
296
+ }
297
+ }
298
+ const killDeadline = Date.now() + 2000;
299
+ while (Date.now() < killDeadline && isPidAlive(handle.pid)) {
300
+ await sleep(LIVENESS_POLL_MS);
301
+ }
302
+ }
303
+ // Wait briefly for the OS to fully tear down the child (Windows cwd lock).
304
+ await Promise.race([exitPromise, sleep(1000)]);
305
+ const wasAlive = handle.alive;
306
+ handle.alive = false;
307
+ this.persist();
308
+ if (wasAlive)
309
+ this.emitStateChange(handle);
310
+ }
311
+ async removeContainer(dockerId) {
312
+ const handle = this.requireHandle(dockerId);
313
+ if (isPidAlive(handle.pid)) {
314
+ await this.stopContainer(dockerId);
315
+ }
316
+ this.portAllocator.release(handle.ports.health);
317
+ this.portAllocator.release(handle.ports.metrics);
318
+ this.portAllocator.release(handle.ports.p2p);
319
+ // On Windows the OS releases the child's cwd handle asynchronously, so
320
+ // retry rmSync to give the kernel a chance to drop it.
321
+ try {
322
+ rmSync(handle.workdir, { recursive: true, force: true, maxRetries: 20, retryDelay: 200 });
323
+ }
324
+ catch (err) {
325
+ log('failed to remove workdir %s: %o', handle.workdir, err);
326
+ }
327
+ this.handles.delete(dockerId);
328
+ this.persist();
329
+ }
330
+ async isRunning(dockerId) {
331
+ let handle = this.handles.get(dockerId);
332
+ let pid;
333
+ let token;
334
+ let workdir;
335
+ if (handle) {
336
+ pid = handle.pid;
337
+ token = handle.startupToken;
338
+ workdir = handle.workdir;
339
+ }
340
+ else {
341
+ try {
342
+ const decoded = decodeDockerId(dockerId);
343
+ pid = decoded.pid;
344
+ token = decoded.token;
345
+ }
346
+ catch {
347
+ return false;
348
+ }
349
+ }
350
+ if (!isPidAlive(pid)) {
351
+ if (handle)
352
+ handle.alive = false;
353
+ return false;
354
+ }
355
+ if (workdir === undefined) {
356
+ // We have no record — without a workdir we can't verify the token,
357
+ // so we must treat this as unknown rather than running.
358
+ return false;
359
+ }
360
+ return tokenMatches(workdir, token);
361
+ }
362
+ async getStats(dockerId) {
363
+ const handle = this.requireHandle(dockerId);
364
+ if (!isPidAlive(handle.pid)) {
365
+ return { cpuPercent: 0, memoryBytes: 0, networkRxBytes: 0, networkTxBytes: 0 };
366
+ }
367
+ try {
368
+ const usage = await pidusage(handle.pid);
369
+ return {
370
+ cpuPercent: usage.cpu,
371
+ memoryBytes: usage.memory,
372
+ networkRxBytes: 0,
373
+ networkTxBytes: 0,
374
+ };
375
+ }
376
+ catch (err) {
377
+ log('pidusage failed for %d: %o', handle.pid, err);
378
+ return { cpuPercent: 0, memoryBytes: 0, networkRxBytes: 0, networkTxBytes: 0 };
379
+ }
380
+ }
381
+ async getLogs(dockerId, tail = 100) {
382
+ const handle = this.requireHandle(dockerId);
383
+ const logPath = defaultLogPath(handle.workdir);
384
+ return tailFile(logPath, tail);
385
+ }
386
+ requireHandle(dockerId) {
387
+ const handle = this.handles.get(dockerId);
388
+ if (!handle) {
389
+ throw new Error(`Container not found: ${dockerId}`);
390
+ }
391
+ return handle;
392
+ }
393
+ buildChildConfig(req, workdir) {
394
+ const cfg = {
395
+ controlNetwork: {
396
+ partyId: req.partyId,
397
+ bootstrapNodes: req.bootstrapNodes,
398
+ },
399
+ profile: req.profile,
400
+ strandFilter: req.strandFilter ?? 'all',
401
+ };
402
+ if (req.profile === 'storage') {
403
+ const storage = {
404
+ type: 'file',
405
+ path: join(workdir, 'storage'),
406
+ };
407
+ if (req.resources?.storageQuotaBytes !== undefined) {
408
+ storage.quotaBytes = req.resources.storageQuotaBytes;
409
+ }
410
+ cfg.storage = storage;
411
+ }
412
+ return cfg;
413
+ }
414
+ persist() {
415
+ const state = {
416
+ version: 1,
417
+ handles: [...this.handles.values()].map((h) => this.toPersisted(h)),
418
+ };
419
+ this.stateStore.save(state);
420
+ }
421
+ emitStateChange(handle) {
422
+ if (this.stateListeners.size === 0)
423
+ return;
424
+ const info = toNodeInfo(handle);
425
+ for (const listener of this.stateListeners) {
426
+ try {
427
+ listener(info);
428
+ }
429
+ catch (err) {
430
+ log('state listener threw for %s: %o', info.id, err);
431
+ }
432
+ }
433
+ }
434
+ toPersisted(h) {
435
+ return {
436
+ containerId: h.containerId,
437
+ dockerId: h.dockerId,
438
+ pid: h.pid,
439
+ startupToken: h.startupToken,
440
+ workdir: h.workdir,
441
+ ports: h.ports,
442
+ spawnedAt: h.spawnedAt,
443
+ partyId: h.partyId,
444
+ profile: h.profile,
445
+ };
446
+ }
447
+ }
448
+ function toNodeInfo(h) {
449
+ return {
450
+ id: h.containerId,
451
+ dockerId: h.dockerId,
452
+ partyId: h.partyId,
453
+ profile: h.profile,
454
+ status: h.alive ? 'running' : 'stopped',
455
+ spawnedAt: h.spawnedAt,
456
+ workdir: h.workdir,
457
+ ports: { ...h.ports },
458
+ };
459
+ }
460
+ /**
461
+ * Locate the cadre-cli bin via the consumer-style module resolver. Works for
462
+ * both yarn-managed workspaces and traditional npm installs.
463
+ */
464
+ function resolveCadreCliBin() {
465
+ const req = createRequire(import.meta.url);
466
+ try {
467
+ return req.resolve('@serfab/cadre-cli/bin/cadre.js');
468
+ }
469
+ catch (err) {
470
+ throw new Error(`Unable to resolve @serfab/cadre-cli bin from cadre-host. ` +
471
+ `Ensure cadre-cli is built (yarn workspace @serfab/cadre-cli build) ` +
472
+ `and listed as a dependency. Underlying error: ${err.message}`);
473
+ }
474
+ }
475
+ function tokenMatches(workdir, expected) {
476
+ const tokenPath = join(workdir, STARTUP_TOKEN_FILE);
477
+ try {
478
+ const contents = readFileSync(tokenPath, 'utf8').trim();
479
+ return contents === expected;
480
+ }
481
+ catch {
482
+ return false;
483
+ }
484
+ }
485
+ /**
486
+ * Rotate the on-disk log files for a workdir if the active file is already
487
+ * at or above the byte threshold. Called from `createContainer` before the
488
+ * child's stdio fd is opened — the only safe rotation point because the
489
+ * caller guarantees no live child is attached to this workdir.
490
+ */
491
+ function maybeRotateAtSpawn(logPath, maxBytes, maxFiles) {
492
+ if (maxBytes <= 0 || maxFiles < 1)
493
+ return;
494
+ let size = 0;
495
+ try {
496
+ size = statSync(logPath).size;
497
+ }
498
+ catch {
499
+ return;
500
+ }
501
+ if (size >= maxBytes) {
502
+ rotateOnDisk(logPath, maxFiles);
503
+ }
504
+ }
505
+ function sleep(ms) {
506
+ return new Promise((res) => {
507
+ const t = setTimeout(res, ms);
508
+ if (typeof t.unref === 'function')
509
+ t.unref();
510
+ });
511
+ }
512
+ /**
513
+ * Read the last `n` lines from a log file. Reads from the tail in chunks
514
+ * rather than slurping the whole file.
515
+ */
516
+ function tailFile(path, n) {
517
+ if (!existsSync(path))
518
+ return '';
519
+ const fd = openSync(path, 'r');
520
+ try {
521
+ const size = statSync(path).size;
522
+ const chunkSize = 8192;
523
+ let pos = size;
524
+ const buffers = [];
525
+ let newlineCount = 0;
526
+ while (pos > 0 && newlineCount <= n) {
527
+ const readLen = Math.min(chunkSize, pos);
528
+ pos -= readLen;
529
+ const buf = Buffer.alloc(readLen);
530
+ readSync(fd, buf, 0, readLen, pos);
531
+ buffers.unshift(buf);
532
+ for (let i = 0; i < buf.length; i++) {
533
+ if (buf[i] === 0x0a)
534
+ newlineCount++;
535
+ }
536
+ }
537
+ const joined = Buffer.concat(buffers).toString('utf8');
538
+ const lines = joined.split('\n');
539
+ // Drop any trailing empty line from a terminating newline before counting.
540
+ const trimmed = lines[lines.length - 1] === '' ? lines.slice(0, -1) : lines;
541
+ return trimmed.slice(-n).join('\n');
542
+ }
543
+ finally {
544
+ closeSync(fd);
545
+ }
546
+ }
547
+ function parseMemoryLimit(limit) {
548
+ if (!limit)
549
+ return undefined;
550
+ const match = limit.match(/^(\d+(?:\.\d+)?)\s*(B|K|M|G|T)?$/i);
551
+ if (!match)
552
+ return undefined;
553
+ const [, num, unit] = match;
554
+ const multipliers = { B: 1, K: 1024, M: 1024 ** 2, G: 1024 ** 3, T: 1024 ** 4 };
555
+ return Math.floor(parseFloat(num) * (multipliers[unit?.toUpperCase() ?? 'B'] ?? 1));
556
+ }
557
+ //# sourceMappingURL=host-process-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-process-orchestrator.js","sourceRoot":"","sources":["../../src/orchestrator/host-process-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { HostProcessOrchestrator } from './host-process-orchestrator.js';
2
+ export type { HostProcessConfig, ManagedNodeInfo, NodeStateListener } from './types.js';
3
+ export type { PersistedHandle } from './state-store.js';
@@ -0,0 +1,2 @@
1
+ export { HostProcessOrchestrator } from './host-process-orchestrator.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/orchestrator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * On-disk log rotation helper.
3
+ *
4
+ * Children spawned by the orchestrator inherit a direct file descriptor to
5
+ * their `node.log` (see `host-process-orchestrator.ts`), so rotation can no
6
+ * longer be driven by an in-process byte counter — renaming the path under a
7
+ * running child would leave it writing to the renamed inode. Instead the
8
+ * orchestrator calls `rotateOnDisk(...)` at spawn time, before the child is
9
+ * launched and its fd is opened. This is the only safe point to rotate
10
+ * without coordinating with the running process.
11
+ *
12
+ * Within a workdir there is at most one live child, so spawn-time rotation
13
+ * is sufficient for v1: a child that exceeds `logMaxBytes` mid-run will
14
+ * keep appending to the active file until it (or its successor) is restarted.
15
+ */
16
+ /**
17
+ * Perform a rotation cascade against on-disk paths: drop the oldest, then
18
+ * shift `.N-1 → .N`, …, `.1 → .2`, and finally `filePath → .1`.
19
+ *
20
+ * Caller is responsible for deciding when to rotate (e.g. when
21
+ * `statSync(filePath).size >= logMaxBytes`). No fd is held by this helper.
22
+ */
23
+ export declare function rotateOnDisk(filePath: string, maxFiles: number): void;
24
+ /** Build the standard log file path for a workdir. */
25
+ export declare function defaultLogPath(workdir: string): string;