@graftland/plugin-remote 0.0.0-stage → 0.2.0-beta.2

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 (380) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +76 -2
  3. package/README.zh-CN.md +71 -0
  4. package/README.zh-TW.md +71 -0
  5. package/dist/Auth-BElTC9_X.js +6 -0
  6. package/dist/Auth.d.ts +49 -0
  7. package/dist/Auth.d.ts.map +1 -0
  8. package/dist/Auth.js +8 -0
  9. package/dist/Auth.js.map +1 -0
  10. package/dist/Bootstrap-MCwivGN1.js +9 -0
  11. package/dist/ConfigDirectory-BCC6q2R4.js +5 -0
  12. package/dist/Contract-CcpSIJm4.js +121 -0
  13. package/dist/Contract.d.ts +71 -0
  14. package/dist/Contract.d.ts.map +1 -0
  15. package/dist/Contract.js +1 -0
  16. package/dist/Contract.js.map +1 -0
  17. package/dist/Errors-oPsTLY7l.js +45 -0
  18. package/dist/Errors.d.ts +67 -0
  19. package/dist/Errors.d.ts.map +1 -0
  20. package/dist/Errors.js +47 -0
  21. package/dist/Errors.js.map +1 -0
  22. package/dist/FailureGroup-BcH0XOBi.js +53 -0
  23. package/dist/Framing-zaYdOJnT.js +61 -0
  24. package/dist/Graft-BsYq3F-J.js +985 -0
  25. package/dist/Instance.d.ts +7 -0
  26. package/dist/Instance.d.ts.map +1 -0
  27. package/dist/Instance.js +14 -0
  28. package/dist/Instance.js.map +1 -0
  29. package/dist/Packages-B1TPk8pa.js +111 -0
  30. package/dist/Peer-IJgFK6mD.js +342 -0
  31. package/dist/ProcessObservation-DEGrEMfP.js +38 -0
  32. package/dist/ServeLifecycle-CJM0gG5B.js +24 -0
  33. package/dist/Testing.d.ts +26 -0
  34. package/dist/Testing.d.ts.map +1 -0
  35. package/dist/Testing.js +69 -0
  36. package/dist/Testing.js.map +1 -0
  37. package/dist/Transport-DULzpsgR.js +6 -0
  38. package/dist/Transport.d.ts +39 -0
  39. package/dist/Transport.d.ts.map +1 -0
  40. package/dist/Transport.js +8 -0
  41. package/dist/Transport.js.map +1 -0
  42. package/dist/WatchdogProtocol-BZmVxrBP.js +17 -0
  43. package/dist/_virtual/_rolldown/runtime.js +12 -0
  44. package/dist/bin.d.ts +1 -0
  45. package/dist/bin.js +28275 -0
  46. package/dist/bin.js.map +1 -0
  47. package/dist/childRuntime-DSqtFN9o.js +188 -0
  48. package/dist/cleanup-BPWr-5U9.js +13 -0
  49. package/dist/command-9zrHdbwT.js +7 -0
  50. package/dist/connectionEnded-DUgcobEd.js +9 -0
  51. package/dist/directTransport-DrexuPSm.js +5 -0
  52. package/dist/entry-SYsx9VNb.js +708 -0
  53. package/dist/host/auth/bearer.d.ts +5 -0
  54. package/dist/host/auth/bearer.d.ts.map +1 -0
  55. package/dist/host/auth/bearer.js +4 -0
  56. package/dist/host/auth/bearer.js.map +1 -0
  57. package/dist/host/auth/jwt.d.ts +5 -0
  58. package/dist/host/auth/jwt.d.ts.map +1 -0
  59. package/dist/host/auth/jwt.js +4 -0
  60. package/dist/host/auth/jwt.js.map +1 -0
  61. package/dist/host/auth/mtls.d.ts +8 -0
  62. package/dist/host/auth/mtls.d.ts.map +1 -0
  63. package/dist/host/auth/mtls.js +34 -0
  64. package/dist/host/auth/mtls.js.map +1 -0
  65. package/dist/host/auth/none.d.ts +3 -0
  66. package/dist/host/auth/none.d.ts.map +1 -0
  67. package/dist/host/auth/none.js +13 -0
  68. package/dist/host/auth/none.js.map +1 -0
  69. package/dist/host/command.d.ts +22 -0
  70. package/dist/host/command.d.ts.map +1 -0
  71. package/dist/host/command.js +61 -0
  72. package/dist/host/command.js.map +1 -0
  73. package/dist/host/local.d.ts +4 -0
  74. package/dist/host/local.d.ts.map +1 -0
  75. package/dist/host/local.js +52 -0
  76. package/dist/host/local.js.map +1 -0
  77. package/dist/host/unix.d.ts +11 -0
  78. package/dist/host/unix.d.ts.map +1 -0
  79. package/dist/host/unix.js +39 -0
  80. package/dist/host/unix.js.map +1 -0
  81. package/dist/host/websocket.d.ts +13 -0
  82. package/dist/host/websocket.d.ts.map +1 -0
  83. package/dist/host/websocket.js +36 -0
  84. package/dist/host/websocket.js.map +1 -0
  85. package/dist/host/worker.d.ts +4 -0
  86. package/dist/host/worker.d.ts.map +1 -0
  87. package/dist/host/worker.js +52 -0
  88. package/dist/host/worker.js.map +1 -0
  89. package/dist/importer-D7zSgqxq.js +347 -0
  90. package/dist/index.d.ts +29 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +86 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/internal/Certificates.js +182 -0
  95. package/dist/internal/Certificates.js.map +1 -0
  96. package/dist/internal/FailureGroup.js +55 -0
  97. package/dist/internal/FailureGroup.js.map +1 -0
  98. package/dist/internal/Limits.d.ts +1 -0
  99. package/dist/internal/Limits.js +17 -0
  100. package/dist/internal/Limits.js.map +1 -0
  101. package/dist/internal/Peer.js +6 -0
  102. package/dist/internal/Peer.js.map +1 -0
  103. package/dist/internal/ServeLifecycle.js +26 -0
  104. package/dist/internal/ServeLifecycle.js.map +1 -0
  105. package/dist/internal/Supervisor.js +7 -0
  106. package/dist/internal/Supervisor.js.map +1 -0
  107. package/dist/internal/assembly.d.ts +5 -0
  108. package/dist/internal/assembly.js +138 -0
  109. package/dist/internal/assembly.js.map +1 -0
  110. package/dist/internal/auth/mtls.js +23 -0
  111. package/dist/internal/auth/mtls.js.map +1 -0
  112. package/dist/internal/auth/token.js +19 -0
  113. package/dist/internal/auth/token.js.map +1 -0
  114. package/dist/internal/auth/tokenCredentials.d.ts +8 -0
  115. package/dist/internal/auth/tokenCredentials.d.ts.map +1 -0
  116. package/dist/internal/auth/tokenCredentials.js +33 -0
  117. package/dist/internal/auth/tokenCredentials.js.map +1 -0
  118. package/dist/internal/child.js +125 -0
  119. package/dist/internal/child.js.map +1 -0
  120. package/dist/internal/childErrors.d.ts +33 -0
  121. package/dist/internal/childErrors.d.ts.map +1 -0
  122. package/dist/internal/childErrors.js +29 -0
  123. package/dist/internal/childErrors.js.map +1 -0
  124. package/dist/internal/childRuntime.js +59 -0
  125. package/dist/internal/childRuntime.js.map +1 -0
  126. package/dist/internal/cleanup.js +15 -0
  127. package/dist/internal/cleanup.js.map +1 -0
  128. package/dist/internal/config.js +6 -0
  129. package/dist/internal/config.js.map +1 -0
  130. package/dist/internal/control.js +42 -0
  131. package/dist/internal/control.js.map +1 -0
  132. package/dist/internal/credentials.d.ts +44 -0
  133. package/dist/internal/credentials.d.ts.map +1 -0
  134. package/dist/internal/credentials.js +54 -0
  135. package/dist/internal/credentials.js.map +1 -0
  136. package/dist/internal/directTransport.d.ts +3 -0
  137. package/dist/internal/directTransport.js +7 -0
  138. package/dist/internal/directTransport.js.map +1 -0
  139. package/dist/internal/entry.d.ts +9 -0
  140. package/dist/internal/entry.d.ts.map +1 -0
  141. package/dist/internal/entry.js +144 -0
  142. package/dist/internal/entry.js.map +1 -0
  143. package/dist/internal/entryConfig.d.ts +202 -0
  144. package/dist/internal/entryConfig.d.ts.map +1 -0
  145. package/dist/internal/entryConfig.js +176 -0
  146. package/dist/internal/entryConfig.js.map +1 -0
  147. package/dist/internal/execution.d.ts +5 -0
  148. package/dist/internal/execution.js +43 -0
  149. package/dist/internal/execution.js.map +1 -0
  150. package/dist/internal/follow.js +11 -0
  151. package/dist/internal/follow.js.map +1 -0
  152. package/dist/internal/forkTree.js +7 -0
  153. package/dist/internal/forkTree.js.map +1 -0
  154. package/dist/internal/host/local.js +28 -0
  155. package/dist/internal/host/local.js.map +1 -0
  156. package/dist/internal/host/runner.js +100 -0
  157. package/dist/internal/host/runner.js.map +1 -0
  158. package/dist/internal/host.js +71 -0
  159. package/dist/internal/host.js.map +1 -0
  160. package/dist/internal/importer.js +18 -0
  161. package/dist/internal/importer.js.map +1 -0
  162. package/dist/internal/listenerStartup.js +17 -0
  163. package/dist/internal/listenerStartup.js.map +1 -0
  164. package/dist/internal/loadModule.js +20 -0
  165. package/dist/internal/loadModule.js.map +1 -0
  166. package/dist/internal/platform.js +9 -0
  167. package/dist/internal/platform.js.map +1 -0
  168. package/dist/internal/port.d.ts +13 -0
  169. package/dist/internal/port.d.ts.map +1 -0
  170. package/dist/internal/port.js +275 -0
  171. package/dist/internal/port.js.map +1 -0
  172. package/dist/internal/release.js +25 -0
  173. package/dist/internal/release.js.map +1 -0
  174. package/dist/internal/runner/Bootstrap.js +11 -0
  175. package/dist/internal/runner/Bootstrap.js.map +1 -0
  176. package/dist/internal/runner/Connection.d.ts +11 -0
  177. package/dist/internal/runner/Connection.js +56 -0
  178. package/dist/internal/runner/Connection.js.map +1 -0
  179. package/dist/internal/runner/Execution.js +115 -0
  180. package/dist/internal/runner/Execution.js.map +1 -0
  181. package/dist/internal/runner/Framing.d.ts +11 -0
  182. package/dist/internal/runner/Framing.d.ts.map +1 -0
  183. package/dist/internal/runner/Framing.js +63 -0
  184. package/dist/internal/runner/Framing.js.map +1 -0
  185. package/dist/internal/runner/Local.js +46 -0
  186. package/dist/internal/runner/Local.js.map +1 -0
  187. package/dist/internal/runner/Lock.js +25 -0
  188. package/dist/internal/runner/Lock.js.map +1 -0
  189. package/dist/internal/runner/Multiplex.d.ts +5 -0
  190. package/dist/internal/runner/Multiplex.js +49 -0
  191. package/dist/internal/runner/Multiplex.js.map +1 -0
  192. package/dist/internal/runner/Packages.d.ts +3 -0
  193. package/dist/internal/runner/Packages.js +108 -0
  194. package/dist/internal/runner/Packages.js.map +1 -0
  195. package/dist/internal/runner/ProcessObservation.js +40 -0
  196. package/dist/internal/runner/ProcessObservation.js.map +1 -0
  197. package/dist/internal/runner/Processes.js +83 -0
  198. package/dist/internal/runner/Processes.js.map +1 -0
  199. package/dist/internal/runner/Retention.js +13 -0
  200. package/dist/internal/runner/Retention.js.map +1 -0
  201. package/dist/internal/runner/Store.js +78 -0
  202. package/dist/internal/runner/Store.js.map +1 -0
  203. package/dist/internal/runner/Supervisor.js +375 -0
  204. package/dist/internal/runner/Supervisor.js.map +1 -0
  205. package/dist/internal/runner/Watchdog.js +47 -0
  206. package/dist/internal/runner/Watchdog.js.map +1 -0
  207. package/dist/internal/runner/WatchdogProtocol.js +19 -0
  208. package/dist/internal/runner/WatchdogProtocol.js.map +1 -0
  209. package/dist/internal/runner/Wire.d.ts +5 -0
  210. package/dist/internal/runner/Wire.js +64 -0
  211. package/dist/internal/runner/Wire.js.map +1 -0
  212. package/dist/internal/runner/accept.js +57 -0
  213. package/dist/internal/runner/accept.js.map +1 -0
  214. package/dist/internal/runner/command.js +9 -0
  215. package/dist/internal/runner/command.js.map +1 -0
  216. package/dist/internal/runner/connectionEnded.js +11 -0
  217. package/dist/internal/runner/connectionEnded.js.map +1 -0
  218. package/dist/internal/runner/model.d.ts +17 -0
  219. package/dist/internal/runner/model.d.ts.map +1 -0
  220. package/dist/internal/runner/model.js +231 -0
  221. package/dist/internal/runner/model.js.map +1 -0
  222. package/dist/internal/serve.js +60 -0
  223. package/dist/internal/serve.js.map +1 -0
  224. package/dist/internal/services.d.ts +18 -0
  225. package/dist/internal/services.d.ts.map +1 -0
  226. package/dist/internal/services.js +22 -0
  227. package/dist/internal/services.js.map +1 -0
  228. package/dist/internal/socketChannel.js +24 -0
  229. package/dist/internal/socketChannel.js.map +1 -0
  230. package/dist/internal/stdioChannel.js +23 -0
  231. package/dist/internal/stdioChannel.js.map +1 -0
  232. package/dist/internal/supervisorPlugin.js +1 -0
  233. package/dist/internal/supervisorPlugin.js.map +1 -0
  234. package/dist/internal/transportOptions.d.ts +18 -0
  235. package/dist/internal/transportOptions.d.ts.map +1 -0
  236. package/dist/internal/watchdogMain.d.ts +1 -0
  237. package/dist/internal/watchdogMain.js +55 -0
  238. package/dist/internal/watchdogMain.js.map +1 -0
  239. package/dist/internal/websocket.js +46 -0
  240. package/dist/internal/websocket.js.map +1 -0
  241. package/dist/internal/websocketServer.js +61 -0
  242. package/dist/internal/websocketServer.js.map +1 -0
  243. package/dist/internal/workerBootstrap.js +9 -0
  244. package/dist/internal/workerBootstrap.js.map +1 -0
  245. package/dist/internal/workerChannel.js +24 -0
  246. package/dist/internal/workerChannel.js.map +1 -0
  247. package/dist/internal/workerMain.d.ts +1 -0
  248. package/dist/internal/workerMain.js +18 -0
  249. package/dist/internal/workerMain.js.map +1 -0
  250. package/dist/port-Blbh8tms.js +285 -0
  251. package/dist/release-BY4Mlluy.js +23 -0
  252. package/dist/rolldown-runtime-DYf_mQCB.js +34 -0
  253. package/dist/runner/auth/bearer.d.ts +7 -0
  254. package/dist/runner/auth/bearer.d.ts.map +1 -0
  255. package/dist/runner/auth/bearer.js +42 -0
  256. package/dist/runner/auth/bearer.js.map +1 -0
  257. package/dist/runner/auth/jwt.d.ts +19 -0
  258. package/dist/runner/auth/jwt.d.ts.map +1 -0
  259. package/dist/runner/auth/jwt.js +65 -0
  260. package/dist/runner/auth/jwt.js.map +1 -0
  261. package/dist/runner/auth/mtls.d.ts +11 -0
  262. package/dist/runner/auth/mtls.d.ts.map +1 -0
  263. package/dist/runner/auth/mtls.js +48 -0
  264. package/dist/runner/auth/mtls.js.map +1 -0
  265. package/dist/runner/auth/none.d.ts +3 -0
  266. package/dist/runner/auth/none.d.ts.map +1 -0
  267. package/dist/runner/auth/none.js +13 -0
  268. package/dist/runner/auth/none.js.map +1 -0
  269. package/dist/runner/index.d.ts +3 -0
  270. package/dist/runner/index.d.ts.map +1 -0
  271. package/dist/runner/index.js +71 -0
  272. package/dist/runner/index.js.map +1 -0
  273. package/dist/runner/stdio.d.ts +7 -0
  274. package/dist/runner/stdio.d.ts.map +1 -0
  275. package/dist/runner/stdio.js +39 -0
  276. package/dist/runner/stdio.js.map +1 -0
  277. package/dist/runner/unix.d.ts +7 -0
  278. package/dist/runner/unix.d.ts.map +1 -0
  279. package/dist/runner/unix.js +42 -0
  280. package/dist/runner/unix.js.map +1 -0
  281. package/dist/runner/websocket.d.ts +28 -0
  282. package/dist/runner/websocket.d.ts.map +1 -0
  283. package/dist/runner/websocket.js +77 -0
  284. package/dist/runner/websocket.js.map +1 -0
  285. package/dist/socketChannel-KmtzF-9G.js +3658 -0
  286. package/dist/supervisorPlugin-Inb1S5IV.js +737 -0
  287. package/dist/token-v5ne2I0-.js +17 -0
  288. package/dist/tokenCredentials-WUJm2AKm.js +31 -0
  289. package/dist/websocketServer-MXcCJx0v.js +58 -0
  290. package/dist/workerChannel-P82YdNjh.js +27 -0
  291. package/package.json +69 -3
  292. package/src/Auth.ts +62 -0
  293. package/src/Contract.ts +100 -0
  294. package/src/Errors.ts +82 -0
  295. package/src/Instance.ts +12 -0
  296. package/src/Testing.ts +135 -0
  297. package/src/Transport.ts +52 -0
  298. package/src/bin.ts +145 -0
  299. package/src/host/auth/bearer.ts +10 -0
  300. package/src/host/auth/jwt.ts +10 -0
  301. package/src/host/auth/mtls.ts +48 -0
  302. package/src/host/auth/none.ts +13 -0
  303. package/src/host/command.ts +131 -0
  304. package/src/host/local.ts +41 -0
  305. package/src/host/unix.ts +65 -0
  306. package/src/host/websocket.ts +66 -0
  307. package/src/host/worker.ts +90 -0
  308. package/src/index.ts +115 -0
  309. package/src/internal/Certificates.ts +330 -0
  310. package/src/internal/FailureGroup.ts +176 -0
  311. package/src/internal/Limits.ts +12 -0
  312. package/src/internal/Peer.ts +4 -0
  313. package/src/internal/ServeLifecycle.ts +53 -0
  314. package/src/internal/Supervisor.ts +14 -0
  315. package/src/internal/assembly.ts +337 -0
  316. package/src/internal/auth/mtls.ts +40 -0
  317. package/src/internal/auth/token.ts +26 -0
  318. package/src/internal/auth/tokenCredentials.ts +65 -0
  319. package/src/internal/child.ts +323 -0
  320. package/src/internal/childErrors.ts +44 -0
  321. package/src/internal/childRuntime.ts +111 -0
  322. package/src/internal/cleanup.ts +34 -0
  323. package/src/internal/config.ts +8 -0
  324. package/src/internal/control.ts +49 -0
  325. package/src/internal/credentials.ts +112 -0
  326. package/src/internal/directTransport.ts +38 -0
  327. package/src/internal/entry.ts +288 -0
  328. package/src/internal/entryConfig.ts +190 -0
  329. package/src/internal/execution.ts +121 -0
  330. package/src/internal/follow.ts +17 -0
  331. package/src/internal/forkTree.ts +13 -0
  332. package/src/internal/host/local.ts +53 -0
  333. package/src/internal/host/runner.ts +187 -0
  334. package/src/internal/host.ts +209 -0
  335. package/src/internal/importer.ts +27 -0
  336. package/src/internal/listenerStartup.ts +55 -0
  337. package/src/internal/loadModule.ts +23 -0
  338. package/src/internal/platform.ts +12 -0
  339. package/src/internal/port.ts +623 -0
  340. package/src/internal/release.ts +71 -0
  341. package/src/internal/runner/Bootstrap.ts +9 -0
  342. package/src/internal/runner/Connection.ts +184 -0
  343. package/src/internal/runner/Execution.ts +244 -0
  344. package/src/internal/runner/Framing.ts +122 -0
  345. package/src/internal/runner/Local.ts +73 -0
  346. package/src/internal/runner/Lock.ts +29 -0
  347. package/src/internal/runner/Multiplex.ts +120 -0
  348. package/src/internal/runner/Packages.ts +178 -0
  349. package/src/internal/runner/ProcessObservation.ts +63 -0
  350. package/src/internal/runner/Processes.ts +109 -0
  351. package/src/internal/runner/Retention.ts +49 -0
  352. package/src/internal/runner/Store.ts +160 -0
  353. package/src/internal/runner/Supervisor.ts +901 -0
  354. package/src/internal/runner/Watchdog.ts +83 -0
  355. package/src/internal/runner/WatchdogProtocol.ts +12 -0
  356. package/src/internal/runner/Wire.ts +99 -0
  357. package/src/internal/runner/accept.ts +103 -0
  358. package/src/internal/runner/command.ts +15 -0
  359. package/src/internal/runner/connectionEnded.ts +28 -0
  360. package/src/internal/runner/model.ts +364 -0
  361. package/src/internal/serve.ts +117 -0
  362. package/src/internal/services.ts +74 -0
  363. package/src/internal/socketChannel.ts +64 -0
  364. package/src/internal/stdioChannel.ts +25 -0
  365. package/src/internal/supervisorPlugin.ts +67 -0
  366. package/src/internal/transportOptions.ts +17 -0
  367. package/src/internal/watchdogMain.ts +72 -0
  368. package/src/internal/websocket.ts +81 -0
  369. package/src/internal/websocketServer.ts +152 -0
  370. package/src/internal/workerBootstrap.ts +6 -0
  371. package/src/internal/workerChannel.ts +54 -0
  372. package/src/internal/workerMain.ts +23 -0
  373. package/src/runner/auth/bearer.ts +66 -0
  374. package/src/runner/auth/jwt.ts +114 -0
  375. package/src/runner/auth/mtls.ts +37 -0
  376. package/src/runner/auth/none.ts +13 -0
  377. package/src/runner/index.ts +97 -0
  378. package/src/runner/stdio.ts +76 -0
  379. package/src/runner/unix.ts +53 -0
  380. package/src/runner/websocket.ts +143 -0
@@ -0,0 +1,184 @@
1
+ import {
2
+ LocalTransport,
3
+ WorkerTransport,
4
+ type Execution,
5
+ } from "../directTransport"
6
+ import * as RunnerConnection from "../host/runner"
7
+ import {
8
+ Array,
9
+ Cause,
10
+ Context,
11
+ Effect,
12
+ Duration,
13
+ Exit,
14
+ Option,
15
+ Scope,
16
+ } from "effect"
17
+ import * as Release from "../release"
18
+ import type { RpcClientError } from "effect/rpc"
19
+ import type { Schema, PlatformError } from "effect"
20
+ import type { RemoteTerminationUnconfirmed } from "./model"
21
+ import type { Expected } from "./Packages"
22
+
23
+ import {
24
+ LocalTerminationTimeout,
25
+ ProcessExited,
26
+ TransportError,
27
+ } from "../../Errors"
28
+ import { cleanupCause } from "../cleanup"
29
+ import * as Port from "../port"
30
+ import * as LocalProcess from "./Local"
31
+ import * as Wire from "./Wire"
32
+
33
+ export interface LocalTarget {
34
+ readonly _tag: "Local"
35
+ readonly command?: readonly [string, ...string[]]
36
+ }
37
+ export interface WorkerTarget {
38
+ readonly _tag: "Worker"
39
+ readonly execArgv?: ReadonlyArray<string>
40
+ }
41
+
42
+ export interface ConfiguredRunner {
43
+ readonly instance: string
44
+ readonly lease?: Duration.Input
45
+ readonly margin?: Duration.Input
46
+ readonly expect?: Expected
47
+ readonly _tag: "Connector"
48
+ readonly explicitAuth?: boolean
49
+ }
50
+ export type Target = LocalTarget | WorkerTarget | ConfiguredRunner
51
+
52
+ type Peer = Port.Port
53
+ export interface Connected {
54
+ readonly resources: Scope.Scope
55
+ readonly pid: Option.Option<number>
56
+ readonly threadId?: number
57
+ readonly diagnostics: Effect.Effect<Cause.Cause<unknown>>
58
+ readonly terminate: (
59
+ graceful: boolean,
60
+ ) => Effect.Effect<
61
+ void,
62
+ | ProcessExited
63
+ | LocalTerminationTimeout
64
+ | TransportError
65
+ | Schema.SchemaError
66
+ | Wire.SessionError
67
+ | RemoteTerminationUnconfirmed
68
+ | RpcClientError.RpcClientError
69
+ >
70
+ readonly transport: {
71
+ readonly clientProtocol: Peer["clientProtocol"]
72
+ readonly serverProtocol: Peer["serverProtocol"]
73
+ readonly failure: Effect.Effect<never, ProcessExited | TransportError>
74
+ readonly report: (cause: Cause.Cause<unknown>) => Effect.Effect<void>
75
+ }
76
+ }
77
+ export class Connection extends Context.Service<Connection, Connected>()(
78
+ "@graftland/plugin-remote/internal/runner/Connection",
79
+ ) {}
80
+ const connected = Connection.of
81
+
82
+ const Local = Effect.fnUntraced(function* (
83
+ target: LocalTarget | WorkerTarget,
84
+ contractModule: string,
85
+ options: Port.Options,
86
+ resources: Scope.Scope,
87
+ processScope: Scope.Scope,
88
+ ) {
89
+ const transport = yield* target._tag === "Local"
90
+ ? LocalTransport
91
+ : WorkerTransport
92
+ const started: Effect.Effect<
93
+ Execution,
94
+ PlatformError.PlatformError | TransportError,
95
+ Scope.Scope
96
+ > = transport.start({ ...target, contractModule, session: options.session })
97
+ const execution = yield* started.pipe(Scope.provide(processScope))
98
+ return yield* LocalProcess.connect(execution, options).pipe(
99
+ Scope.provide(resources),
100
+ )
101
+ })
102
+
103
+ const reason = <A, E>(exit: Exit.Exit<A, E>) =>
104
+ Exit.isFailure(exit) ? exit.cause : Cause.empty
105
+ const finish = (causes: ReadonlyArray<Cause.Cause<unknown>>) => {
106
+ const cause = Array.reduce(causes, Cause.empty, Cause.combine)
107
+ return cause.reasons.length === 0
108
+ ? Effect.void
109
+ : Effect.failCause(cleanupCause(cause))
110
+ }
111
+
112
+ /** Close partially acquired resources too; the normal release observes exit before stopping readers. */
113
+ const scopes = Effect.acquireRelease(
114
+ Effect.all({ resources: Scope.make(), process: Scope.make() }),
115
+ (scopes, exit) =>
116
+ Effect.gen(function* () {
117
+ const process = yield* Effect.exit(Release.close(scopes.process, exit))
118
+ const resources = yield* Effect.exit(
119
+ Release.close(scopes.resources, exit),
120
+ )
121
+ yield* finish([reason(process), reason(resources)])
122
+ }),
123
+ )
124
+
125
+ /** Setup supplies a concrete control lifecycle; release never reads a later-installed effect. */
126
+ export const acquire = <A, E, R, D, DR>(
127
+ target: Target,
128
+ contractModule: string,
129
+ options: Port.Options,
130
+ setup: Effect.Effect<A, E, R | Connection>,
131
+ dispose: (value: A) => Effect.Effect<Cause.Cause<unknown>, D, DR>,
132
+ timeout: Duration.Input,
133
+ ) =>
134
+ Effect.gen(function* () {
135
+ const owned = yield* scopes
136
+ const connection = yield* Effect.acquireRelease(
137
+ Effect.gen(function* () {
138
+ return target._tag === "Local" || target._tag === "Worker"
139
+ ? yield* Local(
140
+ target,
141
+ contractModule,
142
+ options,
143
+ owned.resources,
144
+ owned.process,
145
+ ).pipe(Effect.map(connected))
146
+ : yield* RunnerConnection.connect(
147
+ target,
148
+ contractModule,
149
+ options,
150
+ owned.resources,
151
+ owned.process,
152
+ )
153
+ }).pipe(Effect.interruptible),
154
+ (connection, exit) =>
155
+ Effect.gen(function* () {
156
+ const process = yield* Effect.exit(Release.close(owned.process, exit))
157
+ // Wait for exit while readers are alive; collect their final cause after resources close.
158
+ yield* connection.diagnostics
159
+ const resources = yield* Effect.exit(
160
+ Release.close(owned.resources, exit),
161
+ )
162
+ const diagnostics = yield* connection.diagnostics
163
+ yield* finish([reason(process), reason(resources), diagnostics])
164
+ }),
165
+ )
166
+ return yield* Effect.acquireRelease(
167
+ setup.pipe(Effect.provideService(Connection, connection)),
168
+ (value) =>
169
+ Effect.gen(function* () {
170
+ const graceful = yield* dispose(value).pipe(
171
+ Effect.interruptible,
172
+ Effect.timeout(timeout),
173
+ Effect.exit,
174
+ )
175
+ const terminated = yield* Effect.exit(
176
+ connection.terminate(Exit.isSuccess(graceful)),
177
+ )
178
+ yield* finish([
179
+ Exit.isSuccess(graceful) ? graceful.value : graceful.cause,
180
+ reason(terminated),
181
+ ])
182
+ }),
183
+ )
184
+ })
@@ -0,0 +1,244 @@
1
+ import * as ProcessObservation from "./ProcessObservation"
2
+ import * as FailureGroup from "../FailureGroup"
3
+ import { Command, CommandJson } from "./WatchdogProtocol"
4
+ import {
5
+ Array,
6
+ Cause,
7
+ FileSystem,
8
+ Path,
9
+ Schema,
10
+ Context,
11
+ Effect,
12
+ HashMap,
13
+ HashSet,
14
+ Queue,
15
+ Ref,
16
+ Sink,
17
+ Stream,
18
+ Layer,
19
+ Scope,
20
+ } from "effect"
21
+ import { ChildProcess, ChildProcessSpawner } from "effect/process"
22
+ import { TransportError } from "../../Errors"
23
+ import * as Multiplex from "./Multiplex"
24
+ import * as Packages from "./Packages"
25
+ import * as Processes from "./Processes"
26
+ import {
27
+ Execution,
28
+ ExecutionError,
29
+ SessionConflict,
30
+ SessionStopped,
31
+ } from "./model"
32
+ import { Bootstrap } from "./Bootstrap"
33
+ import { command } from "./command"
34
+
35
+ export class Channels extends Context.Service<
36
+ Channels,
37
+ {
38
+ readonly peer: (
39
+ token: string,
40
+ ) => Effect.Effect<
41
+ Multiplex.Peer,
42
+ SessionStopped | SessionConflict,
43
+ Scope.Scope
44
+ >
45
+ }
46
+ >()("@graftland/plugin-remote/internal/runner/Execution/Channels") {}
47
+
48
+ export const make = (root: string) =>
49
+ Effect.gen(function* () {
50
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
51
+ const fs = yield* FileSystem.FileSystem
52
+ const path = yield* Path.Path
53
+ const platform = Context.make(
54
+ ChildProcessSpawner.ChildProcessSpawner,
55
+ spawner,
56
+ ).pipe(Context.add(FileSystem.FileSystem, fs), Context.add(Path.Path, path))
57
+
58
+ const peers = yield* Ref.make(HashMap.empty<string, Multiplex.Peer>())
59
+ const claimed = yield* Ref.make(HashSet.empty<string>())
60
+ const driver = Execution.of({
61
+ recover: (child) =>
62
+ Processes.recover(child).pipe(Effect.provideContext(platform)),
63
+ spawn: (handle, request, limits) =>
64
+ Effect.gen(function* () {
65
+ const resolved = yield* Packages.resolve(
66
+ root,
67
+ request.specifier,
68
+ request.digest,
69
+ )
70
+ const argv = yield* command()
71
+ const child = yield* spawner.spawn(
72
+ ChildProcess.make(
73
+ argv[0],
74
+ [
75
+ ...Array.drop(argv, 1),
76
+ "child",
77
+ resolved.entry,
78
+ handle.token,
79
+ yield* Schema.encodeEffect(Schema.fromJsonString(Bootstrap))({
80
+ identity: {
81
+ id: handle.key.instance,
82
+ generation: handle.generation,
83
+ },
84
+ limits,
85
+ }),
86
+ ],
87
+ {
88
+ stdin: "pipe",
89
+ stdout: "pipe",
90
+ stderr: "pipe",
91
+ additionalFds: {
92
+ fd3: { type: "output" },
93
+ fd4: { type: "input" },
94
+ },
95
+ forceKillAfter: "1 second",
96
+ },
97
+ ),
98
+ )
99
+ const observation = yield* ProcessObservation.observe(child)
100
+ const exited = observation.exited.pipe(
101
+ Effect.mapError((error) =>
102
+ ExecutionError.make({
103
+ detail: "Observing child exit failed",
104
+ cause: Cause.fail(error),
105
+ }),
106
+ ),
107
+ )
108
+ const failures = yield* FailureGroup.make<ExecutionError>()
109
+ yield* failures.run(
110
+ observation.failure.pipe(
111
+ Effect.mapError((error) =>
112
+ ExecutionError.make({
113
+ detail: "Reading child output failed",
114
+ cause: Cause.fail(error),
115
+ }),
116
+ ),
117
+ ),
118
+ )
119
+ const controls = yield* Queue.bounded<string>(4)
120
+
121
+ yield* failures.run(
122
+ Stream.fromQueue(controls).pipe(
123
+ Stream.map((line) => new TextEncoder().encode(line + "\n")),
124
+ Stream.run(child.getInputFd(4)),
125
+ Effect.mapError((error) =>
126
+ ExecutionError.make({
127
+ detail: "Child supervision channel failed",
128
+ cause: Cause.fail(error),
129
+ }),
130
+ ),
131
+ ),
132
+ )
133
+ const send = (value: typeof Command.Type) =>
134
+ Effect.raceFirst(
135
+ Schema.encodeEffect(CommandJson)(value).pipe(
136
+ Effect.flatMap((line) => Queue.offer(controls, line)),
137
+ Effect.asVoid,
138
+ Effect.mapError((error) =>
139
+ ExecutionError.make({
140
+ detail: "Encoding watchdog command failed",
141
+ cause: Cause.fail(error),
142
+ }),
143
+ ),
144
+ ),
145
+ failures.await,
146
+ )
147
+ const peer = yield* Multiplex.make({
148
+ input: child
149
+ .getOutputFd(3)
150
+ .pipe(
151
+ Stream.mapError((error) =>
152
+ TransportError.make({ cause: Cause.fail(error) }),
153
+ ),
154
+ ),
155
+ output: child.stdin.pipe(
156
+ Sink.mapError((error) =>
157
+ TransportError.make({ cause: Cause.fail(error) }),
158
+ ),
159
+ ),
160
+ })
161
+ const identity = yield* Processes.identity(child.pid)
162
+ yield* Ref.update(peers, HashMap.set(handle.token, peer))
163
+ yield* Effect.addFinalizer(() =>
164
+ Ref.update(peers, HashMap.remove(handle.token)),
165
+ )
166
+ return {
167
+ code: resolved.identity,
168
+ start: send({ kind: "start" }),
169
+ identity,
170
+ exited,
171
+ interrupt: send({ kind: "stop" }),
172
+ kill: child.kill({ killSignal: "SIGKILL" }).pipe(
173
+ Effect.mapError((error) =>
174
+ ExecutionError.make({
175
+ detail: "Killing the child failed",
176
+ cause: Cause.fail(error),
177
+ }),
178
+ ),
179
+ ),
180
+ renew: (millis: number) => send({ kind: "renew", millis }),
181
+ }
182
+ }).pipe(
183
+ Effect.provideContext(platform),
184
+ Effect.catchTags({
185
+ PlatformError: (error) =>
186
+ Effect.fail(
187
+ ExecutionError.make({
188
+ detail: "Starting the child failed",
189
+ cause: Cause.fail(error),
190
+ }),
191
+ ),
192
+ SchemaError: (error) =>
193
+ Effect.fail(
194
+ ExecutionError.make({
195
+ detail: "Encoding child bootstrap failed",
196
+ cause: Cause.fail(error),
197
+ }),
198
+ ),
199
+ }),
200
+ ),
201
+ })
202
+ return {
203
+ driver,
204
+ peer: (token: string) =>
205
+ Effect.acquireRelease(
206
+ Effect.gen(function* () {
207
+ const peer = yield* Ref.get(peers).pipe(
208
+ Effect.flatMap((all) => {
209
+ const peer = HashMap.get(all, token)
210
+ return peer._tag === "Some"
211
+ ? Effect.succeed(peer.value)
212
+ : Effect.fail(
213
+ SessionStopped.make({
214
+ detail: "The execution channel is no longer available",
215
+ }),
216
+ )
217
+ }),
218
+ )
219
+ const occupied = yield* Ref.modify(
220
+ claimed,
221
+ (all) =>
222
+ [HashSet.has(all, token), HashSet.add(all, token)] as const,
223
+ )
224
+ if (occupied)
225
+ return yield* SessionConflict.make({
226
+ detail: "The instance channel is already attached",
227
+ })
228
+ return peer
229
+ }),
230
+ () => Ref.update(claimed, HashSet.remove(token)),
231
+ ),
232
+ }
233
+ })
234
+
235
+ export const layer = (root: string) =>
236
+ Layer.effectContext(
237
+ make(root).pipe(
238
+ Effect.map((execution) =>
239
+ Context.make(Execution, execution.driver).pipe(
240
+ Context.add(Channels, { peer: execution.peer }),
241
+ ),
242
+ ),
243
+ ),
244
+ )
@@ -0,0 +1,122 @@
1
+ import { Array, Effect, MutableRef, Option, Result, Schema } from "effect"
2
+
3
+ export class FrameError extends Schema.TaggedError<
4
+ FrameError,
5
+ { readonly brand: unique symbol }
6
+ >()("FrameError", { detail: Schema.String }) {
7
+ override get message() {
8
+ return this.detail
9
+ }
10
+ }
11
+ /** A complete byte stream ended; malformed trailing bytes remain FrameError. */
12
+ export class EndOfStream extends Schema.TaggedError<
13
+ EndOfStream,
14
+ { readonly brand: unique symbol }
15
+ >()("RunnerEndOfStream", {}) {
16
+ override get message() {
17
+ return "Runner byte channel ended"
18
+ }
19
+ }
20
+ export type Channel = 0 | 1
21
+ export interface Frame {
22
+ readonly channel: Channel
23
+ readonly payload: Uint8Array
24
+ }
25
+ export const headerSize = 8
26
+ export const maxPayload = 1024 * 1024
27
+ const invalid = (detail: string) => FrameError.make({ detail })
28
+
29
+ /** Version 2 carries only channel and length; request admission belongs to port. */
30
+ export const encode = (frame: Frame) =>
31
+ Effect.gen(function* () {
32
+ if (frame.payload.byteLength > maxPayload)
33
+ return yield* invalid("Runner frame exceeds the payload limit")
34
+ const bytes = new Uint8Array(headerSize + frame.payload.byteLength)
35
+ bytes.set([2, frame.channel, 0, 0])
36
+ new DataView(bytes.buffer).setUint32(4, frame.payload.byteLength)
37
+ bytes.set(frame.payload, headerSize)
38
+ return bytes
39
+ })
40
+
41
+ /** Check a message boundary; the decoder still validates the frame's contents. */
42
+ export const isCompleteFrame = (bytes: Uint8Array): boolean =>
43
+ bytes.byteLength >= headerSize &&
44
+ new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(
45
+ 4,
46
+ ) ===
47
+ bytes.byteLength - headerSize
48
+
49
+ /** The decoder owns its byte buffer. Results expose malformed frames without throwing through a generator. */
50
+ export const decoder = () => {
51
+ const pending = MutableRef.make<Result.Result<Uint8Array, FrameError>>(
52
+ Result.succeed(new Uint8Array(0)),
53
+ )
54
+ const decode = (
55
+ chunk: Uint8Array,
56
+ ): Result.Result<ReadonlyArray<Frame>, FrameError> =>
57
+ Result.flatMap(MutableRef.get(pending), (previous) => {
58
+ const bytes = new Uint8Array(previous.length + chunk.length)
59
+ bytes.set(previous)
60
+ bytes.set(chunk, previous.length)
61
+ const frames = Array.unfold(
62
+ 0,
63
+ (
64
+ offset,
65
+ ): Option.Option<
66
+ readonly [Result.Result<Frame, FrameError>, number]
67
+ > => {
68
+ if (bytes.length - offset < headerSize) return Option.none()
69
+ const header = new DataView(bytes.buffer, offset, headerSize)
70
+ const channel = header.getUint8(1)
71
+ const length = header.getUint32(4)
72
+ if (
73
+ header.getUint8(0) !== 2 ||
74
+ (channel !== 0 && channel !== 1) ||
75
+ header.getUint16(2) !== 0 ||
76
+ length > maxPayload
77
+ )
78
+ return Option.some([
79
+ Result.fail(
80
+ invalid("Invalid runner frame header or payload length"),
81
+ ),
82
+ bytes.length,
83
+ ])
84
+ const end = offset + headerSize + length
85
+ if (end > bytes.length) return Option.none()
86
+ return Option.some([
87
+ Result.succeed({
88
+ channel,
89
+ payload: bytes.subarray(offset + headerSize, end),
90
+ }),
91
+ end,
92
+ ])
93
+ },
94
+ )
95
+ const result = Result.all(frames)
96
+ MutableRef.set(
97
+ pending,
98
+ Result.map(result, (frames) =>
99
+ bytes.subarray(
100
+ Array.reduce(
101
+ frames,
102
+ 0,
103
+ (used, frame) => used + headerSize + frame.payload.length,
104
+ ),
105
+ ),
106
+ ),
107
+ )
108
+ return result
109
+ })
110
+ return {
111
+ decode,
112
+ finish: Effect.suspend(() =>
113
+ Effect.fromResult(
114
+ Result.flatMap(MutableRef.get(pending), (bytes) =>
115
+ bytes.length === 0
116
+ ? Result.succeed(undefined)
117
+ : Result.fail(invalid("Runner connection ended inside a frame")),
118
+ ),
119
+ ),
120
+ ),
121
+ }
122
+ }
@@ -0,0 +1,73 @@
1
+ import { Cause, Effect, Fiber, Option } from "effect"
2
+ import type { Execution } from "../directTransport"
3
+ import * as FailureGroup from "../FailureGroup"
4
+ import {
5
+ LocalTerminationTimeout,
6
+ ProcessExited,
7
+ TransportError,
8
+ } from "../../Errors"
9
+ import * as Port from "../port"
10
+ import { stdinExitTimeout } from "./ProcessObservation"
11
+
12
+ /** Direct execution observers stay alive until exit, including forced cleanup. */
13
+ export const connect = Effect.fnUntraced(function* (
14
+ execution: Execution,
15
+ options: Port.Options,
16
+ ) {
17
+ const failures = yield* FailureGroup.make<ProcessExited | TransportError>()
18
+ const exited = yield* execution.exited.pipe(Effect.forkScoped)
19
+ const peer = yield* Port.make(execution.channel, options)
20
+ yield* failures.run(
21
+ Effect.raceFirst(
22
+ peer.await,
23
+ Fiber.join(exited).pipe(Effect.flatMap(Effect.fail)),
24
+ ),
25
+ )
26
+ const report = (cause: Cause.Cause<unknown>) =>
27
+ Cause.hasInterruptsOnly(cause)
28
+ ? Effect.void
29
+ : failures
30
+ .fail(TransportError.make({ cause }))
31
+ .pipe(Effect.andThen(peer.fail(TransportError.make({ cause }))))
32
+ yield* failures.run(execution.failure)
33
+
34
+ return {
35
+ ...peer,
36
+ pid: execution.pid,
37
+ ...(execution.threadId === undefined
38
+ ? {}
39
+ : { threadId: execution.threadId }),
40
+ exited,
41
+ resources: yield* Effect.scope,
42
+ transport: { ...peer, failure: failures.await, report },
43
+ diagnostics: Fiber.await(exited).pipe(Effect.andThen(failures.cause)),
44
+ terminate: (graceful: boolean) =>
45
+ Effect.gen(function* () {
46
+ // Stop observation before intentionally ending stdin or killing the process.
47
+ yield* failures.close
48
+ if (!graceful) return
49
+ // If this fails, the execution scope forces termination and waits for exit.
50
+ const status = yield* peer.end.pipe(
51
+ // Peer EOF can interrupt the writer as its output ends. Still confirm the unit's exit.
52
+ Effect.catchCauseIf(Cause.hasInterruptsOnly, () => Effect.void),
53
+ Effect.andThen(Fiber.join(exited)),
54
+ Effect.interruptible,
55
+ Effect.timeoutOrElse({
56
+ duration: stdinExitTimeout,
57
+ orElse: () =>
58
+ LocalTerminationTimeout.make({
59
+ ...Option.match(execution.pid, {
60
+ onNone: () => ({}),
61
+ onSome: (pid) => ({ pid }),
62
+ }),
63
+ ...(execution.threadId === undefined
64
+ ? {}
65
+ : { threadId: execution.threadId }),
66
+ }),
67
+ }),
68
+ )
69
+ if (status.exitCode !== 0 || status.statusCause.reasons.length > 0)
70
+ return yield* status
71
+ }),
72
+ }
73
+ })
@@ -0,0 +1,29 @@
1
+ import { Cause, Effect, FileSystem, Path } from "effect"
2
+ import { StateDirectoryLocked } from "./model"
3
+
4
+ /** SQLite owns the local directory lock for the enclosing scope, including failed startup. */
5
+ export const acquire = (directory: string) =>
6
+ Effect.gen(function* () {
7
+ const fs = yield* FileSystem.FileSystem
8
+ const path = yield* Path.Path
9
+ yield* fs
10
+ .makeDirectory(directory, { recursive: true })
11
+ .pipe(Effect.uninterruptible)
12
+ const { DatabaseSync } = yield* Effect.promise(
13
+ () => import("node:sqlite"),
14
+ ).pipe(Effect.uninterruptible)
15
+ const locked = (cause: unknown) =>
16
+ StateDirectoryLocked.make({
17
+ detail:
18
+ "The runner state directory is already owned or cannot be locked",
19
+ cause: Cause.die(cause),
20
+ })
21
+ const db = yield* Effect.acquireRelease(
22
+ Effect.try({
23
+ try: () => new DatabaseSync(path.join(directory, "owner.sqlite")),
24
+ catch: locked,
25
+ }),
26
+ (db) => Effect.sync(() => db.close()),
27
+ )
28
+ yield* Effect.try({ try: () => db.exec("BEGIN EXCLUSIVE"), catch: locked })
29
+ })