@graftland/plugin-remote 0.0.0-stage → 0.3.0

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
package/src/index.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { Plugin } from "@graftland/graft"
2
+ import { ModuleResolver } from "@graftland/loader"
3
+ import { Array, Cause, Effect, Path, Schema } from "effect"
4
+ import type { Duration, Schedule } from "effect"
5
+ import { SecureRandom } from "effect/crypto"
6
+ import { ChildProcessSpawner } from "effect/process"
7
+ import { launch } from "./internal/entry"
8
+ import { follow } from "./internal/follow"
9
+ import { CapabilityFailed } from "./internal/assembly"
10
+ import { publicError } from "./internal/execution"
11
+ import * as Configuration from "./internal/entryConfig"
12
+ import * as Credential from "./internal/credentials"
13
+ import { RemoteWithdrawn, RemoteError, MissingInstance } from "./Errors"
14
+ import * as Contract from "./Contract"
15
+ export { Contract }
16
+ export { Instance } from "./Instance"
17
+ export { RemoteTerminationUnconfirmed } from "./internal/runner/model"
18
+ export { RemoteError, RemoteWithdrawn, MissingInstance } from "./Errors"
19
+ export { UndeclaredFailure, ChildFailure } from "./Contract"
20
+ export type {
21
+ Connect,
22
+ Source as CredentialSource,
23
+ } from "./internal/credentials"
24
+
25
+ export interface Options<
26
+ D extends ReadonlyArray<Plugin.Dependency> = readonly [],
27
+ > {
28
+ readonly connect: Credential.Connect<D>
29
+ /** Contract module resolved independently in each execution environment. */
30
+ readonly contractModule: string
31
+ readonly config?: Schema.Json
32
+ readonly retry?: Schedule.Schedule<unknown, unknown> | undefined
33
+ readonly shutdownTimeout?: Duration.Input | undefined
34
+ }
35
+ const publicCause = <E extends Schema.Top>(
36
+ declared: E,
37
+ cause: Cause.Cause<unknown>,
38
+ ): Cause.Cause<
39
+ | E["Type"]
40
+ | Contract.UndeclaredFailure
41
+ | RemoteWithdrawn
42
+ | RemoteError
43
+ | MissingInstance
44
+ > =>
45
+ Cause.fromReasons(
46
+ Array.flatMap(cause.reasons, (reason) => {
47
+ if (reason._tag !== "Fail") return [reason]
48
+ return Schema.is(CapabilityFailed)(reason.error)
49
+ ? Array.map(
50
+ publicCause(declared, reason.error.cause).reasons,
51
+ (inner) => inner.annotate(Cause.reasonAnnotations(reason)),
52
+ )
53
+ : [
54
+ Cause.makeFailReason(publicError(declared, reason.error)).annotate(
55
+ Cause.reasonAnnotations(reason),
56
+ ),
57
+ ]
58
+ }),
59
+ )
60
+
61
+ export const plugin = <
62
+ S extends Schema.Top & {
63
+ readonly Encoded: Schema.Json
64
+ readonly DecodingServices: never
65
+ readonly EncodingServices: never
66
+ },
67
+ E extends Schema.Top & {
68
+ readonly DecodingServices: never
69
+ readonly EncodingServices: never
70
+ },
71
+ const D extends ReadonlyArray<Plugin.Dependency> = readonly [],
72
+ >(
73
+ contract: Contract.Contract<S, E>,
74
+ options: Options<D> & { readonly config?: S["Encoded"] },
75
+ ): Plugin.Plugin<
76
+ void,
77
+ void,
78
+ | E["Type"]
79
+ | Contract.UndeclaredFailure
80
+ | RemoteError
81
+ | RemoteWithdrawn
82
+ | MissingInstance
83
+ > =>
84
+ Plugin.make({
85
+ name: contract.name,
86
+ inject: [
87
+ Plugin.optional(ModuleResolver.ModuleResolver),
88
+ Path.Path,
89
+ SecureRandom.SecureRandom,
90
+ ChildProcessSpawner.ChildProcessSpawner,
91
+ ],
92
+ retry: options.retry,
93
+ apply: () =>
94
+ Effect.gen(function* () {
95
+ const input = yield* Schema.decodeUnknownEffect(Configuration.Host)({
96
+ contract: options.contractModule,
97
+ connect: options.connect,
98
+ config: options.config === undefined ? {} : options.config,
99
+ })
100
+ yield* Schema.decodeEffect(contract.config)(input.config)
101
+ const child = yield* launch(
102
+ contract,
103
+ input,
104
+ {
105
+ contractModule: options.contractModule,
106
+ shutdownTimeout: options.shutdownTimeout,
107
+ },
108
+ Credential.invocation(options.connect),
109
+ )
110
+ yield* follow(child, (cause) =>
111
+ Effect.failCause(publicCause(contract.error, cause)),
112
+ )
113
+ }).pipe(Effect.mapError((error) => publicError(contract.error, error))),
114
+ })
115
+ export { host as default } from "./internal/entry"
@@ -0,0 +1,330 @@
1
+ import {
2
+ Array,
3
+ DateTime,
4
+ Effect,
5
+ FileSystem,
6
+ Path,
7
+ Redacted,
8
+ Result,
9
+ Schema,
10
+ String,
11
+ } from "effect"
12
+ import { SecureRandom, WebCrypto } from "effect/crypto"
13
+ import { Base64 } from "effect/encoding"
14
+ import { NetAddress } from "effect/net"
15
+ import * as asn1js from "asn1js"
16
+ import * as pki from "pkijs"
17
+
18
+ export class CertificateError extends Schema.TaggedError<
19
+ CertificateError,
20
+ { readonly brand: unique symbol }
21
+ >()("CertificateError", {
22
+ detail: Schema.String,
23
+ cause: Schema.optional(Schema.Defect()),
24
+ }) {
25
+ override get message() {
26
+ return this.detail
27
+ }
28
+ }
29
+
30
+ /** A requested output already exists and replacing it was not asked for. */
31
+ export class CertificateExists extends Schema.TaggedError<
32
+ CertificateExists,
33
+ { readonly brand: unique symbol }
34
+ >()("CertificateExists", { file: Schema.String }) {
35
+ override get message() {
36
+ return `${this.file} already exists; use --force to replace the requested certificates`
37
+ }
38
+ }
39
+
40
+ /** Only PEM leaves this boundary; PKI.js objects stay local to each operation. */
41
+ export interface Pem {
42
+ readonly certificate: string
43
+ readonly privateKey: Redacted.Redacted<string>
44
+ }
45
+ export interface IssueOptions {
46
+ readonly name: string
47
+ readonly days: number
48
+ readonly usage: "ca" | "server" | "client"
49
+ readonly hosts?: ReadonlyArray<string>
50
+ readonly identities?: ReadonlyArray<string>
51
+ readonly issuer?: Pem
52
+ }
53
+ const pem = (label: string, bytes: ArrayBuffer) =>
54
+ `-----BEGIN ${label}-----\n${String.replace(/.{64}(?=.)/g, "$&\n")(Base64.encode(new Uint8Array(bytes)))}\n-----END ${label}-----\n`
55
+ // WebCrypto and PKI.js take ArrayBuffer-backed bytes, so the decoded view is copied into one.
56
+ const der = (value: string) =>
57
+ Effect.fromResult(
58
+ Base64.decode(String.replace(/-----[^-]+-----|\s/g, "")(value)),
59
+ ).pipe(Effect.map((bytes) => new Uint8Array(bytes)))
60
+ const subject = (name: string) =>
61
+ new pki.RelativeDistinguishedNames({
62
+ typesAndValues: [
63
+ new pki.AttributeTypeAndValue({
64
+ type: "2.5.4.3",
65
+ value: new asn1js.Utf8String({ value: name }),
66
+ }),
67
+ ],
68
+ })
69
+ const hostName = (host: string) =>
70
+ Result.match(NetAddress.ipFromString(host), {
71
+ onFailure: () => new pki.GeneralName({ type: 2, value: host }),
72
+ onSuccess: (ip) =>
73
+ new pki.GeneralName({
74
+ type: 7,
75
+ value: new asn1js.OctetString({
76
+ valueHex: new Uint8Array(
77
+ ip._tag === "Ipv4Address"
78
+ ? NetAddress.ipv4ToOctets(ip)
79
+ : NetAddress.ipv6ToOctets(ip),
80
+ ),
81
+ }),
82
+ }),
83
+ })
84
+
85
+ export const issue = Effect.fn("Certificates.issue")(function* (
86
+ options: IssueOptions,
87
+ ) {
88
+ const random = yield* SecureRandom.SecureRandom
89
+ const serial = yield* random.randomBytes(19)
90
+ const now = yield* DateTime.now
91
+ const webcrypto = yield* WebCrypto.WebCrypto
92
+ const engine = new pki.CryptoEngine({
93
+ name: "Node WebCrypto",
94
+ crypto: webcrypto,
95
+ })
96
+ const failure = (cause: unknown) =>
97
+ CertificateError.make({
98
+ detail: `Could not issue the certificate for ${options.name}`,
99
+ cause,
100
+ })
101
+ const keys = yield* Effect.tryPromise({
102
+ try: () =>
103
+ webcrypto.subtle.generateKey(
104
+ { name: "ECDSA", namedCurve: "P-256" },
105
+ true,
106
+ ["sign", "verify"],
107
+ ),
108
+ catch: failure,
109
+ })
110
+ // Reused CA keys have the same P-256 / PKCS#8 format as the ones this command creates.
111
+ const authority =
112
+ options.issuer === undefined
113
+ ? undefined
114
+ : {
115
+ certificate: yield* Effect.mapError(
116
+ der(options.issuer.certificate),
117
+ failure,
118
+ ),
119
+ privateKey: yield* Effect.mapError(
120
+ der(Redacted.value(options.issuer.privateKey)),
121
+ failure,
122
+ ),
123
+ }
124
+ const signingKey =
125
+ authority === undefined
126
+ ? keys.privateKey
127
+ : yield* Effect.tryPromise({
128
+ try: () =>
129
+ webcrypto.subtle.importKey(
130
+ "pkcs8",
131
+ authority.privateKey,
132
+ { name: "ECDSA", namedCurve: "P-256" },
133
+ false,
134
+ ["sign"],
135
+ ),
136
+ catch: failure,
137
+ })
138
+ const certificate = yield* Effect.try({
139
+ try: () => {
140
+ const issuer =
141
+ authority === undefined
142
+ ? undefined
143
+ : pki.Certificate.fromBER(authority.certificate)
144
+ const names = [
145
+ ...Array.map(options.hosts ?? [], hostName),
146
+ ...Array.map(
147
+ options.identities ?? [],
148
+ (identity) =>
149
+ new pki.GeneralName({ type: 6, value: `graft://${identity}` }),
150
+ ),
151
+ ]
152
+ return new pki.Certificate({
153
+ version: 2,
154
+ // A leading nonzero byte keeps the serial positive without losing random bits.
155
+ serialNumber: new asn1js.Integer({
156
+ valueHex: new Uint8Array([1, ...serial]),
157
+ }),
158
+ subject: subject(options.name),
159
+ issuer: issuer?.subject ?? subject(options.name),
160
+ notBefore: new pki.Time({ value: DateTime.toDateUtc(now) }),
161
+ notAfter: new pki.Time({
162
+ value: DateTime.toDateUtc(DateTime.add(now, { days: options.days })),
163
+ }),
164
+ extensions: [
165
+ new pki.Extension({
166
+ extnID: "2.5.29.19",
167
+ critical: true,
168
+ extnValue: new pki.BasicConstraints({ cA: options.usage === "ca" })
169
+ .toSchema()
170
+ .toBER(),
171
+ }),
172
+ new pki.Extension({
173
+ extnID: "2.5.29.15",
174
+ critical: true,
175
+ extnValue: new asn1js.BitString({
176
+ valueHex: new Uint8Array([options.usage === "ca" ? 0x06 : 0x80]),
177
+ }).toBER(),
178
+ }),
179
+ ...(options.usage === "ca"
180
+ ? []
181
+ : [
182
+ new pki.Extension({
183
+ extnID: "2.5.29.37",
184
+ extnValue: new pki.ExtKeyUsage({
185
+ keyPurposes: [
186
+ options.usage === "server"
187
+ ? "1.3.6.1.5.5.7.3.1"
188
+ : "1.3.6.1.5.5.7.3.2",
189
+ ],
190
+ })
191
+ .toSchema()
192
+ .toBER(),
193
+ }),
194
+ ]),
195
+ ...(names.length === 0
196
+ ? []
197
+ : [
198
+ new pki.Extension({
199
+ extnID: "2.5.29.17",
200
+ extnValue: new pki.AltName({ altNames: names })
201
+ .toSchema()
202
+ .toBER(),
203
+ }),
204
+ ]),
205
+ ],
206
+ })
207
+ },
208
+ catch: failure,
209
+ })
210
+ yield* Effect.tryPromise({
211
+ try: () =>
212
+ certificate.subjectPublicKeyInfo.importKey(keys.publicKey, engine),
213
+ catch: failure,
214
+ })
215
+ yield* Effect.tryPromise({
216
+ try: () => certificate.sign(signingKey, "SHA-256", engine),
217
+ catch: failure,
218
+ })
219
+ const privateKey = yield* Effect.tryPromise({
220
+ try: () => webcrypto.subtle.exportKey("pkcs8", keys.privateKey),
221
+ catch: failure,
222
+ })
223
+ return yield* Effect.try({
224
+ try: () => ({
225
+ certificate: pem("CERTIFICATE", certificate.toSchema().toBER()),
226
+ privateKey: Redacted.make(pem("PRIVATE KEY", privateKey)),
227
+ }),
228
+ catch: failure,
229
+ })
230
+ })
231
+
232
+ export const read = Effect.fn("Certificates.read")(function* (base: string) {
233
+ const fs = yield* FileSystem.FileSystem
234
+ const certificate = yield* fs.readFileString(base + ".crt")
235
+ const privateKey = yield* fs.readFileString(base + ".key")
236
+ return { certificate, privateKey: Redacted.make(privateKey) }
237
+ })
238
+ export const write = Effect.fn("Certificates.write")(function* (
239
+ base: string,
240
+ pair: Pem,
241
+ force: boolean = false,
242
+ ) {
243
+ const fs = yield* FileSystem.FileSystem
244
+ yield* fs
245
+ .writeFileString(base + ".key", Redacted.value(pair.privateKey), {
246
+ flag: force ? "w" : "wx",
247
+ mode: 0o600,
248
+ })
249
+ .pipe(Effect.uninterruptible)
250
+ // Opening an existing file does not change its permissions when renewing it.
251
+ yield* fs.chmod(base + ".key", 0o600).pipe(Effect.uninterruptible)
252
+ yield* fs
253
+ .writeFileString(base + ".crt", pair.certificate, {
254
+ flag: force ? "w" : "wx",
255
+ })
256
+ .pipe(Effect.uninterruptible)
257
+ })
258
+
259
+ export interface Options {
260
+ readonly out: string
261
+ readonly server: ReadonlyArray<string>
262
+ readonly identity: ReadonlyArray<string>
263
+ readonly days: number
264
+ readonly force: boolean
265
+ }
266
+ /** URI-encode names so each identity has a distinct filename, including names with slashes. */
267
+ export const clientName = (identity: string) =>
268
+ `client-${encodeURIComponent(identity)}`
269
+ export const generate = Effect.fn("Certificates.generate")(function* (
270
+ options: Options,
271
+ ) {
272
+ const fs = yield* FileSystem.FileSystem
273
+ const path = yield* Path.Path
274
+ const outputs = [
275
+ ...(options.server.length === 0 ? [] : ["server"]),
276
+ ...Array.map(Array.dedupe(options.identity), clientName),
277
+ ]
278
+ if (!options.force) {
279
+ const files = Array.flatMap(outputs, (name) =>
280
+ Array.map([".crt", ".key"], (extension) =>
281
+ path.join(options.out, name + extension),
282
+ ),
283
+ )
284
+ const taken = yield* Effect.filter(files, fs.exists)
285
+ if (Array.isReadonlyArrayNonEmpty(taken))
286
+ return yield* CertificateExists.make({ file: taken[0] })
287
+ }
288
+ yield* fs
289
+ .makeDirectory(options.out, { recursive: true })
290
+ .pipe(Effect.uninterruptible)
291
+ const ca = path.join(options.out, "ca")
292
+ const existing =
293
+ (yield* fs.exists(ca + ".crt")) || (yield* fs.exists(ca + ".key"))
294
+ // An incomplete CA pair fails on read. Even --force never replaces the signing authority.
295
+ const issuer = existing
296
+ ? yield* read(ca)
297
+ : yield* issue({ name: "Graft CA", usage: "ca", days: options.days }).pipe(
298
+ Effect.tap((pair) => write(ca, pair)),
299
+ )
300
+ if (options.server.length > 0) {
301
+ const pair = yield* issue({
302
+ name: "Graft runner",
303
+ usage: "server",
304
+ hosts: options.server,
305
+ days: options.days,
306
+ issuer,
307
+ })
308
+ yield* write(path.join(options.out, "server"), pair, options.force)
309
+ }
310
+ yield* Effect.forEach(
311
+ Array.dedupe(options.identity),
312
+ (identity) =>
313
+ issue({
314
+ name: identity,
315
+ usage: "client",
316
+ identities: [identity],
317
+ days: options.days,
318
+ issuer,
319
+ }).pipe(
320
+ Effect.flatMap((pair) =>
321
+ write(
322
+ path.join(options.out, clientName(identity)),
323
+ pair,
324
+ options.force,
325
+ ),
326
+ ),
327
+ ),
328
+ { discard: true },
329
+ )
330
+ })
@@ -0,0 +1,176 @@
1
+ import {
2
+ Array,
3
+ Cause,
4
+ Fiber,
5
+ Data,
6
+ Deferred,
7
+ Effect,
8
+ Exit,
9
+ FiberSet,
10
+ Ref,
11
+ Scope,
12
+ Schema,
13
+ TxRef,
14
+ } from "effect"
15
+ import * as Release from "./release"
16
+
17
+ type State<E> = Data.TaggedEnum<{
18
+ Open: {}
19
+ Failed: { readonly cause: Cause.Cause<E> }
20
+ Closed: {}
21
+ }>
22
+ interface StateDefinition extends Data.TaggedEnum.WithGenerics<1> {
23
+ readonly taggedEnum: State<this["A"]>
24
+ }
25
+ const State = Data.taggedEnum<StateDefinition>()
26
+ export interface FailureGroup<E> {
27
+ readonly await: Effect.Effect<never, E>
28
+ readonly check: Effect.Effect<void, E>
29
+ readonly cause: Effect.Effect<Cause.Cause<E>>
30
+ readonly run: <A, R>(
31
+ effect: Effect.Effect<A, E, R>,
32
+ ) => Effect.Effect<Fiber.Fiber<A, E>, never, R>
33
+ readonly fail: (error: E) => Effect.Effect<void>
34
+ readonly failCause: (cause: Cause.Cause<E>) => Effect.Effect<void>
35
+ readonly race: <A, E2, R>(
36
+ effect: Effect.Effect<A, E2, R>,
37
+ ) => Effect.Effect<A, E | E2, R>
38
+ readonly runtime: <R>() => Effect.Effect<
39
+ (effect: Effect.Effect<unknown, E, R>) => Fiber.Fiber<unknown, E>,
40
+ never,
41
+ R
42
+ >
43
+ readonly close: Effect.Effect<void, E>
44
+ }
45
+
46
+ /** One owner for first failure, transaction wakeups, and interruption of sibling work. */
47
+ export const make = <E>(): Effect.Effect<FailureGroup<E>, never, Scope.Scope> =>
48
+ Effect.gen(function* () {
49
+ const fibers = yield* FiberSet.make<unknown, E>()
50
+ const state = yield* TxRef.make<State<E>>(State.Open())
51
+ const failures = yield* Ref.make<Cause.Cause<E>>(Cause.empty)
52
+ const cleanup = yield* Ref.make<Cause.Cause<E>>(Cause.empty)
53
+ const check = TxRef.get(state).pipe(
54
+ Effect.flatMap((s) =>
55
+ s._tag === "Failed"
56
+ ? Effect.failCause(s.cause)
57
+ : s._tag === "Closed"
58
+ ? Effect.interrupt
59
+ : Effect.void,
60
+ ),
61
+ )
62
+ const publish = (cause: Cause.Cause<E>) =>
63
+ TxRef.update(state, (s): State<E> =>
64
+ s._tag === "Open" ? State.Failed({ cause }) : s,
65
+ )
66
+
67
+ const observe = <A, R>(effect: Effect.Effect<A, E, R>) =>
68
+ Effect.uninterruptibleMask((restore) =>
69
+ Effect.gen(function* () {
70
+ const scope = yield* Scope.make()
71
+ // The owned child makes cancellation explicit, even when a stream closes an internal scope.
72
+ const ownerId = yield* Effect.withFiber((self) =>
73
+ Effect.succeed(self.id),
74
+ )
75
+ const worker = yield* Effect.forkIn(
76
+ restore(Scope.provide(scope)(effect)),
77
+ scope,
78
+ )
79
+ const waiting = yield* Effect.exit(restore(Fiber.await(worker)))
80
+ if (Exit.isFailure(waiting)) yield* Fiber.interrupt(worker)
81
+ const body = yield* Fiber.await(worker)
82
+ const closed = yield* Effect.exit(Release.close(scope, body))
83
+ // Forwarding this exact cancellation from a finalizer is indistinguishable from acknowledging it.
84
+ const expected =
85
+ Exit.isFailure(waiting) &&
86
+ Exit.isFailure(body) &&
87
+ Array.every(
88
+ body.cause.reasons,
89
+ (reason) =>
90
+ reason._tag === "Interrupt" && reason.fiberId === ownerId,
91
+ )
92
+ const bodyCause =
93
+ Exit.isFailure(body) && !expected ? body.cause : Cause.empty
94
+ // Release.close marks independent interruptions; an unmarked one is pending cancellation.
95
+ const releaseCause =
96
+ Exit.isFailure(closed) && !Cause.hasInterruptsOnly(closed.cause)
97
+ ? closed.cause
98
+ : Cause.empty
99
+ const failure = Cause.combine(bodyCause, releaseCause)
100
+ // Body cleanup may carry either an interruption or a release defect from an inner group.
101
+ const closing = Cause.combine(
102
+ Cause.hasInterrupts(bodyCause) ||
103
+ Array.some(
104
+ bodyCause.reasons,
105
+ (reason) =>
106
+ reason._tag === "Die" &&
107
+ Schema.is(Release.ReleaseInterrupted)(reason.defect),
108
+ )
109
+ ? bodyCause
110
+ : Cause.empty,
111
+ releaseCause,
112
+ )
113
+ yield* Ref.update(cleanup, (cause) => Cause.combine(cause, closing))
114
+ if (failure.reasons.length > 0) {
115
+ yield* Ref.update(failures, (cause) =>
116
+ Cause.combine(cause, failure),
117
+ )
118
+ yield* publish(failure)
119
+ yield* Deferred.failCause(fibers.deferred, failure)
120
+ }
121
+ if (Exit.isFailure(closed))
122
+ return yield* Effect.failCause(
123
+ Exit.isFailure(body)
124
+ ? Cause.combine(body.cause, closed.cause)
125
+ : closed.cause,
126
+ )
127
+ if (Exit.isFailure(waiting) && Exit.isSuccess(body))
128
+ return yield* Effect.failCause(waiting.cause)
129
+ return yield* body
130
+ }),
131
+ )
132
+ yield* FiberSet.join(fibers).pipe(
133
+ Effect.catchCause((cause) =>
134
+ publish(cause).pipe(
135
+ Effect.andThen(FiberSet.clear(fibers)),
136
+ Effect.uninterruptible,
137
+ ),
138
+ ),
139
+ Effect.forkScoped,
140
+ )
141
+ const failure = Effect.tx(check.pipe(Effect.andThen(Effect.txRetry)))
142
+ const failCause = (cause: Cause.Cause<E>) =>
143
+ // This is an explicit failure report, not cancellation of an owned worker.
144
+ FiberSet.run(fibers, observe(Effect.failCause(cause))).pipe(Effect.asVoid)
145
+ const close = TxRef.update(state, (s) =>
146
+ s._tag === "Open" ? State.Closed() : s,
147
+ ).pipe(
148
+ Effect.andThen(FiberSet.clear(fibers)),
149
+ Effect.andThen(Ref.get(cleanup)),
150
+ Effect.flatMap((cause) =>
151
+ cause.reasons.length > 0 ? Effect.failCause(cause) : Effect.void,
152
+ ),
153
+ Effect.uninterruptible,
154
+ )
155
+ // Operational failure is delivered by await; release must also deliver sibling cleanup failures.
156
+ yield* Effect.addFinalizer(() => close.pipe(Effect.orDie))
157
+ return {
158
+ await: failure,
159
+ check,
160
+ cause: Ref.get(failures),
161
+ runtime: <R>() =>
162
+ FiberSet.runtime(fibers)<R>().pipe(
163
+ Effect.map(
164
+ (run) => (effect: Effect.Effect<unknown, E, R>) =>
165
+ run(check.pipe(Effect.andThen(observe(effect)))),
166
+ ),
167
+ ),
168
+ run: (effect) =>
169
+ FiberSet.run(fibers, check.pipe(Effect.andThen(observe(effect)))),
170
+ fail: (error) => failCause(Cause.fail(error)),
171
+ failCause,
172
+ race: (effect) =>
173
+ check.pipe(Effect.andThen(Effect.raceFirst(effect, failure))),
174
+ close,
175
+ }
176
+ })
@@ -0,0 +1,12 @@
1
+ import { Schema } from "effect"
2
+
3
+ export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0))
4
+ export const PositiveFinite = Schema.Finite.check(Schema.isGreaterThan(0))
5
+ export const Limits = Schema.Struct({
6
+ control: PositiveInt,
7
+ data: PositiveInt,
8
+ log: PositiveInt,
9
+ })
10
+ export type Limits = typeof Limits.Type
11
+ export type Priority = keyof Limits
12
+ export const defaults: Limits = { control: 8, data: 16, log: 2 }
@@ -0,0 +1,4 @@
1
+ import { Context } from "effect"
2
+ export class Peer extends Context.Service<Peer, string>()(
3
+ "@graftland/plugin-remote/internal/Peer",
4
+ ) {}
@@ -0,0 +1,53 @@
1
+ import { Context, Deferred, Effect, Exit, Option, Schema, Scope } from "effect"
2
+ import * as Release from "./release"
3
+ import type { TransportError } from "../Errors"
4
+
5
+ export class StartupError extends Schema.TaggedError<
6
+ StartupError,
7
+ { readonly brand: unique symbol }
8
+ >()("RunnerStartupError", {
9
+ detail: Schema.String,
10
+ cause: Schema.optionalKey(Schema.Cause(Schema.Unknown, Schema.Defect())),
11
+ }) {
12
+ override get message() {
13
+ return this.detail
14
+ }
15
+ }
16
+
17
+ export class ServeLifecycle extends Context.Service<
18
+ ServeLifecycle,
19
+ {
20
+ readonly ended: Deferred.Deferred<void, TransportError>
21
+ readonly released: Deferred.Deferred<void, StartupError>
22
+ }
23
+ >()("@graftland/plugin-remote/internal/ServeLifecycle") {}
24
+
25
+ export const make = Effect.all({
26
+ ended: Deferred.make<void, TransportError>(),
27
+ released: Deferred.make<void, StartupError>(),
28
+ })
29
+
30
+ /** Observe shutdown independently of the loader, which logs child cleanup failures. */
31
+ export const resources = Effect.fnUntraced(function* (
32
+ lifecycle: Option.Option<typeof ServeLifecycle.Service>,
33
+ ) {
34
+ return yield* Effect.acquireRelease(Scope.make(), (scope, exit) =>
35
+ Release.close(scope, exit).pipe(
36
+ Effect.onExit((released) =>
37
+ Option.isNone(lifecycle)
38
+ ? Effect.void
39
+ : Deferred.done(
40
+ lifecycle.value.released,
41
+ Exit.isSuccess(released)
42
+ ? Exit.void
43
+ : Exit.fail(
44
+ StartupError.make({
45
+ detail: "Supervisor shutdown failed",
46
+ cause: released.cause,
47
+ }),
48
+ ),
49
+ ).pipe(Effect.asVoid),
50
+ ),
51
+ ),
52
+ )
53
+ })
@@ -0,0 +1,14 @@
1
+ /** A listener hands an authenticated byte channel to the supervisor. */
2
+ import { Context } from "effect"
3
+ import type { Effect, Scope } from "effect"
4
+ import type { Peer } from "./Peer"
5
+ import type { Channel } from "../Transport"
6
+ import type { TransportError } from "../Errors"
7
+ export class Supervisor extends Context.Service<
8
+ Supervisor,
9
+ {
10
+ readonly accept: (
11
+ channel: Channel,
12
+ ) => Effect.Effect<void, TransportError, Peer | Scope.Scope>
13
+ }
14
+ >()("@graftland/plugin-remote/internal/Supervisor") {}