@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.
- package/CHANGELOG.md +211 -0
- package/LICENSE +21 -0
- package/README.md +165 -2
- package/bin/darwin-arm64/smithers-jj-export +0 -0
- package/bin/darwin-x64/smithers-jj-export +0 -0
- package/bin/linux-arm64/smithers-jj-export +0 -0
- package/bin/linux-x64/smithers-jj-export +4 -0
- package/bin/win32-x64/smithers-jj-export.exe +0 -0
- package/dist/cjs/AtomicFileSystem.d.ts +147 -0
- package/dist/cjs/AtomicFileSystem.d.ts.map +1 -0
- package/dist/cjs/AtomicFileSystem.js +234 -0
- package/dist/cjs/AtomicFileSystem.js.map +7 -0
- package/dist/cjs/EgressHttpClient.d.ts +106 -0
- package/dist/cjs/EgressHttpClient.d.ts.map +1 -0
- package/dist/cjs/EgressHttpClient.js +202 -0
- package/dist/cjs/EgressHttpClient.js.map +7 -0
- package/dist/cjs/HostLiveness.d.ts +81 -0
- package/dist/cjs/HostLiveness.d.ts.map +1 -0
- package/dist/cjs/HostLiveness.js +49 -0
- package/dist/cjs/HostLiveness.js.map +7 -0
- package/dist/cjs/NodeHost.d.ts +145 -0
- package/dist/cjs/NodeHost.d.ts.map +1 -0
- package/dist/cjs/NodeHost.js +128 -0
- package/dist/cjs/NodeHost.js.map +7 -0
- package/dist/cjs/ProcessConfinement.d.ts +61 -0
- package/dist/cjs/ProcessConfinement.d.ts.map +1 -0
- package/dist/cjs/ProcessConfinement.js +292 -0
- package/dist/cjs/ProcessConfinement.js.map +7 -0
- package/dist/cjs/ProcessReaper.d.ts +457 -0
- package/dist/cjs/ProcessReaper.d.ts.map +1 -0
- package/dist/cjs/ProcessReaper.js +349 -0
- package/dist/cjs/ProcessReaper.js.map +7 -0
- package/dist/cjs/ProcessSandbox.d.ts +391 -0
- package/dist/cjs/ProcessSandbox.d.ts.map +1 -0
- package/dist/cjs/ProcessSandbox.js +774 -0
- package/dist/cjs/ProcessSandbox.js.map +7 -0
- package/dist/cjs/ScopedProcess.d.ts +66 -0
- package/dist/cjs/ScopedProcess.d.ts.map +1 -0
- package/dist/cjs/ScopedProcess.js +87 -0
- package/dist/cjs/ScopedProcess.js.map +7 -0
- package/dist/cjs/index.d.ts +38 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +47 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/AtomicFileSystemExecutable.d.ts +61 -0
- package/dist/cjs/internal/AtomicFileSystemExecutable.d.ts.map +1 -0
- package/dist/cjs/internal/AtomicFileSystemExecutable.js +250 -0
- package/dist/cjs/internal/AtomicFileSystemExecutable.js.map +7 -0
- package/dist/cjs/internal/AtomicFileSystemProtocol.d.ts +78 -0
- package/dist/cjs/internal/AtomicFileSystemProtocol.d.ts.map +1 -0
- package/dist/cjs/internal/AtomicFileSystemProtocol.js +382 -0
- package/dist/cjs/internal/AtomicFileSystemProtocol.js.map +7 -0
- package/dist/cjs/internal/AtomicFileSystemTransport.d.ts +44 -0
- package/dist/cjs/internal/AtomicFileSystemTransport.d.ts.map +1 -0
- package/dist/cjs/internal/AtomicFileSystemTransport.js +197 -0
- package/dist/cjs/internal/AtomicFileSystemTransport.js.map +7 -0
- package/dist/cjs/internal/AtomicHelperError.d.ts +35 -0
- package/dist/cjs/internal/AtomicHelperError.d.ts.map +1 -0
- package/dist/cjs/internal/AtomicHelperError.js +45 -0
- package/dist/cjs/internal/AtomicHelperError.js.map +7 -0
- package/dist/cjs/internal/AtomicHelperFault.d.ts +59 -0
- package/dist/cjs/internal/AtomicHelperFault.d.ts.map +1 -0
- package/dist/cjs/internal/AtomicHelperFault.js +66 -0
- package/dist/cjs/internal/AtomicHelperFault.js.map +7 -0
- package/dist/cjs/internal/PipedProcess.d.ts +35 -0
- package/dist/cjs/internal/PipedProcess.d.ts.map +1 -0
- package/dist/cjs/internal/PipedProcess.js +309 -0
- package/dist/cjs/internal/PipedProcess.js.map +7 -0
- package/dist/cjs/internal/ProcSnapshot.d.ts +85 -0
- package/dist/cjs/internal/ProcSnapshot.d.ts.map +1 -0
- package/dist/cjs/internal/ProcSnapshot.js +123 -0
- package/dist/cjs/internal/ProcSnapshot.js.map +7 -0
- package/dist/cjs/internal/ProcessCleanup.d.ts +64 -0
- package/dist/cjs/internal/ProcessCleanup.d.ts.map +1 -0
- package/dist/cjs/internal/ProcessCleanup.js +62 -0
- package/dist/cjs/internal/ProcessCleanup.js.map +7 -0
- package/dist/cjs/internal/ProcessCleanupPolicyError.d.ts +30 -0
- package/dist/cjs/internal/ProcessCleanupPolicyError.d.ts.map +1 -0
- package/dist/cjs/internal/ProcessCleanupPolicyError.js +33 -0
- package/dist/cjs/internal/ProcessCleanupPolicyError.js.map +7 -0
- package/dist/cjs/internal/ProcessFault.d.ts +63 -0
- package/dist/cjs/internal/ProcessFault.d.ts.map +1 -0
- package/dist/cjs/internal/ProcessFault.js +63 -0
- package/dist/cjs/internal/ProcessFault.js.map +7 -0
- package/dist/cjs/internal/ProcessSupervisor.d.ts +143 -0
- package/dist/cjs/internal/ProcessSupervisor.d.ts.map +1 -0
- package/dist/cjs/internal/ProcessSupervisor.js +685 -0
- package/dist/cjs/internal/ProcessSupervisor.js.map +7 -0
- package/dist/cjs/internal/SupervisorProgram.d.ts +9 -0
- package/dist/cjs/internal/SupervisorProgram.d.ts.map +1 -0
- package/dist/cjs/internal/SupervisorProgram.js +326 -0
- package/dist/cjs/internal/SupervisorProgram.js.map +7 -0
- package/dist/cjs/internal/WindowsProcessJob.d.ts +39 -0
- package/dist/cjs/internal/WindowsProcessJob.d.ts.map +1 -0
- package/dist/cjs/internal/WindowsProcessJob.js +113 -0
- package/dist/cjs/internal/WindowsProcessJob.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/AtomicFileSystem.d.ts +147 -0
- package/dist/esm/AtomicFileSystem.d.ts.map +1 -0
- package/dist/esm/AtomicFileSystem.js +290 -0
- package/dist/esm/AtomicFileSystem.js.map +1 -0
- package/dist/esm/EgressHttpClient.d.ts +106 -0
- package/dist/esm/EgressHttpClient.d.ts.map +1 -0
- package/dist/esm/EgressHttpClient.js +259 -0
- package/dist/esm/EgressHttpClient.js.map +1 -0
- package/dist/esm/HostLiveness.d.ts +81 -0
- package/dist/esm/HostLiveness.d.ts.map +1 -0
- package/dist/esm/HostLiveness.js +68 -0
- package/dist/esm/HostLiveness.js.map +1 -0
- package/dist/esm/NodeHost.d.ts +145 -0
- package/dist/esm/NodeHost.d.ts.map +1 -0
- package/dist/esm/NodeHost.js +162 -0
- package/dist/esm/NodeHost.js.map +1 -0
- package/dist/esm/ProcessConfinement.d.ts +61 -0
- package/dist/esm/ProcessConfinement.d.ts.map +1 -0
- package/dist/esm/ProcessConfinement.js +311 -0
- package/dist/esm/ProcessConfinement.js.map +1 -0
- package/dist/esm/ProcessReaper.d.ts +457 -0
- package/dist/esm/ProcessReaper.d.ts.map +1 -0
- package/dist/esm/ProcessReaper.js +711 -0
- package/dist/esm/ProcessReaper.js.map +1 -0
- package/dist/esm/ProcessSandbox.d.ts +391 -0
- package/dist/esm/ProcessSandbox.d.ts.map +1 -0
- package/dist/esm/ProcessSandbox.js +1043 -0
- package/dist/esm/ProcessSandbox.js.map +1 -0
- package/dist/esm/ScopedProcess.d.ts +66 -0
- package/dist/esm/ScopedProcess.d.ts.map +1 -0
- package/dist/esm/ScopedProcess.js +67 -0
- package/dist/esm/ScopedProcess.js.map +1 -0
- package/dist/esm/index.d.ts +38 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +38 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/AtomicFileSystemExecutable.d.ts +61 -0
- package/dist/esm/internal/AtomicFileSystemExecutable.d.ts.map +1 -0
- package/dist/esm/internal/AtomicFileSystemExecutable.js +350 -0
- package/dist/esm/internal/AtomicFileSystemExecutable.js.map +1 -0
- package/dist/esm/internal/AtomicFileSystemProtocol.d.ts +78 -0
- package/dist/esm/internal/AtomicFileSystemProtocol.d.ts.map +1 -0
- package/dist/esm/internal/AtomicFileSystemProtocol.js +412 -0
- package/dist/esm/internal/AtomicFileSystemProtocol.js.map +1 -0
- package/dist/esm/internal/AtomicFileSystemTransport.d.ts +44 -0
- package/dist/esm/internal/AtomicFileSystemTransport.d.ts.map +1 -0
- package/dist/esm/internal/AtomicFileSystemTransport.js +242 -0
- package/dist/esm/internal/AtomicFileSystemTransport.js.map +1 -0
- package/dist/esm/internal/AtomicHelperError.d.ts +35 -0
- package/dist/esm/internal/AtomicHelperError.d.ts.map +1 -0
- package/dist/esm/internal/AtomicHelperError.js +39 -0
- package/dist/esm/internal/AtomicHelperError.js.map +1 -0
- package/dist/esm/internal/AtomicHelperFault.d.ts +59 -0
- package/dist/esm/internal/AtomicHelperFault.d.ts.map +1 -0
- package/dist/esm/internal/AtomicHelperFault.js +66 -0
- package/dist/esm/internal/AtomicHelperFault.js.map +1 -0
- package/dist/esm/internal/PipedProcess.d.ts +35 -0
- package/dist/esm/internal/PipedProcess.d.ts.map +1 -0
- package/dist/esm/internal/PipedProcess.js +321 -0
- package/dist/esm/internal/PipedProcess.js.map +1 -0
- package/dist/esm/internal/ProcSnapshot.d.ts +85 -0
- package/dist/esm/internal/ProcSnapshot.d.ts.map +1 -0
- package/dist/esm/internal/ProcSnapshot.js +188 -0
- package/dist/esm/internal/ProcSnapshot.js.map +1 -0
- package/dist/esm/internal/ProcessCleanup.d.ts +64 -0
- package/dist/esm/internal/ProcessCleanup.d.ts.map +1 -0
- package/dist/esm/internal/ProcessCleanup.js +45 -0
- package/dist/esm/internal/ProcessCleanup.js.map +1 -0
- package/dist/esm/internal/ProcessCleanupPolicyError.d.ts +30 -0
- package/dist/esm/internal/ProcessCleanupPolicyError.d.ts.map +1 -0
- package/dist/esm/internal/ProcessCleanupPolicyError.js +25 -0
- package/dist/esm/internal/ProcessCleanupPolicyError.js.map +1 -0
- package/dist/esm/internal/ProcessFault.d.ts +63 -0
- package/dist/esm/internal/ProcessFault.d.ts.map +1 -0
- package/dist/esm/internal/ProcessFault.js +64 -0
- package/dist/esm/internal/ProcessFault.js.map +1 -0
- package/dist/esm/internal/ProcessSupervisor.d.ts +143 -0
- package/dist/esm/internal/ProcessSupervisor.d.ts.map +1 -0
- package/dist/esm/internal/ProcessSupervisor.js +689 -0
- package/dist/esm/internal/ProcessSupervisor.js.map +1 -0
- package/dist/esm/internal/SupervisorProgram.d.ts +9 -0
- package/dist/esm/internal/SupervisorProgram.d.ts.map +1 -0
- package/dist/esm/internal/SupervisorProgram.js +310 -0
- package/dist/esm/internal/SupervisorProgram.js.map +1 -0
- package/dist/esm/internal/WindowsProcessJob.d.ts +39 -0
- package/dist/esm/internal/WindowsProcessJob.d.ts.map +1 -0
- package/dist/esm/internal/WindowsProcessJob.js +115 -0
- package/dist/esm/internal/WindowsProcessJob.js.map +1 -0
- package/dist/vendor/adapters.json +1757 -0
- package/dist/vendor/chunk-2Y7WC4KU.js +109 -0
- package/dist/vendor/chunk-3GR5VZ2M.js +118 -0
- package/dist/vendor/chunk-42QKY6T6.js +40 -0
- package/dist/vendor/chunk-54RLBMTZ.js +61 -0
- package/dist/vendor/chunk-5ZMHBXIK.js +55 -0
- package/dist/vendor/chunk-6ME2W7TF.js +28 -0
- package/dist/vendor/chunk-AMQKOQNT.js +34 -0
- package/dist/vendor/chunk-B3FZ67QU.js +59 -0
- package/dist/vendor/chunk-BKTBUBQY.js +437 -0
- package/dist/vendor/chunk-DS7GF46S.js +34 -0
- package/dist/vendor/chunk-DVOAHXPG.js +104 -0
- package/dist/vendor/chunk-DWSHTSVX.js +229 -0
- package/dist/vendor/chunk-EGBNVEEW.js +14 -0
- package/dist/vendor/chunk-EZWY45HP.js +18 -0
- package/dist/vendor/chunk-FNZOJHSV.js +71 -0
- package/dist/vendor/chunk-GXCHI7BM.js +131 -0
- package/dist/vendor/chunk-IIJ52ZU6.js +20 -0
- package/dist/vendor/chunk-J7A4CZDO.js +92 -0
- package/dist/vendor/chunk-JG5TTWPT.js +85 -0
- package/dist/vendor/chunk-JJ24ARBQ.js +394 -0
- package/dist/vendor/chunk-KOZMM5PZ.js +426 -0
- package/dist/vendor/chunk-KUUXSID7.js +18 -0
- package/dist/vendor/chunk-LEUPYT3Q.js +36 -0
- package/dist/vendor/chunk-M32LDTW7.js +18 -0
- package/dist/vendor/chunk-M7CLUILA.js +0 -0
- package/dist/vendor/chunk-MBSKBQ5D.js +21 -0
- package/dist/vendor/chunk-MLKGABMK.js +9 -0
- package/dist/vendor/chunk-NBVRTDTV.js +129 -0
- package/dist/vendor/chunk-OXNGN5H7.js +81 -0
- package/dist/vendor/chunk-QPLDT6A6.js +564 -0
- package/dist/vendor/chunk-QYBKAIA6.js +18 -0
- package/dist/vendor/chunk-RO2R4MJH.js +62 -0
- package/dist/vendor/chunk-SIR62W3Y.js +398 -0
- package/dist/vendor/chunk-TFIKFFSC.js +26 -0
- package/dist/vendor/chunk-TXKLEBBL.js +143 -0
- package/dist/vendor/chunk-UFH5UUZK.js +48 -0
- package/dist/vendor/chunk-VANKHF46.js +96 -0
- package/dist/vendor/chunk-VZBDV3TV.js +18 -0
- package/dist/vendor/chunk-XDKNKFBW.js +22 -0
- package/dist/vendor/chunk-XH4U3JSV.js +249 -0
- package/dist/vendor/chunk-Y35ZAO5U.js +53 -0
- package/dist/vendor/chunk-ZJMRMY57.js +0 -0
- package/dist/vendor/cjs/node/NodeChildProcessSpawner.d.ts +7 -0
- package/dist/vendor/cjs/node/NodeChildProcessSpawner.js +1 -0
- package/dist/vendor/cjs/node/NodeClusterHttp.d.ts +63 -0
- package/dist/vendor/cjs/node/NodeClusterHttp.js +1 -0
- package/dist/vendor/cjs/node/NodeClusterSocket.d.ts +79 -0
- package/dist/vendor/cjs/node/NodeClusterSocket.js +1 -0
- package/dist/vendor/cjs/node/NodeCrypto.d.ts +10 -0
- package/dist/vendor/cjs/node/NodeCrypto.js +1 -0
- package/dist/vendor/cjs/node/NodeFileSystem.d.ts +10 -0
- package/dist/vendor/cjs/node/NodeFileSystem.js +1 -0
- package/dist/vendor/cjs/node/NodeHttpClient.d.ts +179 -0
- package/dist/vendor/cjs/node/NodeHttpClient.js +1 -0
- package/dist/vendor/cjs/node/NodeHttpIncomingMessage.d.ts +62 -0
- package/dist/vendor/cjs/node/NodeHttpIncomingMessage.js +1 -0
- package/dist/vendor/cjs/node/NodeHttpPlatform.d.ts +36 -0
- package/dist/vendor/cjs/node/NodeHttpPlatform.js +1 -0
- package/dist/vendor/cjs/node/NodeHttpServer.d.ts +120 -0
- package/dist/vendor/cjs/node/NodeHttpServer.js +1 -0
- package/dist/vendor/cjs/node/NodeHttpServerRequest.d.ts +29 -0
- package/dist/vendor/cjs/node/NodeHttpServerRequest.js +1 -0
- package/dist/vendor/cjs/node/NodeMultipart.d.ts +46 -0
- package/dist/vendor/cjs/node/NodeMultipart.js +1 -0
- package/dist/vendor/cjs/node/NodeMultipartParser.d.ts +97 -0
- package/dist/vendor/cjs/node/NodeMultipartParser.js +1 -0
- package/dist/vendor/cjs/node/NodePath.d.ts +27 -0
- package/dist/vendor/cjs/node/NodePath.js +1 -0
- package/dist/vendor/cjs/node/NodeRedis.d.ts +74 -0
- package/dist/vendor/cjs/node/NodeRedis.js +1 -0
- package/dist/vendor/cjs/node/NodeRuntime.d.ts +85 -0
- package/dist/vendor/cjs/node/NodeRuntime.js +1 -0
- package/dist/vendor/cjs/node/NodeServices.d.ts +34 -0
- package/dist/vendor/cjs/node/NodeServices.js +1 -0
- package/dist/vendor/cjs/node/NodeSink.d.ts +8 -0
- package/dist/vendor/cjs/node/NodeSink.js +1 -0
- package/dist/vendor/cjs/node/NodeSocket.d.ts +38 -0
- package/dist/vendor/cjs/node/NodeSocket.js +1 -0
- package/dist/vendor/cjs/node/NodeSocketServer.d.ts +8 -0
- package/dist/vendor/cjs/node/NodeSocketServer.js +1 -0
- package/dist/vendor/cjs/node/NodeStdio.d.ts +11 -0
- package/dist/vendor/cjs/node/NodeStdio.js +1 -0
- package/dist/vendor/cjs/node/NodeStream.d.ts +8 -0
- package/dist/vendor/cjs/node/NodeStream.js +1 -0
- package/dist/vendor/cjs/node/NodeTerminal.d.ts +21 -0
- package/dist/vendor/cjs/node/NodeTerminal.js +1 -0
- package/dist/vendor/cjs/node/NodeWorker.d.ts +22 -0
- package/dist/vendor/cjs/node/NodeWorker.js +1 -0
- package/dist/vendor/cjs/node/NodeWorkerRunner.d.ts +12 -0
- package/dist/vendor/cjs/node/NodeWorkerRunner.js +1 -0
- package/dist/vendor/cjs/node/Undici.d.ts +28 -0
- package/dist/vendor/cjs/node/Undici.js +1 -0
- package/dist/vendor/cjs/node/index.d.ts +100 -0
- package/dist/vendor/cjs/node/index.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.d.ts +57 -0
- package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeClusterSocket.d.ts +22 -0
- package/dist/vendor/cjs/node-shared/NodeClusterSocket.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeCrypto.d.ts +27 -0
- package/dist/vendor/cjs/node-shared/NodeCrypto.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeFileSystem.d.ts +11 -0
- package/dist/vendor/cjs/node-shared/NodeFileSystem.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeHttpCompression.d.ts +36 -0
- package/dist/vendor/cjs/node-shared/NodeHttpCompression.js +1 -0
- package/dist/vendor/cjs/node-shared/NodePath.d.ts +27 -0
- package/dist/vendor/cjs/node-shared/NodePath.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeRuntime.d.ts +47 -0
- package/dist/vendor/cjs/node-shared/NodeRuntime.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeSink.d.ts +69 -0
- package/dist/vendor/cjs/node-shared/NodeSink.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeSocket.d.ts +134 -0
- package/dist/vendor/cjs/node-shared/NodeSocket.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeSocketServer.d.ts +80 -0
- package/dist/vendor/cjs/node-shared/NodeSocketServer.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeStdio.d.ts +12 -0
- package/dist/vendor/cjs/node-shared/NodeStdio.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeStream.d.ts +179 -0
- package/dist/vendor/cjs/node-shared/NodeStream.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeTerminal.d.ts +22 -0
- package/dist/vendor/cjs/node-shared/NodeTerminal.js +1 -0
- package/dist/vendor/cjs/node-shared/index.d.ts +56 -0
- package/dist/vendor/cjs/node-shared/index.js +1 -0
- package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.d.ts +4 -0
- package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.js +1 -0
- package/dist/vendor/cjs/node-shared/internal/utils.d.ts +2 -0
- package/dist/vendor/cjs/node-shared/internal/utils.js +1 -0
- package/dist/vendor/cjs/package.json +1 -0
- package/dist/vendor/cjs/platform-node-shared.d.ts +56 -0
- package/dist/vendor/cjs/platform-node-shared.js +1 -0
- package/dist/vendor/cjs/platform-node.d.ts +100 -0
- package/dist/vendor/cjs/platform-node.js +1 -0
- package/dist/vendor/node/LICENSE +21 -0
- package/dist/vendor/node/NodeChildProcessSpawner.d.ts +7 -0
- package/dist/vendor/node/NodeChildProcessSpawner.js +14 -0
- package/dist/vendor/node/NodeClusterHttp.d.ts +63 -0
- package/dist/vendor/node/NodeClusterHttp.js +43 -0
- package/dist/vendor/node/NodeClusterSocket.d.ts +79 -0
- package/dist/vendor/node/NodeClusterSocket.js +30 -0
- package/dist/vendor/node/NodeCrypto.d.ts +10 -0
- package/dist/vendor/node/NodeCrypto.js +8 -0
- package/dist/vendor/node/NodeFileSystem.d.ts +10 -0
- package/dist/vendor/node/NodeFileSystem.js +9 -0
- package/dist/vendor/node/NodeHttpClient.d.ts +179 -0
- package/dist/vendor/node/NodeHttpClient.js +46 -0
- package/dist/vendor/node/NodeHttpIncomingMessage.d.ts +62 -0
- package/dist/vendor/node/NodeHttpIncomingMessage.js +10 -0
- package/dist/vendor/node/NodeHttpPlatform.d.ts +36 -0
- package/dist/vendor/node/NodeHttpPlatform.js +16 -0
- package/dist/vendor/node/NodeHttpServer.d.ts +120 -0
- package/dist/vendor/node/NodeHttpServer.js +46 -0
- package/dist/vendor/node/NodeHttpServerRequest.d.ts +29 -0
- package/dist/vendor/node/NodeHttpServerRequest.js +9 -0
- package/dist/vendor/node/NodeMultipart.d.ts +46 -0
- package/dist/vendor/node/NodeMultipart.js +15 -0
- package/dist/vendor/node/NodeMultipartParser.d.ts +97 -0
- package/dist/vendor/node/NodeMultipartParser.js +11 -0
- package/dist/vendor/node/NodePath.d.ts +27 -0
- package/dist/vendor/node/NodePath.js +12 -0
- package/dist/vendor/node/NodeRedis.d.ts +74 -0
- package/dist/vendor/node/NodeRedis.js +11 -0
- package/dist/vendor/node/NodeRuntime.d.ts +85 -0
- package/dist/vendor/node/NodeRuntime.js +8 -0
- package/dist/vendor/node/NodeServices.d.ts +34 -0
- package/dist/vendor/node/NodeServices.js +23 -0
- package/dist/vendor/node/NodeSink.d.ts +8 -0
- package/dist/vendor/node/NodeSink.js +12 -0
- package/dist/vendor/node/NodeSocket.d.ts +38 -0
- package/dist/vendor/node/NodeSocket.js +31 -0
- package/dist/vendor/node/NodeSocketServer.d.ts +8 -0
- package/dist/vendor/node/NodeSocketServer.js +21 -0
- package/dist/vendor/node/NodeStdio.d.ts +11 -0
- package/dist/vendor/node/NodeStdio.js +10 -0
- package/dist/vendor/node/NodeStream.d.ts +8 -0
- package/dist/vendor/node/NodeStream.js +27 -0
- package/dist/vendor/node/NodeTerminal.d.ts +21 -0
- package/dist/vendor/node/NodeTerminal.js +10 -0
- package/dist/vendor/node/NodeWorker.d.ts +22 -0
- package/dist/vendor/node/NodeWorker.js +9 -0
- package/dist/vendor/node/NodeWorkerRunner.d.ts +12 -0
- package/dist/vendor/node/NodeWorkerRunner.js +7 -0
- package/dist/vendor/node/Undici.d.ts +28 -0
- package/dist/vendor/node/Undici.js +9 -0
- package/dist/vendor/node/index.d.ts +100 -0
- package/dist/vendor/node/index.js +115 -0
- package/dist/vendor/node-shared/LICENSE +21 -0
- package/dist/vendor/node-shared/NodeChildProcessSpawner.d.ts +57 -0
- package/dist/vendor/node-shared/NodeChildProcessSpawner.js +13 -0
- package/dist/vendor/node-shared/NodeClusterSocket.d.ts +22 -0
- package/dist/vendor/node-shared/NodeClusterSocket.js +11 -0
- package/dist/vendor/node-shared/NodeCrypto.d.ts +27 -0
- package/dist/vendor/node-shared/NodeCrypto.js +9 -0
- package/dist/vendor/node-shared/NodeFileSystem.d.ts +11 -0
- package/dist/vendor/node-shared/NodeFileSystem.js +8 -0
- package/dist/vendor/node-shared/NodeHttpCompression.d.ts +36 -0
- package/dist/vendor/node-shared/NodeHttpCompression.js +13 -0
- package/dist/vendor/node-shared/NodePath.d.ts +27 -0
- package/dist/vendor/node-shared/NodePath.js +11 -0
- package/dist/vendor/node-shared/NodeRuntime.d.ts +47 -0
- package/dist/vendor/node-shared/NodeRuntime.js +7 -0
- package/dist/vendor/node-shared/NodeSink.d.ts +69 -0
- package/dist/vendor/node-shared/NodeSink.js +11 -0
- package/dist/vendor/node-shared/NodeSocket.d.ts +134 -0
- package/dist/vendor/node-shared/NodeSocket.js +23 -0
- package/dist/vendor/node-shared/NodeSocketServer.d.ts +80 -0
- package/dist/vendor/node-shared/NodeSocketServer.js +20 -0
- package/dist/vendor/node-shared/NodeStdio.d.ts +12 -0
- package/dist/vendor/node-shared/NodeStdio.js +9 -0
- package/dist/vendor/node-shared/NodeStream.d.ts +179 -0
- package/dist/vendor/node-shared/NodeStream.js +26 -0
- package/dist/vendor/node-shared/NodeTerminal.d.ts +22 -0
- package/dist/vendor/node-shared/NodeTerminal.js +9 -0
- package/dist/vendor/node-shared/index.d.ts +56 -0
- package/dist/vendor/node-shared/index.js +58 -0
- package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.d.ts +4 -0
- package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.js +7 -0
- package/dist/vendor/node-shared/internal/utils.d.ts +2 -0
- package/dist/vendor/node-shared/internal/utils.js +7 -0
- package/dist/vendor/platform-node-shared.d.ts +56 -0
- package/dist/vendor/platform-node-shared.js +58 -0
- package/dist/vendor/platform-node.d.ts +100 -0
- package/dist/vendor/platform-node.js +115 -0
- package/docs/README.md +129 -0
- package/docs/api.md +553 -0
- package/docs/concepts/descriptor-relative-filesystem.md +181 -0
- package/docs/concepts/host-bundle.md +125 -0
- package/docs/concepts/process-containment.md +190 -0
- package/docs/guides/answer-run-ownership.md +87 -0
- package/docs/guides/configure-the-filesystem-helper.md +152 -0
- package/docs/guides/contain-child-processes.md +139 -0
- package/docs/guides/match-files-with-glob.md +151 -0
- package/docs/installation.md +204 -0
- package/docs/quickstart.md +147 -0
- package/docs/troubleshooting.md +130 -0
- package/package.json +202 -3
- package/src/AtomicFileSystem.ts +415 -0
- package/src/EgressHttpClient.ts +327 -0
- package/src/HostLiveness.ts +103 -0
- package/src/NodeHost.ts +253 -0
- package/src/ProcessConfinement.ts +363 -0
- package/src/ProcessReaper.ts +951 -0
- package/src/ProcessSandbox.ts +1307 -0
- package/src/ScopedProcess.ts +124 -0
- package/src/index.ts +44 -0
- package/src/internal/AtomicFileSystemExecutable.ts +379 -0
- package/src/internal/AtomicFileSystemProtocol.ts +502 -0
- package/src/internal/AtomicFileSystemTransport.ts +272 -0
- package/src/internal/AtomicHelperError.ts +50 -0
- package/src/internal/AtomicHelperFault.ts +84 -0
- package/src/internal/PipedProcess.ts +357 -0
- package/src/internal/ProcSnapshot.ts +193 -0
- package/src/internal/ProcessCleanup.ts +99 -0
- package/src/internal/ProcessCleanupPolicyError.ts +30 -0
- package/src/internal/ProcessFault.ts +82 -0
- package/src/internal/ProcessSupervisor.ts +807 -0
- package/src/internal/SupervisorProgram.ts +309 -0
- package/src/internal/WindowsProcessJob.ts +114 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native I/O ownership for transient commands and prepared process owners.
|
|
3
|
+
* @since 1.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as NodeSink from "@effect/platform-node/NodeSink"
|
|
7
|
+
import * as NodeStream from "@effect/platform-node/NodeStream"
|
|
8
|
+
import * as Effect from "effect/Effect"
|
|
9
|
+
import * as PlatformError from "effect/PlatformError"
|
|
10
|
+
import type * as Scope from "effect/Scope"
|
|
11
|
+
import * as Sink from "effect/Sink"
|
|
12
|
+
import * as Stream from "effect/Stream"
|
|
13
|
+
import * as ChildProcess from "effect/unstable/process/ChildProcess"
|
|
14
|
+
import { type ChildProcessHandle, ExitCode, makeHandle, ProcessId } from "effect/unstable/process/ChildProcessSpawner"
|
|
15
|
+
import * as Native from "node:child_process"
|
|
16
|
+
import { NativeProcessError } from "./ProcessFault.ts"
|
|
17
|
+
|
|
18
|
+
const ownerDescriptors = new WeakMap<ChildProcessHandle, ReadonlyArray<number | "ignore">>()
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Windows owners receive caller streams above the reserved CRT standard slots.
|
|
22
|
+
* @private
|
|
23
|
+
* @since 1.0.0
|
|
24
|
+
*/
|
|
25
|
+
export const standardFdsOf = (handle: ChildProcessHandle): ReadonlyArray<number | "ignore"> | undefined =>
|
|
26
|
+
ownerDescriptors.get(handle)
|
|
27
|
+
|
|
28
|
+
const promise = <A>() => {
|
|
29
|
+
let resolve!: (value: A) => void
|
|
30
|
+
let reject!: (cause: unknown) => void
|
|
31
|
+
const promise = new Promise<A>((onSuccess, onFailure) => {
|
|
32
|
+
resolve = onSuccess
|
|
33
|
+
reject = onFailure
|
|
34
|
+
})
|
|
35
|
+
void promise.catch(() => {})
|
|
36
|
+
return { promise, resolve, reject }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Converts native errors without losing their errno or signal.
|
|
41
|
+
* @private
|
|
42
|
+
* @since 1.0.0
|
|
43
|
+
*/
|
|
44
|
+
export const failure = (method: string, cause: unknown): PlatformError.PlatformError => {
|
|
45
|
+
const error = cause instanceof Error ? cause : new NativeProcessError({ message: String(cause) })
|
|
46
|
+
const code = (error as NodeJS.ErrnoException).code
|
|
47
|
+
return PlatformError.systemError({
|
|
48
|
+
_tag: code === "ENOENT" ? "NotFound" : code === "EACCES" || code === "EPERM" ? "PermissionDenied" : "Unknown",
|
|
49
|
+
module: "ChildProcess",
|
|
50
|
+
method,
|
|
51
|
+
description: error.message,
|
|
52
|
+
cause: error
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const inputConfig = (value: ChildProcess.CommandOptions["stdin"]): ChildProcess.StdinConfig =>
|
|
57
|
+
value === undefined || typeof value === "string" || Stream.isStream(value)
|
|
58
|
+
? { stream: value ?? "pipe" }
|
|
59
|
+
: value
|
|
60
|
+
|
|
61
|
+
const outputConfig = (
|
|
62
|
+
value: ChildProcess.CommandOptions["stdout"]
|
|
63
|
+
): ChildProcess.CommandOutput =>
|
|
64
|
+
value === undefined || typeof value === "string" || Sink.isSink(value)
|
|
65
|
+
? value ?? "pipe"
|
|
66
|
+
: value.stream ?? "pipe"
|
|
67
|
+
|
|
68
|
+
const descriptorConfig = (options: ChildProcess.CommandOptions) => {
|
|
69
|
+
const stdin = inputConfig(options.stdin)
|
|
70
|
+
const stdout = outputConfig(options.stdout)
|
|
71
|
+
const stderr = outputConfig(options.stderr)
|
|
72
|
+
const additional: Array<{ readonly fd: number; readonly config: ChildProcess.AdditionalFdConfig }> = []
|
|
73
|
+
for (const [name, config] of Object.entries(options.additionalFds ?? {})) {
|
|
74
|
+
const fd = ChildProcess.parseFdName(name)
|
|
75
|
+
if (fd === undefined) continue
|
|
76
|
+
// A sparse descriptor declaration must not allocate an unbounded stdio
|
|
77
|
+
// table. The OS may impose a smaller limit when opening the actual pipes.
|
|
78
|
+
if (!Number.isSafeInteger(fd) || fd > 65_535) {
|
|
79
|
+
throw new RangeError("Additional file descriptors must be below 65536")
|
|
80
|
+
}
|
|
81
|
+
additional.push({ fd, config })
|
|
82
|
+
}
|
|
83
|
+
additional.sort((left, right) => left.fd - right.fd)
|
|
84
|
+
const stdio: Array<Native.IOType> = Array.from(
|
|
85
|
+
{ length: Math.max(2, ...additional.map(({ fd }) => fd)) + 1 },
|
|
86
|
+
() => "ignore"
|
|
87
|
+
)
|
|
88
|
+
stdio[0] = typeof stdin.stream === "string" ? stdin.stream : "pipe"
|
|
89
|
+
stdio[1] = typeof stdout === "string" ? stdout : "pipe"
|
|
90
|
+
stdio[2] = typeof stderr === "string" ? stderr : "pipe"
|
|
91
|
+
for (const { fd } of additional) stdio[fd] = "pipe"
|
|
92
|
+
return { stdin, stdout, stderr, additional, stdio }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Native standard-command I/O, including configured streams and custom pipes.
|
|
97
|
+
* Lifetime error listeners remain on every owned pipe after any consumer is
|
|
98
|
+
* interrupted, so a pending native write cannot raise an unhandled late EPIPE.
|
|
99
|
+
* Consumers still receive the original error through NodeStream/NodeSink.
|
|
100
|
+
* This adapter also preserves native Windows verbatim arguments.
|
|
101
|
+
*
|
|
102
|
+
* It never sends a negative-pid signal. POSIX tree cleanup belongs to the
|
|
103
|
+
* prepared supervisor, which remains alive while it signals its own group.
|
|
104
|
+
* @private
|
|
105
|
+
* @since 1.0.0
|
|
106
|
+
*/
|
|
107
|
+
export const spawn = (
|
|
108
|
+
command: ChildProcess.StandardCommand,
|
|
109
|
+
windowsVerbatimArguments: boolean | undefined,
|
|
110
|
+
owner = false
|
|
111
|
+
): Effect.Effect<ChildProcessHandle, PlatformError.PlatformError, Scope.Scope> =>
|
|
112
|
+
Effect.gen(function*() {
|
|
113
|
+
const descriptors = yield* Effect.try({
|
|
114
|
+
try: () => descriptorConfig(command.options),
|
|
115
|
+
catch: (cause) => failure("spawn", cause)
|
|
116
|
+
})
|
|
117
|
+
const standardFds: Array<number | "ignore"> = [0, 1, 2]
|
|
118
|
+
const physicalFds = [0, 1, 2]
|
|
119
|
+
const stdio: Array<Native.IOType | number> = [...descriptors.stdio]
|
|
120
|
+
if (owner && process.platform === "win32") {
|
|
121
|
+
const first = stdio.length
|
|
122
|
+
for (const fd of [0, 1, 2]) {
|
|
123
|
+
const mode = stdio[fd]!
|
|
124
|
+
physicalFds[fd] = first + fd
|
|
125
|
+
standardFds[fd] = mode === "ignore" ? "ignore" : first + fd
|
|
126
|
+
stdio.push(mode === "inherit" ? fd : mode)
|
|
127
|
+
stdio[fd] = "ignore"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const state = yield* Effect.acquireRelease(
|
|
131
|
+
Effect.try({
|
|
132
|
+
try: () => {
|
|
133
|
+
const ready = promise<void>()
|
|
134
|
+
// Startup errors reject ready before any handle is exposed. Once
|
|
135
|
+
// started, the native exit event or retained native status supplies
|
|
136
|
+
// this result.
|
|
137
|
+
let recordExit!: (result: readonly [number | null, NodeJS.Signals | null]) => void
|
|
138
|
+
const exited = new Promise<readonly [number | null, NodeJS.Signals | null]>((resolve) => {
|
|
139
|
+
recordExit = resolve
|
|
140
|
+
})
|
|
141
|
+
const options = command.options
|
|
142
|
+
const child = Native.spawn(command.command, [...command.args], {
|
|
143
|
+
cwd: options.cwd,
|
|
144
|
+
env: options.extendEnv ? { ...process.env, ...options.env } : options.env,
|
|
145
|
+
shell: options.shell,
|
|
146
|
+
detached: options.detached ?? process.platform !== "win32",
|
|
147
|
+
windowsHide: options.windowsHide ?? true,
|
|
148
|
+
windowsVerbatimArguments,
|
|
149
|
+
stdio
|
|
150
|
+
})
|
|
151
|
+
const state = {
|
|
152
|
+
child,
|
|
153
|
+
ready: ready.promise,
|
|
154
|
+
exited,
|
|
155
|
+
ended: false,
|
|
156
|
+
started: false,
|
|
157
|
+
referenced: true,
|
|
158
|
+
pipeErrors: new WeakMap<object, Error>(),
|
|
159
|
+
error: undefined as Error | undefined
|
|
160
|
+
}
|
|
161
|
+
child.once("spawn", () => {
|
|
162
|
+
state.started = true
|
|
163
|
+
ready.resolve()
|
|
164
|
+
})
|
|
165
|
+
child.on("error", (error) => {
|
|
166
|
+
state.error = error
|
|
167
|
+
if (!state.started) {
|
|
168
|
+
state.ended = true
|
|
169
|
+
ready.reject(error)
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
const onExit = (code: number | null, signal: NodeJS.Signals | null) => {
|
|
173
|
+
state.ended = true
|
|
174
|
+
recordExit([code, signal])
|
|
175
|
+
}
|
|
176
|
+
child.once("exit", onExit)
|
|
177
|
+
// Bun can emit spawn before Native.spawn returns on a cold start.
|
|
178
|
+
// A returned pid proves that the native child was created; failed
|
|
179
|
+
// native spawns have no pid and still reject through the error event.
|
|
180
|
+
if (child.pid !== undefined) {
|
|
181
|
+
state.started = true
|
|
182
|
+
ready.resolve()
|
|
183
|
+
}
|
|
184
|
+
// Likewise retain an exit already reflected by the native handle
|
|
185
|
+
// before listeners could attach. Later events settle the same result.
|
|
186
|
+
if (child.exitCode != null || child.signalCode != null) {
|
|
187
|
+
onExit(child.exitCode ?? null, child.signalCode ?? null)
|
|
188
|
+
}
|
|
189
|
+
// A pipe can fail before a consumer has started reading or writing.
|
|
190
|
+
// Preserve the cause for consumers that attach after its error event.
|
|
191
|
+
for (const pipe of child.stdio) {
|
|
192
|
+
pipe?.on("error", (error: Error) => {
|
|
193
|
+
state.pipeErrors.set(pipe, error)
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
// Node resumes unread stdio after exit to deliver its close event.
|
|
197
|
+
// A fast target can exit before activation returns the public handle;
|
|
198
|
+
// flowing at that point discards bytes before any consumer subscribes.
|
|
199
|
+
// Keep declared outputs in readable mode for their entire lifetime.
|
|
200
|
+
// This listener does not drain or copy data: the native high-water
|
|
201
|
+
// mark still applies backpressure until NodeStream pulls the bytes.
|
|
202
|
+
for (
|
|
203
|
+
const fd of [
|
|
204
|
+
physicalFds[1]!,
|
|
205
|
+
physicalFds[2]!,
|
|
206
|
+
...descriptors.additional.filter(({ config }) => config.type === "output").map(({ fd }) => fd)
|
|
207
|
+
]
|
|
208
|
+
) {
|
|
209
|
+
const pipe = child.stdio[fd]
|
|
210
|
+
pipe?.on("readable", () => {})
|
|
211
|
+
// POSIX sockets can close the unused writer independently. Bun
|
|
212
|
+
// needs this to retain buffered output after child exit. Windows
|
|
213
|
+
// named-pipe shutdown instead starts libuv's EOF timer, which can
|
|
214
|
+
// close both directions before the child writes. Leave it open.
|
|
215
|
+
if (process.platform !== "win32" && fd > 2 && pipe !== null && pipe !== undefined && "end" in pipe) {
|
|
216
|
+
pipe.end()
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return state
|
|
220
|
+
},
|
|
221
|
+
catch: (cause) => failure("spawn", cause)
|
|
222
|
+
}),
|
|
223
|
+
(state) =>
|
|
224
|
+
Effect.gen(function*() {
|
|
225
|
+
if (state.referenced && !state.ended) {
|
|
226
|
+
yield* Effect.try({
|
|
227
|
+
try: () => {
|
|
228
|
+
// Native kill returns false for an exit whose event is still
|
|
229
|
+
// queued. Require that event below; never infer a live failure
|
|
230
|
+
// or successful cleanup from the boolean alone.
|
|
231
|
+
if (!state.child.kill("SIGKILL") && state.error !== undefined) throw state.error
|
|
232
|
+
},
|
|
233
|
+
catch: (cause) => failure("kill", cause)
|
|
234
|
+
})
|
|
235
|
+
yield* Effect.promise(() => state.exited).pipe(
|
|
236
|
+
Effect.timeout("2 seconds")
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
}).pipe(
|
|
240
|
+
Effect.ensuring(Effect.sync(() => {
|
|
241
|
+
for (const pipe of state.child.stdio) {
|
|
242
|
+
if (pipe !== null && pipe !== undefined && "destroy" in pipe && typeof pipe.destroy === "function") {
|
|
243
|
+
pipe.destroy()
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
})),
|
|
247
|
+
Effect.orDie
|
|
248
|
+
)
|
|
249
|
+
)
|
|
250
|
+
yield* Effect.tryPromise({ try: () => state.ready, catch: (cause) => failure("spawn", cause) })
|
|
251
|
+
const wait = Effect.promise(() => state.exited)
|
|
252
|
+
const kill: ChildProcessHandle["kill"] = (options) =>
|
|
253
|
+
Effect.suspend(() => {
|
|
254
|
+
if (state.ended) return Effect.void
|
|
255
|
+
const signal = options?.killSignal ?? command.options.killSignal ?? "SIGTERM"
|
|
256
|
+
const send = (signal: ChildProcess.Signal) =>
|
|
257
|
+
Effect.try({
|
|
258
|
+
try: () => {
|
|
259
|
+
if (!state.child.kill(signal) && state.error !== undefined) throw state.error
|
|
260
|
+
},
|
|
261
|
+
catch: (cause) => failure("kill", cause)
|
|
262
|
+
})
|
|
263
|
+
return send(signal).pipe(
|
|
264
|
+
Effect.andThen(wait.pipe(Effect.timeoutOrElse({
|
|
265
|
+
duration: options?.forceKillAfter ?? command.options.forceKillAfter ?? 2000,
|
|
266
|
+
orElse: () => send("SIGKILL").pipe(Effect.andThen(wait), Effect.timeout("2 seconds"))
|
|
267
|
+
}))),
|
|
268
|
+
Effect.mapError((cause) => cause instanceof PlatformError.PlatformError ? cause : failure("kill", cause)),
|
|
269
|
+
Effect.asVoid,
|
|
270
|
+
Effect.uninterruptible
|
|
271
|
+
)
|
|
272
|
+
})
|
|
273
|
+
const input = (fd: number, config?: ChildProcess.StdinConfig): ChildProcessHandle["stdin"] => {
|
|
274
|
+
const pipe = state.child.stdio[fd]
|
|
275
|
+
if (pipe === null || pipe === undefined || !("write" in pipe)) return Sink.drain
|
|
276
|
+
const writable = pipe
|
|
277
|
+
const method = fd === 0 ? "stdin" : `fd${fd}`
|
|
278
|
+
return Sink.suspend(() => {
|
|
279
|
+
const error = state.pipeErrors.get(pipe) ?? writable.errored ?? undefined
|
|
280
|
+
if (error !== undefined) return Sink.fail(failure(method, error))
|
|
281
|
+
if (writable.destroyed || writable.writableEnded) {
|
|
282
|
+
return Sink.fail(failure(method, new NativeProcessError({ message: `${method} is closed`, code: "EPIPE" })))
|
|
283
|
+
}
|
|
284
|
+
return NodeSink.fromWritable({
|
|
285
|
+
evaluate: () => writable,
|
|
286
|
+
onError: (cause) => failure(method, cause),
|
|
287
|
+
encoding: config?.encoding,
|
|
288
|
+
endOnDone: config?.endOnDone
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
const output = (fd: number, transform?: ChildProcess.CommandOutput): ChildProcessHandle["stdout"] => {
|
|
293
|
+
const pipe = state.child.stdio[fd]
|
|
294
|
+
const stream = pipe !== null && pipe !== undefined && "read" in pipe
|
|
295
|
+
? Stream.suspend(() => {
|
|
296
|
+
const method = fd === 1 ? "stdout" : fd === 2 ? "stderr" : `fd${fd}`
|
|
297
|
+
const error = state.pipeErrors.get(pipe) ?? pipe.errored ?? undefined
|
|
298
|
+
return error !== undefined ?
|
|
299
|
+
Stream.fail(failure(method, error)) :
|
|
300
|
+
NodeStream.fromReadable<Uint8Array, PlatformError.PlatformError>({
|
|
301
|
+
evaluate: () => pipe,
|
|
302
|
+
onError: (cause) => failure(method, cause)
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
: Stream.empty
|
|
306
|
+
return Sink.isSink(transform) ? Stream.transduce(stream, transform) : stream
|
|
307
|
+
}
|
|
308
|
+
const stdin = input(physicalFds[0]!, descriptors.stdin)
|
|
309
|
+
const stdout = output(physicalFds[1]!, descriptors.stdout)
|
|
310
|
+
const stderr = output(physicalFds[2]!, descriptors.stderr)
|
|
311
|
+
if (Stream.isStream(descriptors.stdin.stream)) {
|
|
312
|
+
yield* Stream.run(descriptors.stdin.stream, stdin).pipe(Effect.forkScoped)
|
|
313
|
+
}
|
|
314
|
+
const inputs = new Map<number, ChildProcessHandle["stdin"]>()
|
|
315
|
+
const outputs = new Map<number, ChildProcessHandle["stdout"]>()
|
|
316
|
+
for (const { fd, config } of descriptors.additional) {
|
|
317
|
+
if (config.type === "input") {
|
|
318
|
+
const sink = input(fd)
|
|
319
|
+
inputs.set(fd, sink)
|
|
320
|
+
if (config.stream !== undefined) yield* Stream.run(config.stream, sink).pipe(Effect.forkScoped)
|
|
321
|
+
} else outputs.set(fd, output(fd, config.sink))
|
|
322
|
+
}
|
|
323
|
+
const handle = makeHandle({
|
|
324
|
+
pid: ProcessId(state.child.pid!),
|
|
325
|
+
exitCode: wait.pipe(Effect.flatMap(([code, signal]) =>
|
|
326
|
+
code === null
|
|
327
|
+
? Effect.fail(
|
|
328
|
+
failure(
|
|
329
|
+
"exitCode",
|
|
330
|
+
new NativeProcessError({
|
|
331
|
+
message: `Process interrupted due to receipt of signal: '${signal}'`,
|
|
332
|
+
signal: String(signal)
|
|
333
|
+
})
|
|
334
|
+
)
|
|
335
|
+
)
|
|
336
|
+
: Effect.succeed(ExitCode(code))
|
|
337
|
+
)),
|
|
338
|
+
isRunning: Effect.sync(() => !state.ended),
|
|
339
|
+
kill,
|
|
340
|
+
stdin,
|
|
341
|
+
stdout,
|
|
342
|
+
stderr,
|
|
343
|
+
all: Stream.merge(stdout, stderr),
|
|
344
|
+
getInputFd: (fd) => inputs.get(fd) ?? Sink.drain,
|
|
345
|
+
getOutputFd: (fd) => outputs.get(fd) ?? Stream.empty,
|
|
346
|
+
unref: Effect.sync(() => {
|
|
347
|
+
state.referenced = false
|
|
348
|
+
state.child.unref()
|
|
349
|
+
return Effect.sync(() => {
|
|
350
|
+
state.referenced = true
|
|
351
|
+
state.child.ref()
|
|
352
|
+
})
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
if (owner && process.platform === "win32") ownerDescriptors.set(handle, standardFds)
|
|
356
|
+
return handle
|
|
357
|
+
})
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-group observation read from Linux `/proc`, with no `ps` binary.
|
|
3
|
+
* @since 1.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readdirSync, readFileSync } from "node:fs"
|
|
7
|
+
import type * as ProcessCleanup from "./ProcessCleanup.ts"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The kernel's own process table, which is the production root.
|
|
11
|
+
* @private
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
export const defaultProcRoot = "/proc"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The `/proc` root a platform publishes its process table under, if any.
|
|
18
|
+
* @private
|
|
19
|
+
* @since 1.0.0-rc.1
|
|
20
|
+
*/
|
|
21
|
+
export const rootFor = (platform: string): string | undefined => platform === "linux" ? defaultProcRoot : undefined
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* `/proc` reports `starttime` in USER_HZ, which Linux fixes at 100 for this
|
|
25
|
+
* interface however the running kernel is configured.
|
|
26
|
+
*/
|
|
27
|
+
const userHz = 100
|
|
28
|
+
|
|
29
|
+
/** A pid, as both a directory name and the first field of a stat line. */
|
|
30
|
+
const pidName = /^[0-9]+$/
|
|
31
|
+
|
|
32
|
+
/** `/proc/stat`'s boot instant, in seconds since the epoch. */
|
|
33
|
+
const bootLine = /^btime[ \t]+([0-9]+)$/m
|
|
34
|
+
|
|
35
|
+
/** Fields 3 through 22 inclusive: state, then pgrp third, then starttime. */
|
|
36
|
+
const statFieldsAfterComm = 20
|
|
37
|
+
|
|
38
|
+
/** A read that failed because the file is no longer there. */
|
|
39
|
+
const missing = (cause: unknown): boolean => (cause as NodeJS.ErrnoException).code === "ENOENT"
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* One process's group, zombie state and start time, from a `/proc/<pid>/stat`
|
|
43
|
+
* line.
|
|
44
|
+
*
|
|
45
|
+
* `comm` is the second field, it is wrapped in parentheses, and a process may
|
|
46
|
+
* put both spaces and parentheses inside it, so the numeric fields after it are
|
|
47
|
+
* taken from the LAST `)` rather than by splitting the whole line. The first
|
|
48
|
+
* field after that paren is field 3, so field N is at index N - 3.
|
|
49
|
+
*
|
|
50
|
+
* Anything that is not a stat line in that shape answers `undefined` rather
|
|
51
|
+
* than a record built out of whichever fields happened to parse.
|
|
52
|
+
* @private
|
|
53
|
+
* @since 1.0.0
|
|
54
|
+
*/
|
|
55
|
+
export const parseStat = (
|
|
56
|
+
text: string,
|
|
57
|
+
bootMs: number
|
|
58
|
+
): { readonly pgid: number; readonly member: ProcessCleanup.Member } | undefined => {
|
|
59
|
+
const open = text.indexOf("(")
|
|
60
|
+
const close = text.lastIndexOf(")")
|
|
61
|
+
if (open <= 0 || close < open) return undefined
|
|
62
|
+
const head = text.slice(0, open).trim()
|
|
63
|
+
if (!pidName.test(head)) return undefined
|
|
64
|
+
const after = text.slice(close + 1).trim().split(/[ \t]+/)
|
|
65
|
+
if (after.length < statFieldsAfterComm) return undefined
|
|
66
|
+
const pid = Number(head)
|
|
67
|
+
const pgid = Number(after[2])
|
|
68
|
+
const startedTicks = Number(after[19])
|
|
69
|
+
if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(pgid) || !Number.isSafeInteger(startedTicks)) {
|
|
70
|
+
return undefined
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
pgid,
|
|
74
|
+
// A zombie holds a slot without being a process the caller has to wait for,
|
|
75
|
+
// so the distinction has to survive the read.
|
|
76
|
+
member: { pid, startedAtMs: bootMs + Math.round((startedTicks / userHz) * 1000), zombie: after[0] === "Z" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Every member of `pgid`, plus this process's own group, read from `/proc`.
|
|
82
|
+
*
|
|
83
|
+
* Answering `undefined` means the question could not be asked here, which is
|
|
84
|
+
* what a non-Linux host and a `hidepid` mount both produce; the caller keeps
|
|
85
|
+
* its record rather than acting on a table it could not read. A pid that
|
|
86
|
+
* disappears between listing the directory and reading its `stat` is not an
|
|
87
|
+
* unreadable table: it is a process that ended, which is the same end state as
|
|
88
|
+
* never having been in the group, so it is skipped.
|
|
89
|
+
* @private
|
|
90
|
+
* @since 1.0.0
|
|
91
|
+
*/
|
|
92
|
+
export const snapshot = (root: string) => (pgid: number): ProcessCleanup.Snapshot | undefined => {
|
|
93
|
+
let bootMs: number
|
|
94
|
+
let ownGroup: number
|
|
95
|
+
let names: ReadonlyArray<string>
|
|
96
|
+
try {
|
|
97
|
+
const boot = bootLine.exec(readFileSync(`${root}/stat`, "utf8"))
|
|
98
|
+
if (boot === null) return undefined
|
|
99
|
+
bootMs = Number(boot[1]) * 1000
|
|
100
|
+
if (!Number.isSafeInteger(bootMs)) return undefined
|
|
101
|
+
const self = parseStat(readFileSync(`${root}/self/stat`, "utf8"), bootMs)
|
|
102
|
+
if (self === undefined || self.pgid <= 0) return undefined
|
|
103
|
+
ownGroup = self.pgid
|
|
104
|
+
names = readdirSync(root)
|
|
105
|
+
} catch {
|
|
106
|
+
return undefined
|
|
107
|
+
}
|
|
108
|
+
const members: Array<ProcessCleanup.Member> = []
|
|
109
|
+
for (const name of names) {
|
|
110
|
+
if (!pidName.test(name)) continue
|
|
111
|
+
let text: string
|
|
112
|
+
try {
|
|
113
|
+
text = readFileSync(`${root}/${name}/stat`, "utf8")
|
|
114
|
+
} catch (cause) {
|
|
115
|
+
if (missing(cause)) continue
|
|
116
|
+
return undefined
|
|
117
|
+
}
|
|
118
|
+
const parsed = parseStat(text, bootMs)
|
|
119
|
+
if (parsed === undefined) return undefined
|
|
120
|
+
if (parsed.pgid !== pgid) continue
|
|
121
|
+
members.push(parsed.member)
|
|
122
|
+
}
|
|
123
|
+
return { ownGroup, members }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* This machine's boot instant from `${root}/stat`, in epoch milliseconds, or
|
|
128
|
+
* `undefined` when the table cannot be read here.
|
|
129
|
+
* @private
|
|
130
|
+
* @since 1.0.0
|
|
131
|
+
*/
|
|
132
|
+
export const bootMs = (root: string): number | undefined => {
|
|
133
|
+
try {
|
|
134
|
+
const boot = bootLine.exec(readFileSync(`${root}/stat`, "utf8"))
|
|
135
|
+
if (boot === null) return undefined
|
|
136
|
+
const ms = Number(boot[1]) * 1000
|
|
137
|
+
return Number.isSafeInteger(ms) ? ms : undefined
|
|
138
|
+
} catch {
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* This process's own process group, read from `/proc/self/stat`, or `null`
|
|
145
|
+
* when the file cannot be read or parsed.
|
|
146
|
+
*
|
|
147
|
+
* The reaper's own-group guard needs this number before it may signal any
|
|
148
|
+
* group. Reading it here instead of from `ps` keeps the guard working on a
|
|
149
|
+
* Linux image that ships no `procps`.
|
|
150
|
+
* @private
|
|
151
|
+
* @since 1.0.0
|
|
152
|
+
*/
|
|
153
|
+
export const ownGroup = (root: string) => (): number | null => {
|
|
154
|
+
try {
|
|
155
|
+
const self = parseStat(readFileSync(`${root}/self/stat`, "utf8"), 0)
|
|
156
|
+
return self === undefined || self.pgid <= 0 ? null : self.pgid
|
|
157
|
+
} catch {
|
|
158
|
+
return null
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* When `pid` started, in epoch milliseconds, read from `/proc/<pid>/stat` and
|
|
164
|
+
* `/proc/stat`'s `btime`.
|
|
165
|
+
*
|
|
166
|
+
* `gone` is the table having no entry for the pid (`ENOENT`). Every other
|
|
167
|
+
* failure is `unavailable`: the question could not be asked, so the caller
|
|
168
|
+
* keeps its record instead of acting on it.
|
|
169
|
+
* @private
|
|
170
|
+
* @since 1.0.0
|
|
171
|
+
*/
|
|
172
|
+
export const startedAtMs = (root: string) =>
|
|
173
|
+
(
|
|
174
|
+
pid: number
|
|
175
|
+
):
|
|
176
|
+
| { readonly _tag: "started"; readonly startedAtMs: number }
|
|
177
|
+
| { readonly _tag: "gone" }
|
|
178
|
+
| { readonly _tag: "unavailable" } =>
|
|
179
|
+
{
|
|
180
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return { _tag: "unavailable" }
|
|
181
|
+
const boot = bootMs(root)
|
|
182
|
+
if (boot === undefined) return { _tag: "unavailable" }
|
|
183
|
+
let text: string
|
|
184
|
+
try {
|
|
185
|
+
text = readFileSync(`${root}/${pid}/stat`, "utf8")
|
|
186
|
+
} catch (cause) {
|
|
187
|
+
return missing(cause) ? { _tag: "gone" } : { _tag: "unavailable" }
|
|
188
|
+
}
|
|
189
|
+
const parsed = parseStat(text, boot)
|
|
190
|
+
return parsed === undefined || parsed.member.pid !== pid
|
|
191
|
+
? { _tag: "unavailable" }
|
|
192
|
+
: { _tag: "started", startedAtMs: parsed.member.startedAtMs }
|
|
193
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepared process ownership and bounded release for Node and Bun hosts.
|
|
3
|
+
* @since 1.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defaultGraceMs, type Lifecycle } from "@smthrs/kernel/ContainedSpawner"
|
|
7
|
+
import * as Duration from "effect/Duration"
|
|
8
|
+
import * as Effect from "effect/Effect"
|
|
9
|
+
import type * as PlatformError from "effect/PlatformError"
|
|
10
|
+
import type * as ChildProcess from "effect/unstable/process/ChildProcess"
|
|
11
|
+
import { constants } from "node:os"
|
|
12
|
+
import { ProcessCleanupPolicyError } from "./ProcessCleanupPolicyError.ts"
|
|
13
|
+
import * as Supervisor from "./ProcessSupervisor.ts"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* An operating-system identity observed in a group.
|
|
17
|
+
* @private
|
|
18
|
+
* @since 1.0.0
|
|
19
|
+
*/
|
|
20
|
+
export interface Member {
|
|
21
|
+
readonly pid: number
|
|
22
|
+
readonly startedAtMs: number
|
|
23
|
+
readonly zombie: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* One bounded observation, including the host group.
|
|
28
|
+
* @private
|
|
29
|
+
* @since 1.0.0
|
|
30
|
+
*/
|
|
31
|
+
export interface Snapshot {
|
|
32
|
+
readonly ownGroup: number
|
|
33
|
+
readonly members: ReadonlyArray<Member>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Observations can shorten or verify cleanup, but never authorize signals.
|
|
38
|
+
* @private
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
41
|
+
export interface System {
|
|
42
|
+
readonly platform: string
|
|
43
|
+
readonly snapshot: (pgid: number) => Snapshot | undefined
|
|
44
|
+
/**
|
|
45
|
+
* True only when the kernel proves the group has no process at all. False
|
|
46
|
+
* means occupied or unknown; `snapshot` still decides those.
|
|
47
|
+
*/
|
|
48
|
+
readonly vacant: (pgid: number) => boolean
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* A finite termination deadline understood by the private owner.
|
|
53
|
+
* @private
|
|
54
|
+
* @since 1.0.0
|
|
55
|
+
*/
|
|
56
|
+
export interface Policy {
|
|
57
|
+
readonly killSignal: ChildProcess.Signal
|
|
58
|
+
readonly graceMs: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Normalize and validate the deadline before it enters a native timer.
|
|
63
|
+
* @private
|
|
64
|
+
* @since 1.0.0
|
|
65
|
+
*/
|
|
66
|
+
export const policy = (
|
|
67
|
+
options: ChildProcess.KillOptions,
|
|
68
|
+
defaults: ChildProcess.KillOptions = {}
|
|
69
|
+
): Effect.Effect<Policy, PlatformError.PlatformError> =>
|
|
70
|
+
Effect.try({
|
|
71
|
+
try: () => {
|
|
72
|
+
const killSignal = options.killSignal ?? defaults.killSignal ?? "SIGTERM"
|
|
73
|
+
if (killSignal === "SIGSTOP" || constants.signals[killSignal] === undefined) {
|
|
74
|
+
throw new ProcessCleanupPolicyError({
|
|
75
|
+
code: "kill_signal_unsupported",
|
|
76
|
+
message: `Unsupported process termination signal ${killSignal}`
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
const graceMs = Duration.toMillis(options.forceKillAfter ?? defaults.forceKillAfter ?? defaultGraceMs)
|
|
80
|
+
// Node/Bun clamp an overflowing timeout to 1 ms. Refuse that policy rather
|
|
81
|
+
// than silently replacing a caller's grace with immediate termination.
|
|
82
|
+
if (!Number.isFinite(graceMs) || graceMs < 0 || graceMs > 2_147_483_647) {
|
|
83
|
+
throw new ProcessCleanupPolicyError({
|
|
84
|
+
code: "grace_out_of_range",
|
|
85
|
+
message: "Process cleanup grace must fit a finite nonnegative native timer"
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
return { killSignal, graceMs }
|
|
89
|
+
},
|
|
90
|
+
catch: (cause) => Supervisor.failure("kill", "process cleanup policy", cause)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Prepare a live owner before target activation. Windows attaches that owner
|
|
95
|
+
* to a native job; POSIX uses its independently bounded process supervisor.
|
|
96
|
+
* @private
|
|
97
|
+
* @since 1.0.0
|
|
98
|
+
*/
|
|
99
|
+
export const lifecycle = (system: System): Lifecycle => Supervisor.prepare(system, policy)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A process cleanup policy that cannot be honoured: a termination signal the
|
|
3
|
+
* platform does not define or cannot deliver, or a grace that overflows a
|
|
4
|
+
* native timer. `policy` reports one as the `cause` of a `PlatformError`.
|
|
5
|
+
*
|
|
6
|
+
* @since 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Schema } from "effect"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Which part of the policy was refused.
|
|
13
|
+
*
|
|
14
|
+
* @category models
|
|
15
|
+
* @since 1.0.0
|
|
16
|
+
*/
|
|
17
|
+
export const ProcessCleanupPolicyErrorCode = Schema.Literals(["kill_signal_unsupported", "grace_out_of_range"])
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A cleanup policy outside what a native timer and the platform allow.
|
|
21
|
+
*
|
|
22
|
+
* @category errors
|
|
23
|
+
* @since 1.0.0
|
|
24
|
+
*/
|
|
25
|
+
export class ProcessCleanupPolicyError extends Schema.TaggedError<ProcessCleanupPolicyError>()(
|
|
26
|
+
"@smthrs/platform-node/ProcessCleanupPolicyError",
|
|
27
|
+
{ code: ProcessCleanupPolicyErrorCode, message: Schema.String }
|
|
28
|
+
) {
|
|
29
|
+
override readonly name = "ProcessCleanupPolicyError"
|
|
30
|
+
}
|