@smthrs/platform-node 0.0.0-stage → 1.0.0-rc.4

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 (442) hide show
  1. package/CHANGELOG.md +211 -0
  2. package/LICENSE +21 -0
  3. package/README.md +165 -2
  4. package/bin/darwin-arm64/smithers-jj-export +0 -0
  5. package/bin/darwin-x64/smithers-jj-export +0 -0
  6. package/bin/linux-arm64/smithers-jj-export +0 -0
  7. package/bin/linux-x64/smithers-jj-export +4 -0
  8. package/bin/win32-x64/smithers-jj-export.exe +0 -0
  9. package/dist/cjs/AtomicFileSystem.d.ts +147 -0
  10. package/dist/cjs/AtomicFileSystem.d.ts.map +1 -0
  11. package/dist/cjs/AtomicFileSystem.js +234 -0
  12. package/dist/cjs/AtomicFileSystem.js.map +7 -0
  13. package/dist/cjs/EgressHttpClient.d.ts +106 -0
  14. package/dist/cjs/EgressHttpClient.d.ts.map +1 -0
  15. package/dist/cjs/EgressHttpClient.js +202 -0
  16. package/dist/cjs/EgressHttpClient.js.map +7 -0
  17. package/dist/cjs/HostLiveness.d.ts +81 -0
  18. package/dist/cjs/HostLiveness.d.ts.map +1 -0
  19. package/dist/cjs/HostLiveness.js +49 -0
  20. package/dist/cjs/HostLiveness.js.map +7 -0
  21. package/dist/cjs/NodeHost.d.ts +145 -0
  22. package/dist/cjs/NodeHost.d.ts.map +1 -0
  23. package/dist/cjs/NodeHost.js +128 -0
  24. package/dist/cjs/NodeHost.js.map +7 -0
  25. package/dist/cjs/ProcessConfinement.d.ts +61 -0
  26. package/dist/cjs/ProcessConfinement.d.ts.map +1 -0
  27. package/dist/cjs/ProcessConfinement.js +292 -0
  28. package/dist/cjs/ProcessConfinement.js.map +7 -0
  29. package/dist/cjs/ProcessReaper.d.ts +457 -0
  30. package/dist/cjs/ProcessReaper.d.ts.map +1 -0
  31. package/dist/cjs/ProcessReaper.js +349 -0
  32. package/dist/cjs/ProcessReaper.js.map +7 -0
  33. package/dist/cjs/ProcessSandbox.d.ts +391 -0
  34. package/dist/cjs/ProcessSandbox.d.ts.map +1 -0
  35. package/dist/cjs/ProcessSandbox.js +774 -0
  36. package/dist/cjs/ProcessSandbox.js.map +7 -0
  37. package/dist/cjs/ScopedProcess.d.ts +66 -0
  38. package/dist/cjs/ScopedProcess.d.ts.map +1 -0
  39. package/dist/cjs/ScopedProcess.js +87 -0
  40. package/dist/cjs/ScopedProcess.js.map +7 -0
  41. package/dist/cjs/index.d.ts +38 -0
  42. package/dist/cjs/index.d.ts.map +1 -0
  43. package/dist/cjs/index.js +47 -0
  44. package/dist/cjs/index.js.map +7 -0
  45. package/dist/cjs/internal/AtomicFileSystemExecutable.d.ts +61 -0
  46. package/dist/cjs/internal/AtomicFileSystemExecutable.d.ts.map +1 -0
  47. package/dist/cjs/internal/AtomicFileSystemExecutable.js +250 -0
  48. package/dist/cjs/internal/AtomicFileSystemExecutable.js.map +7 -0
  49. package/dist/cjs/internal/AtomicFileSystemProtocol.d.ts +78 -0
  50. package/dist/cjs/internal/AtomicFileSystemProtocol.d.ts.map +1 -0
  51. package/dist/cjs/internal/AtomicFileSystemProtocol.js +382 -0
  52. package/dist/cjs/internal/AtomicFileSystemProtocol.js.map +7 -0
  53. package/dist/cjs/internal/AtomicFileSystemTransport.d.ts +44 -0
  54. package/dist/cjs/internal/AtomicFileSystemTransport.d.ts.map +1 -0
  55. package/dist/cjs/internal/AtomicFileSystemTransport.js +197 -0
  56. package/dist/cjs/internal/AtomicFileSystemTransport.js.map +7 -0
  57. package/dist/cjs/internal/AtomicHelperError.d.ts +35 -0
  58. package/dist/cjs/internal/AtomicHelperError.d.ts.map +1 -0
  59. package/dist/cjs/internal/AtomicHelperError.js +45 -0
  60. package/dist/cjs/internal/AtomicHelperError.js.map +7 -0
  61. package/dist/cjs/internal/AtomicHelperFault.d.ts +59 -0
  62. package/dist/cjs/internal/AtomicHelperFault.d.ts.map +1 -0
  63. package/dist/cjs/internal/AtomicHelperFault.js +66 -0
  64. package/dist/cjs/internal/AtomicHelperFault.js.map +7 -0
  65. package/dist/cjs/internal/PipedProcess.d.ts +35 -0
  66. package/dist/cjs/internal/PipedProcess.d.ts.map +1 -0
  67. package/dist/cjs/internal/PipedProcess.js +309 -0
  68. package/dist/cjs/internal/PipedProcess.js.map +7 -0
  69. package/dist/cjs/internal/ProcSnapshot.d.ts +85 -0
  70. package/dist/cjs/internal/ProcSnapshot.d.ts.map +1 -0
  71. package/dist/cjs/internal/ProcSnapshot.js +123 -0
  72. package/dist/cjs/internal/ProcSnapshot.js.map +7 -0
  73. package/dist/cjs/internal/ProcessCleanup.d.ts +64 -0
  74. package/dist/cjs/internal/ProcessCleanup.d.ts.map +1 -0
  75. package/dist/cjs/internal/ProcessCleanup.js +62 -0
  76. package/dist/cjs/internal/ProcessCleanup.js.map +7 -0
  77. package/dist/cjs/internal/ProcessCleanupPolicyError.d.ts +30 -0
  78. package/dist/cjs/internal/ProcessCleanupPolicyError.d.ts.map +1 -0
  79. package/dist/cjs/internal/ProcessCleanupPolicyError.js +33 -0
  80. package/dist/cjs/internal/ProcessCleanupPolicyError.js.map +7 -0
  81. package/dist/cjs/internal/ProcessFault.d.ts +63 -0
  82. package/dist/cjs/internal/ProcessFault.d.ts.map +1 -0
  83. package/dist/cjs/internal/ProcessFault.js +63 -0
  84. package/dist/cjs/internal/ProcessFault.js.map +7 -0
  85. package/dist/cjs/internal/ProcessSupervisor.d.ts +143 -0
  86. package/dist/cjs/internal/ProcessSupervisor.d.ts.map +1 -0
  87. package/dist/cjs/internal/ProcessSupervisor.js +685 -0
  88. package/dist/cjs/internal/ProcessSupervisor.js.map +7 -0
  89. package/dist/cjs/internal/SupervisorProgram.d.ts +9 -0
  90. package/dist/cjs/internal/SupervisorProgram.d.ts.map +1 -0
  91. package/dist/cjs/internal/SupervisorProgram.js +326 -0
  92. package/dist/cjs/internal/SupervisorProgram.js.map +7 -0
  93. package/dist/cjs/internal/WindowsProcessJob.d.ts +39 -0
  94. package/dist/cjs/internal/WindowsProcessJob.d.ts.map +1 -0
  95. package/dist/cjs/internal/WindowsProcessJob.js +113 -0
  96. package/dist/cjs/internal/WindowsProcessJob.js.map +7 -0
  97. package/dist/cjs/package.json +1 -0
  98. package/dist/esm/AtomicFileSystem.d.ts +147 -0
  99. package/dist/esm/AtomicFileSystem.d.ts.map +1 -0
  100. package/dist/esm/AtomicFileSystem.js +290 -0
  101. package/dist/esm/AtomicFileSystem.js.map +1 -0
  102. package/dist/esm/EgressHttpClient.d.ts +106 -0
  103. package/dist/esm/EgressHttpClient.d.ts.map +1 -0
  104. package/dist/esm/EgressHttpClient.js +259 -0
  105. package/dist/esm/EgressHttpClient.js.map +1 -0
  106. package/dist/esm/HostLiveness.d.ts +81 -0
  107. package/dist/esm/HostLiveness.d.ts.map +1 -0
  108. package/dist/esm/HostLiveness.js +68 -0
  109. package/dist/esm/HostLiveness.js.map +1 -0
  110. package/dist/esm/NodeHost.d.ts +145 -0
  111. package/dist/esm/NodeHost.d.ts.map +1 -0
  112. package/dist/esm/NodeHost.js +162 -0
  113. package/dist/esm/NodeHost.js.map +1 -0
  114. package/dist/esm/ProcessConfinement.d.ts +61 -0
  115. package/dist/esm/ProcessConfinement.d.ts.map +1 -0
  116. package/dist/esm/ProcessConfinement.js +311 -0
  117. package/dist/esm/ProcessConfinement.js.map +1 -0
  118. package/dist/esm/ProcessReaper.d.ts +457 -0
  119. package/dist/esm/ProcessReaper.d.ts.map +1 -0
  120. package/dist/esm/ProcessReaper.js +711 -0
  121. package/dist/esm/ProcessReaper.js.map +1 -0
  122. package/dist/esm/ProcessSandbox.d.ts +391 -0
  123. package/dist/esm/ProcessSandbox.d.ts.map +1 -0
  124. package/dist/esm/ProcessSandbox.js +1043 -0
  125. package/dist/esm/ProcessSandbox.js.map +1 -0
  126. package/dist/esm/ScopedProcess.d.ts +66 -0
  127. package/dist/esm/ScopedProcess.d.ts.map +1 -0
  128. package/dist/esm/ScopedProcess.js +67 -0
  129. package/dist/esm/ScopedProcess.js.map +1 -0
  130. package/dist/esm/index.d.ts +38 -0
  131. package/dist/esm/index.d.ts.map +1 -0
  132. package/dist/esm/index.js +38 -0
  133. package/dist/esm/index.js.map +1 -0
  134. package/dist/esm/internal/AtomicFileSystemExecutable.d.ts +61 -0
  135. package/dist/esm/internal/AtomicFileSystemExecutable.d.ts.map +1 -0
  136. package/dist/esm/internal/AtomicFileSystemExecutable.js +350 -0
  137. package/dist/esm/internal/AtomicFileSystemExecutable.js.map +1 -0
  138. package/dist/esm/internal/AtomicFileSystemProtocol.d.ts +78 -0
  139. package/dist/esm/internal/AtomicFileSystemProtocol.d.ts.map +1 -0
  140. package/dist/esm/internal/AtomicFileSystemProtocol.js +412 -0
  141. package/dist/esm/internal/AtomicFileSystemProtocol.js.map +1 -0
  142. package/dist/esm/internal/AtomicFileSystemTransport.d.ts +44 -0
  143. package/dist/esm/internal/AtomicFileSystemTransport.d.ts.map +1 -0
  144. package/dist/esm/internal/AtomicFileSystemTransport.js +242 -0
  145. package/dist/esm/internal/AtomicFileSystemTransport.js.map +1 -0
  146. package/dist/esm/internal/AtomicHelperError.d.ts +35 -0
  147. package/dist/esm/internal/AtomicHelperError.d.ts.map +1 -0
  148. package/dist/esm/internal/AtomicHelperError.js +39 -0
  149. package/dist/esm/internal/AtomicHelperError.js.map +1 -0
  150. package/dist/esm/internal/AtomicHelperFault.d.ts +59 -0
  151. package/dist/esm/internal/AtomicHelperFault.d.ts.map +1 -0
  152. package/dist/esm/internal/AtomicHelperFault.js +66 -0
  153. package/dist/esm/internal/AtomicHelperFault.js.map +1 -0
  154. package/dist/esm/internal/PipedProcess.d.ts +35 -0
  155. package/dist/esm/internal/PipedProcess.d.ts.map +1 -0
  156. package/dist/esm/internal/PipedProcess.js +321 -0
  157. package/dist/esm/internal/PipedProcess.js.map +1 -0
  158. package/dist/esm/internal/ProcSnapshot.d.ts +85 -0
  159. package/dist/esm/internal/ProcSnapshot.d.ts.map +1 -0
  160. package/dist/esm/internal/ProcSnapshot.js +188 -0
  161. package/dist/esm/internal/ProcSnapshot.js.map +1 -0
  162. package/dist/esm/internal/ProcessCleanup.d.ts +64 -0
  163. package/dist/esm/internal/ProcessCleanup.d.ts.map +1 -0
  164. package/dist/esm/internal/ProcessCleanup.js +45 -0
  165. package/dist/esm/internal/ProcessCleanup.js.map +1 -0
  166. package/dist/esm/internal/ProcessCleanupPolicyError.d.ts +30 -0
  167. package/dist/esm/internal/ProcessCleanupPolicyError.d.ts.map +1 -0
  168. package/dist/esm/internal/ProcessCleanupPolicyError.js +25 -0
  169. package/dist/esm/internal/ProcessCleanupPolicyError.js.map +1 -0
  170. package/dist/esm/internal/ProcessFault.d.ts +63 -0
  171. package/dist/esm/internal/ProcessFault.d.ts.map +1 -0
  172. package/dist/esm/internal/ProcessFault.js +64 -0
  173. package/dist/esm/internal/ProcessFault.js.map +1 -0
  174. package/dist/esm/internal/ProcessSupervisor.d.ts +143 -0
  175. package/dist/esm/internal/ProcessSupervisor.d.ts.map +1 -0
  176. package/dist/esm/internal/ProcessSupervisor.js +689 -0
  177. package/dist/esm/internal/ProcessSupervisor.js.map +1 -0
  178. package/dist/esm/internal/SupervisorProgram.d.ts +9 -0
  179. package/dist/esm/internal/SupervisorProgram.d.ts.map +1 -0
  180. package/dist/esm/internal/SupervisorProgram.js +310 -0
  181. package/dist/esm/internal/SupervisorProgram.js.map +1 -0
  182. package/dist/esm/internal/WindowsProcessJob.d.ts +39 -0
  183. package/dist/esm/internal/WindowsProcessJob.d.ts.map +1 -0
  184. package/dist/esm/internal/WindowsProcessJob.js +115 -0
  185. package/dist/esm/internal/WindowsProcessJob.js.map +1 -0
  186. package/dist/vendor/adapters.json +1757 -0
  187. package/dist/vendor/chunk-2Y7WC4KU.js +109 -0
  188. package/dist/vendor/chunk-3GR5VZ2M.js +118 -0
  189. package/dist/vendor/chunk-42QKY6T6.js +40 -0
  190. package/dist/vendor/chunk-54RLBMTZ.js +61 -0
  191. package/dist/vendor/chunk-5ZMHBXIK.js +55 -0
  192. package/dist/vendor/chunk-6ME2W7TF.js +28 -0
  193. package/dist/vendor/chunk-AMQKOQNT.js +34 -0
  194. package/dist/vendor/chunk-B3FZ67QU.js +59 -0
  195. package/dist/vendor/chunk-BKTBUBQY.js +437 -0
  196. package/dist/vendor/chunk-DS7GF46S.js +34 -0
  197. package/dist/vendor/chunk-DVOAHXPG.js +104 -0
  198. package/dist/vendor/chunk-DWSHTSVX.js +229 -0
  199. package/dist/vendor/chunk-EGBNVEEW.js +14 -0
  200. package/dist/vendor/chunk-EZWY45HP.js +18 -0
  201. package/dist/vendor/chunk-FNZOJHSV.js +71 -0
  202. package/dist/vendor/chunk-GXCHI7BM.js +131 -0
  203. package/dist/vendor/chunk-IIJ52ZU6.js +20 -0
  204. package/dist/vendor/chunk-J7A4CZDO.js +92 -0
  205. package/dist/vendor/chunk-JG5TTWPT.js +85 -0
  206. package/dist/vendor/chunk-JJ24ARBQ.js +394 -0
  207. package/dist/vendor/chunk-KOZMM5PZ.js +426 -0
  208. package/dist/vendor/chunk-KUUXSID7.js +18 -0
  209. package/dist/vendor/chunk-LEUPYT3Q.js +36 -0
  210. package/dist/vendor/chunk-M32LDTW7.js +18 -0
  211. package/dist/vendor/chunk-M7CLUILA.js +0 -0
  212. package/dist/vendor/chunk-MBSKBQ5D.js +21 -0
  213. package/dist/vendor/chunk-MLKGABMK.js +9 -0
  214. package/dist/vendor/chunk-NBVRTDTV.js +129 -0
  215. package/dist/vendor/chunk-OXNGN5H7.js +81 -0
  216. package/dist/vendor/chunk-QPLDT6A6.js +564 -0
  217. package/dist/vendor/chunk-QYBKAIA6.js +18 -0
  218. package/dist/vendor/chunk-RO2R4MJH.js +62 -0
  219. package/dist/vendor/chunk-SIR62W3Y.js +398 -0
  220. package/dist/vendor/chunk-TFIKFFSC.js +26 -0
  221. package/dist/vendor/chunk-TXKLEBBL.js +143 -0
  222. package/dist/vendor/chunk-UFH5UUZK.js +48 -0
  223. package/dist/vendor/chunk-VANKHF46.js +96 -0
  224. package/dist/vendor/chunk-VZBDV3TV.js +18 -0
  225. package/dist/vendor/chunk-XDKNKFBW.js +22 -0
  226. package/dist/vendor/chunk-XH4U3JSV.js +249 -0
  227. package/dist/vendor/chunk-Y35ZAO5U.js +53 -0
  228. package/dist/vendor/chunk-ZJMRMY57.js +0 -0
  229. package/dist/vendor/cjs/node/NodeChildProcessSpawner.d.ts +7 -0
  230. package/dist/vendor/cjs/node/NodeChildProcessSpawner.js +1 -0
  231. package/dist/vendor/cjs/node/NodeClusterHttp.d.ts +63 -0
  232. package/dist/vendor/cjs/node/NodeClusterHttp.js +1 -0
  233. package/dist/vendor/cjs/node/NodeClusterSocket.d.ts +79 -0
  234. package/dist/vendor/cjs/node/NodeClusterSocket.js +1 -0
  235. package/dist/vendor/cjs/node/NodeCrypto.d.ts +10 -0
  236. package/dist/vendor/cjs/node/NodeCrypto.js +1 -0
  237. package/dist/vendor/cjs/node/NodeFileSystem.d.ts +10 -0
  238. package/dist/vendor/cjs/node/NodeFileSystem.js +1 -0
  239. package/dist/vendor/cjs/node/NodeHttpClient.d.ts +179 -0
  240. package/dist/vendor/cjs/node/NodeHttpClient.js +1 -0
  241. package/dist/vendor/cjs/node/NodeHttpIncomingMessage.d.ts +62 -0
  242. package/dist/vendor/cjs/node/NodeHttpIncomingMessage.js +1 -0
  243. package/dist/vendor/cjs/node/NodeHttpPlatform.d.ts +36 -0
  244. package/dist/vendor/cjs/node/NodeHttpPlatform.js +1 -0
  245. package/dist/vendor/cjs/node/NodeHttpServer.d.ts +120 -0
  246. package/dist/vendor/cjs/node/NodeHttpServer.js +1 -0
  247. package/dist/vendor/cjs/node/NodeHttpServerRequest.d.ts +29 -0
  248. package/dist/vendor/cjs/node/NodeHttpServerRequest.js +1 -0
  249. package/dist/vendor/cjs/node/NodeMultipart.d.ts +46 -0
  250. package/dist/vendor/cjs/node/NodeMultipart.js +1 -0
  251. package/dist/vendor/cjs/node/NodeMultipartParser.d.ts +97 -0
  252. package/dist/vendor/cjs/node/NodeMultipartParser.js +1 -0
  253. package/dist/vendor/cjs/node/NodePath.d.ts +27 -0
  254. package/dist/vendor/cjs/node/NodePath.js +1 -0
  255. package/dist/vendor/cjs/node/NodeRedis.d.ts +74 -0
  256. package/dist/vendor/cjs/node/NodeRedis.js +1 -0
  257. package/dist/vendor/cjs/node/NodeRuntime.d.ts +85 -0
  258. package/dist/vendor/cjs/node/NodeRuntime.js +1 -0
  259. package/dist/vendor/cjs/node/NodeServices.d.ts +34 -0
  260. package/dist/vendor/cjs/node/NodeServices.js +1 -0
  261. package/dist/vendor/cjs/node/NodeSink.d.ts +8 -0
  262. package/dist/vendor/cjs/node/NodeSink.js +1 -0
  263. package/dist/vendor/cjs/node/NodeSocket.d.ts +38 -0
  264. package/dist/vendor/cjs/node/NodeSocket.js +1 -0
  265. package/dist/vendor/cjs/node/NodeSocketServer.d.ts +8 -0
  266. package/dist/vendor/cjs/node/NodeSocketServer.js +1 -0
  267. package/dist/vendor/cjs/node/NodeStdio.d.ts +11 -0
  268. package/dist/vendor/cjs/node/NodeStdio.js +1 -0
  269. package/dist/vendor/cjs/node/NodeStream.d.ts +8 -0
  270. package/dist/vendor/cjs/node/NodeStream.js +1 -0
  271. package/dist/vendor/cjs/node/NodeTerminal.d.ts +21 -0
  272. package/dist/vendor/cjs/node/NodeTerminal.js +1 -0
  273. package/dist/vendor/cjs/node/NodeWorker.d.ts +22 -0
  274. package/dist/vendor/cjs/node/NodeWorker.js +1 -0
  275. package/dist/vendor/cjs/node/NodeWorkerRunner.d.ts +12 -0
  276. package/dist/vendor/cjs/node/NodeWorkerRunner.js +1 -0
  277. package/dist/vendor/cjs/node/Undici.d.ts +28 -0
  278. package/dist/vendor/cjs/node/Undici.js +1 -0
  279. package/dist/vendor/cjs/node/index.d.ts +100 -0
  280. package/dist/vendor/cjs/node/index.js +1 -0
  281. package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.d.ts +57 -0
  282. package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.js +1 -0
  283. package/dist/vendor/cjs/node-shared/NodeClusterSocket.d.ts +22 -0
  284. package/dist/vendor/cjs/node-shared/NodeClusterSocket.js +1 -0
  285. package/dist/vendor/cjs/node-shared/NodeCrypto.d.ts +27 -0
  286. package/dist/vendor/cjs/node-shared/NodeCrypto.js +1 -0
  287. package/dist/vendor/cjs/node-shared/NodeFileSystem.d.ts +11 -0
  288. package/dist/vendor/cjs/node-shared/NodeFileSystem.js +1 -0
  289. package/dist/vendor/cjs/node-shared/NodeHttpCompression.d.ts +36 -0
  290. package/dist/vendor/cjs/node-shared/NodeHttpCompression.js +1 -0
  291. package/dist/vendor/cjs/node-shared/NodePath.d.ts +27 -0
  292. package/dist/vendor/cjs/node-shared/NodePath.js +1 -0
  293. package/dist/vendor/cjs/node-shared/NodeRuntime.d.ts +47 -0
  294. package/dist/vendor/cjs/node-shared/NodeRuntime.js +1 -0
  295. package/dist/vendor/cjs/node-shared/NodeSink.d.ts +69 -0
  296. package/dist/vendor/cjs/node-shared/NodeSink.js +1 -0
  297. package/dist/vendor/cjs/node-shared/NodeSocket.d.ts +134 -0
  298. package/dist/vendor/cjs/node-shared/NodeSocket.js +1 -0
  299. package/dist/vendor/cjs/node-shared/NodeSocketServer.d.ts +80 -0
  300. package/dist/vendor/cjs/node-shared/NodeSocketServer.js +1 -0
  301. package/dist/vendor/cjs/node-shared/NodeStdio.d.ts +12 -0
  302. package/dist/vendor/cjs/node-shared/NodeStdio.js +1 -0
  303. package/dist/vendor/cjs/node-shared/NodeStream.d.ts +179 -0
  304. package/dist/vendor/cjs/node-shared/NodeStream.js +1 -0
  305. package/dist/vendor/cjs/node-shared/NodeTerminal.d.ts +22 -0
  306. package/dist/vendor/cjs/node-shared/NodeTerminal.js +1 -0
  307. package/dist/vendor/cjs/node-shared/index.d.ts +56 -0
  308. package/dist/vendor/cjs/node-shared/index.js +1 -0
  309. package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.d.ts +4 -0
  310. package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.js +1 -0
  311. package/dist/vendor/cjs/node-shared/internal/utils.d.ts +2 -0
  312. package/dist/vendor/cjs/node-shared/internal/utils.js +1 -0
  313. package/dist/vendor/cjs/package.json +1 -0
  314. package/dist/vendor/cjs/platform-node-shared.d.ts +56 -0
  315. package/dist/vendor/cjs/platform-node-shared.js +1 -0
  316. package/dist/vendor/cjs/platform-node.d.ts +100 -0
  317. package/dist/vendor/cjs/platform-node.js +1 -0
  318. package/dist/vendor/node/LICENSE +21 -0
  319. package/dist/vendor/node/NodeChildProcessSpawner.d.ts +7 -0
  320. package/dist/vendor/node/NodeChildProcessSpawner.js +14 -0
  321. package/dist/vendor/node/NodeClusterHttp.d.ts +63 -0
  322. package/dist/vendor/node/NodeClusterHttp.js +43 -0
  323. package/dist/vendor/node/NodeClusterSocket.d.ts +79 -0
  324. package/dist/vendor/node/NodeClusterSocket.js +30 -0
  325. package/dist/vendor/node/NodeCrypto.d.ts +10 -0
  326. package/dist/vendor/node/NodeCrypto.js +8 -0
  327. package/dist/vendor/node/NodeFileSystem.d.ts +10 -0
  328. package/dist/vendor/node/NodeFileSystem.js +9 -0
  329. package/dist/vendor/node/NodeHttpClient.d.ts +179 -0
  330. package/dist/vendor/node/NodeHttpClient.js +46 -0
  331. package/dist/vendor/node/NodeHttpIncomingMessage.d.ts +62 -0
  332. package/dist/vendor/node/NodeHttpIncomingMessage.js +10 -0
  333. package/dist/vendor/node/NodeHttpPlatform.d.ts +36 -0
  334. package/dist/vendor/node/NodeHttpPlatform.js +16 -0
  335. package/dist/vendor/node/NodeHttpServer.d.ts +120 -0
  336. package/dist/vendor/node/NodeHttpServer.js +46 -0
  337. package/dist/vendor/node/NodeHttpServerRequest.d.ts +29 -0
  338. package/dist/vendor/node/NodeHttpServerRequest.js +9 -0
  339. package/dist/vendor/node/NodeMultipart.d.ts +46 -0
  340. package/dist/vendor/node/NodeMultipart.js +15 -0
  341. package/dist/vendor/node/NodeMultipartParser.d.ts +97 -0
  342. package/dist/vendor/node/NodeMultipartParser.js +11 -0
  343. package/dist/vendor/node/NodePath.d.ts +27 -0
  344. package/dist/vendor/node/NodePath.js +12 -0
  345. package/dist/vendor/node/NodeRedis.d.ts +74 -0
  346. package/dist/vendor/node/NodeRedis.js +11 -0
  347. package/dist/vendor/node/NodeRuntime.d.ts +85 -0
  348. package/dist/vendor/node/NodeRuntime.js +8 -0
  349. package/dist/vendor/node/NodeServices.d.ts +34 -0
  350. package/dist/vendor/node/NodeServices.js +23 -0
  351. package/dist/vendor/node/NodeSink.d.ts +8 -0
  352. package/dist/vendor/node/NodeSink.js +12 -0
  353. package/dist/vendor/node/NodeSocket.d.ts +38 -0
  354. package/dist/vendor/node/NodeSocket.js +31 -0
  355. package/dist/vendor/node/NodeSocketServer.d.ts +8 -0
  356. package/dist/vendor/node/NodeSocketServer.js +21 -0
  357. package/dist/vendor/node/NodeStdio.d.ts +11 -0
  358. package/dist/vendor/node/NodeStdio.js +10 -0
  359. package/dist/vendor/node/NodeStream.d.ts +8 -0
  360. package/dist/vendor/node/NodeStream.js +27 -0
  361. package/dist/vendor/node/NodeTerminal.d.ts +21 -0
  362. package/dist/vendor/node/NodeTerminal.js +10 -0
  363. package/dist/vendor/node/NodeWorker.d.ts +22 -0
  364. package/dist/vendor/node/NodeWorker.js +9 -0
  365. package/dist/vendor/node/NodeWorkerRunner.d.ts +12 -0
  366. package/dist/vendor/node/NodeWorkerRunner.js +7 -0
  367. package/dist/vendor/node/Undici.d.ts +28 -0
  368. package/dist/vendor/node/Undici.js +9 -0
  369. package/dist/vendor/node/index.d.ts +100 -0
  370. package/dist/vendor/node/index.js +115 -0
  371. package/dist/vendor/node-shared/LICENSE +21 -0
  372. package/dist/vendor/node-shared/NodeChildProcessSpawner.d.ts +57 -0
  373. package/dist/vendor/node-shared/NodeChildProcessSpawner.js +13 -0
  374. package/dist/vendor/node-shared/NodeClusterSocket.d.ts +22 -0
  375. package/dist/vendor/node-shared/NodeClusterSocket.js +11 -0
  376. package/dist/vendor/node-shared/NodeCrypto.d.ts +27 -0
  377. package/dist/vendor/node-shared/NodeCrypto.js +9 -0
  378. package/dist/vendor/node-shared/NodeFileSystem.d.ts +11 -0
  379. package/dist/vendor/node-shared/NodeFileSystem.js +8 -0
  380. package/dist/vendor/node-shared/NodeHttpCompression.d.ts +36 -0
  381. package/dist/vendor/node-shared/NodeHttpCompression.js +13 -0
  382. package/dist/vendor/node-shared/NodePath.d.ts +27 -0
  383. package/dist/vendor/node-shared/NodePath.js +11 -0
  384. package/dist/vendor/node-shared/NodeRuntime.d.ts +47 -0
  385. package/dist/vendor/node-shared/NodeRuntime.js +7 -0
  386. package/dist/vendor/node-shared/NodeSink.d.ts +69 -0
  387. package/dist/vendor/node-shared/NodeSink.js +11 -0
  388. package/dist/vendor/node-shared/NodeSocket.d.ts +134 -0
  389. package/dist/vendor/node-shared/NodeSocket.js +23 -0
  390. package/dist/vendor/node-shared/NodeSocketServer.d.ts +80 -0
  391. package/dist/vendor/node-shared/NodeSocketServer.js +20 -0
  392. package/dist/vendor/node-shared/NodeStdio.d.ts +12 -0
  393. package/dist/vendor/node-shared/NodeStdio.js +9 -0
  394. package/dist/vendor/node-shared/NodeStream.d.ts +179 -0
  395. package/dist/vendor/node-shared/NodeStream.js +26 -0
  396. package/dist/vendor/node-shared/NodeTerminal.d.ts +22 -0
  397. package/dist/vendor/node-shared/NodeTerminal.js +9 -0
  398. package/dist/vendor/node-shared/index.d.ts +56 -0
  399. package/dist/vendor/node-shared/index.js +58 -0
  400. package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.d.ts +4 -0
  401. package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.js +7 -0
  402. package/dist/vendor/node-shared/internal/utils.d.ts +2 -0
  403. package/dist/vendor/node-shared/internal/utils.js +7 -0
  404. package/dist/vendor/platform-node-shared.d.ts +56 -0
  405. package/dist/vendor/platform-node-shared.js +58 -0
  406. package/dist/vendor/platform-node.d.ts +100 -0
  407. package/dist/vendor/platform-node.js +115 -0
  408. package/docs/README.md +129 -0
  409. package/docs/api.md +553 -0
  410. package/docs/concepts/descriptor-relative-filesystem.md +181 -0
  411. package/docs/concepts/host-bundle.md +125 -0
  412. package/docs/concepts/process-containment.md +190 -0
  413. package/docs/guides/answer-run-ownership.md +87 -0
  414. package/docs/guides/configure-the-filesystem-helper.md +152 -0
  415. package/docs/guides/contain-child-processes.md +139 -0
  416. package/docs/guides/match-files-with-glob.md +151 -0
  417. package/docs/installation.md +204 -0
  418. package/docs/quickstart.md +147 -0
  419. package/docs/troubleshooting.md +130 -0
  420. package/package.json +202 -3
  421. package/src/AtomicFileSystem.ts +415 -0
  422. package/src/EgressHttpClient.ts +327 -0
  423. package/src/HostLiveness.ts +103 -0
  424. package/src/NodeHost.ts +253 -0
  425. package/src/ProcessConfinement.ts +363 -0
  426. package/src/ProcessReaper.ts +951 -0
  427. package/src/ProcessSandbox.ts +1307 -0
  428. package/src/ScopedProcess.ts +124 -0
  429. package/src/index.ts +44 -0
  430. package/src/internal/AtomicFileSystemExecutable.ts +379 -0
  431. package/src/internal/AtomicFileSystemProtocol.ts +502 -0
  432. package/src/internal/AtomicFileSystemTransport.ts +272 -0
  433. package/src/internal/AtomicHelperError.ts +50 -0
  434. package/src/internal/AtomicHelperFault.ts +84 -0
  435. package/src/internal/PipedProcess.ts +357 -0
  436. package/src/internal/ProcSnapshot.ts +193 -0
  437. package/src/internal/ProcessCleanup.ts +99 -0
  438. package/src/internal/ProcessCleanupPolicyError.ts +30 -0
  439. package/src/internal/ProcessFault.ts +82 -0
  440. package/src/internal/ProcessSupervisor.ts +807 -0
  441. package/src/internal/SupervisorProgram.ts +309 -0
  442. package/src/internal/WindowsProcessJob.ts +114 -0
@@ -0,0 +1,711 @@
1
+ /**
2
+ * Reaping the processes a dead host incarnation abandoned.
3
+ *
4
+ * Scope closure cleans up work a live host still owns. On POSIX, a prepared
5
+ * supervisor also receives private-channel EOF when its host disappears and
6
+ * independently requests group cleanup. The durable ledger remains the fallback
7
+ * when that cleanup is incomplete or cannot be verified; the next incarnation
8
+ * uses this module to examine the recorded process identities before acting.
9
+ *
10
+ * The rules are narrow on purpose, because the input is a durable record that
11
+ * outlived the process that wrote it and a pid is reused. A record is signalled
12
+ * only when ALL of these hold:
13
+ *
14
+ * - it belongs to a DIFFERENT incarnation of the SAME `hostId`
15
+ * ({@link ProcessLedger.Service.orphans} already filters that);
16
+ * - its owner is gone. A pid that exists but belongs to another user counts as
17
+ * alive, exactly as {@link HostLiveness} counts it, so only `ESRCH` reads as
18
+ * dead and every other answer keeps the record;
19
+ * - it names a target the platform can actually signal. On POSIX that is a
20
+ * process group the child leads itself, so `pgid` has to be a safe integer
21
+ * above 1 and equal to `pid`; on Windows it is a pid, so `pgid` has to be
22
+ * absent. The check is made against the DURABLE record rather than trusted
23
+ * from it: `process.kill(-0, "SIGKILL")` signals this host's own process
24
+ * group, and `@smthrs/kernel`'s ledger schema admits zero;
25
+ * - that group is not THIS process's group, and its pid is not this process's
26
+ * pid. The host's real process group is read from the operating system,
27
+ * because a stored number can claim anything and the shell that started this
28
+ * host shares its group. A host that cannot read its own group keeps the
29
+ * record rather than signalling it on a guard that did not run;
30
+ * - the number still names the process the record describes. A record written
31
+ * before this machine booted names a pid from a pid space that no longer
32
+ * exists, and within one boot the recorded start time has to match the start
33
+ * time the operating system reports for that pid. A host that cannot ASK the
34
+ * question answers {@link StartTime} `unavailable`, which refuses the kill
35
+ * and keeps the record; no evidence never authorizes a signal.
36
+ *
37
+ * The outcome of the signal is part of the record. A kill that succeeds, or
38
+ * that reports the group is already gone, retires the record through
39
+ * {@link ProcessLedger.Service.reaped}; a kill that FAILS for any other reason
40
+ * leaves the record inherited so the next incarnation tries again. A record
41
+ * refused on grounds the operating system will not revisit — a number no
42
+ * platform can signal, a pid that is gone, a start time that does not match — is
43
+ * retired through {@link ProcessLedger.Service.skipped}, which says in the
44
+ * journal that nothing was signalled and stops every later incarnation
45
+ * re-examining a number the operating system has moved on from. The three
46
+ * refusals a later incarnation CAN answer differently — `owner-alive`,
47
+ * `identity-unverified`, and `own-group-unknown` — retire nothing.
48
+ *
49
+ * @since 0.1.0
50
+ */
51
+ import * as ContainedSpawner from "@smthrs/kernel/ContainedSpawner";
52
+ import * as ProcessLedger from "@smthrs/kernel/ProcessLedger";
53
+ import * as Effect from "effect/Effect";
54
+ import * as Layer from "effect/Layer";
55
+ import * as Metric from "effect/Metric";
56
+ import { ChildProcessSpawner, make as makeSpawner } from "effect/unstable/process/ChildProcessSpawner";
57
+ import { spawnSync } from "node:child_process";
58
+ import { uptime } from "node:os";
59
+ import { parse, win32 } from "node:path";
60
+ import { packageRoot, resolveDefaultExecutable } from "./internal/AtomicFileSystemExecutable.js";
61
+ import { usableExecutable } from "./internal/AtomicFileSystemTransport.js";
62
+ import * as PipedProcess from "./internal/PipedProcess.js";
63
+ import * as ProcessCleanup from "./internal/ProcessCleanup.js";
64
+ import * as ProcSnapshot from "./internal/ProcSnapshot.js";
65
+ const errorCode = (cause) => cause?.code;
66
+ const liveness = (pid) => {
67
+ try {
68
+ // Signal 0 delivers nothing; it only asks whether the pid is signalable.
69
+ process.kill(pid, 0);
70
+ return "alive";
71
+ }
72
+ catch (cause) {
73
+ // ESRCH is the only answer that means gone. EPERM means the process
74
+ // exists and belongs to another user; anything else is a question this
75
+ // host could not ask, and both keep the record rather than kill on it.
76
+ return errorCode(cause) === "ESRCH" ? "dead" : "unknown";
77
+ }
78
+ };
79
+ const bootedAtMs = () => Date.now() - Math.round(uptime() * 1000);
80
+ /**
81
+ * The start time `ps` reports for a pid.
82
+ *
83
+ * `lstart` is the one start-time column both BSD (macOS) and procps (Linux)
84
+ * spell the same way, and it prints an absolute time rather than an elapsed
85
+ * one, so the answer does not drift between reading it and comparing it. It is
86
+ * also a LOCALIZED column, so the probe pins `LC_ALL=C` and `TZ=UTC`.
87
+ * Its text has no zone; parsing explicitly as UTC keeps the identity independent
88
+ * of the host runtime's timezone.
89
+ */
90
+ const startedAtMs = (executable) => (pid) => {
91
+ const answer = ps(executable, "lstart", pid);
92
+ if (answer._tag === "gone") {
93
+ // A nonzero exit is `ps` saying the pid does not exist, but it is also what
94
+ // a `ps` that rejected the column, or one that is not the `ps` this probe
95
+ // expects, says about a pid that is very much alive. The kernel is asked
96
+ // directly before a live process is retired as gone.
97
+ return liveness(pid) === "dead" ? answer : { _tag: "unavailable" };
98
+ }
99
+ if (answer._tag !== "printed")
100
+ return answer;
101
+ const parsed = Date.parse(`${answer.text} UTC`);
102
+ return Number.isNaN(parsed) ? { _tag: "unavailable" } : { _tag: "started", startedAtMs: parsed };
103
+ };
104
+ /**
105
+ * The absolute path the process probe is run from.
106
+ *
107
+ * Never a `PATH` lookup. The inherited environment belongs to whoever started
108
+ * this host, and a planted `ps` that prints a fabricated start time — or none
109
+ * at all — would decide whether a `SIGKILL` is authorized.
110
+ *
111
+ * @category constants
112
+ * @since 1.0.0-rc.0
113
+ */
114
+ export const defaultPsExecutable = "/bin/ps";
115
+ /** How long the probe may take before it counts as an answer nobody gave. */
116
+ const psTimeoutMs = 5000;
117
+ /**
118
+ * The Windows directory the host was started with, when it names one.
119
+ */
120
+ const windowsRoot = () => {
121
+ const systemRoot = process.env.SystemRoot;
122
+ return systemRoot !== undefined && win32.isAbsolute(systemRoot) ? systemRoot : "C:\\Windows";
123
+ };
124
+ /**
125
+ * The system `taskkill`, by absolute path. Windows resolves a bare name from
126
+ * the current directory before `PATH`, so a flow that wrote `taskkill.exe`
127
+ * into the host's working directory would otherwise run as the host.
128
+ */
129
+ const taskkillExecutable = () => win32.join(windowsRoot(), "System32", "taskkill.exe");
130
+ /** A live-release probe has its own short bound within the shutdown deadline. */
131
+ const cleanupProbeTimeoutMs = 2000;
132
+ /**
133
+ * One fixed-path snapshot supplies group membership, start identities and our
134
+ * own group together. Only numeric fields and C-locale lstart are read; command
135
+ * text and the caller's PATH never influence signal authority.
136
+ */
137
+ const psGroupSnapshot = (pgid) => {
138
+ const result = spawnSync(defaultPsExecutable, ["-A", "-o", "pid=,pgid=,stat=,lstart="], {
139
+ encoding: "utf8",
140
+ timeout: cleanupProbeTimeoutMs,
141
+ killSignal: "SIGKILL",
142
+ env: { LC_ALL: "C", TZ: "UTC", PATH: "/usr/bin:/bin" }
143
+ });
144
+ if (result.error !== undefined || result.signal !== null || result.status !== 0)
145
+ return undefined;
146
+ let own;
147
+ const members = [];
148
+ for (const line of result.stdout.trim().split("\n")) {
149
+ const match = /^\s*([0-9]+)\s+([0-9]+)\s+(\S+)\s+(.+)$/.exec(line);
150
+ if (match === null)
151
+ return undefined;
152
+ const pid = Number(match[1]);
153
+ const group = Number(match[2]);
154
+ if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(group))
155
+ return undefined;
156
+ if (pid === process.pid)
157
+ own = group;
158
+ if (group !== pgid)
159
+ continue;
160
+ const started = Date.parse(`${match[4]} UTC`);
161
+ if (Number.isNaN(started))
162
+ return undefined;
163
+ members.push({ pid, startedAtMs: started, zombie: match[3].startsWith("Z") });
164
+ }
165
+ return own === undefined || own <= 0 ? undefined : { ownGroup: own, members };
166
+ };
167
+ /**
168
+ * The observation the supervisor polls, from the source that platform has.
169
+ *
170
+ * Linux publishes the whole process table as files under `/proc`, which is
171
+ * where `ps` itself reads it, so the kernel is asked directly. That needs no
172
+ * `procps` in the image, cannot be answered by a planted binary, and costs no
173
+ * fork on a poll that runs every 10ms. A missing `/bin/ps` is not a
174
+ * hypothetical: `procps` is not in `debian:bookworm-slim`, and on Cloud CI run
175
+ * 11727 every spawned target in every task finished its work and then failed
176
+ * cleanup verification with `Unknown: ChildProcess.kill`, because this
177
+ * observation could not be made.
178
+ *
179
+ * Every other POSIX host keeps the `ps` reading, which is the only portable
180
+ * spelling of this question off Linux.
181
+ *
182
+ * @category constructors
183
+ * @since 1.0.0
184
+ */
185
+ export const groupSnapshotFor = (platform) => platform === "linux" ? ProcSnapshot.snapshot(ProcSnapshot.defaultProcRoot) : psGroupSnapshot;
186
+ /**
187
+ * Whether the kernel reports no process at all in a group.
188
+ *
189
+ * Signal 0 delivers nothing; it only asks the kernel whether the group has a
190
+ * member. `ESRCH` is the one answer that proves the group empty, with no fork
191
+ * and no process table to parse, so it still answers on a loaded host where a
192
+ * `ps` snapshot cannot be taken. A live member, a zombie (macOS answers
193
+ * `EPERM`, Linux succeeds), another user's member or any other error answers
194
+ * `false`, which leaves the question to the snapshot.
195
+ *
196
+ * @category constructors
197
+ * @since 1.0.0
198
+ */
199
+ export const groupVacant = (pgid) => {
200
+ // kill(0) and kill(-1) address the caller's group and every process.
201
+ if (!Number.isSafeInteger(pgid) || pgid <= 1)
202
+ return false;
203
+ try {
204
+ process.kill(-pgid, 0);
205
+ return false;
206
+ }
207
+ catch (cause) {
208
+ return errorCode(cause) === "ESRCH";
209
+ }
210
+ };
211
+ /**
212
+ * Live cleanup for Node and Bun contained spawners.
213
+ *
214
+ * A trusted supervisor remains the group owner after the target exits. It
215
+ * enforces cleanup on target completion, parent loss and explicit release; the
216
+ * target starts only after its owner is durably recorded. Host observations
217
+ * never signal a pid: they only shorten the owner's deadline or verify an empty
218
+ * group before retiring its record. Failed verification retains the record.
219
+ *
220
+ * @category constructors
221
+ * @since 1.0.0
222
+ */
223
+ export const processLifecycle = ProcessCleanup.lifecycle({
224
+ platform: process.platform,
225
+ snapshot: groupSnapshotFor(process.platform),
226
+ vacant: groupVacant
227
+ });
228
+ /**
229
+ * Provides a ledger-backed spawner with this platform's prepared cleanup.
230
+ *
231
+ * Native pipe listeners live until their descriptors close, including writes
232
+ * interrupted by owner loss. The kernel expands pipelines before this private
233
+ * standard-command adapter is called. Windows owners join a native job before
234
+ * activation; POSIX owners enforce their process-group cleanup deadline.
235
+ *
236
+ * The caller supplies the durable or in-memory ledger. This layer records new
237
+ * owners; {@link layer} separately reaps
238
+ * records inherited from a previous host incarnation.
239
+ * @category layers
240
+ * @since 1.0.0
241
+ */
242
+ export const layerSpawner = (options) => {
243
+ const contained = ContainedSpawner.layer({ graceMs: options?.graceMs, platform: process.platform }, processLifecycle);
244
+ const standard = makeSpawner((command) => PipedProcess.spawn(command, undefined, true));
245
+ return Layer.provide(contained, Layer.succeed(ChildProcessSpawner)(standard));
246
+ };
247
+ /** A whole number and nothing else, which is all a `pgid` column may be. */
248
+ const decimal = /^[0-9]+$/;
249
+ /**
250
+ * One `ps` column for one pid.
251
+ *
252
+ * `printed` is an answer; every other tag is the absence of one. A nonzero exit
253
+ * with no error is `ps` saying the pid does not exist, which is evidence; a
254
+ * spawn that failed, a signal, or a timeout is not.
255
+ */
256
+ const ps = (executable, column, pid) => {
257
+ const result = spawnSync(executable, ["-o", `${column}=`, "-p", String(pid)], {
258
+ encoding: "utf8",
259
+ timeout: psTimeoutMs,
260
+ // `SIGKILL` rather than the default `SIGTERM`, because this call blocks the
261
+ // event loop while a host is being built: `spawnSync` keeps waiting past
262
+ // the deadline for a process that ignores the signal, so a `TERM` the probe
263
+ // can decline is not a deadline at all.
264
+ killSignal: "SIGKILL",
265
+ // An empty-ish environment for the same reason the helper in
266
+ // `AtomicFileSystem` gets one: nothing the caller exported may change what
267
+ // this answers. Pin both the column's spelling and its timezone; the parser
268
+ // supplies UTC explicitly because `lstart` does not print a zone.
269
+ env: { LC_ALL: "C", TZ: "UTC", PATH: "/usr/bin:/bin" }
270
+ });
271
+ if (result.error !== undefined || result.signal !== null || result.status === null) {
272
+ return { _tag: "unavailable" };
273
+ }
274
+ if (result.status !== 0)
275
+ return { _tag: "gone" };
276
+ const printed = result.stdout.trim();
277
+ return printed === "" ? { _tag: "unavailable" } : { _tag: "printed", text: printed };
278
+ };
279
+ /**
280
+ * This process's own process group.
281
+ *
282
+ * Node exposes no `getpgrp`, so the answer comes from `ps`, which both BSD and
283
+ * procps spell `pgid`. A host that cannot read it answers `null` and loses one
284
+ * guard, which is why the pid comparison below is kept as well.
285
+ *
286
+ * The text is required to be one run of decimal digits naming a real group,
287
+ * rather than run through `Number.parseInt`, which reads a PREFIX: `"12 34"`,
288
+ * `"12abc"`, and `"0x10"` all become a number that is not this host's group. A
289
+ * wrong number is worse here than no number at all. It silently passes the
290
+ * own-group comparison in {@link refuse}, and because it is not `null` it also
291
+ * suppresses the `own-group-unknown` refusal that exists to say the comparison
292
+ * could not be made, so the guard neither runs nor reports that it did not run
293
+ * and a `SIGKILL` goes out on it. Anything else answers `null`, which refuses.
294
+ */
295
+ const ownGroup = (executable) => () => {
296
+ const answer = ps(executable, "pgid", process.pid);
297
+ if (answer._tag !== "printed")
298
+ return null;
299
+ if (!decimal.test(answer.text))
300
+ return null;
301
+ const parsed = Number(answer.text);
302
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
303
+ };
304
+ /**
305
+ * Whether a durable record names a POSIX process group this host may signal.
306
+ *
307
+ * `process.kill(-pgid, ...)` turns the stored number into a target directly, so
308
+ * every value that is not a real foreign group has to be refused before it gets
309
+ * there: `0` signals THIS process's group, a negative value stops naming a
310
+ * group at all and names a single pid, and a `pgid` that differs from `pid`
311
+ * describes a child that does not lead the group it claims —
312
+ * `ContainedSpawner.groupOf` writes `pgid === pid` for every detached POSIX
313
+ * child, so anything else is a record no writer in this repository produced.
314
+ */
315
+ const refusePosixTarget = (record) => {
316
+ if (record.pgid === null)
317
+ return "no-group";
318
+ if (!Number.isSafeInteger(record.pid) || record.pid <= 1)
319
+ return "invalid-record";
320
+ if (!Number.isSafeInteger(record.pgid) || record.pgid <= 1)
321
+ return "invalid-record";
322
+ return record.pgid === record.pid ? undefined : "invalid-record";
323
+ };
324
+ /**
325
+ * Whether a durable record names a Windows process tree this host may signal.
326
+ *
327
+ * Windows has no process groups, so `ContainedSpawner.groupOf` records `null`
328
+ * there and `taskkill /T` walks the tree from the pid instead. A win32 record
329
+ * carrying a number is therefore a record some other platform wrote.
330
+ */
331
+ const refuseWindowsTarget = (record) => {
332
+ if (record.pgid !== null)
333
+ return "invalid-record";
334
+ return Number.isSafeInteger(record.pid) && record.pid > 1 && record.pid <= 0xffff_ffff ? undefined : "invalid-record";
335
+ };
336
+ /**
337
+ * Reaping on a POSIX host, with the identity probe configured.
338
+ *
339
+ * The group is killed outright rather than asked politely first. `SIGTERM`
340
+ * buys a graceful shutdown only when someone is left to wait for it, and the
341
+ * incarnation that owned these processes is by definition gone.
342
+ *
343
+ * @category constructors
344
+ * @since 1.0.0-rc.0
345
+ */
346
+ export const posixSystemWith = (options) => posixSystemFrom({
347
+ startedAtMs: startedAtMs(options?.psExecutable ?? defaultPsExecutable),
348
+ ownGroup: ownGroup(options?.psExecutable ?? defaultPsExecutable),
349
+ bootedAtMs
350
+ }, options?.ownerPid ?? process.pid);
351
+ /**
352
+ * Reaping on Linux, with every identity question read from `/proc` rather
353
+ * than from `ps`.
354
+ *
355
+ * `procps` is not in `debian:bookworm-slim` (Cloud CI run 11727), and a
356
+ * `ps`-based reaper on such a host can read neither its own group nor any
357
+ * start time, so it refuses every orphan as `own-group-unknown` on every
358
+ * restart. The live-cleanup observation ({@link groupSnapshotFor}) already
359
+ * reads `/proc` for the same reason; this is the crash-recovery half.
360
+ *
361
+ * A pid with no `/proc/<pid>/stat` is `gone` only when the kernel also says so,
362
+ * because a `hidepid` mount hides another user's live process the same way.
363
+ *
364
+ * @category constructors
365
+ * @since 1.0.0-rc.1
366
+ */
367
+ export const procSystemWith = (options) => {
368
+ const root = options?.procRoot ?? ProcSnapshot.defaultProcRoot;
369
+ const readStart = ProcSnapshot.startedAtMs(root);
370
+ return posixSystemFrom({
371
+ startedAtMs: (pid) => {
372
+ const answer = readStart(pid);
373
+ return answer._tag === "gone" && liveness(pid) !== "dead" ? { _tag: "unavailable" } : answer;
374
+ },
375
+ ownGroup: ProcSnapshot.ownGroup(root),
376
+ bootedAtMs: () => ProcSnapshot.bootMs(root) ?? bootedAtMs()
377
+ }, options?.ownerPid ?? process.pid);
378
+ };
379
+ /** The POSIX kill path over whichever probes the platform answers with. */
380
+ const posixSystemFrom = (probes, ownerPid) => {
381
+ const readOwnGroup = probes.ownGroup;
382
+ return {
383
+ isAlive: liveness,
384
+ startedAtMs: probes.startedAtMs,
385
+ ownGroup: readOwnGroup,
386
+ bootedAtMs: probes.bootedAtMs,
387
+ refuseTarget: refusePosixTarget,
388
+ killTree: (record) => {
389
+ // Repeated here and not only in `refuse`: this function is exported, and
390
+ // the negation below is the one place a stored number becomes a signal.
391
+ if (refusePosixTarget(record) !== undefined)
392
+ return "failed";
393
+ // The host's own identity, repeated for the same reason. `refuse` holds
394
+ // one `ownGroup` reading for the whole sweep; a caller that reaches this
395
+ // function directly has made no such reading, and `process.kill(-pgid)`
396
+ // does not care which way the number arrived. A group that cannot be
397
+ // read is a comparison that did not happen, so nothing is signalled.
398
+ if (record.pid === ownerPid || record.pgid === ownerPid)
399
+ return "failed";
400
+ const group = readOwnGroup();
401
+ if (group === null || record.pid === group || record.pgid === group)
402
+ return "failed";
403
+ try {
404
+ process.kill(-record.pgid, "SIGKILL");
405
+ return "signalled";
406
+ }
407
+ catch (cause) {
408
+ // The group settled between the liveness check and the signal: the end
409
+ // state is the one that was wanted. Anything else is a kill that did NOT
410
+ // happen, and saying so is what gets the record tried again.
411
+ return errorCode(cause) === "ESRCH" ? "already-gone" : "failed";
412
+ }
413
+ }
414
+ };
415
+ };
416
+ /**
417
+ * Reaping on a POSIX host: one `SIGKILL` to the abandoned process group, with
418
+ * the identity probe at {@link defaultPsExecutable}.
419
+ *
420
+ * @category constructors
421
+ * @since 0.1.0
422
+ */
423
+ export const posixSystem = posixSystemWith();
424
+ /**
425
+ * Reaping on Windows, with the identity the sweep must never signal
426
+ * configured.
427
+ *
428
+ * @category constructors
429
+ * @since 1.0.0-rc.0
430
+ */
431
+ export const windowsSystemWith = (options) => {
432
+ const ownerPid = options?.ownerPid ?? process.pid;
433
+ const startedAtMs = (pid) => {
434
+ if (!Number.isSafeInteger(pid) || pid <= 1 || pid > 0xffff_ffff)
435
+ return { _tag: "unavailable" };
436
+ try {
437
+ const configured = options?.processExecutable ?? process.env.SMITHERS_WORKSPACE_JJ_EXPORT_BINARY;
438
+ const executable = configured === undefined
439
+ ? resolveDefaultExecutable(packageRoot, undefined)
440
+ : usableExecutable(configured, undefined);
441
+ const result = spawnSync(executable, ["--process-info", String(pid)], {
442
+ cwd: parse(process.execPath).root,
443
+ env: {},
444
+ encoding: "utf8",
445
+ timeout: psTimeoutMs,
446
+ killSignal: "SIGKILL",
447
+ maxBuffer: 4096
448
+ });
449
+ if (result.error !== undefined || result.signal !== null || result.status !== 0)
450
+ return { _tag: "unavailable" };
451
+ const value = JSON.parse(result.stdout);
452
+ if (value?.status === "gone")
453
+ return { _tag: "gone" };
454
+ return value?.status === "started" && typeof value.startedAtMs === "number" &&
455
+ Number.isSafeInteger(value.startedAtMs) && value.startedAtMs >= 0
456
+ ? { _tag: "started", startedAtMs: value.startedAtMs }
457
+ : { _tag: "unavailable" };
458
+ }
459
+ catch {
460
+ return { _tag: "unavailable" };
461
+ }
462
+ };
463
+ return {
464
+ isAlive: liveness,
465
+ startedAtMs,
466
+ ownGroup: () => null,
467
+ bootedAtMs,
468
+ refuseTarget: (record) => record.pid === ownerPid ? "own-group" : refuseWindowsTarget(record),
469
+ killTree: (record) => {
470
+ if (refuseWindowsTarget(record) !== undefined)
471
+ return "failed";
472
+ // `taskkill /T` walks the tree DOWN from the pid it is given, so a record
473
+ // naming this host takes the host and everything it started with it.
474
+ if (record.pid === ownerPid)
475
+ return "failed";
476
+ const result = spawnSync(taskkillExecutable(), ["/pid", String(record.pid), "/T", "/F"], {
477
+ // An inert cwd and only the variable Windows system binaries need.
478
+ cwd: parse(process.execPath).root,
479
+ env: { SystemRoot: windowsRoot() },
480
+ stdio: "ignore"
481
+ });
482
+ if (result.error !== undefined)
483
+ return "failed";
484
+ // 128 is `taskkill`'s "no such process", which is the same end state a
485
+ // successful kill produces.
486
+ if (result.status === 0)
487
+ return "signalled";
488
+ return result.status === 128 ? "already-gone" : "failed";
489
+ }
490
+ };
491
+ };
492
+ /**
493
+ * Reaping on Windows, which has no process groups: `taskkill /T /F` by pid.
494
+ *
495
+ * **Windows is outside the 1.0.0-rc.0 support contract**
496
+ * (`docs/pages/installation.md`). Full Windows process containment remains
497
+ * under verification. It is kept — and reachable through {@link reap} rather than only
498
+ * by calling it directly — because a reaper that silently retired every win32
499
+ * record would be the "excluded feature that appears to work partially" the
500
+ * release policy forbids. Treat it as unsupported best-effort.
501
+ *
502
+ * The packaged native helper reads creation time from a pinned process handle.
503
+ * A missing helper, malformed reply, or denied query keeps the durable record
504
+ * for retry. Windows has no process groups, so own-group refusal uses the pid.
505
+ *
506
+ * @category constructors
507
+ * @since 0.1.0
508
+ */
509
+ export const windowsSystem = windowsSystemWith();
510
+ /**
511
+ * Reaping on Linux from the kernel's own `/proc`.
512
+ *
513
+ * @category constructors
514
+ * @since 1.0.0-rc.1
515
+ */
516
+ export const procSystem = procSystemWith();
517
+ /**
518
+ * Selects the reaping implementation a platform needs.
519
+ *
520
+ * @category constructors
521
+ * @since 0.1.0
522
+ */
523
+ export const systemFor = (platform) => platform === "win32" ? windowsSystem : platform === "linux" ? procSystem : posixSystem;
524
+ /**
525
+ * How far apart a recorded start time and the operating system's may be and
526
+ * still describe the same process.
527
+ *
528
+ * `lstart` has one-second granularity and the ledger writes its record just
529
+ * after the spawn returns, so the two never agree exactly. Two seconds covers
530
+ * the gap; a pid the operating system handed to somebody else is minutes or
531
+ * hours away from it, not milliseconds.
532
+ *
533
+ * @category models
534
+ * @since 0.1.0
535
+ */
536
+ export const identityToleranceMs = 2000;
537
+ /**
538
+ * The refusals that leave a record inherited instead of retiring it.
539
+ *
540
+ * A refusal is final when the operating system has moved on from the number:
541
+ * saying so in the journal is what stops every later incarnation re-examining
542
+ * it. These three are not final. `owner-alive` means the incarnation that owns
543
+ * the record will contain its own children; `identity-unverified` and
544
+ * `own-group-unknown` mean this host could not ask a question at all — a host
545
+ * that CAN ask has to get the chance.
546
+ */
547
+ const retained = new Set([
548
+ "owner-alive",
549
+ "identity-unverified",
550
+ "own-group-unknown"
551
+ ]);
552
+ /** The identity half of the decision, split out because it reads as a list. */
553
+ const refuseOnIdentity = (system, record, bootMs) => {
554
+ // A record older than this boot names a pid from a pid space that no longer
555
+ // exists. The tolerance points BACKWARDS from the boot instant on purpose:
556
+ // `uptime` is second-granular, so a record written moments after boot could
557
+ // otherwise be read as predating it, and refusing to kill is the safe way to
558
+ // be wrong.
559
+ //
560
+ // The consequence is a narrow, deliberate leak, and it is a leak rather than
561
+ // a retry: `reap` retires a `pre-boot` refusal through `ledger.skipped`, so a
562
+ // group spawned within `identityToleranceMs` of the computed boot instant is
563
+ // never reaped by any later incarnation either. That is the price of refusing
564
+ // to kill on an instant `uptime` can only place to the nearest second.
565
+ if (record.startedAtMs < bootMs + identityToleranceMs)
566
+ return "pre-boot";
567
+ const started = system.startedAtMs(record.pid);
568
+ // A platform with no start-time column at all has already been checked
569
+ // against this boot, which is the whole of its documented weaker guarantee.
570
+ if (started._tag === "unsupported")
571
+ return undefined;
572
+ if (started._tag === "gone")
573
+ return "process-gone";
574
+ if (started._tag === "unavailable")
575
+ return "identity-unverified";
576
+ return Math.abs(started.startedAtMs - record.startedAtMs) <= identityToleranceMs
577
+ ? undefined
578
+ : "identity-mismatch";
579
+ };
580
+ /** Everything the reaper checks before it is willing to signal a record. */
581
+ const refuse = (system, record, ownerPid, ownGroup, bootMs) => {
582
+ // The host's own identity comes first, before the platform is consulted at
583
+ // all: a record naming this process is refused on every platform, whatever
584
+ // shape its numbers have.
585
+ if (record.pgid === ownerPid || record.pid === ownerPid)
586
+ return "own-group";
587
+ if (ownGroup !== null && (record.pgid === ownGroup || record.pid === ownGroup))
588
+ return "own-group";
589
+ const target = system.refuseTarget(record);
590
+ if (target !== undefined)
591
+ return target;
592
+ // A record naming a group can only be cleared of naming THIS host's group by
593
+ // reading that group. When the probe cannot answer, the comparison above was
594
+ // not made rather than made and passed, so the record is kept instead of
595
+ // signalled on a guard that did not run.
596
+ if (record.pgid !== null && ownGroup === null)
597
+ return "own-group-unknown";
598
+ if (system.isAlive(record.ownerPid) !== "dead")
599
+ return "owner-alive";
600
+ return refuseOnIdentity(system, record, bootMs);
601
+ };
602
+ /**
603
+ * Kills the process groups a previous incarnation of this host abandoned.
604
+ *
605
+ * Returns one entry per inherited record so a caller can log what it decided;
606
+ * `killed: false` carries the {@link Refusal} that produced it. Fails with
607
+ * {@link ProcessLedger.ProcessLedgerReplayError} when the inherited history
608
+ * cannot be read to its end: nothing is signalled or retired, so the next
609
+ * sweep inherits every record again.
610
+ *
611
+ * @category constructors
612
+ * @since 0.1.0
613
+ */
614
+ export const reap = (options) => Effect.gen(function* () {
615
+ const ledger = yield* ProcessLedger.ProcessLedger;
616
+ const system = options?.system ?? systemFor(process.platform);
617
+ const ownerPid = options?.ownerPid ?? process.pid;
618
+ const ownGroup = system.ownGroup();
619
+ const bootMs = system.bootedAtMs();
620
+ const orphans = yield* ledger.orphans;
621
+ const decided = [];
622
+ for (const record of orphans) {
623
+ const refusal = refuse(system, record, ownerPid, ownGroup, bootMs);
624
+ if (refusal === undefined) {
625
+ const outcome = system.killTree(record);
626
+ if (outcome === "failed") {
627
+ // Nothing was killed, so nothing is retired: leaving the record
628
+ // inherited is what makes the next incarnation try again.
629
+ decided.push({ record, killed: false, refusal: "kill-failed" });
630
+ continue;
631
+ }
632
+ yield* retire(ledger.reaped(record), record.pid, "reaped");
633
+ decided.push({ record, killed: true });
634
+ continue;
635
+ }
636
+ // A retained refusal is not this host's to retire; every other refusal is
637
+ // final and says so in the journal.
638
+ if (!retained.has(refusal)) {
639
+ yield* retire(ledger.skipped(record, refusal), record.pid, "reap-skipped");
640
+ }
641
+ decided.push({ record, killed: false, refusal });
642
+ }
643
+ return decided;
644
+ });
645
+ /**
646
+ * Writes one ledger retirement, logging rather than failing the sweep.
647
+ *
648
+ * A retirement that does not commit is not a lost kill: the process is already
649
+ * dead and the record stays inherited, so the next incarnation reads it, finds
650
+ * the pid gone, and retires it then. Failing the whole sweep over it would
651
+ * take the host down for a bookkeeping write.
652
+ */
653
+ const retire = (write, pid, what) => write.pipe(Effect.catch((error) => Effect.logWarning(`process reaper could not journal ${what} for ${pid}`, error)));
654
+ /**
655
+ * Refusals that leave a dead incarnation's process running with no live owner
656
+ * to contain it: the host could not ask, or its signal failed.
657
+ */
658
+ const unreaped = new Set(["identity-unverified", "own-group-unknown", "kill-failed"]);
659
+ /**
660
+ * Counter over inherited records the reaper did not kill, with a `refusal`
661
+ * attribute naming why.
662
+ *
663
+ * @category metrics
664
+ * @since 1.0.0-rc.1
665
+ */
666
+ export const refusals = Metric.counter("flows_process_reaper_refusals", {
667
+ description: "Inherited process records the reaper did not kill, by refusal"
668
+ });
669
+ /**
670
+ * Reports one sweep: a counter update per refusal and one summary line. The
671
+ * line is a warning when a record stays inherited (a retained refusal) or a
672
+ * signal failed, because either leaves a crashed incarnation's processes
673
+ * running with nothing else to say so.
674
+ *
675
+ * @category layers
676
+ * @since 1.0.0-rc.1
677
+ */
678
+ export const report = (decided) => Effect.gen(function* () {
679
+ if (decided.length === 0)
680
+ return;
681
+ const counts = {};
682
+ let killed = 0;
683
+ for (const entry of decided) {
684
+ if (entry.killed) {
685
+ killed += 1;
686
+ continue;
687
+ }
688
+ counts[entry.refusal] = (counts[entry.refusal] ?? 0) + 1;
689
+ }
690
+ for (const [refusal, count] of Object.entries(counts)) {
691
+ yield* Metric.update(Metric.withAttributes(refusals, { refusal }), count);
692
+ }
693
+ const annotations = { killed, ...counts };
694
+ const alarming = decided.some((entry) => !entry.killed && unreaped.has(entry.refusal));
695
+ const line = "process reaper swept inherited records";
696
+ yield* (alarming ? Effect.logWarning(line) : Effect.logInfo(line)).pipe(Effect.annotateLogs(annotations));
697
+ });
698
+ /**
699
+ * Runs {@link reap} once while the layer is built.
700
+ *
701
+ * Compose it into a host layer so standing a host up is also what cleans up
702
+ * after the incarnation that crashed. A history that cannot be read refuses
703
+ * the sweep with an error log and leaves every record inherited; the host
704
+ * still starts, because the processes it will spawn are recorded and
705
+ * contained regardless. Every decision is {@link report}ed.
706
+ *
707
+ * @category layers
708
+ * @since 0.1.0
709
+ */
710
+ export const layer = (options) => Layer.effectDiscard(reap(options).pipe(Effect.flatMap(report), Effect.catchTag("@smthrs/kernel/ProcessLedgerReplayError", (error) => Effect.logError("process reaper refused to sweep: the ledger history is incomplete", error))));
711
+ //# sourceMappingURL=ProcessReaper.js.map