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

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 +287 -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 +377 -0
  34. package/dist/cjs/ProcessSandbox.d.ts.map +1 -0
  35. package/dist/cjs/ProcessSandbox.js +759 -0
  36. package/dist/cjs/ProcessSandbox.js.map +7 -0
  37. package/dist/cjs/ScopedProcess.d.ts +65 -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 +141 -0
  86. package/dist/cjs/internal/ProcessSupervisor.d.ts.map +1 -0
  87. package/dist/cjs/internal/ProcessSupervisor.js +682 -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 +306 -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 +377 -0
  123. package/dist/esm/ProcessSandbox.d.ts.map +1 -0
  124. package/dist/esm/ProcessSandbox.js +1014 -0
  125. package/dist/esm/ProcessSandbox.js.map +1 -0
  126. package/dist/esm/ScopedProcess.d.ts +65 -0
  127. package/dist/esm/ScopedProcess.d.ts.map +1 -0
  128. package/dist/esm/ScopedProcess.js +66 -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 +141 -0
  175. package/dist/esm/internal/ProcessSupervisor.d.ts.map +1 -0
  176. package/dist/esm/internal/ProcessSupervisor.js +682 -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 +290 -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 +552 -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 +182 -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 +356 -0
  426. package/src/ProcessReaper.ts +951 -0
  427. package/src/ProcessSandbox.ts +1273 -0
  428. package/src/ScopedProcess.ts +123 -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 +801 -0
  441. package/src/internal/SupervisorProgram.ts +289 -0
  442. package/src/internal/WindowsProcessJob.ts +114 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * The outbound HTTP client a Node process should use, read off its environment.
3
+ *
4
+ * `@effect/platform-node` ships `NodeHttpClient.layerUndici`, and its
5
+ * dispatcher is a bare Undici `Agent`. A bare `Agent` dials every origin
6
+ * directly: it does not read `HTTP_PROXY`, `HTTPS_PROXY` or `NO_PROXY`, and
7
+ * nothing at the call site says so. That is invisible on a developer machine
8
+ * with open egress and fatal inside a sandbox whose egress is default-deny
9
+ * behind a named proxy — the request leaves for the origin, the firewall drops
10
+ * it, and the only symptom is a transport failure far from the composition
11
+ * that chose the client.
12
+ *
13
+ * This module is the one place that decision is made. {@link layer} is the
14
+ * client every Node host composition installs; it honours the proxy the
15
+ * environment names. Requests without a web destination use a shared pool;
16
+ * web requests receive a fresh pinned dispatcher.
17
+ *
18
+ * The rule for loopback is fixed here, not by the environment: `localhost`,
19
+ * `127.0.0.1` and `[::1]` are always reached directly, even when the
20
+ * environment names a proxy and no exclusion, and every other origin follows
21
+ * `NO_PROXY`. A proxy is how a process leaves its machine, and
22
+ * `--remote http://127.0.0.1:3000` is not leaving it. The exemption is those
23
+ * three names and nothing wider: Undici matches `NO_PROXY` entries by name,
24
+ * never by resolved address, so `127.0.0.2` or a hostname that resolves to
25
+ * loopback is an origin like any other and goes through the proxy.
26
+ *
27
+ * @since 1.0.0-rc.0
28
+ */
29
+
30
+ import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient"
31
+ import type * as Undici from "@effect/platform-node/Undici"
32
+ import { GrantStore } from "@smthrs/kernel/GrantStore"
33
+ import * as KernelHttpClient from "@smthrs/kernel/HttpClient"
34
+ import { Destination, withDestinationPinning } from "@smthrs/kernel/HttpClient"
35
+ import * as Effect from "effect/Effect"
36
+ import * as Exit from "effect/Exit"
37
+ import * as Layer from "effect/Layer"
38
+ import * as Schema from "effect/Schema"
39
+ import * as Scope from "effect/Scope"
40
+ import * as Semaphore from "effect/Semaphore"
41
+ import { HttpClient } from "effect/unstable/http/HttpClient"
42
+ import * as EffectHttpClient from "effect/unstable/http/HttpClient"
43
+ import * as HttpClientError from "effect/unstable/http/HttpClientError"
44
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest"
45
+ import { isIP } from "node:net"
46
+
47
+ /**
48
+ * A pinned connection asked for an address family none of the authorized
49
+ * addresses has. It is the `cause` of the `TransportError` the request fails
50
+ * with; `code` is always `no_approved_address`.
51
+ *
52
+ * @category errors
53
+ * @since 1.0.0
54
+ */
55
+ export class EgressAddressError extends Schema.TaggedError<EgressAddressError>()(
56
+ "@smthrs/platform-node/EgressAddressError",
57
+ { code: Schema.Literal("no_approved_address"), message: Schema.String }
58
+ ) {
59
+ override readonly name = "EgressAddressError"
60
+ }
61
+
62
+ /**
63
+ * The hosts a proxy is never for. A proxy is how a process leaves its machine;
64
+ * these names are the machine itself. Matched by name, the way Undici matches
65
+ * every `NO_PROXY` entry, so the list is exactly these three and not
66
+ * `127.0.0.0/8`.
67
+ */
68
+ const loopback = ["localhost", "127.0.0.1", "::1"] as const
69
+
70
+ /**
71
+ * The exclusion list to hand Undici, given the one the environment names.
72
+ *
73
+ * Undici proxies *every* origin when `NO_PROXY` is empty — `#shouldProxy`
74
+ * returns early with "Always proxy if NO_PROXY is not set or empty" — so a host
75
+ * that names a proxy to reach the internet would also send `smthrs --remote
76
+ * http://127.0.0.1:3000` and a local Ollama at `http://localhost:11434` to it.
77
+ * Nothing in this repository has ever needed `NO_PROXY=127.0.0.1`, because the
78
+ * client these compositions used before ignored the proxy variables outright.
79
+ * So loopback is always excluded, the way Go's `net/http.ProxyFromEnvironment`
80
+ * excludes it, and the environment's own entries are kept beside it.
81
+ *
82
+ * `*` is returned untouched: Undici recognises the wildcard only as the entire
83
+ * value, and it already means every origin is direct.
84
+ */
85
+ const exclusions = (declared: string): string =>
86
+ declared === "*" ? declared : [declared, ...loopback].filter((entry) => entry !== "").join(",")
87
+
88
+ // Split ESM bundles expose CommonJS Undici through default, without synthetic
89
+ // named exports. Node and Bun also expose its constructors through default.
90
+ // Its typings declare `default` as a namespace without them, and `bundler`
91
+ // resolution reads that, so the value is typed as the module it carries.
92
+ const loadUndici = Effect.promise(
93
+ async () => (await import("undici/index.js")).default as unknown as typeof Undici
94
+ )
95
+
96
+ /**
97
+ * An Undici dispatcher that routes through the egress proxy the supplied
98
+ * environment names, or a direct one when it names none.
99
+ *
100
+ * The proxy variables are read in the order Undici itself reads them,
101
+ * lowercase first, and passed explicitly rather than left to
102
+ * `EnvHttpProxyAgent`'s own ambient lookup: a host serving a guest's
103
+ * environment is not the guest, and the pool has to follow the record it was
104
+ * handed. Loopback is always direct; see {@link exclusions}. Each dispatcher is
105
+ * acquired in the caller's scope and destroyed with it, so a composition that
106
+ * builds several still owns every pool it opened.
107
+ *
108
+ * @param environment the environment record whose proxy variables decide the route
109
+ * @category constructors
110
+ * @since 1.0.0-rc.0
111
+ */
112
+ export const dispatcher = (
113
+ environment: Readonly<Record<string, string | undefined>>
114
+ ): Effect.Effect<Undici.Dispatcher, never, Scope.Scope> =>
115
+ Effect.suspend(() => {
116
+ const httpProxy = environment.http_proxy ?? environment.HTTP_PROXY ?? ""
117
+ const httpsProxy = environment.https_proxy ?? environment.HTTPS_PROXY ?? ""
118
+ const noProxy = exclusions(environment.no_proxy ?? environment.NO_PROXY ?? "")
119
+ // Explicit empty values prevent Undici from falling back to a different
120
+ // ambient environment. Each replacement pool uses the same proxy policy.
121
+ //
122
+ // Undici is loaded here rather than imported at the top, the way
123
+ // `NodeHttpClient.makeDispatcher` loads it, because this module is imported
124
+ // by `NodeHost` and every bundle built on it. A static import pulls the
125
+ // whole of Undici into any process that merely composes a host, whose
126
+ // side effects a host bundle must not carry: it reddened the Node host's
127
+ // own `FileSystem` contract case, which never makes a request. The explicit
128
+ // package entry also avoids Bun's incomplete built-in "undici" substitute.
129
+ return Effect.acquireRelease(
130
+ Effect.map(
131
+ loadUndici,
132
+ (undici) => new undici.EnvHttpProxyAgent({ httpProxy, httpsProxy, noProxy })
133
+ ),
134
+ (dispatcher) => Effect.promise(() => dispatcher.destroy())
135
+ )
136
+ })
137
+
138
+ /**
139
+ * The Undici `HttpClient` to install, given the environment the process runs in.
140
+ *
141
+ * Use this wherever `NodeHttpClient.layerUndici` would otherwise be provided
142
+ * under a layer that takes `HttpClient` from context — a model transport, a
143
+ * judge, a fetch rule, a host bundle. The two differ only in whether the pool
144
+ * honours `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY`, which is the difference
145
+ * between a request that reaches the gateway from inside a default-deny
146
+ * sandbox and one the firewall drops.
147
+ *
148
+ * @param environment the environment record whose proxy variables decide the route
149
+ * @category layers
150
+ * @since 1.0.0-rc.0
151
+ */
152
+ export const layer = (
153
+ environment: Readonly<Record<string, string | undefined>>
154
+ ): Layer.Layer<HttpClient> =>
155
+ Layer.effect(
156
+ HttpClient,
157
+ Effect.gen(function*() {
158
+ const shared = yield* dispatcher(environment)
159
+ const ordinary = yield* NodeHttpClient.makeUndici.pipe(Effect.provideService(NodeHttpClient.Dispatcher, shared))
160
+ return withDestinationPinning(EffectHttpClient.transform(ordinary, (execute, request) =>
161
+ Effect.gen(function*() {
162
+ const destination = yield* Destination
163
+ if (destination === undefined) return yield* execute
164
+ const url = new URL(request.url)
165
+ if (
166
+ url.origin !== destination.origin || destination.addresses.length === 0 ||
167
+ destination.addresses.some((address) => isIP(address) === 0)
168
+ ) {
169
+ return yield* Effect.fail(
170
+ new HttpClientError.HttpClientError({
171
+ reason: new HttpClientError.TransportError({
172
+ request,
173
+ description: "Invalid pinned HTTP destination"
174
+ })
175
+ })
176
+ )
177
+ }
178
+ const proxies = [
179
+ environment.http_proxy ?? environment.HTTP_PROXY,
180
+ environment.https_proxy ?? environment.HTTPS_PROXY
181
+ ]
182
+ // The record is read per request, and a live one such as NodeHost's
183
+ // `process.env` can name an unparsable proxy after the shared pool
184
+ // was built from it; that is a refusal here, never a thrown URL error.
185
+ const validProxies = proxies.every((proxy) => {
186
+ if (!proxy) return true
187
+ try {
188
+ return ["http:", "https:"].includes(new URL(proxy).protocol)
189
+ } catch {
190
+ return false
191
+ }
192
+ })
193
+ if (!validProxies) {
194
+ return yield* Effect.fail(
195
+ new HttpClientError.HttpClientError({
196
+ reason: new HttpClientError.TransportError({
197
+ request,
198
+ description: "Pinned HTTP requests require HTTP or HTTPS proxies"
199
+ })
200
+ })
201
+ )
202
+ }
203
+ const undici = yield* loadUndici
204
+ const addresses = destination.addresses.map((address) => ({ address, family: isIP(address) }))
205
+ // Construction and its disposal are one uninterruptible step: an
206
+ // interruption that lands after the agent exists but before the request
207
+ // owns it would otherwise leave the agent neither destroyed nor closed.
208
+ return yield* Effect.uninterruptibleMask((restore) => {
209
+ const pinned = new undici.EnvHttpProxyAgent({
210
+ httpProxy: environment.http_proxy ?? environment.HTTP_PROXY ?? "",
211
+ httpsProxy: environment.https_proxy ?? environment.HTTPS_PROXY ?? "",
212
+ noProxy: exclusions(environment.no_proxy ?? environment.NO_PROXY ?? ""),
213
+ // Tunnelling HTTP too prevents the proxy resolving the target hostname.
214
+ proxyTunnel: true,
215
+ connect: {
216
+ lookup: (_hostname, options, callback) => {
217
+ const candidates = options.family
218
+ ? addresses.filter((item) => item.family === options.family)
219
+ : addresses
220
+ const first = candidates[0]
221
+ if (first === undefined) {
222
+ return callback(
223
+ new EgressAddressError({
224
+ code: "no_approved_address",
225
+ message: "No approved address for family"
226
+ }),
227
+ "",
228
+ 4
229
+ )
230
+ }
231
+ if (options.all) callback(null, candidates)
232
+ else callback(null, first.address, first.family)
233
+ }
234
+ },
235
+ clientFactory: (origin, options) => {
236
+ const proxy = new undici.Pool(origin, options)
237
+ const connect = proxy.connect.bind(proxy)
238
+ // EnvHttpProxyAgent selects the route using the ORIGINAL hostname.
239
+ // Only the proxy tunnel destination changes; endpoint TLS still uses
240
+ // the original hostname for SNI and certificate verification.
241
+ proxy.connect = (options: Undici.Dispatcher.ConnectOptions) => {
242
+ const address = addresses[0]!.address
243
+ const host = isIP(address) === 6 ? `[${address}]` : address
244
+ const authority = `${host}:${url.port || (url.protocol === "https:" ? "443" : "80")}`
245
+ return connect({ ...options, path: authority, headers: { ...options.headers, host: authority } })
246
+ }
247
+ return proxy
248
+ }
249
+ })
250
+ const pinnedRequest = request.pipe(
251
+ HttpClientRequest.setHeader("host", url.host),
252
+ HttpClientRequest.removeHeader("proxy-authorization"),
253
+ HttpClientRequest.removeHeader("connection"),
254
+ HttpClientRequest.removeHeader("transfer-encoding"),
255
+ HttpClientRequest.removeHeader("content-length")
256
+ )
257
+ return restore(NodeHttpClient.makeUndici.pipe(
258
+ Effect.provideService(NodeHttpClient.Dispatcher, pinned),
259
+ Effect.flatMap((client) => client.execute(pinnedRequest))
260
+ )).pipe(Effect.onExit((exit) =>
261
+ Exit.isFailure(exit)
262
+ ? Effect.promise(() => pinned.destroy())
263
+ // close prevents reuse immediately, but lets the active body drain.
264
+ : Effect.sync(() => {
265
+ void pinned.close().catch(() => pinned.destroy())
266
+ })
267
+ ))
268
+ })
269
+ })))
270
+ })
271
+ )
272
+
273
+ /**
274
+ * Owns one replaceable Undici pool in the caller's scope. Each replacement
275
+ * receives the same middleware and closes the previous pool.
276
+ *
277
+ * @category constructors
278
+ * @since 1.0.0
279
+ */
280
+ export const rebuildableTransport = (
281
+ acquire: Effect.Effect<Undici.Dispatcher, never, Scope.Scope>,
282
+ decorate: (client: HttpClient) => Effect.Effect<HttpClient> = Effect.succeed
283
+ ): Effect.Effect<
284
+ {
285
+ readonly client: HttpClient
286
+ readonly rebuild: Effect.Effect<HttpClient>
287
+ },
288
+ never,
289
+ Scope.Scope
290
+ > =>
291
+ Effect.gen(function*() {
292
+ const scope = yield* Scope.Scope
293
+ const gate = yield* Semaphore.make(1)
294
+ let held: Scope.Closeable | undefined = undefined
295
+ const rebuild = gate.withPermit(Effect.uninterruptibleMask((restore) =>
296
+ Effect.gen(function*() {
297
+ const owned = yield* Scope.fork(scope)
298
+ const client = yield* restore(NodeHttpClient.makeUndici.pipe(
299
+ Effect.provideServiceEffect(NodeHttpClient.Dispatcher, acquire),
300
+ Effect.flatMap(decorate),
301
+ Effect.provideService(Scope.Scope, owned)
302
+ )).pipe(Effect.onExit((exit) => Exit.isSuccess(exit) ? Effect.void : Scope.close(owned, exit)))
303
+ const previous = held
304
+ held = owned
305
+ if (previous !== undefined) yield* Scope.close(previous, Exit.void)
306
+ return client
307
+ })
308
+ ))
309
+ return { client: yield* rebuild, rebuild }
310
+ })
311
+
312
+ /**
313
+ * A model transport whose replacements retain the caller's grant store and
314
+ * environment proxy policy. Pass it to RequestExecutor.makeWith in the host scope.
315
+ *
316
+ * @category constructors
317
+ * @since 1.0.0
318
+ */
319
+ export const guardedTransport = (environment: Readonly<Record<string, string | undefined>>) =>
320
+ Effect.gen(function*() {
321
+ const grants = yield* GrantStore
322
+ return yield* rebuildableTransport(dispatcher(environment), (client) =>
323
+ HttpClient.pipe(Effect.provide(KernelHttpClient.layer.pipe(
324
+ Layer.provide(Layer.succeed(HttpClient)(client)),
325
+ Layer.provide(Layer.succeed(GrantStore)(grants))
326
+ ))))
327
+ })
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Answers whether a recorded run owner is still alive on this host.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+
7
+ import * as Effect from "effect/Effect"
8
+
9
+ /**
10
+ * The owner identity fields liveness is decided from.
11
+ *
12
+ * Structural on purpose: `@smthrs/journal`'s `OwnerId` is exactly this shape
13
+ * plus a nonce, so an `OwnerId` is accepted here without this package taking a
14
+ * dependency on the journal to name a type.
15
+ *
16
+ * @category models
17
+ * @since 0.1.0
18
+ */
19
+ export interface Owner {
20
+ /** The host the owner ran on. */
21
+ readonly hostId: string
22
+ /** The operating-system process id that held the run. */
23
+ readonly pid: number
24
+ }
25
+
26
+ /**
27
+ * Liveness configuration.
28
+ *
29
+ * @category models
30
+ * @since 0.1.0
31
+ */
32
+ export interface Options {
33
+ /** The host id this process answers for. */
34
+ readonly hostId: string
35
+ /**
36
+ * How the probe asks the operating system. Default `process.kill`, which
37
+ * delivers nothing for signal 0 and only reports whether the pid is
38
+ * signalable.
39
+ */
40
+ readonly signal?: ((pid: number, signal: 0) => void) | undefined
41
+ }
42
+
43
+ const signalable = (send: (pid: number, signal: 0) => void, pid: number): boolean => {
44
+ try {
45
+ send(pid, 0)
46
+ return true
47
+ } catch (cause) {
48
+ // ESRCH means the process is gone. EPERM means it exists and belongs to
49
+ // another user, which is still a live owner this host must not rob. A throw
50
+ // that is not an object at all carries no code, and reading through it
51
+ // rather than off it is what stops that crashing the probe: a thrown string
52
+ // or `null` is an answer nobody gave, which is a live owner.
53
+ return (cause as { readonly code?: string } | null | undefined)?.code !== "ESRCH"
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Builds the liveness probe `EngineStore` consults before it steals a run.
59
+ *
60
+ * The engine asks this before taking a run whose recorded owner it is not, so
61
+ * a wrong `true` strands a run and a wrong `false` runs it twice. The rule is
62
+ * therefore asymmetric on purpose:
63
+ *
64
+ * - An owner from a **different host** is alive. A pid means nothing across
65
+ * machines, and the process table this probe reads is only this machine's.
66
+ * - An owner from **this host** is dead only when the signal-0 probe reports
67
+ * `ESRCH`. Every other result preserves liveness.
68
+ *
69
+ * The residual risk is pid reuse. An owner whose pid was recycled by an
70
+ * unrelated program reads as alive and its run waits for an operator, which is
71
+ * the safe direction: nothing about a recycled pid can tell this process
72
+ * whether the run is still being driven, and the cost of guessing wrong the
73
+ * other way is two hosts executing one run.
74
+ *
75
+ * A multi-process deployment with a supervisor or a lease system knows better
76
+ * than any pid probe and should answer from that instead.
77
+ *
78
+ * `@smthrs/run-store`'s `Ownership.sameHostPidProbe` fills the same
79
+ * `LivenessCheck`. Both probes use the same `ESRCH`-only death rule.
80
+ * `EPERM`, `EINVAL`, and unknown signal errors preserve liveness.
81
+ *
82
+ * The cross-host policy differs. `sameHostPidProbe` compares the owner's
83
+ * `hostId` with `context.claimant.hostId` and returns `false` for a foreign
84
+ * host, leaving the expired lease to govern reclaiming the run. This probe
85
+ * compares with the configured `hostId` and returns `true` for a foreign
86
+ * host, so a permanently dead foreign host's runs wait for an operator.
87
+ *
88
+ * Which answer a deployment gets depends on the entry point it used:
89
+ * `@smthrs/flows`' `NodeRuntime` defaults to this function, while
90
+ * `@smthrs/cli`'s `NodeControl` passes `sameHostPidProbe`. This function
91
+ * returns a one-argument function, which is structurally accepted as an
92
+ * `Ownership.LivenessCheck` and ignores its `context` argument. Pick the
93
+ * probe for its cross-host policy and source of host identity.
94
+ *
95
+ * @category constructors
96
+ * @since 0.1.0
97
+ */
98
+ export const isAlive = (options: Options): (owner: Owner) => Effect.Effect<boolean> => {
99
+ const send = options.signal ?? ((pid, signal) => {
100
+ process.kill(pid, signal)
101
+ })
102
+ return (owner) => Effect.sync(() => owner.hostId !== options.hostId || signalable(send, owner.pid))
103
+ }
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Aggregate Node.js Host bundle.
3
+ *
4
+ * This module defines the `NodeHost` service union and a single `layer` that
5
+ * provides the closed Host surface backed by Node: `@effect/platform-node`'s
6
+ * filesystem, child-process spawner, Undici `HttpClient`, native `Path`,
7
+ * and the Node `Jj` adapter from its own package. Use the layer when a Node
8
+ * program wants every host capability from one place; use the individual
9
+ * modules when a program should only be able to reach part of the host. The
10
+ * bundle also supplies native `ProcessConfinement` for the kernel spawner.
11
+ *
12
+ * There is no Node HTTP module either: outgoing requests are Effect's
13
+ * `HttpClient`, and `@effect/platform-node` already ships the Undici-backed
14
+ * implementation. Undici follows no redirect unless a redirect interceptor is
15
+ * installed, so every hop stays visible to `@smthrs/kernel`'s decorator.
16
+ *
17
+ * There is no Node shell module: running a command is Effect's
18
+ * `ChildProcessSpawner`, and `@effect/platform-node` already ships the
19
+ * implementation.
20
+ *
21
+ * @since 0.1.0
22
+ */
23
+
24
+ import * as NodeChildProcessSpawner from "@effect/platform-node/NodeChildProcessSpawner"
25
+ import * as NodeCrypto from "@effect/platform-node/NodeCrypto"
26
+ import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem"
27
+ import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient"
28
+ import * as NodePath from "@effect/platform-node/NodePath"
29
+ import type { Jj, JjError } from "@smthrs/jj"
30
+ import * as NodeJj from "@smthrs/jj/node/NodeJj"
31
+ import type { HostServiceIds } from "@smthrs/kernel/HostServices"
32
+ import type * as KernelProcessConfinement from "@smthrs/kernel/ProcessConfinement"
33
+ import type * as ProcessLedger from "@smthrs/kernel/ProcessLedger"
34
+ import type { FileSystem } from "effect/FileSystem"
35
+ import * as Layer from "effect/Layer"
36
+ import type * as Path from "effect/Path"
37
+ import * as Schema from "effect/Schema"
38
+ import type { HttpClient } from "effect/unstable/http/HttpClient"
39
+ import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
40
+ import { isAbsolute } from "node:path"
41
+ import * as AtomicFileSystem from "./AtomicFileSystem.ts"
42
+ import * as EgressHttpClient from "./EgressHttpClient.ts"
43
+ import * as ProcessConfinement from "./ProcessConfinement.ts"
44
+ import * as ProcessReaper from "./ProcessReaper.ts"
45
+
46
+ /**
47
+ * The Node platform modules Effect ships, re-exported so a program that wants
48
+ * only part of the host has one place to reach for them. `NodeJj` belongs to
49
+ * `@smthrs/jj`; import it from there.
50
+ *
51
+ * `NodeCrypto` is here for a different reason than the rest. `Crypto` is not a
52
+ * Host service — it carries no host authority the kernel could attenuate, so
53
+ * it is not in {@link NodeHost} and not in the closed list — but every durable
54
+ * composition needs one, and a program that already depends on this package
55
+ * for its host should not have to add a second dependency for the digest.
56
+ *
57
+ * @category re-exports
58
+ * @since 0.1.0
59
+ */
60
+ export {
61
+ AtomicFileSystem,
62
+ EgressHttpClient,
63
+ NodeChildProcessSpawner,
64
+ NodeCrypto,
65
+ NodeFileSystem,
66
+ NodeHttpClient,
67
+ ProcessReaper
68
+ }
69
+
70
+ /**
71
+ * The `HttpClient` every bundle below installs: Undici through the egress
72
+ * proxy this process's environment names, and a direct Undici pool when it
73
+ * names none.
74
+ *
75
+ * `NodeHttpClient.layerUndici` is the direct pool unconditionally. It is still
76
+ * re-exported above for a program composing its own services, but a bundle
77
+ * that spans a whole host has to work inside a sandbox whose only way out is a
78
+ * proxy, so the bundles read the environment. See {@link EgressHttpClient}.
79
+ */
80
+ const httpClient = EgressHttpClient.layer(process.env)
81
+
82
+ /**
83
+ * The union of host services provided by the Node host layer.
84
+ *
85
+ * @category models
86
+ * @since 0.1.0
87
+ */
88
+ export type NodeHost =
89
+ | FileSystem
90
+ | Path.Path
91
+ | ChildProcessSpawner
92
+ | Jj
93
+ | HttpClient
94
+ | KernelProcessConfinement.ProcessConfinement
95
+
96
+ /**
97
+ * Invalid repository-root configuration, refused before layer construction.
98
+ * @category errors
99
+ * @since 1.0.0-rc.0
100
+ */
101
+ export class NodeHostError extends Schema.TaggedError<NodeHostError>()("@smthrs/platform-node/NodeHostError", {
102
+ code: Schema.Literal("invalid_repository_root"),
103
+ message: Schema.String
104
+ }) {
105
+ override readonly name = "NodeHostError"
106
+ }
107
+
108
+ const absoluteRoot = (root: string): string => {
109
+ if (isAbsolute(root)) return root
110
+ throw new NodeHostError({
111
+ code: "invalid_repository_root",
112
+ message: `NodeHost requires an absolute repository root, got ${
113
+ JSON.stringify(Array.from(root).slice(0, 64).join(""))
114
+ }`
115
+ })
116
+ }
117
+
118
+ /**
119
+ * Stable implementation identities for the raw bundle's five Host slots.
120
+ * Contained POSIX factories replace its spawner with {@link ProcessReaper.layerSpawner}.
121
+ * @category models
122
+ * @since 1.0.0-rc.0
123
+ */
124
+ export const implementationIds: Readonly<Record<(typeof HostServiceIds)[number], string>> = {
125
+ "effect/FileSystem": "@smthrs/platform-node/AtomicFileSystem",
126
+ "effect/Path": "@effect/platform-node/NodePath",
127
+ "effect/process/ChildProcessSpawner": "@effect/platform-node/NodeChildProcessSpawner",
128
+ "@smthrs/jj/Jj": "@smthrs/jj/node/NodeJj",
129
+ "effect/HttpClient": "@smthrs/platform-node/EgressHttpClient"
130
+ }
131
+
132
+ /** The two services `NodeChildProcessSpawner` resolves paths and files with. */
133
+ const platform = Layer.mergeAll(AtomicFileSystem.layer, NodePath.layer)
134
+
135
+ /**
136
+ * What a caller may configure about a contained Node host.
137
+ *
138
+ * `platform` is deliberately absent. `ContainedSpawner.Options` declares it so a
139
+ * caller that supplies its own spawner can describe one, but this native host
140
+ * detaches by `process.platform` whatever a record claims. A caller-supplied
141
+ * `"win32"` on a POSIX host would therefore
142
+ * record `pgid: null` for a child that really does lead a group, and
143
+ * {@link ProcessReaper.reap} would retire that record as `no-group` and leave
144
+ * the orphan running forever — a durable lie rather than a compile error.
145
+ *
146
+ * @category models
147
+ * @since 1.0.0-rc.0
148
+ */
149
+ export type ContainedOptions = ProcessReaper.SpawnerOptions & ProcessReaper.Options
150
+
151
+ /** The reaper half of {@link ContainedOptions}. */
152
+ const reaping = (options?: ContainedOptions): ProcessReaper.Options => ({
153
+ ownerPid: options?.ownerPid,
154
+ system: options?.system
155
+ })
156
+
157
+ /**
158
+ * Provides the default Node implementations for the whole closed Host surface.
159
+ *
160
+ * @category layers
161
+ * @since 0.1.0
162
+ */
163
+ export const layer: Layer.Layer<NodeHost, JjError> = Layer.mergeAll(
164
+ ProcessConfinement.layer(),
165
+ platform,
166
+ Layer.provide(NodeChildProcessSpawner.layer, platform),
167
+ httpClient,
168
+ NodeJj.layer
169
+ )
170
+
171
+ /**
172
+ * Provides the Node host with `Jj` bound to one absolute repository root.
173
+ *
174
+ * @category layers
175
+ * @since 1.0.0
176
+ */
177
+ export const layerAt = (repositoryRoot: string): Layer.Layer<NodeHost, JjError> =>
178
+ Layer.mergeAll(
179
+ ProcessConfinement.layer(),
180
+ platform,
181
+ Layer.provide(NodeChildProcessSpawner.layer, platform),
182
+ httpClient,
183
+ NodeJj.layerAt(absoluteRoot(repositoryRoot))
184
+ )
185
+
186
+ /**
187
+ * Provides the Node host with process containment turned on.
188
+ *
189
+ * The difference from {@link layer} is what happens to a spawned process when
190
+ * its run stops. Under {@link layer} a child is signalled when its scope
191
+ * closes and then waited for, forever if it ignores `SIGTERM`, and a host that
192
+ * dies without closing its scopes abandons every child it started. This layer
193
+ * gives each child an escalation deadline and records it in the
194
+ * `ProcessLedger`, then sweeps the records a previous incarnation of the same
195
+ * host left behind before it hands the host over
196
+ * ({@link ProcessReaper.reap}).
197
+ *
198
+ * jj is contained here too: `layerContained` builds the `Jj` service over the
199
+ * same spawner rather than letting it start its own children, so a `jj`
200
+ * invocation a crashed host left running is a record the next incarnation
201
+ * reaps like any other.
202
+ *
203
+ * The ledger is a requirement rather than a default because the durable half
204
+ * of containment is only as good as the journal underneath it:
205
+ * `ProcessLedger.layer` inherits a crashed incarnation's processes,
206
+ * `ProcessLedger.layerMemory` contains this incarnation and nothing more, and
207
+ * the choice belongs to the program that knows which it has.
208
+ *
209
+ * @category layers
210
+ * @since 0.1.0
211
+ */
212
+ export const layerContained = (
213
+ options?: ContainedOptions
214
+ ): Layer.Layer<NodeHost, JjError, ProcessLedger.ProcessLedger> => {
215
+ const spawner = Layer.provide(
216
+ ProcessReaper.layerSpawner({ graceMs: options?.graceMs }),
217
+ Layer.provide(NodeChildProcessSpawner.layer, platform)
218
+ )
219
+ return Layer.mergeAll(
220
+ ProcessConfinement.layer(),
221
+ platform,
222
+ httpClient,
223
+ // jj goes through the CONTAINED spawner here, not around it. `NodeJj.layer`
224
+ // spawns its own children, which is right for a host that has no spawner
225
+ // to offer, but under containment it would mean a `jj` that leads no
226
+ // recorded process group, appears in no ledger, and survives the
227
+ // incarnation that started it.
228
+ Layer.provideMerge(NodeJj.layerSpawner, spawner)
229
+ ).pipe(Layer.provideMerge(ProcessReaper.layer(reaping(options))))
230
+ }
231
+
232
+ /**
233
+ * Provides the contained Node host with `Jj` bound to one absolute repository
234
+ * root.
235
+ *
236
+ * @category layers
237
+ * @since 1.0.0
238
+ */
239
+ export const layerContainedAt = (
240
+ repositoryRoot: string,
241
+ options?: ContainedOptions
242
+ ): Layer.Layer<NodeHost, JjError, ProcessLedger.ProcessLedger> => {
243
+ const spawner = Layer.provide(
244
+ ProcessReaper.layerSpawner({ graceMs: options?.graceMs }),
245
+ Layer.provide(NodeChildProcessSpawner.layer, platform)
246
+ )
247
+ return Layer.mergeAll(
248
+ ProcessConfinement.layer(),
249
+ platform,
250
+ httpClient,
251
+ Layer.provideMerge(NodeJj.layerSpawnerAt(absoluteRoot(repositoryRoot)), spawner)
252
+ ).pipe(Layer.provideMerge(ProcessReaper.layer(reaping(options))))
253
+ }