@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,807 @@
1
+ /**
2
+ * Private parent connection for a POSIX process owner. Effect retains ownership
3
+ * of the caller's streams; separate sockets carry requests and lifetime status.
4
+ * @since 1.0.0
5
+ */
6
+
7
+ import type { Lifecycle } from "@smthrs/kernel/ContainedSpawner"
8
+ import * as Channel from "effect/Channel"
9
+ import * as Clock from "effect/Clock"
10
+ import * as Effect from "effect/Effect"
11
+ import * as PlatformError from "effect/PlatformError"
12
+ import * as Sink from "effect/Sink"
13
+ import * as Stream from "effect/Stream"
14
+ import * as ChildProcess from "effect/unstable/process/ChildProcess"
15
+ import { type ChildProcessHandle, ExitCode, makeHandle } from "effect/unstable/process/ChildProcessSpawner"
16
+ import { randomBytes } from "node:crypto"
17
+ import { chmodSync, mkdtempSync, rmdirSync, rmSync } from "node:fs"
18
+ import { createConnection, createServer, type Socket } from "node:net"
19
+ import { tmpdir } from "node:os"
20
+ import { join, parse, resolve } from "node:path"
21
+ import * as Tls from "node:tls"
22
+ import { standardFdsOf } from "./PipedProcess.ts"
23
+ import type { Policy, Snapshot, System } from "./ProcessCleanup.ts"
24
+ import { NativeProcessError, processFault } from "./ProcessFault.ts"
25
+ import { source } from "./SupervisorProgram.ts"
26
+ import { resolveJobExecutable, WindowsProcessJob } from "./WindowsProcessJob.ts"
27
+
28
+ const startupMs = 5000
29
+ const deliveryMs = 500
30
+ const exitAllowanceMs = 2500
31
+ // Host-wide process observations can exceed a socket-delivery deadline on a
32
+ // loaded machine. Keep verification bounded without mistaking that delay for
33
+ // an unclean exit; an unknown observation still never counts as success.
34
+ const verificationMs = 2500
35
+ const targets = new WeakMap<ChildProcessHandle, Control>()
36
+ // Native owners and sockets keep running when the caller freezes its Clock.
37
+ // Their delivery bounds and cleanup retries must keep running with them.
38
+ const processClock = Clock.Clock.defaultValue()
39
+
40
+ /**
41
+ * Actual service pid, distinct from the owner recorded by the host.
42
+ * @private
43
+ * @since 1.0.0
44
+ */
45
+ export const targetPidOf = (handle: ChildProcessHandle): number | undefined => targets.get(handle)?.targetPid
46
+
47
+ /** Native error fields remain data on the public PlatformError cause. */
48
+ const nativeError = (cause: unknown): Error & { code?: string | undefined; syscall?: string | undefined } => {
49
+ if (cause instanceof Error) return cause
50
+ const value = (cause ?? {}) as Record<string, unknown>
51
+ const text = (field: string): string | undefined => typeof value[field] === "string" ? value[field] : undefined
52
+ return new NativeProcessError({
53
+ message: text("message") ?? "The process supervisor failed",
54
+ code: text("code"),
55
+ errno: typeof value.errno === "number" ? value.errno : undefined,
56
+ reason: text("reason"),
57
+ syscall: text("syscall"),
58
+ path: text("path"),
59
+ signal: text("signal")
60
+ })
61
+ }
62
+
63
+ /**
64
+ * Preserve the platform's errno and signal vocabulary across the private wire.
65
+ * @private
66
+ * @since 1.0.0
67
+ */
68
+ export const failure = (method: string, command: string, cause: unknown): PlatformError.PlatformError => {
69
+ const error = nativeError(cause)
70
+ const tags: Readonly<Record<string, PlatformError.SystemErrorTag>> = {
71
+ ENOENT: "NotFound",
72
+ EACCES: "PermissionDenied",
73
+ EEXIST: "AlreadyExists",
74
+ EISDIR: "BadResource",
75
+ ENOTDIR: "BadResource",
76
+ ELOOP: "BadResource",
77
+ EBUSY: "Busy"
78
+ }
79
+ return PlatformError.systemError({
80
+ _tag: tags[error.code ?? ""] ?? "Unknown",
81
+ module: "ChildProcess",
82
+ method,
83
+ pathOrDescriptor: command,
84
+ syscall: error.syscall,
85
+ description: error.message,
86
+ cause: error
87
+ })
88
+ }
89
+
90
+ /**
91
+ * The observation behind an unverified cleanup, in the message itself: a
92
+ * failure report usually shows only the message, and whether the receipt, the
93
+ * kernel or the snapshot was missing decides host load versus a live survivor.
94
+ * @private
95
+ * @since 1.0.0
96
+ */
97
+ export const unverifiedCleanup = (
98
+ control: {
99
+ readonly fault: unknown
100
+ readonly cleanupFailed: boolean
101
+ readonly cleanupAcknowledged: boolean
102
+ readonly targetDone: boolean
103
+ },
104
+ cleanupRequired: boolean,
105
+ vacant: boolean,
106
+ observed: Snapshot | undefined
107
+ ): string =>
108
+ [
109
+ `target exited: ${control.targetDone}`,
110
+ `cleanup receipt: ${
111
+ control.cleanupFailed
112
+ ? "failed"
113
+ : !cleanupRequired
114
+ ? "not required"
115
+ : control.cleanupAcknowledged
116
+ ? "acknowledged"
117
+ : "missing"
118
+ }`,
119
+ `group vacant: ${vacant}`,
120
+ observed === undefined
121
+ ? "group snapshot: unavailable"
122
+ : `group members: ${
123
+ observed.members.length === 0
124
+ ? "none"
125
+ : observed.members.map((member) => `${member.pid} ${member.zombie ? "zombie" : "live"}`).join(", ")
126
+ }; host group ${observed.ownGroup}`,
127
+ ...(control.fault === undefined
128
+ ? []
129
+ : [`fault: ${String((control.fault as { message?: unknown })?.message ?? control.fault)}`])
130
+ ].join("; ")
131
+
132
+ const promise = <A>() => {
133
+ let resolve!: (value: A) => void
134
+ let reject!: (cause: unknown) => void
135
+ const promise = new Promise<A>((yes, no) => {
136
+ resolve = yes
137
+ reject = no
138
+ })
139
+ // A status may arrive before its Effect consumer starts waiting.
140
+ void promise.catch(() => {})
141
+ return { promise, resolve, reject }
142
+ }
143
+
144
+ const wait = <A>(value: Promise<A>, method: string, command: string) =>
145
+ Effect.tryPromise({ try: () => value, catch: (cause) => failure(method, command, cause) })
146
+
147
+ const bounded = <A, E, R>(effect: Effect.Effect<A, E, R>, millis: number, method: string, command: string) =>
148
+ effect.pipe(
149
+ Effect.timeoutOrElse({
150
+ duration: millis,
151
+ orElse: () =>
152
+ Effect.fail(
153
+ failure(method, command, processFault("supervisor_timeout", `Process supervisor ${method} timed out`))
154
+ )
155
+ }),
156
+ Effect.provideService(Clock.Clock, processClock)
157
+ )
158
+
159
+ /**
160
+ * Standalone application executables do not implement the runtime's eval CLI.
161
+ * Refuse them before spawning rather than recursively launching the application.
162
+ * @private
163
+ * @since 1.0.0
164
+ */
165
+ export const bootstrapArguments = (runtime: { readonly bun: boolean; readonly main: string; readonly sea: boolean }) =>
166
+ runtime.sea || runtime.main.startsWith("/$bunfs/")
167
+ ? Effect.fail(
168
+ failure(
169
+ "spawn",
170
+ process.execPath,
171
+ processFault(
172
+ "runtime_unsupported",
173
+ "Process supervision requires a Node or Bun runtime executable, not a compiled application"
174
+ )
175
+ )
176
+ )
177
+ : Effect.succeed(runtime.bun ? ["--no-env-file", "--config=/dev/null"] : [])
178
+
179
+ const channelEnvironment = "SMITHERS_PROCESS_CHANNEL"
180
+ const tlsOptions = { minVersion: "TLSv1.3", maxVersion: "TLSv1.3", ciphers: "TLS_AES_128_GCM_SHA256" } as const
181
+
182
+ /**
183
+ * Connect an owner to its authenticated private channel.
184
+ * @private
185
+ * @since 1.0.0
186
+ */
187
+ export const connectOwner = (path: string, environment: Readonly<Record<string, string | undefined>>): Socket => {
188
+ const encoded = environment[channelEnvironment]
189
+ if (encoded === undefined) return createConnection(path)
190
+ const channel = JSON.parse(encoded) as { key: string; status: number; requests: number }
191
+ return Tls.connect({
192
+ ...tlsOptions,
193
+ host: "127.0.0.1",
194
+ port: path.endsWith("/r") ? channel.requests : channel.status,
195
+ pskCallback: () => ({ identity: "smithers-owner", psk: Buffer.from(channel.key, "hex") })
196
+ })
197
+ }
198
+
199
+ /**
200
+ * Kept separate from Effect scopes so native socket callbacks only settle
201
+ * promises; none can start an unowned fiber or signal an observed process id.
202
+ * @private
203
+ * @since 1.0.0
204
+ */
205
+ export class Control {
206
+ readonly ready = promise<number>()
207
+ readonly started = promise<void>()
208
+ readonly exited = promise<ExitCode>()
209
+ readonly lost = promise<never>()
210
+ readonly ended = promise<void>()
211
+ readonly requestsReady = promise<void>()
212
+ readonly directory: string
213
+ readonly path: string
214
+ readonly requestPath: string
215
+ readonly server
216
+ readonly requestServer
217
+ readonly listening: Promise<void>
218
+ private readonly key: Buffer | undefined
219
+ private readonly connections = new Set<Socket>()
220
+ socket: Socket | undefined
221
+ requestSocket: Socket | undefined
222
+ targetDone = false
223
+ ownerCreation: unknown
224
+ targetPid: number | undefined
225
+ /** The owner's group guardian: a member that is neither target nor owner. */
226
+ guardianPid: number | undefined
227
+ ownerDone = false
228
+ spawnFailed = false
229
+ cleanupFailed = false
230
+ cleanupAcknowledged = false
231
+ activationSent = false
232
+ closeSent = false
233
+ fault: unknown
234
+ onTargetExit: () => void = () => {}
235
+ onCleanup: () => void = () => {}
236
+ private receivedReady = false
237
+ private receivedStarted = false
238
+ private withdrawn = false
239
+
240
+ constructor(transport: "native" | "tls" = "native") {
241
+ this.key = transport === "tls" || process.platform === "win32" ? randomBytes(32) : undefined
242
+ this.directory = mkdtempSync(this.key === undefined ? "/tmp/sm-p-" : join(tmpdir(), "sm-p-"))
243
+ this.path = `${this.directory}/s`
244
+ this.requestPath = `${this.directory}/r`
245
+ const servers: Array<ReturnType<typeof createServer>> = []
246
+ try {
247
+ chmodSync(this.directory, 0o700)
248
+ this.server = this.makeServer((socket) => this.accept(socket))
249
+ servers.push(this.server)
250
+ this.requestServer = this.makeServer((socket) => this.acceptRequests(socket))
251
+ servers.push(this.requestServer)
252
+ this.listening = Promise.all([
253
+ new Promise<void>((resolve, reject) => {
254
+ this.server.once("error", reject)
255
+ if (this.key === undefined) this.server.listen(this.path, resolve)
256
+ else this.server.listen(0, "127.0.0.1", resolve)
257
+ }),
258
+ new Promise<void>((resolve, reject) => {
259
+ this.requestServer.once("error", reject)
260
+ if (this.key === undefined) this.requestServer.listen(this.requestPath, resolve)
261
+ else this.requestServer.listen(0, "127.0.0.1", resolve)
262
+ })
263
+ ]).then(() => {})
264
+ } catch (cause) {
265
+ for (const server of servers) server.close()
266
+ rmSync(this.directory, { recursive: true, force: true })
267
+ throw cause
268
+ }
269
+ }
270
+
271
+ private makeServer(accept: (socket: Socket) => void): ReturnType<typeof createServer> {
272
+ if (this.key === undefined) return createServer(accept)
273
+ const server = Tls.createServer({
274
+ ...tlsOptions,
275
+ handshakeTimeout: startupMs,
276
+ pskCallback: (_socket, identity) => identity === "smithers-owner" ? this.key! : null
277
+ }, accept)
278
+ server.on("connection", (socket) => {
279
+ this.connections.add(socket)
280
+ socket.once("close", () => this.connections.delete(socket))
281
+ })
282
+ server.on("tlsClientError", (_error, socket) => socket.destroy())
283
+ return server
284
+ }
285
+
286
+ /** Only the trusted owner receives this environment; target configuration replaces it. */
287
+ environment(): Readonly<Record<string, string>> {
288
+ if (this.key === undefined) return {}
289
+ const status = this.server.address() as { port: number }
290
+ const requests = this.requestServer.address() as { port: number }
291
+ return {
292
+ [channelEnvironment]: JSON.stringify({
293
+ key: this.key.toString("hex"),
294
+ status: status.port,
295
+ requests: requests.port
296
+ })
297
+ }
298
+ }
299
+
300
+ /** The test peer uses the same authenticated transport as the isolated owner. */
301
+ connect(requests = false): Socket {
302
+ return connectOwner(requests ? this.requestPath : this.path, this.environment())
303
+ }
304
+
305
+ /** Validate the stored READY after the raw spawn effect has returned its pid. */
306
+ withdraw(pid: number, actual: number): void {
307
+ if (pid !== actual) throw processFault("identity_mismatch", "Wrong supervisor identity")
308
+ this.server.close()
309
+ this.server.unref()
310
+ this.requestServer.close()
311
+ this.requestServer.unref()
312
+ // Node may unlink the owned socket synchronously inside server.close().
313
+ rmSync(this.path, { force: true })
314
+ rmSync(this.requestPath, { force: true })
315
+ rmdirSync(this.directory)
316
+ this.withdrawn = true
317
+ }
318
+
319
+ /** Request EOF asks for cleanup; leave its independent status reader intact. */
320
+ disconnect(): void {
321
+ this.requestSocket?.destroy()
322
+ }
323
+
324
+ dispose(): void {
325
+ for (const socket of this.connections) socket.destroy()
326
+ this.disconnect()
327
+ this.socket?.destroy()
328
+ this.server.close()
329
+ this.requestServer.close()
330
+ if (!this.withdrawn) rmSync(this.directory, { recursive: true, force: true })
331
+ }
332
+
333
+ rawEnded(): void {
334
+ this.ownerDone = true
335
+ // An accepted socket may still have buffered status frames. Its close event
336
+ // rejects missing outcomes only after Node has delivered those frames.
337
+ if (this.socket === undefined) this.closed()
338
+ }
339
+
340
+ write(message: unknown): Promise<void> {
341
+ return new Promise((resolve, reject) => {
342
+ const socket = this.requestSocket
343
+ if (socket === undefined || socket.destroyed || !socket.writable) {
344
+ reject(processFault("control_channel_closed", "Private process control channel closed"))
345
+ return
346
+ }
347
+ const data = `${JSON.stringify(message)}\n`
348
+ if (Buffer.byteLength(data) > 4 * 1024 * 1024) {
349
+ reject(processFault("configuration_too_large", "Process configuration exceeds the private frame limit"))
350
+ return
351
+ }
352
+ socket.write(data, (error) => error ? reject(error) : resolve())
353
+ })
354
+ }
355
+
356
+ private closed(): void {
357
+ this.disconnect()
358
+ const cause = this.fault ??
359
+ processFault("outcome_missing", "Process supervisor closed before reporting its outcome")
360
+ if (this.activationSent && !this.targetDone && !this.spawnFailed) this.lost.reject(cause)
361
+ this.ready.reject(cause)
362
+ this.requestsReady.reject(cause)
363
+ this.started.reject(cause)
364
+ this.exited.reject(cause)
365
+ this.ended.resolve()
366
+ }
367
+
368
+ private acceptRequests(socket: Socket): void {
369
+ if (this.requestSocket !== undefined) {
370
+ socket.destroy()
371
+ return
372
+ }
373
+ this.requestSocket = socket
374
+ // A late write may fail after the owner has sent its last status frames.
375
+ // Destroying this socket must never discard those frames on the reader.
376
+ socket.on("error", (cause) => {
377
+ this.fault = cause
378
+ })
379
+ this.requestsReady.resolve()
380
+ }
381
+
382
+ private accept(socket: Socket): void {
383
+ if (this.socket !== undefined) {
384
+ socket.destroy()
385
+ return
386
+ }
387
+ this.socket = socket
388
+ let buffer = ""
389
+ socket.setEncoding("utf8")
390
+ socket.on("data", (data: string) => {
391
+ try {
392
+ buffer += data
393
+ if (Buffer.byteLength(buffer) > 16 * 1024) {
394
+ throw processFault("status_too_large", "Process status frame exceeds its limit")
395
+ }
396
+ for (;;) {
397
+ const end = buffer.indexOf("\n")
398
+ if (end < 0) break
399
+ const line = buffer.slice(0, end)
400
+ buffer = buffer.slice(end + 1)
401
+ this.receive(JSON.parse(line))
402
+ }
403
+ } catch (cause) {
404
+ this.fault = cause
405
+ socket.destroy()
406
+ }
407
+ })
408
+ socket.on("error", (cause) => {
409
+ this.fault = cause
410
+ })
411
+ socket.once("close", () => this.closed())
412
+ }
413
+
414
+ private receive(value: unknown): void {
415
+ if (typeof value !== "object" || value === null) throw processFault("status_invalid", "Invalid process status")
416
+ const message = value as Record<string, unknown>
417
+ switch (message.type) {
418
+ case "ready":
419
+ if (
420
+ this.receivedReady || message.version !== 1 || !Number.isSafeInteger(message.pid) || Number(message.pid) <= 1
421
+ ) {
422
+ throw processFault("status_invalid", "Invalid process readiness")
423
+ }
424
+ this.receivedReady = true
425
+ this.ownerCreation = message.created
426
+ this.ready.resolve(Number(message.pid))
427
+ return
428
+ case "spawned":
429
+ if (
430
+ !this.activationSent || this.receivedStarted || !Number.isSafeInteger(message.pid) ||
431
+ Number(message.pid) <= 1 ||
432
+ message.guardian !== undefined && (!Number.isSafeInteger(message.guardian) || Number(message.guardian) <= 1)
433
+ ) {
434
+ throw processFault("status_invalid", "Invalid target startup")
435
+ }
436
+ this.receivedStarted = true
437
+ this.targetPid = Number(message.pid)
438
+ if (message.guardian !== undefined) this.guardianPid = Number(message.guardian)
439
+ this.started.resolve()
440
+ return
441
+ case "spawn_error":
442
+ if (!this.activationSent || this.receivedStarted) {
443
+ throw processFault("status_invalid", "Invalid target spawn failure")
444
+ }
445
+ this.spawnFailed = true
446
+ this.fault = message
447
+ this.started.reject(message)
448
+ this.exited.reject(message)
449
+ return
450
+ case "fault":
451
+ this.fault = message
452
+ this.started.reject(message)
453
+ this.exited.reject(message)
454
+ return
455
+ case "exit":
456
+ if (
457
+ !this.receivedStarted || this.targetDone ||
458
+ !(Number.isInteger(message.code) && Number(message.code) >= 0 && message.signal === null ||
459
+ message.code === null && typeof message.signal === "string" && /^SIG[A-Z0-9]+$/.test(message.signal))
460
+ ) {
461
+ throw processFault("status_invalid", "Invalid target exit status")
462
+ }
463
+ this.targetDone = true
464
+ if (message.code === null) {
465
+ this.exited.reject({
466
+ message: `Process interrupted due to receipt of signal: '${message.signal}'`,
467
+ signal: message.signal
468
+ })
469
+ } else this.exited.resolve(ExitCode(Number(message.code)))
470
+ this.onTargetExit()
471
+ return
472
+ case "cleanup_error":
473
+ this.cleanupFailed = true
474
+ this.fault = message
475
+ return
476
+ case "cleanup":
477
+ this.cleanupAcknowledged = true
478
+ this.onCleanup()
479
+ return
480
+ default:
481
+ throw processFault("status_unknown", "Unknown process status")
482
+ }
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Prepare a private, independently bounded process owner before target launch.
488
+ * @private
489
+ * @since 1.0.0
490
+ */
491
+ export const prepare = (
492
+ system: System,
493
+ policy: (
494
+ options: ChildProcess.KillOptions,
495
+ defaults?: ChildProcess.KillOptions
496
+ ) => Effect.Effect<Policy, PlatformError.PlatformError>,
497
+ transport: "native" | "tls" = "native"
498
+ ): Lifecycle =>
499
+ (command, spawn) =>
500
+ Effect.gen(function*() {
501
+ const initial = yield* policy(command.options)
502
+ const bun = process.versions.bun !== undefined
503
+ const sea = bun ? false : (yield* Effect.tryPromise({
504
+ try: () => import("node:sea"),
505
+ catch: (cause) => failure("spawn", process.execPath, cause)
506
+ })).isSea()
507
+ const bootstrap = yield* bootstrapArguments({
508
+ bun,
509
+ sea,
510
+ main: (globalThis as { readonly Bun?: { readonly main?: string } }).Bun?.main ?? ""
511
+ })
512
+ const windows = system.platform === "win32"
513
+ const grouped = !windows && (command.options.detached ?? true)
514
+ const jobExecutable = windows ?
515
+ yield* Effect.try({
516
+ try: resolveJobExecutable,
517
+ catch: (cause) => failure("spawn", command.command, cause)
518
+ }) :
519
+ undefined
520
+ const control = yield* Effect.acquireRelease(
521
+ Effect.try({ try: () => new Control(transport), catch: (cause) => failure("spawn", command.command, cause) }),
522
+ (control) => Effect.sync(() => control.dispose())
523
+ )
524
+ yield* bounded(wait(control.listening, "spawn", command.command), startupMs, "spawn", command.command)
525
+ const raw = yield* spawn(ChildProcess.make(process.execPath, [
526
+ ...bootstrap,
527
+ "-e",
528
+ source,
529
+ control.path,
530
+ grouped ? "group" : "direct"
531
+ ], {
532
+ ...command.options,
533
+ cwd: parse(process.execPath).root,
534
+ env: {
535
+ PATH: "/usr/bin:/bin",
536
+ HOME: "/",
537
+ XDG_CONFIG_HOME: "/",
538
+ BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0",
539
+ ...control.environment(),
540
+ ...(jobExecutable === undefined ? {} : { SMITHERS_PROCESS_JOB_HELPER: jobExecutable })
541
+ },
542
+ extendEnv: false,
543
+ shell: false,
544
+ detached: grouped,
545
+ killSignal: "SIGTERM",
546
+ forceKillAfter: initial.graceMs
547
+ }))
548
+ yield* Effect.exit(raw.exitCode).pipe(Effect.andThen(Effect.sync(() => control.rawEnded())), Effect.forkScoped)
549
+ let job: WindowsProcessJob | undefined
550
+ let settled = false
551
+ let referenced = true
552
+ let reref: Effect.Effect<void, PlatformError.PlatformError> = Effect.void
553
+ let selected = initial
554
+ let requireCleanupReceipt = false
555
+ const snapshot = () => system.snapshot(raw.pid)
556
+ const alone = () => {
557
+ if (!grouped) return control.targetDone
558
+ const observed = snapshot()
559
+ if (observed === undefined || observed.ownGroup === raw.pid) return false
560
+ // The guardian leaves with the owner's final group SIGKILL.
561
+ const running = observed.members.filter((member) => !member.zombie && member.pid !== control.guardianPid)
562
+ return running.length === 1 && running[0]!.pid === raw.pid
563
+ }
564
+ // This observation only shortens the owner's deadline. The live owner makes
565
+ // the signal, so neither a stale observation nor a reused pid grants a kill.
566
+ control.onTargetExit = () => {
567
+ // An explicit stop already owns its deadline and escaped-child sweep.
568
+ // Natural exit must not replace that policy with a second fast stop.
569
+ if (control.closeSent) return
570
+ if (!alone()) return
571
+ control.closeSent = true
572
+ void control.write({ type: "stop", killSignal: "SIGKILL", fast: true }).catch(() => control.disconnect())
573
+ }
574
+ const finish = yield* Effect.cached(Effect.gen(function*() {
575
+ yield* bounded(Effect.exit(raw.exitCode), selected.graceMs + exitAllowanceMs, "kill", command.command).pipe(
576
+ Effect.catch((cause) =>
577
+ job === undefined ? Effect.fail(cause) : Effect.gen(function*() {
578
+ // The native guardian can terminate a stalled owner independently.
579
+ job!.stop()
580
+ yield* bounded(Effect.exit(raw.exitCode), exitAllowanceMs, "kill", command.command)
581
+ })
582
+ )
583
+ )
584
+ if (job !== undefined) {
585
+ yield* bounded(wait(job.settled.promise, "kill", command.command), 5500, "kill", command.command)
586
+ settled = true
587
+ return
588
+ }
589
+ yield* bounded(wait(control.ended.promise, "kill", command.command), deliveryMs, "kill", command.command).pipe(
590
+ Effect.ignore
591
+ )
592
+ const deadline = Date.now() + verificationMs
593
+ for (;;) {
594
+ // The kernel's ESRCH proves the group empty with no fork. A `ps`
595
+ // snapshot can go unanswered on a loaded host, so it only decides what
596
+ // the kernel cannot: a group still holding zombies, or an unknown one.
597
+ // A live member keeps both answers false. This host is alive, so a
598
+ // vacant group is never this host's own group.
599
+ const vacant = grouped && system.vacant(raw.pid)
600
+ const observed = grouped && !vacant ? snapshot() : undefined
601
+ settled = !control.cleanupFailed && (!requireCleanupReceipt || control.cleanupAcknowledged) && (grouped
602
+ ? vacant ||
603
+ observed !== undefined && observed.ownGroup !== raw.pid && observed.members.every((member) => member.zombie)
604
+ : control.targetDone || control.spawnFailed || !control.activationSent)
605
+ if (settled) return
606
+ if (Date.now() >= deadline) {
607
+ return yield* Effect.fail(
608
+ failure(
609
+ "kill",
610
+ command.command,
611
+ processFault(
612
+ "cleanup_unverified",
613
+ "Process cleanup could not be verified; its ledger record is retained " +
614
+ `(${unverifiedCleanup(control, requireCleanupReceipt, vacant, observed)})`,
615
+ {
616
+ cause: {
617
+ fault: control.fault,
618
+ cleanupFailed: control.cleanupFailed,
619
+ cleanupRequired: requireCleanupReceipt,
620
+ cleanupAcknowledged: control.cleanupAcknowledged,
621
+ targetDone: control.targetDone,
622
+ groupVacant: vacant,
623
+ ownerObserved: observed !== undefined,
624
+ members: observed?.members
625
+ }
626
+ }
627
+ )
628
+ )
629
+ )
630
+ }
631
+ yield* Effect.sleep(10).pipe(Effect.provideService(Clock.Clock, processClock))
632
+ }
633
+ }))
634
+ const kill = (options: ChildProcess.KillOptions = {}) =>
635
+ Effect.gen(function*() {
636
+ const requested = yield* policy(options, command.options)
637
+ if (!referenced) {
638
+ job?.reference(true)
639
+ control.socket?.ref()
640
+ control.requestSocket?.ref()
641
+ yield* reref
642
+ referenced = true
643
+ }
644
+ if (!control.closeSent) {
645
+ control.closeSent = true
646
+ selected = requested
647
+ // An empty original group cannot prove an explicit escaped-descendant
648
+ // sweep succeeded if its status frames were lost. Startup and natural
649
+ // completion have no such additional contract.
650
+ requireCleanupReceipt = grouped && control.activationSent && !control.spawnFailed && !control.targetDone
651
+ yield* bounded(
652
+ wait(
653
+ control.write({
654
+ type: "stop",
655
+ explicit: true,
656
+ ...requested,
657
+ // A live target can move out of this group with setsid().
658
+ // Only an owner whose target was never activated can replace
659
+ // the requested signal; natural exit has its own fast path.
660
+ killSignal: !control.activationSent && alone() ? "SIGKILL" : requested.killSignal
661
+ }),
662
+ "kill",
663
+ command.command
664
+ ),
665
+ deliveryMs,
666
+ "kill",
667
+ command.command
668
+ )
669
+ .pipe(Effect.catch(() => Effect.sync(() => control.disconnect())))
670
+ }
671
+ yield* finish
672
+ }).pipe(Effect.uninterruptible)
673
+ yield* Effect.addFinalizer(() =>
674
+ kill().pipe(
675
+ // A stuck owner keeps its ledger entry. Disable the underlying spawner's
676
+ // unconditional group-kill finalizer rather than signal a stale identity.
677
+ Effect.ensuring(
678
+ Effect.suspend(() =>
679
+ settled ? Effect.void : Effect.andThen(
680
+ raw.unref,
681
+ Effect.sync(() => {
682
+ job?.stop()
683
+ job?.reference(false)
684
+ control.disconnect()
685
+ })
686
+ )
687
+ ).pipe(Effect.orDie)
688
+ ),
689
+ Effect.orDie
690
+ )
691
+ )
692
+ const ready = yield* bounded(
693
+ wait(control.ready.promise, "spawn", command.command),
694
+ startupMs,
695
+ "spawn",
696
+ command.command
697
+ )
698
+ yield* bounded(wait(control.requestsReady.promise, "spawn", command.command), startupMs, "spawn", command.command)
699
+ yield* Effect.try({
700
+ try: () => control.withdraw(ready, raw.pid),
701
+ catch: (cause) => failure("spawn", command.command, cause)
702
+ })
703
+ if (windows) {
704
+ job = yield* Effect.try({
705
+ try: () => new WindowsProcessJob(raw.pid, control.ownerCreation, jobExecutable!),
706
+ catch: (cause) => failure("spawn", command.command, cause)
707
+ })
708
+ yield* bounded(wait(job.ready.promise, "spawn", command.command), startupMs, "spawn", command.command)
709
+ }
710
+ const acknowledgeCleanup = windows || transport === "tls"
711
+ if (acknowledgeCleanup) {
712
+ control.onCleanup = () => {
713
+ if (!control.ownerDone) {
714
+ void control.write({ type: "cleanup_ack" }).catch(() => control.disconnect())
715
+ }
716
+ }
717
+ }
718
+ const options = command.options
719
+ // Match Effect/Node's undefined-vs-empty environment semantics in the host,
720
+ // before replacing the helper's environment with its isolated bootstrap.
721
+ const env = options.extendEnv ? { ...process.env, ...options.env } : options.env ?? { ...process.env }
722
+ yield* bounded(
723
+ wait(
724
+ control.write({
725
+ type: "configure",
726
+ acknowledgeCleanup,
727
+ command: command.command,
728
+ args: command.args,
729
+ cwd: resolve(options.cwd ?? process.cwd()),
730
+ env,
731
+ shell: options.shell,
732
+ windowsHide: options.windowsHide ?? true,
733
+ windowsVerbatimArguments:
734
+ (options as ChildProcess.CommandOptions & { readonly windowsVerbatimArguments?: boolean })
735
+ .windowsVerbatimArguments,
736
+ standardFds: standardFdsOf(raw),
737
+ userFds: [
738
+ ...new Set(
739
+ Object.keys(options.additionalFds ?? {}).map(ChildProcess.parseFdName)
740
+ .filter((fd): fd is number => fd !== undefined)
741
+ )
742
+ ],
743
+ ...initial
744
+ }),
745
+ "spawn",
746
+ command.command
747
+ ),
748
+ deliveryMs,
749
+ "spawn",
750
+ command.command
751
+ )
752
+ const activate = yield* Effect.cached(Effect.gen(function*() {
753
+ control.activationSent = true
754
+ yield* bounded(
755
+ wait(control.write({ type: "start" }), "spawn", command.command),
756
+ deliveryMs,
757
+ "spawn",
758
+ command.command
759
+ )
760
+ yield* bounded(wait(control.started.promise, "spawn", command.command), startupMs, "spawn", command.command)
761
+ }))
762
+ const unref = Effect.gen(function*() {
763
+ if (referenced) {
764
+ reref = yield* raw.unref
765
+ job?.reference(false)
766
+ control.socket?.unref()
767
+ control.requestSocket?.unref()
768
+ referenced = false
769
+ }
770
+ return Effect.gen(function*() {
771
+ if (!referenced) {
772
+ job?.reference(true)
773
+ control.socket?.ref()
774
+ control.requestSocket?.ref()
775
+ yield* reref
776
+ referenced = true
777
+ }
778
+ })
779
+ })
780
+ const output = <A>(stream: Stream.Stream<A, PlatformError.PlatformError>) =>
781
+ stream.pipe(
782
+ Stream.interruptWhen(wait(control.lost.promise, "read", command.command))
783
+ )
784
+ const input = <A>(sink: Sink.Sink<A, Uint8Array, never, PlatformError.PlatformError>) =>
785
+ Sink.fromChannel(
786
+ Sink.toChannel(sink).pipe(Channel.interruptWhen(wait(control.lost.promise, "write", command.command)))
787
+ )
788
+ const handle = makeHandle({
789
+ ...raw,
790
+ exitCode: wait(control.exited.promise, "exitCode", command.command),
791
+ isRunning: Effect.sync(() => !control.targetDone && !control.ownerDone),
792
+ stdin: input(raw.stdin),
793
+ getInputFd: (fd) => input(raw.getInputFd(fd)),
794
+ stdout: output(raw.stdout),
795
+ stderr: output(raw.stderr),
796
+ all: output(raw.all),
797
+ getOutputFd: (fd) => output(raw.getOutputFd(fd)),
798
+ kill,
799
+ unref
800
+ })
801
+ targets.set(handle, control)
802
+ return {
803
+ handle,
804
+ activate,
805
+ settled: Effect.sync(() => settled)
806
+ }
807
+ })