@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,124 @@
1
+ /**
2
+ * Scoped transient commands with the host's process-tree cleanup policy.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ import * as Effect from "effect/Effect"
7
+ import * as Exit from "effect/Exit"
8
+ import type * as PlatformError from "effect/PlatformError"
9
+ import * as Scope from "effect/Scope"
10
+ import * as ChildProcess from "effect/unstable/process/ChildProcess"
11
+ import type { ChildProcessHandle } from "effect/unstable/process/ChildProcessSpawner"
12
+ import * as PipedProcess from "./internal/PipedProcess.ts"
13
+ import { targetPidOf } from "./internal/ProcessSupervisor.ts"
14
+ import * as ProcessReaper from "./ProcessReaper.ts"
15
+
16
+ /**
17
+ * One command's literal argv, environment, pipes and termination policy.
18
+ * @category models
19
+ * @since 1.0.0
20
+ */
21
+ export interface Options extends ChildProcess.KillOptions {
22
+ readonly command: string
23
+ readonly args?: ReadonlyArray<string> | undefined
24
+ readonly cwd?: string | undefined
25
+ readonly env?: Readonly<Record<string, string | undefined>> | undefined
26
+ readonly stdin?: "ignore" | "pipe" | undefined
27
+ readonly windowsVerbatimArguments?: boolean | undefined
28
+ readonly windowsHide?: boolean | undefined
29
+ }
30
+
31
+ /**
32
+ * The managed owner identity and the actual target identity are distinct.
33
+ * @category models
34
+ * @since 1.0.0
35
+ */
36
+ export interface Handle extends ChildProcessHandle {
37
+ /** The native target's pid, for diagnostics and service liveness. */
38
+ readonly targetPid: number
39
+ }
40
+
41
+ /**
42
+ * Starts a pipe-based command and contains its lifetime inside the caller's
43
+ * scope. The returned pid names the live supervisor; exitCode reports
44
+ * the actual target. The private parent connection stops the tree on host loss,
45
+ * and the supervisor's group guardian stops the group on supervisor loss.
46
+ * Transient commands have no durable ledger; durable hosts use NodeHost instead.
47
+ *
48
+ * Unconsumed output stays in bounded native buffers until it is read or the
49
+ * scope closes. Consume stdout and stderr alongside exitCode: a command can
50
+ * block when an unread pipe is full.
51
+ *
52
+ * Failed startup closes its child scope before returning an error, even when
53
+ * the caller catches that error and retains the surrounding scope.
54
+ * @category constructors
55
+ * @since 1.0.0
56
+ */
57
+ export const spawn = (
58
+ options: Options
59
+ ): Effect.Effect<Handle, PlatformError.PlatformError, Scope.Scope> =>
60
+ Effect.uninterruptibleMask((restore) =>
61
+ Effect.gen(function*() {
62
+ const scope = yield* Scope.fork(yield* Scope.Scope)
63
+ const command = ChildProcess.make(options.command, [...options.args ?? []], {
64
+ cwd: options.cwd,
65
+ env: options.env,
66
+ extendEnv: false,
67
+ stdin: options.stdin ?? "ignore",
68
+ stdout: "pipe",
69
+ stderr: "pipe",
70
+ detached: process.platform !== "win32",
71
+ killSignal: options.killSignal ?? "SIGTERM",
72
+ forceKillAfter: options.forceKillAfter ?? 2000,
73
+ windowsHide: options.windowsHide ?? true,
74
+ // Preserve the target's native option through the private protocol.
75
+ ...{ windowsVerbatimArguments: options.windowsVerbatimArguments }
76
+ })
77
+ return yield* restore(
78
+ Effect.gen(function*() {
79
+ const prepared = yield* ProcessReaper.processLifecycle(
80
+ command,
81
+ (command) => PipedProcess.spawn(command, false, true)
82
+ )
83
+ yield* prepared.activate
84
+ const targetPid = targetPidOf(prepared.handle)
85
+ if (targetPid === undefined) {
86
+ return yield* Effect.fail(
87
+ PipedProcess.failure("spawn", new Error("The supervisor did not identify its target"))
88
+ )
89
+ }
90
+ return Object.defineProperty(prepared.handle, "targetPid", { value: targetPid, enumerable: true }) as Handle
91
+ }).pipe(Scope.provide(scope))
92
+ ).pipe(
93
+ Effect.onError((cause) => Scope.close(scope, Exit.failCause(cause)))
94
+ )
95
+ })
96
+ )
97
+
98
+ /**
99
+ * The native command's result, preserving a signal instead of inventing a code.
100
+ * @category models
101
+ * @since 1.0.0
102
+ */
103
+ export interface Status {
104
+ readonly code: number | null
105
+ readonly signal: ChildProcess.Signal | null
106
+ }
107
+
108
+ /**
109
+ * Reads the target's result. Failures without an actual target signal remain
110
+ * platform failures, including loss of the supervisor before a result arrives.
111
+ * @category execution
112
+ * @since 1.0.0
113
+ */
114
+ export const status = (handle: ChildProcessHandle): Effect.Effect<Status, PlatformError.PlatformError> =>
115
+ handle.exitCode.pipe(
116
+ Effect.map((code): Status => ({ code, signal: null })),
117
+ Effect.catch((error) => {
118
+ const cause = "cause" in error.reason ? error.reason.cause : undefined
119
+ const signal = typeof cause === "object" && cause !== null && "signal" in cause ? cause.signal : undefined
120
+ return typeof signal === "string" && /^SIG[A-Z0-9]+$/.test(signal)
121
+ ? Effect.succeed({ code: null, signal: signal as ChildProcess.Signal })
122
+ : Effect.fail(error)
123
+ })
124
+ )
package/src/index.ts ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `@smthrs/platform-node`, the Node.js Host bundle.
3
+ *
4
+ * `@effect/platform-node` already ships `FileSystem`, `Path`,
5
+ * `ChildProcessSpawner`, and an Undici-backed `HttpClient` for Node, and
6
+ * `NodeHost.layer` composes the complete closed five-tag Host surface out of
7
+ * them plus the Node `Jj` adapter, which lives in `@smthrs/jj`.
8
+ *
9
+ * The host adapters add guarantees beyond Effect's base services.
10
+ * `AtomicFileSystem` performs every filesystem operation relative to
11
+ * a pinned directory descriptor, so a symlink swapped in after authorization
12
+ * cannot redirect it; `ProcessReaper` kills the process groups a crashed
13
+ * incarnation of this host abandoned; `HostLiveness` answers whether a recorded
14
+ * run owner is still running here. `ScopedProcess` runs transient commands with
15
+ * supervised process cleanup and owns their input and output pipes.
16
+ *
17
+ * `AtomicFileSystem` is `NodeHost`'s filesystem slot. It executes operations
18
+ * through the packaged `smithers-jj-export --atomic-fs` helper, selected by
19
+ * `SMITHERS_WORKSPACE_JJ_EXPORT_BINARY` or `layerWith({ executable })`.
20
+ * A missing helper fails guarded operations closed. Windows is unsupported.
21
+ *
22
+ * @since 0.1.0
23
+ */
24
+
25
+ /** The complete closed Host bundle for Node. */
26
+ export * as NodeHost from "./NodeHost.ts"
27
+
28
+ /** The outbound HTTP client a Node process should use, read off its environment. */
29
+ export * as EgressHttpClient from "./EgressHttpClient.ts"
30
+
31
+ /** Whether a recorded run owner is still alive on this host. */
32
+ export * as HostLiveness from "./HostLiveness.ts"
33
+
34
+ /** Reaping the process groups a dead incarnation of this host abandoned. */
35
+ export * as ProcessReaper from "./ProcessReaper.ts"
36
+
37
+ /** Transient pipe-based commands with supervised process cleanup. */
38
+ export * as ScopedProcess from "./ScopedProcess.ts"
39
+
40
+ /** Native confinement of approved processes under the kernel grants. */
41
+ export * as ProcessConfinement from "./ProcessConfinement.ts"
42
+
43
+ /** Shared operating-system sandbox for build and agent processes. */
44
+ export * as ProcessSandbox from "./ProcessSandbox.ts"
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Finds the native filesystem helper embedded in a host, shipped with this package, or built in a
3
+ * source checkout, without accepting an executable from the workspace.
4
+ * @since 1.0.0
5
+ */
6
+
7
+ import { createHash, randomBytes } from "node:crypto"
8
+ import {
9
+ chmodSync,
10
+ existsSync,
11
+ lstatSync,
12
+ mkdirSync,
13
+ readdirSync,
14
+ readFileSync,
15
+ realpathSync,
16
+ renameSync,
17
+ rmSync,
18
+ statSync,
19
+ utimes,
20
+ utimesSync,
21
+ writeFileSync
22
+ } from "node:fs"
23
+ import { createRequire } from "node:module"
24
+ import { homedir, tmpdir } from "node:os"
25
+ import { basename, dirname, join, resolve } from "node:path"
26
+ import { fileURLToPath } from "node:url"
27
+ import { inside, usableExecutable } from "./AtomicFileSystemTransport.ts"
28
+ import { AtomicHelperError } from "./AtomicHelperError.ts"
29
+
30
+ /* v8 ignore next -- the packed CJS consumer uses its loader's __dirname; source tests use the ESM loader */
31
+ const moduleDirectory = typeof __dirname === "string" ? __dirname : dirname(fileURLToPath(import.meta.url))
32
+
33
+ /**
34
+ * The same source module lives one directory deeper after an npm build.
35
+ * @private
36
+ * @since 1.0.0
37
+ */
38
+ export const resolvePackageRoot = (directory: string): string => {
39
+ const sourcePackageRoot = resolve(directory, "../..")
40
+ return existsSync(join(sourcePackageRoot, "package.json"))
41
+ ? sourcePackageRoot
42
+ : resolve(directory, "../../..")
43
+ }
44
+
45
+ /**
46
+ * Finds the installed package even when a host bundles this adapter elsewhere.
47
+ * @private
48
+ * @since 1.0.0
49
+ */
50
+ export const installedPackageRoot = (modulePath: string, fallback: string): string => {
51
+ try {
52
+ return dirname(createRequire(modulePath).resolve("@smthrs/platform-node/package.json"))
53
+ } catch {
54
+ // A compiled executable has no installed package; its bootstrap supplies
55
+ // the embedded helper. Source-only fixtures retain the directory fallback.
56
+ return fallback
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Package containing the currently loaded helper adapter.
62
+ * @private
63
+ * @since 1.0.0
64
+ */
65
+ export const packageRoot = installedPackageRoot(
66
+ join(moduleDirectory, "resolver.cjs"),
67
+ resolvePackageRoot(moduleDirectory)
68
+ )
69
+
70
+ /** Each source's staged copy, and when this process last marked its directory in use. */
71
+ const staged = new Map<string, { readonly path: string; touchedAt: number }>()
72
+ /**
73
+ * Package roots already staged, and the sources that staging copied. Staging
74
+ * happens once per root per process: a later layer build runs after flows may
75
+ * have planted a helper, so only what existed at the FIRST build is trusted.
76
+ */
77
+ const stagedRoots = new Set<string>()
78
+ const trusted = new Set<string>()
79
+ const installHint = "install @smthrs/platform-node with its native helper, " +
80
+ "run cargo build --locked --release -p smithers-ffi --bin smithers-jj-export in a source checkout, " +
81
+ "or set SMITHERS_WORKSPACE_JJ_EXPORT_BINARY to its absolute path"
82
+
83
+ const helperName = process.platform === "win32" ? "smithers-jj-export.exe" : "smithers-jj-export"
84
+
85
+ const sha256 = (bytes: Uint8Array): string => createHash("sha256").update(bytes).digest("hex")
86
+
87
+ /** Whether this user owns `info`; Windows has no POSIX owner and relies on the per-user profile ACL. */
88
+ const ownedByThisUser = (info: { readonly uid: number }): boolean => {
89
+ const uid = process.getuid?.()
90
+ return uid === undefined || info.uid === uid
91
+ }
92
+
93
+ /** Creates or adopts the per-user staging directory, refusing links and other owners. */
94
+ const privateDirectory = (directory: string): void => {
95
+ try {
96
+ mkdirSync(directory, { mode: 0o700 })
97
+ } catch (cause) {
98
+ if ((cause as NodeJS.ErrnoException).code !== "EEXIST") throw cause
99
+ }
100
+ const info = lstatSync(directory)
101
+ if (!info.isDirectory() || !ownedByThisUser(info)) {
102
+ throw new AtomicHelperError({
103
+ code: "staging_directory_not_private",
104
+ message: `atomic helper staging directory is not a private directory: ${directory}`
105
+ })
106
+ }
107
+ chmodSync(directory, 0o700)
108
+ }
109
+
110
+ /**
111
+ * Whether the staged copy is this user's own single-link file holding exactly
112
+ * the helper's bytes. A planted link, even one with the right bytes, is
113
+ * replaced: rename swaps the directory entry, never the linked inode.
114
+ */
115
+ const matches = (destination: string, digest: string): boolean => {
116
+ try {
117
+ const info = lstatSync(destination)
118
+ if (!info.isFile() || info.nlink !== 1 || !ownedByThisUser(info)) return false
119
+ return sha256(readFileSync(destination)) === digest
120
+ } catch {
121
+ return false
122
+ }
123
+ }
124
+
125
+ /** A staged copy no process has used for this long is removed; use refreshes the directory's time. */
126
+ const staleMs = 7 * 24 * 60 * 60 * 1000
127
+ const refreshMs = 60 * 60 * 1000
128
+
129
+ /** Marks a staging directory in use, at most hourly, so no other process prunes it while this one runs. */
130
+ const refresh = (copy: { readonly path: string; touchedAt: number }): void => {
131
+ const now = Date.now()
132
+ if (now - copy.touchedAt < refreshMs) return
133
+ copy.touchedAt = now
134
+ // Best effort and off the request path: a failed touch only risks a later re-stage.
135
+ utimes(dirname(copy.path), now / 1000, now / 1000, () => {})
136
+ }
137
+
138
+ /**
139
+ * Removes this user's stale staging directories beside `keep`, and incomplete
140
+ * temporary files left in live directories when a writer exited on a signal.
141
+ */
142
+ const prune = (base: string, keep: string): void => {
143
+ const now = Date.now()
144
+ let names: Array<string>
145
+ try {
146
+ names = readdirSync(base)
147
+ } catch {
148
+ return
149
+ }
150
+ const temporaryPrefix = `.${helperName}.`
151
+ for (const name of names) {
152
+ if (!name.startsWith(".smthrs-atomic-helper-")) continue
153
+ const directory = join(base, name)
154
+ try {
155
+ const info = lstatSync(directory)
156
+ if (!info.isDirectory() || !ownedByThisUser(info)) continue
157
+ if (name !== keep && now - info.mtimeMs > staleMs) {
158
+ rmSync(directory, { recursive: true, force: true })
159
+ continue
160
+ }
161
+ for (const entry of readdirSync(directory)) {
162
+ if (!entry.startsWith(temporaryPrefix) || !/^\d+\.[0-9a-f]{12}$/.test(entry.slice(temporaryPrefix.length))) {
163
+ continue
164
+ }
165
+ const temporary = join(directory, entry)
166
+ try {
167
+ const file = lstatSync(temporary)
168
+ if (file.isFile() && ownedByThisUser(file) && now - file.mtimeMs > staleMs) {
169
+ rmSync(temporary, { force: true })
170
+ }
171
+ } catch {
172
+ // A writer or another pruner removed this entry first.
173
+ }
174
+ }
175
+ } catch {
176
+ // Another process removed or replaced it first.
177
+ }
178
+ }
179
+ }
180
+
181
+ let embeddedHelper: string | undefined
182
+
183
+ /**
184
+ * Supplies the build's native asset without touching disk during --help.
185
+ * @private
186
+ * @since 1.0.0
187
+ */
188
+ export const registerEmbeddedHelper = (source: string): void => {
189
+ embeddedHelper = source
190
+ }
191
+
192
+ /**
193
+ * Pin an install inside the workspace before any flow can modify its bytes.
194
+ * @private
195
+ * @since 1.0.0
196
+ */
197
+ export const outsideWorkspace = (
198
+ source: string,
199
+ boundaryRoot: string | undefined,
200
+ bases: ReadonlyArray<string> = [tmpdir(), homedir()]
201
+ ): string => {
202
+ const cached = staged.get(source)
203
+ if (cached !== undefined) {
204
+ if (existsSync(cached.path)) {
205
+ refresh(cached)
206
+ return usableExecutable(cached.path, boundaryRoot)
207
+ }
208
+ // A newer build's process pruned this copy after a week unused: stage it again.
209
+ staged.delete(source)
210
+ }
211
+ // readFile also supports assets embedded in a Bun executable; copyfile
212
+ // delegates to the OS, which cannot open its virtual /$bunfs path.
213
+ const bytes = readFileSync(source)
214
+ const digest = sha256(bytes)
215
+ for (const [index, base] of bases.entries()) {
216
+ const directory = join(base, `.smthrs-atomic-helper-${digest}`)
217
+ const destination = join(directory, helperName)
218
+ let temporary: string | undefined
219
+ try {
220
+ privateDirectory(directory)
221
+ // Fresh before it is read, so a concurrent prune passes it by.
222
+ const now = new Date()
223
+ utimesSync(directory, now, now)
224
+ if (!matches(destination, digest)) {
225
+ // One copy per user and helper: concurrent processes each write a
226
+ // private temporary file and rename it over the shared name, so a
227
+ // reader only ever sees a complete copy.
228
+ temporary = join(directory, `.${helperName}.${process.pid}.${randomBytes(6).toString("hex")}`)
229
+ writeFileSync(temporary, bytes, { flag: "wx", mode: 0o500 })
230
+ chmodSync(temporary, 0o500)
231
+ renameSync(temporary, destination)
232
+ temporary = undefined
233
+ }
234
+ const executable = usableExecutable(destination, boundaryRoot)
235
+ prune(base, `.smthrs-atomic-helper-${digest}`)
236
+ staged.set(source, { path: executable, touchedAt: now.getTime() })
237
+ return executable
238
+ } catch (cause) {
239
+ if (temporary !== undefined) rmSync(temporary, { force: true })
240
+ if (index === bases.length - 1) throw cause
241
+ }
242
+ }
243
+ throw new AtomicHelperError({
244
+ code: "staging_unavailable",
245
+ message: "no staging location for smithers-jj-export"
246
+ })
247
+ }
248
+
249
+ /** The helper an installed package ships for this platform. */
250
+ const packagedHelper = (root: string): string => join(root, "bin", `${process.platform}-${process.arch}`, helperName)
251
+
252
+ /** Source-checkout builds, when `root` is this package inside a checkout. */
253
+ const checkoutHelpers = (root: string): ReadonlyArray<string> => {
254
+ const checkout = resolve(root, "../../../..")
255
+ return existsSync(join(checkout, "pnpm-workspace.yaml"))
256
+ ? [join(checkout, "target/release", helperName), join(checkout, "target/debug", helperName)]
257
+ : []
258
+ }
259
+
260
+ /**
261
+ * Stages the packaged helper and any source-checkout build the first time a
262
+ * host layer over `root` is built in this process, so the bytes later requests
263
+ * execute are the ones present before any flow ran. Later builds stage
264
+ * nothing: a flow of an earlier run may already have planted a helper by then.
265
+ * A flow that rewrites a workspace-local install or build afterwards changes
266
+ * nothing that is executed. A missing or unusable helper is left for the first
267
+ * request to report.
268
+ * @private
269
+ * @since 1.0.0
270
+ */
271
+ export const stagePackaged = (root: string): void => {
272
+ if (stagedRoots.has(root)) return
273
+ stagedRoots.add(root)
274
+ const candidate = embeddedHelper ?? packagedHelper(root)
275
+ try {
276
+ if (existsSync(candidate) && statSync(candidate).isFile()) {
277
+ outsideWorkspace(candidate, undefined)
278
+ trusted.add(candidate)
279
+ }
280
+ } catch {
281
+ // The request path resolves again and reports the refusal it meets.
282
+ }
283
+ if (embeddedHelper !== undefined) return
284
+ for (const build of checkoutHelpers(root)) {
285
+ try {
286
+ if (existsSync(build)) {
287
+ const executable = usableExecutable(build, undefined)
288
+ outsideWorkspace(executable, undefined)
289
+ trusted.add(executable)
290
+ }
291
+ } catch {
292
+ // As above: the request path reports it.
293
+ }
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Whether a flow confined to `boundaryRoot` could have supplied what
299
+ * `candidate` runs: the name itself lies inside the workspace (so a flow could
300
+ * have replaced it with a link to any host binary), its directory resolves
301
+ * inside it, or the file it resolves to does.
302
+ */
303
+ const workspaceSupplied = (candidate: string, source: string, boundaryRoot: string): boolean =>
304
+ inside(boundaryRoot, resolve(candidate)) ||
305
+ inside(boundaryRoot, join(realpathSync.native(dirname(candidate)), basename(candidate))) ||
306
+ inside(boundaryRoot, realpathSync.native(source))
307
+
308
+ /**
309
+ * Copies `source` to a private directory only when the workspace cannot have
310
+ * supplied its bytes: neither `candidate` nor what it resolves to lies inside
311
+ * the confined workspace, or `source` was staged at the first host build,
312
+ * before any flow ran. A helper, or a link to one, that appeared inside the
313
+ * workspace later is exactly what a flow would plant.
314
+ */
315
+ const pinned = (candidate: string, source: string, boundaryRoot: string | undefined): string => {
316
+ if (boundaryRoot !== undefined && !trusted.has(source) && workspaceSupplied(candidate, source, boundaryRoot)) {
317
+ throw new AtomicHelperError({
318
+ code: "helper_inside_workspace",
319
+ message: `atomic helper executable must live outside the confined workspace: ${candidate} ` +
320
+ "was not present when the host was built"
321
+ })
322
+ }
323
+ return outsideWorkspace(source, boundaryRoot)
324
+ }
325
+
326
+ /**
327
+ * Select only trusted package or checkout locations; never consult PATH or cwd.
328
+ * @private
329
+ * @since 1.0.0
330
+ */
331
+ export const resolveDefaultExecutable = (
332
+ root: string,
333
+ boundaryRoot: string | undefined,
334
+ fallback = "/usr/local/bin/smithers-jj-export"
335
+ ): string => {
336
+ if (embeddedHelper !== undefined) return outsideWorkspace(embeddedHelper, boundaryRoot)
337
+ const candidates = [packagedHelper(root), ...checkoutHelpers(root), fallback]
338
+ for (const [index, candidate] of candidates.entries()) {
339
+ if (!existsSync(candidate)) continue
340
+ if (index === 0) {
341
+ if (!statSync(candidate).isFile()) {
342
+ throw new AtomicHelperError({
343
+ code: "helper_not_regular_file",
344
+ message: `packaged atomic helper is not a regular file: ${candidate}`
345
+ })
346
+ }
347
+ // npm/pnpm tarballs may store package files without executable bits.
348
+ return pinned(candidate, candidate, boundaryRoot)
349
+ }
350
+ const executable = usableExecutable(candidate, undefined)
351
+ return boundaryRoot !== undefined && workspaceSupplied(candidate, executable, boundaryRoot)
352
+ ? pinned(candidate, executable, boundaryRoot)
353
+ : executable
354
+ }
355
+ throw new AtomicHelperError({
356
+ code: "helper_missing",
357
+ message: `smithers-jj-export is missing; ${installHint} (searched ${candidates.join(", ")})`
358
+ })
359
+ }
360
+
361
+ /**
362
+ * The helper `SMITHERS_WORKSPACE_JJ_EXPORT_BINARY` names, refused with the same
363
+ * install hint as a missing one.
364
+ * @private
365
+ * @since 1.0.0
366
+ */
367
+ export const resolveConfiguredExecutable = (configured: string, boundaryRoot: string | undefined): string => {
368
+ try {
369
+ return usableExecutable(configured, boundaryRoot)
370
+ } catch (cause) {
371
+ // `usableExecutable` and the node:fs calls it makes throw only Error objects.
372
+ const reason = (cause as Error).message
373
+ throw new AtomicHelperError({
374
+ code: "helper_unusable",
375
+ message:
376
+ `smithers-jj-export is unusable at SMITHERS_WORKSPACE_JJ_EXPORT_BINARY=${configured}: ${reason}; ${installHint}`
377
+ })
378
+ }
379
+ }