@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,106 @@
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
+ import type * as Undici from "../vendor/node/Undici.js";
30
+ import { GrantStore } from "@smthrs/kernel/GrantStore";
31
+ import * as Effect from "effect/Effect";
32
+ import * as Layer from "effect/Layer";
33
+ import * as Schema from "effect/Schema";
34
+ import * as Scope from "effect/Scope";
35
+ import { HttpClient } from "effect/unstable/http/HttpClient";
36
+ declare const EgressAddressError_base: Schema.Class<EgressAddressError, Schema.TaggedStruct<"@smthrs/platform-node/EgressAddressError", {
37
+ readonly code: Schema.Literal<"no_approved_address">;
38
+ readonly message: Schema.String;
39
+ }>, import("effect/Cause").YieldableError>;
40
+ /**
41
+ * A pinned connection asked for an address family none of the authorized
42
+ * addresses has. It is the `cause` of the `TransportError` the request fails
43
+ * with; `code` is always `no_approved_address`.
44
+ *
45
+ * @category errors
46
+ * @since 1.0.0
47
+ */
48
+ export declare class EgressAddressError extends EgressAddressError_base {
49
+ readonly name = "EgressAddressError";
50
+ }
51
+ /**
52
+ * An Undici dispatcher that routes through the egress proxy the supplied
53
+ * environment names, or a direct one when it names none.
54
+ *
55
+ * The proxy variables are read in the order Undici itself reads them,
56
+ * lowercase first, and passed explicitly rather than left to
57
+ * `EnvHttpProxyAgent`'s own ambient lookup: a host serving a guest's
58
+ * environment is not the guest, and the pool has to follow the record it was
59
+ * handed. Loopback is always direct; see {@link exclusions}. Each dispatcher is
60
+ * acquired in the caller's scope and destroyed with it, so a composition that
61
+ * builds several still owns every pool it opened.
62
+ *
63
+ * @param environment the environment record whose proxy variables decide the route
64
+ * @category constructors
65
+ * @since 1.0.0-rc.0
66
+ */
67
+ export declare const dispatcher: (environment: Readonly<Record<string, string | undefined>>) => Effect.Effect<Undici.Dispatcher, never, Scope.Scope>;
68
+ /**
69
+ * The Undici `HttpClient` to install, given the environment the process runs in.
70
+ *
71
+ * Use this wherever `NodeHttpClient.layerUndici` would otherwise be provided
72
+ * under a layer that takes `HttpClient` from context — a model transport, a
73
+ * judge, a fetch rule, a host bundle. The two differ only in whether the pool
74
+ * honours `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY`, which is the difference
75
+ * between a request that reaches the gateway from inside a default-deny
76
+ * sandbox and one the firewall drops.
77
+ *
78
+ * @param environment the environment record whose proxy variables decide the route
79
+ * @category layers
80
+ * @since 1.0.0-rc.0
81
+ */
82
+ export declare const layer: (environment: Readonly<Record<string, string | undefined>>) => Layer.Layer<HttpClient>;
83
+ /**
84
+ * Owns one replaceable Undici pool in the caller's scope. Each replacement
85
+ * receives the same middleware and closes the previous pool.
86
+ *
87
+ * @category constructors
88
+ * @since 1.0.0
89
+ */
90
+ export declare const rebuildableTransport: (acquire: Effect.Effect<Undici.Dispatcher, never, Scope.Scope>, decorate?: (client: HttpClient) => Effect.Effect<HttpClient>) => Effect.Effect<{
91
+ readonly client: HttpClient;
92
+ readonly rebuild: Effect.Effect<HttpClient>;
93
+ }, never, Scope.Scope>;
94
+ /**
95
+ * A model transport whose replacements retain the caller's grant store and
96
+ * environment proxy policy. Pass it to RequestExecutor.makeWith in the host scope.
97
+ *
98
+ * @category constructors
99
+ * @since 1.0.0
100
+ */
101
+ export declare const guardedTransport: (environment: Readonly<Record<string, string | undefined>>) => Effect.Effect<{
102
+ readonly client: HttpClient;
103
+ readonly rebuild: Effect.Effect<HttpClient>;
104
+ }, never, GrantStore | Scope.Scope>;
105
+ export {};
106
+ //# sourceMappingURL=EgressHttpClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EgressHttpClient.d.ts","sourceRoot":"","sources":["../../src/EgressHttpClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,KAAK,MAAM,MAAM,8BAA8B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAGtD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;;;;;AAM5D;;;;;;;GAOG;AACH,qBAAa,kBAAmB,SAAQ,uBAGvC;IACC,SAAkB,IAAI,wBAAuB;CAC9C;AAoCD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GACrB,aAAa,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KACxD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAsBlD,CAAA;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,KAAK,GAChB,aAAa,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KACxD,KAAK,CAAC,KAAK,CAAC,UAAU,CAqHtB,CAAA;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAC7D,WAAU,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,CAAkB,KAC3E,MAAM,CAAC,MAAM,CACd;IACE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;CAC5C,EACD,KAAK,EACL,KAAK,CAAC,KAAK,CAqBT,CAAA;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,aAAa,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;qBAlCrE,UAAU;sBACT,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;mCAyC3C,CAAA"}
@@ -0,0 +1,259 @@
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
+ import * as NodeHttpClient from "../vendor/node/NodeHttpClient.js";
30
+ import { GrantStore } from "@smthrs/kernel/GrantStore";
31
+ import * as KernelHttpClient from "@smthrs/kernel/HttpClient";
32
+ import { Destination, withDestinationPinning } from "@smthrs/kernel/HttpClient";
33
+ import * as Effect from "effect/Effect";
34
+ import * as Exit from "effect/Exit";
35
+ import * as Layer from "effect/Layer";
36
+ import * as Schema from "effect/Schema";
37
+ import * as Scope from "effect/Scope";
38
+ import * as Semaphore from "effect/Semaphore";
39
+ import { HttpClient } from "effect/unstable/http/HttpClient";
40
+ import * as EffectHttpClient from "effect/unstable/http/HttpClient";
41
+ import * as HttpClientError from "effect/unstable/http/HttpClientError";
42
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
43
+ import { isIP } from "node:net";
44
+ /**
45
+ * A pinned connection asked for an address family none of the authorized
46
+ * addresses has. It is the `cause` of the `TransportError` the request fails
47
+ * with; `code` is always `no_approved_address`.
48
+ *
49
+ * @category errors
50
+ * @since 1.0.0
51
+ */
52
+ export class EgressAddressError extends Schema.TaggedError()("@smthrs/platform-node/EgressAddressError", { code: Schema.Literal("no_approved_address"), message: Schema.String }) {
53
+ name = "EgressAddressError";
54
+ }
55
+ /**
56
+ * The hosts a proxy is never for. A proxy is how a process leaves its machine;
57
+ * these names are the machine itself. Matched by name, the way Undici matches
58
+ * every `NO_PROXY` entry, so the list is exactly these three and not
59
+ * `127.0.0.0/8`.
60
+ */
61
+ const loopback = ["localhost", "127.0.0.1", "::1"];
62
+ /**
63
+ * The exclusion list to hand Undici, given the one the environment names.
64
+ *
65
+ * Undici proxies *every* origin when `NO_PROXY` is empty — `#shouldProxy`
66
+ * returns early with "Always proxy if NO_PROXY is not set or empty" — so a host
67
+ * that names a proxy to reach the internet would also send `smthrs --remote
68
+ * http://127.0.0.1:3000` and a local Ollama at `http://localhost:11434` to it.
69
+ * Nothing in this repository has ever needed `NO_PROXY=127.0.0.1`, because the
70
+ * client these compositions used before ignored the proxy variables outright.
71
+ * So loopback is always excluded, the way Go's `net/http.ProxyFromEnvironment`
72
+ * excludes it, and the environment's own entries are kept beside it.
73
+ *
74
+ * `*` is returned untouched: Undici recognises the wildcard only as the entire
75
+ * value, and it already means every origin is direct.
76
+ */
77
+ const exclusions = (declared) => declared === "*" ? declared : [declared, ...loopback].filter((entry) => entry !== "").join(",");
78
+ // Split ESM bundles expose CommonJS Undici through default, without synthetic
79
+ // named exports. Node and Bun also expose its constructors through default.
80
+ // Its typings declare `default` as a namespace without them, and `bundler`
81
+ // resolution reads that, so the value is typed as the module it carries.
82
+ const loadUndici = Effect.promise(async () => (await import("undici/index.js")).default);
83
+ /**
84
+ * An Undici dispatcher that routes through the egress proxy the supplied
85
+ * environment names, or a direct one when it names none.
86
+ *
87
+ * The proxy variables are read in the order Undici itself reads them,
88
+ * lowercase first, and passed explicitly rather than left to
89
+ * `EnvHttpProxyAgent`'s own ambient lookup: a host serving a guest's
90
+ * environment is not the guest, and the pool has to follow the record it was
91
+ * handed. Loopback is always direct; see {@link exclusions}. Each dispatcher is
92
+ * acquired in the caller's scope and destroyed with it, so a composition that
93
+ * builds several still owns every pool it opened.
94
+ *
95
+ * @param environment the environment record whose proxy variables decide the route
96
+ * @category constructors
97
+ * @since 1.0.0-rc.0
98
+ */
99
+ export const dispatcher = (environment) => Effect.suspend(() => {
100
+ const httpProxy = environment.http_proxy ?? environment.HTTP_PROXY ?? "";
101
+ const httpsProxy = environment.https_proxy ?? environment.HTTPS_PROXY ?? "";
102
+ const noProxy = exclusions(environment.no_proxy ?? environment.NO_PROXY ?? "");
103
+ // Explicit empty values prevent Undici from falling back to a different
104
+ // ambient environment. Each replacement pool uses the same proxy policy.
105
+ //
106
+ // Undici is loaded here rather than imported at the top, the way
107
+ // `NodeHttpClient.makeDispatcher` loads it, because this module is imported
108
+ // by `NodeHost` and every bundle built on it. A static import pulls the
109
+ // whole of Undici into any process that merely composes a host, whose
110
+ // side effects a host bundle must not carry: it reddened the Node host's
111
+ // own `FileSystem` contract case, which never makes a request. The explicit
112
+ // package entry also avoids Bun's incomplete built-in "undici" substitute.
113
+ return Effect.acquireRelease(Effect.map(loadUndici, (undici) => new undici.EnvHttpProxyAgent({ httpProxy, httpsProxy, noProxy })), (dispatcher) => Effect.promise(() => dispatcher.destroy()));
114
+ });
115
+ /**
116
+ * The Undici `HttpClient` to install, given the environment the process runs in.
117
+ *
118
+ * Use this wherever `NodeHttpClient.layerUndici` would otherwise be provided
119
+ * under a layer that takes `HttpClient` from context — a model transport, a
120
+ * judge, a fetch rule, a host bundle. The two differ only in whether the pool
121
+ * honours `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY`, which is the difference
122
+ * between a request that reaches the gateway from inside a default-deny
123
+ * sandbox and one the firewall drops.
124
+ *
125
+ * @param environment the environment record whose proxy variables decide the route
126
+ * @category layers
127
+ * @since 1.0.0-rc.0
128
+ */
129
+ export const layer = (environment) => Layer.effect(HttpClient, Effect.gen(function* () {
130
+ const shared = yield* dispatcher(environment);
131
+ const ordinary = yield* NodeHttpClient.makeUndici.pipe(Effect.provideService(NodeHttpClient.Dispatcher, shared));
132
+ return withDestinationPinning(EffectHttpClient.transform(ordinary, (execute, request) => Effect.gen(function* () {
133
+ const destination = yield* Destination;
134
+ if (destination === undefined)
135
+ return yield* execute;
136
+ const url = new URL(request.url);
137
+ if (url.origin !== destination.origin || destination.addresses.length === 0 ||
138
+ destination.addresses.some((address) => isIP(address) === 0)) {
139
+ return yield* Effect.fail(new HttpClientError.HttpClientError({
140
+ reason: new HttpClientError.TransportError({
141
+ request,
142
+ description: "Invalid pinned HTTP destination"
143
+ })
144
+ }));
145
+ }
146
+ const proxies = [
147
+ environment.http_proxy ?? environment.HTTP_PROXY,
148
+ environment.https_proxy ?? environment.HTTPS_PROXY
149
+ ];
150
+ // The record is read per request, and a live one such as NodeHost's
151
+ // `process.env` can name an unparsable proxy after the shared pool
152
+ // was built from it; that is a refusal here, never a thrown URL error.
153
+ const validProxies = proxies.every((proxy) => {
154
+ if (!proxy)
155
+ return true;
156
+ try {
157
+ return ["http:", "https:"].includes(new URL(proxy).protocol);
158
+ }
159
+ catch {
160
+ return false;
161
+ }
162
+ });
163
+ if (!validProxies) {
164
+ return yield* Effect.fail(new HttpClientError.HttpClientError({
165
+ reason: new HttpClientError.TransportError({
166
+ request,
167
+ description: "Pinned HTTP requests require HTTP or HTTPS proxies"
168
+ })
169
+ }));
170
+ }
171
+ const undici = yield* loadUndici;
172
+ const addresses = destination.addresses.map((address) => ({ address, family: isIP(address) }));
173
+ // Construction and its disposal are one uninterruptible step: an
174
+ // interruption that lands after the agent exists but before the request
175
+ // owns it would otherwise leave the agent neither destroyed nor closed.
176
+ return yield* Effect.uninterruptibleMask((restore) => {
177
+ const pinned = new undici.EnvHttpProxyAgent({
178
+ httpProxy: environment.http_proxy ?? environment.HTTP_PROXY ?? "",
179
+ httpsProxy: environment.https_proxy ?? environment.HTTPS_PROXY ?? "",
180
+ noProxy: exclusions(environment.no_proxy ?? environment.NO_PROXY ?? ""),
181
+ // Tunnelling HTTP too prevents the proxy resolving the target hostname.
182
+ proxyTunnel: true,
183
+ connect: {
184
+ lookup: (_hostname, options, callback) => {
185
+ const candidates = options.family
186
+ ? addresses.filter((item) => item.family === options.family)
187
+ : addresses;
188
+ const first = candidates[0];
189
+ if (first === undefined) {
190
+ return callback(new EgressAddressError({
191
+ code: "no_approved_address",
192
+ message: "No approved address for family"
193
+ }), "", 4);
194
+ }
195
+ if (options.all)
196
+ callback(null, candidates);
197
+ else
198
+ callback(null, first.address, first.family);
199
+ }
200
+ },
201
+ clientFactory: (origin, options) => {
202
+ const proxy = new undici.Pool(origin, options);
203
+ const connect = proxy.connect.bind(proxy);
204
+ // EnvHttpProxyAgent selects the route using the ORIGINAL hostname.
205
+ // Only the proxy tunnel destination changes; endpoint TLS still uses
206
+ // the original hostname for SNI and certificate verification.
207
+ proxy.connect = (options) => {
208
+ const address = addresses[0].address;
209
+ const host = isIP(address) === 6 ? `[${address}]` : address;
210
+ const authority = `${host}:${url.port || (url.protocol === "https:" ? "443" : "80")}`;
211
+ return connect({ ...options, path: authority, headers: { ...options.headers, host: authority } });
212
+ };
213
+ return proxy;
214
+ }
215
+ });
216
+ const pinnedRequest = request.pipe(HttpClientRequest.setHeader("host", url.host), HttpClientRequest.removeHeader("proxy-authorization"), HttpClientRequest.removeHeader("connection"), HttpClientRequest.removeHeader("transfer-encoding"), HttpClientRequest.removeHeader("content-length"));
217
+ return restore(NodeHttpClient.makeUndici.pipe(Effect.provideService(NodeHttpClient.Dispatcher, pinned), Effect.flatMap((client) => client.execute(pinnedRequest)))).pipe(Effect.onExit((exit) => Exit.isFailure(exit)
218
+ ? Effect.promise(() => pinned.destroy())
219
+ // close prevents reuse immediately, but lets the active body drain.
220
+ : Effect.sync(() => {
221
+ void pinned.close().catch(() => pinned.destroy());
222
+ })));
223
+ });
224
+ })));
225
+ }));
226
+ /**
227
+ * Owns one replaceable Undici pool in the caller's scope. Each replacement
228
+ * receives the same middleware and closes the previous pool.
229
+ *
230
+ * @category constructors
231
+ * @since 1.0.0
232
+ */
233
+ export const rebuildableTransport = (acquire, decorate = Effect.succeed) => Effect.gen(function* () {
234
+ const scope = yield* Scope.Scope;
235
+ const gate = yield* Semaphore.make(1);
236
+ let held = undefined;
237
+ const rebuild = gate.withPermit(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
238
+ const owned = yield* Scope.fork(scope);
239
+ const client = yield* restore(NodeHttpClient.makeUndici.pipe(Effect.provideServiceEffect(NodeHttpClient.Dispatcher, acquire), Effect.flatMap(decorate), Effect.provideService(Scope.Scope, owned))).pipe(Effect.onExit((exit) => Exit.isSuccess(exit) ? Effect.void : Scope.close(owned, exit)));
240
+ const previous = held;
241
+ held = owned;
242
+ if (previous !== undefined)
243
+ yield* Scope.close(previous, Exit.void);
244
+ return client;
245
+ })));
246
+ return { client: yield* rebuild, rebuild };
247
+ });
248
+ /**
249
+ * A model transport whose replacements retain the caller's grant store and
250
+ * environment proxy policy. Pass it to RequestExecutor.makeWith in the host scope.
251
+ *
252
+ * @category constructors
253
+ * @since 1.0.0
254
+ */
255
+ export const guardedTransport = (environment) => Effect.gen(function* () {
256
+ const grants = yield* GrantStore;
257
+ return yield* rebuildableTransport(dispatcher(environment), (client) => HttpClient.pipe(Effect.provide(KernelHttpClient.layer.pipe(Layer.provide(Layer.succeed(HttpClient)(client)), Layer.provide(Layer.succeed(GrantStore)(grants))))));
258
+ });
259
+ //# sourceMappingURL=EgressHttpClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EgressHttpClient.js","sourceRoot":"","sources":["../../src/EgressHttpClient.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The outbound HTTP client a Node process should use, read off its environment.\n *\n * `@effect/platform-node` ships `NodeHttpClient.layerUndici`, and its\n * dispatcher is a bare Undici `Agent`. A bare `Agent` dials every origin\n * directly: it does not read `HTTP_PROXY`, `HTTPS_PROXY` or `NO_PROXY`, and\n * nothing at the call site says so. That is invisible on a developer machine\n * with open egress and fatal inside a sandbox whose egress is default-deny\n * behind a named proxy — the request leaves for the origin, the firewall drops\n * it, and the only symptom is a transport failure far from the composition\n * that chose the client.\n *\n * This module is the one place that decision is made. {@link layer} is the\n * client every Node host composition installs; it honours the proxy the\n * environment names. Requests without a web destination use a shared pool;\n * web requests receive a fresh pinned dispatcher.\n *\n * The rule for loopback is fixed here, not by the environment: `localhost`,\n * `127.0.0.1` and `[::1]` are always reached directly, even when the\n * environment names a proxy and no exclusion, and every other origin follows\n * `NO_PROXY`. A proxy is how a process leaves its machine, and\n * `--remote http://127.0.0.1:3000` is not leaving it. The exemption is those\n * three names and nothing wider: Undici matches `NO_PROXY` entries by name,\n * never by resolved address, so `127.0.0.2` or a hostname that resolves to\n * loopback is an origin like any other and goes through the proxy.\n *\n * @since 1.0.0-rc.0\n */\n\nimport * as NodeHttpClient from \"@effect/platform-node/NodeHttpClient\"\nimport type * as Undici from \"@effect/platform-node/Undici\"\nimport { GrantStore } from \"@smthrs/kernel/GrantStore\"\nimport * as KernelHttpClient from \"@smthrs/kernel/HttpClient\"\nimport { Destination, withDestinationPinning } from \"@smthrs/kernel/HttpClient\"\nimport * as Effect from \"effect/Effect\"\nimport * as Exit from \"effect/Exit\"\nimport * as Layer from \"effect/Layer\"\nimport * as Schema from \"effect/Schema\"\nimport * as Scope from \"effect/Scope\"\nimport * as Semaphore from \"effect/Semaphore\"\nimport { HttpClient } from \"effect/unstable/http/HttpClient\"\nimport * as EffectHttpClient from \"effect/unstable/http/HttpClient\"\nimport * as HttpClientError from \"effect/unstable/http/HttpClientError\"\nimport * as HttpClientRequest from \"effect/unstable/http/HttpClientRequest\"\nimport { isIP } from \"node:net\"\n\n/**\n * A pinned connection asked for an address family none of the authorized\n * addresses has. It is the `cause` of the `TransportError` the request fails\n * with; `code` is always `no_approved_address`.\n *\n * @category errors\n * @since 1.0.0\n */\nexport class EgressAddressError extends Schema.TaggedError<EgressAddressError>()(\n \"@smthrs/platform-node/EgressAddressError\",\n { code: Schema.Literal(\"no_approved_address\"), message: Schema.String }\n) {\n override readonly name = \"EgressAddressError\"\n}\n\n/**\n * The hosts a proxy is never for. A proxy is how a process leaves its machine;\n * these names are the machine itself. Matched by name, the way Undici matches\n * every `NO_PROXY` entry, so the list is exactly these three and not\n * `127.0.0.0/8`.\n */\nconst loopback = [\"localhost\", \"127.0.0.1\", \"::1\"] as const\n\n/**\n * The exclusion list to hand Undici, given the one the environment names.\n *\n * Undici proxies *every* origin when `NO_PROXY` is empty — `#shouldProxy`\n * returns early with \"Always proxy if NO_PROXY is not set or empty\" — so a host\n * that names a proxy to reach the internet would also send `smthrs --remote\n * http://127.0.0.1:3000` and a local Ollama at `http://localhost:11434` to it.\n * Nothing in this repository has ever needed `NO_PROXY=127.0.0.1`, because the\n * client these compositions used before ignored the proxy variables outright.\n * So loopback is always excluded, the way Go's `net/http.ProxyFromEnvironment`\n * excludes it, and the environment's own entries are kept beside it.\n *\n * `*` is returned untouched: Undici recognises the wildcard only as the entire\n * value, and it already means every origin is direct.\n */\nconst exclusions = (declared: string): string =>\n declared === \"*\" ? declared : [declared, ...loopback].filter((entry) => entry !== \"\").join(\",\")\n\n// Split ESM bundles expose CommonJS Undici through default, without synthetic\n// named exports. Node and Bun also expose its constructors through default.\n// Its typings declare `default` as a namespace without them, and `bundler`\n// resolution reads that, so the value is typed as the module it carries.\nconst loadUndici = Effect.promise(\n async () => (await import(\"undici/index.js\")).default as unknown as typeof Undici\n)\n\n/**\n * An Undici dispatcher that routes through the egress proxy the supplied\n * environment names, or a direct one when it names none.\n *\n * The proxy variables are read in the order Undici itself reads them,\n * lowercase first, and passed explicitly rather than left to\n * `EnvHttpProxyAgent`'s own ambient lookup: a host serving a guest's\n * environment is not the guest, and the pool has to follow the record it was\n * handed. Loopback is always direct; see {@link exclusions}. Each dispatcher is\n * acquired in the caller's scope and destroyed with it, so a composition that\n * builds several still owns every pool it opened.\n *\n * @param environment the environment record whose proxy variables decide the route\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const dispatcher = (\n environment: Readonly<Record<string, string | undefined>>\n): Effect.Effect<Undici.Dispatcher, never, Scope.Scope> =>\n Effect.suspend(() => {\n const httpProxy = environment.http_proxy ?? environment.HTTP_PROXY ?? \"\"\n const httpsProxy = environment.https_proxy ?? environment.HTTPS_PROXY ?? \"\"\n const noProxy = exclusions(environment.no_proxy ?? environment.NO_PROXY ?? \"\")\n // Explicit empty values prevent Undici from falling back to a different\n // ambient environment. Each replacement pool uses the same proxy policy.\n //\n // Undici is loaded here rather than imported at the top, the way\n // `NodeHttpClient.makeDispatcher` loads it, because this module is imported\n // by `NodeHost` and every bundle built on it. A static import pulls the\n // whole of Undici into any process that merely composes a host, whose\n // side effects a host bundle must not carry: it reddened the Node host's\n // own `FileSystem` contract case, which never makes a request. The explicit\n // package entry also avoids Bun's incomplete built-in \"undici\" substitute.\n return Effect.acquireRelease(\n Effect.map(\n loadUndici,\n (undici) => new undici.EnvHttpProxyAgent({ httpProxy, httpsProxy, noProxy })\n ),\n (dispatcher) => Effect.promise(() => dispatcher.destroy())\n )\n })\n\n/**\n * The Undici `HttpClient` to install, given the environment the process runs in.\n *\n * Use this wherever `NodeHttpClient.layerUndici` would otherwise be provided\n * under a layer that takes `HttpClient` from context — a model transport, a\n * judge, a fetch rule, a host bundle. The two differ only in whether the pool\n * honours `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY`, which is the difference\n * between a request that reaches the gateway from inside a default-deny\n * sandbox and one the firewall drops.\n *\n * @param environment the environment record whose proxy variables decide the route\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer = (\n environment: Readonly<Record<string, string | undefined>>\n): Layer.Layer<HttpClient> =>\n Layer.effect(\n HttpClient,\n Effect.gen(function*() {\n const shared = yield* dispatcher(environment)\n const ordinary = yield* NodeHttpClient.makeUndici.pipe(Effect.provideService(NodeHttpClient.Dispatcher, shared))\n return withDestinationPinning(EffectHttpClient.transform(ordinary, (execute, request) =>\n Effect.gen(function*() {\n const destination = yield* Destination\n if (destination === undefined) return yield* execute\n const url = new URL(request.url)\n if (\n url.origin !== destination.origin || destination.addresses.length === 0 ||\n destination.addresses.some((address) => isIP(address) === 0)\n ) {\n return yield* Effect.fail(\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n description: \"Invalid pinned HTTP destination\"\n })\n })\n )\n }\n const proxies = [\n environment.http_proxy ?? environment.HTTP_PROXY,\n environment.https_proxy ?? environment.HTTPS_PROXY\n ]\n // The record is read per request, and a live one such as NodeHost's\n // `process.env` can name an unparsable proxy after the shared pool\n // was built from it; that is a refusal here, never a thrown URL error.\n const validProxies = proxies.every((proxy) => {\n if (!proxy) return true\n try {\n return [\"http:\", \"https:\"].includes(new URL(proxy).protocol)\n } catch {\n return false\n }\n })\n if (!validProxies) {\n return yield* Effect.fail(\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.TransportError({\n request,\n description: \"Pinned HTTP requests require HTTP or HTTPS proxies\"\n })\n })\n )\n }\n const undici = yield* loadUndici\n const addresses = destination.addresses.map((address) => ({ address, family: isIP(address) }))\n // Construction and its disposal are one uninterruptible step: an\n // interruption that lands after the agent exists but before the request\n // owns it would otherwise leave the agent neither destroyed nor closed.\n return yield* Effect.uninterruptibleMask((restore) => {\n const pinned = new undici.EnvHttpProxyAgent({\n httpProxy: environment.http_proxy ?? environment.HTTP_PROXY ?? \"\",\n httpsProxy: environment.https_proxy ?? environment.HTTPS_PROXY ?? \"\",\n noProxy: exclusions(environment.no_proxy ?? environment.NO_PROXY ?? \"\"),\n // Tunnelling HTTP too prevents the proxy resolving the target hostname.\n proxyTunnel: true,\n connect: {\n lookup: (_hostname, options, callback) => {\n const candidates = options.family\n ? addresses.filter((item) => item.family === options.family)\n : addresses\n const first = candidates[0]\n if (first === undefined) {\n return callback(\n new EgressAddressError({\n code: \"no_approved_address\",\n message: \"No approved address for family\"\n }),\n \"\",\n 4\n )\n }\n if (options.all) callback(null, candidates)\n else callback(null, first.address, first.family)\n }\n },\n clientFactory: (origin, options) => {\n const proxy = new undici.Pool(origin, options)\n const connect = proxy.connect.bind(proxy)\n // EnvHttpProxyAgent selects the route using the ORIGINAL hostname.\n // Only the proxy tunnel destination changes; endpoint TLS still uses\n // the original hostname for SNI and certificate verification.\n proxy.connect = (options: Undici.Dispatcher.ConnectOptions) => {\n const address = addresses[0]!.address\n const host = isIP(address) === 6 ? `[${address}]` : address\n const authority = `${host}:${url.port || (url.protocol === \"https:\" ? \"443\" : \"80\")}`\n return connect({ ...options, path: authority, headers: { ...options.headers, host: authority } })\n }\n return proxy\n }\n })\n const pinnedRequest = request.pipe(\n HttpClientRequest.setHeader(\"host\", url.host),\n HttpClientRequest.removeHeader(\"proxy-authorization\"),\n HttpClientRequest.removeHeader(\"connection\"),\n HttpClientRequest.removeHeader(\"transfer-encoding\"),\n HttpClientRequest.removeHeader(\"content-length\")\n )\n return restore(NodeHttpClient.makeUndici.pipe(\n Effect.provideService(NodeHttpClient.Dispatcher, pinned),\n Effect.flatMap((client) => client.execute(pinnedRequest))\n )).pipe(Effect.onExit((exit) =>\n Exit.isFailure(exit)\n ? Effect.promise(() => pinned.destroy())\n // close prevents reuse immediately, but lets the active body drain.\n : Effect.sync(() => {\n void pinned.close().catch(() => pinned.destroy())\n })\n ))\n })\n })))\n })\n )\n\n/**\n * Owns one replaceable Undici pool in the caller's scope. Each replacement\n * receives the same middleware and closes the previous pool.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const rebuildableTransport = (\n acquire: Effect.Effect<Undici.Dispatcher, never, Scope.Scope>,\n decorate: (client: HttpClient) => Effect.Effect<HttpClient> = Effect.succeed\n): Effect.Effect<\n {\n readonly client: HttpClient\n readonly rebuild: Effect.Effect<HttpClient>\n },\n never,\n Scope.Scope\n> =>\n Effect.gen(function*() {\n const scope = yield* Scope.Scope\n const gate = yield* Semaphore.make(1)\n let held: Scope.Closeable | undefined = undefined\n const rebuild = gate.withPermit(Effect.uninterruptibleMask((restore) =>\n Effect.gen(function*() {\n const owned = yield* Scope.fork(scope)\n const client = yield* restore(NodeHttpClient.makeUndici.pipe(\n Effect.provideServiceEffect(NodeHttpClient.Dispatcher, acquire),\n Effect.flatMap(decorate),\n Effect.provideService(Scope.Scope, owned)\n )).pipe(Effect.onExit((exit) => Exit.isSuccess(exit) ? Effect.void : Scope.close(owned, exit)))\n const previous = held\n held = owned\n if (previous !== undefined) yield* Scope.close(previous, Exit.void)\n return client\n })\n ))\n return { client: yield* rebuild, rebuild }\n })\n\n/**\n * A model transport whose replacements retain the caller's grant store and\n * environment proxy policy. Pass it to RequestExecutor.makeWith in the host scope.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const guardedTransport = (environment: Readonly<Record<string, string | undefined>>) =>\n Effect.gen(function*() {\n const grants = yield* GrantStore\n return yield* rebuildableTransport(dispatcher(environment), (client) =>\n HttpClient.pipe(Effect.provide(KernelHttpClient.layer.pipe(\n Layer.provide(Layer.succeed(HttpClient)(client)),\n Layer.provide(Layer.succeed(GrantStore)(grants))\n ))))\n })\n"]}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Answers whether a recorded run owner is still alive on this host.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+ import * as Effect from "effect/Effect";
7
+ /**
8
+ * The owner identity fields liveness is decided from.
9
+ *
10
+ * Structural on purpose: `@smthrs/journal`'s `OwnerId` is exactly this shape
11
+ * plus a nonce, so an `OwnerId` is accepted here without this package taking a
12
+ * dependency on the journal to name a type.
13
+ *
14
+ * @category models
15
+ * @since 0.1.0
16
+ */
17
+ export interface Owner {
18
+ /** The host the owner ran on. */
19
+ readonly hostId: string;
20
+ /** The operating-system process id that held the run. */
21
+ readonly pid: number;
22
+ }
23
+ /**
24
+ * Liveness configuration.
25
+ *
26
+ * @category models
27
+ * @since 0.1.0
28
+ */
29
+ export interface Options {
30
+ /** The host id this process answers for. */
31
+ readonly hostId: string;
32
+ /**
33
+ * How the probe asks the operating system. Default `process.kill`, which
34
+ * delivers nothing for signal 0 and only reports whether the pid is
35
+ * signalable.
36
+ */
37
+ readonly signal?: ((pid: number, signal: 0) => void) | undefined;
38
+ }
39
+ /**
40
+ * Builds the liveness probe `EngineStore` consults before it steals a run.
41
+ *
42
+ * The engine asks this before taking a run whose recorded owner it is not, so
43
+ * a wrong `true` strands a run and a wrong `false` runs it twice. The rule is
44
+ * therefore asymmetric on purpose:
45
+ *
46
+ * - An owner from a **different host** is alive. A pid means nothing across
47
+ * machines, and the process table this probe reads is only this machine's.
48
+ * - An owner from **this host** is dead only when the signal-0 probe reports
49
+ * `ESRCH`. Every other result preserves liveness.
50
+ *
51
+ * The residual risk is pid reuse. An owner whose pid was recycled by an
52
+ * unrelated program reads as alive and its run waits for an operator, which is
53
+ * the safe direction: nothing about a recycled pid can tell this process
54
+ * whether the run is still being driven, and the cost of guessing wrong the
55
+ * other way is two hosts executing one run.
56
+ *
57
+ * A multi-process deployment with a supervisor or a lease system knows better
58
+ * than any pid probe and should answer from that instead.
59
+ *
60
+ * `@smthrs/run-store`'s `Ownership.sameHostPidProbe` fills the same
61
+ * `LivenessCheck`. Both probes use the same `ESRCH`-only death rule.
62
+ * `EPERM`, `EINVAL`, and unknown signal errors preserve liveness.
63
+ *
64
+ * The cross-host policy differs. `sameHostPidProbe` compares the owner's
65
+ * `hostId` with `context.claimant.hostId` and returns `false` for a foreign
66
+ * host, leaving the expired lease to govern reclaiming the run. This probe
67
+ * compares with the configured `hostId` and returns `true` for a foreign
68
+ * host, so a permanently dead foreign host's runs wait for an operator.
69
+ *
70
+ * Which answer a deployment gets depends on the entry point it used:
71
+ * `@smthrs/flows`' `NodeRuntime` defaults to this function, while
72
+ * `@smthrs/cli`'s `NodeControl` passes `sameHostPidProbe`. This function
73
+ * returns a one-argument function, which is structurally accepted as an
74
+ * `Ownership.LivenessCheck` and ignores its `context` argument. Pick the
75
+ * probe for its cross-host policy and source of host identity.
76
+ *
77
+ * @category constructors
78
+ * @since 0.1.0
79
+ */
80
+ export declare const isAlive: (options: Options) => (owner: Owner) => Effect.Effect<boolean>;
81
+ //# sourceMappingURL=HostLiveness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HostLiveness.d.ts","sourceRoot":"","sources":["../../src/HostLiveness.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;GASG;AACH,MAAM,WAAW,KAAK;IACpB,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;CACjE;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,OAAO,GAAI,SAAS,OAAO,KAAG,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,CAKjF,CAAA"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Answers whether a recorded run owner is still alive on this host.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+ import * as Effect from "effect/Effect";
7
+ const signalable = (send, pid) => {
8
+ try {
9
+ send(pid, 0);
10
+ return true;
11
+ }
12
+ catch (cause) {
13
+ // ESRCH means the process is gone. EPERM means it exists and belongs to
14
+ // another user, which is still a live owner this host must not rob. A throw
15
+ // that is not an object at all carries no code, and reading through it
16
+ // rather than off it is what stops that crashing the probe: a thrown string
17
+ // or `null` is an answer nobody gave, which is a live owner.
18
+ return cause?.code !== "ESRCH";
19
+ }
20
+ };
21
+ /**
22
+ * Builds the liveness probe `EngineStore` consults before it steals a run.
23
+ *
24
+ * The engine asks this before taking a run whose recorded owner it is not, so
25
+ * a wrong `true` strands a run and a wrong `false` runs it twice. The rule is
26
+ * therefore asymmetric on purpose:
27
+ *
28
+ * - An owner from a **different host** is alive. A pid means nothing across
29
+ * machines, and the process table this probe reads is only this machine's.
30
+ * - An owner from **this host** is dead only when the signal-0 probe reports
31
+ * `ESRCH`. Every other result preserves liveness.
32
+ *
33
+ * The residual risk is pid reuse. An owner whose pid was recycled by an
34
+ * unrelated program reads as alive and its run waits for an operator, which is
35
+ * the safe direction: nothing about a recycled pid can tell this process
36
+ * whether the run is still being driven, and the cost of guessing wrong the
37
+ * other way is two hosts executing one run.
38
+ *
39
+ * A multi-process deployment with a supervisor or a lease system knows better
40
+ * than any pid probe and should answer from that instead.
41
+ *
42
+ * `@smthrs/run-store`'s `Ownership.sameHostPidProbe` fills the same
43
+ * `LivenessCheck`. Both probes use the same `ESRCH`-only death rule.
44
+ * `EPERM`, `EINVAL`, and unknown signal errors preserve liveness.
45
+ *
46
+ * The cross-host policy differs. `sameHostPidProbe` compares the owner's
47
+ * `hostId` with `context.claimant.hostId` and returns `false` for a foreign
48
+ * host, leaving the expired lease to govern reclaiming the run. This probe
49
+ * compares with the configured `hostId` and returns `true` for a foreign
50
+ * host, so a permanently dead foreign host's runs wait for an operator.
51
+ *
52
+ * Which answer a deployment gets depends on the entry point it used:
53
+ * `@smthrs/flows`' `NodeRuntime` defaults to this function, while
54
+ * `@smthrs/cli`'s `NodeControl` passes `sameHostPidProbe`. This function
55
+ * returns a one-argument function, which is structurally accepted as an
56
+ * `Ownership.LivenessCheck` and ignores its `context` argument. Pick the
57
+ * probe for its cross-host policy and source of host identity.
58
+ *
59
+ * @category constructors
60
+ * @since 0.1.0
61
+ */
62
+ export const isAlive = (options) => {
63
+ const send = options.signal ?? ((pid, signal) => {
64
+ process.kill(pid, signal);
65
+ });
66
+ return (owner) => Effect.sync(() => owner.hostId !== options.hostId || signalable(send, owner.pid));
67
+ };
68
+ //# sourceMappingURL=HostLiveness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HostLiveness.js","sourceRoot":"","sources":["../../src/HostLiveness.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAoCvC,MAAM,UAAU,GAAG,CAAC,IAAsC,EAAE,GAAW,EAAW,EAAE;IAClF,IAAI,CAAC;QACH,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACZ,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wEAAwE;QACxE,4EAA4E;QAC5E,uEAAuE;QACvE,4EAA4E;QAC5E,6DAA6D;QAC7D,OAAQ,KAAuD,EAAE,IAAI,KAAK,OAAO,CAAA;IACnF,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAgB,EAA4C,EAAE;IACpF,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;QAC9C,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IACF,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;AACrG,CAAC,CAAA","sourcesContent":["/**\n * Answers whether a recorded run owner is still alive on this host.\n *\n * @since 0.1.0\n */\n\nimport * as Effect from \"effect/Effect\"\n\n/**\n * The owner identity fields liveness is decided from.\n *\n * Structural on purpose: `@smthrs/journal`'s `OwnerId` is exactly this shape\n * plus a nonce, so an `OwnerId` is accepted here without this package taking a\n * dependency on the journal to name a type.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Owner {\n /** The host the owner ran on. */\n readonly hostId: string\n /** The operating-system process id that held the run. */\n readonly pid: number\n}\n\n/**\n * Liveness configuration.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Options {\n /** The host id this process answers for. */\n readonly hostId: string\n /**\n * How the probe asks the operating system. Default `process.kill`, which\n * delivers nothing for signal 0 and only reports whether the pid is\n * signalable.\n */\n readonly signal?: ((pid: number, signal: 0) => void) | undefined\n}\n\nconst signalable = (send: (pid: number, signal: 0) => void, pid: number): boolean => {\n try {\n send(pid, 0)\n return true\n } catch (cause) {\n // ESRCH means the process is gone. EPERM means it exists and belongs to\n // another user, which is still a live owner this host must not rob. A throw\n // that is not an object at all carries no code, and reading through it\n // rather than off it is what stops that crashing the probe: a thrown string\n // or `null` is an answer nobody gave, which is a live owner.\n return (cause as { readonly code?: string } | null | undefined)?.code !== \"ESRCH\"\n }\n}\n\n/**\n * Builds the liveness probe `EngineStore` consults before it steals a run.\n *\n * The engine asks this before taking a run whose recorded owner it is not, so\n * a wrong `true` strands a run and a wrong `false` runs it twice. The rule is\n * therefore asymmetric on purpose:\n *\n * - An owner from a **different host** is alive. A pid means nothing across\n * machines, and the process table this probe reads is only this machine's.\n * - An owner from **this host** is dead only when the signal-0 probe reports\n * `ESRCH`. Every other result preserves liveness.\n *\n * The residual risk is pid reuse. An owner whose pid was recycled by an\n * unrelated program reads as alive and its run waits for an operator, which is\n * the safe direction: nothing about a recycled pid can tell this process\n * whether the run is still being driven, and the cost of guessing wrong the\n * other way is two hosts executing one run.\n *\n * A multi-process deployment with a supervisor or a lease system knows better\n * than any pid probe and should answer from that instead.\n *\n * `@smthrs/run-store`'s `Ownership.sameHostPidProbe` fills the same\n * `LivenessCheck`. Both probes use the same `ESRCH`-only death rule.\n * `EPERM`, `EINVAL`, and unknown signal errors preserve liveness.\n *\n * The cross-host policy differs. `sameHostPidProbe` compares the owner's\n * `hostId` with `context.claimant.hostId` and returns `false` for a foreign\n * host, leaving the expired lease to govern reclaiming the run. This probe\n * compares with the configured `hostId` and returns `true` for a foreign\n * host, so a permanently dead foreign host's runs wait for an operator.\n *\n * Which answer a deployment gets depends on the entry point it used:\n * `@smthrs/flows`' `NodeRuntime` defaults to this function, while\n * `@smthrs/cli`'s `NodeControl` passes `sameHostPidProbe`. This function\n * returns a one-argument function, which is structurally accepted as an\n * `Ownership.LivenessCheck` and ignores its `context` argument. Pick the\n * probe for its cross-host policy and source of host identity.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const isAlive = (options: Options): (owner: Owner) => Effect.Effect<boolean> => {\n const send = options.signal ?? ((pid, signal) => {\n process.kill(pid, signal)\n })\n return (owner) => Effect.sync(() => owner.hostId !== options.hostId || signalable(send, owner.pid))\n}\n"]}