@graftland/plugin-remote 0.0.0-placeholder.0 → 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 +75 -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 +71 -11
  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,120 @@
1
+ import {
2
+ Cause,
3
+ Effect,
4
+ Fiber,
5
+ Option,
6
+ Queue,
7
+ Sink,
8
+ Stream,
9
+ TxQueue,
10
+ } from "effect"
11
+ import type { Socket } from "effect/socket"
12
+ import { TransportError } from "../../Errors"
13
+ import type { Channel as ByteChannel } from "../port"
14
+ import * as FailureGroup from "../FailureGroup"
15
+ import * as Framing from "./Framing"
16
+
17
+ export interface Peer {
18
+ readonly await: Effect.Effect<never, TransportError>
19
+ readonly fail: (error: TransportError) => Effect.Effect<void>
20
+ readonly end: Effect.Effect<void, TransportError>
21
+ readonly send: (
22
+ channel: Framing.Channel,
23
+ payload: Uint8Array,
24
+ ) => Effect.Effect<void, TransportError | Framing.FrameError>
25
+ readonly take: (
26
+ channel: Framing.Channel,
27
+ ) => Effect.Effect<Uint8Array, TransportError>
28
+ }
29
+ /** Ports own admission and ACK backpressure. This layer only frames and separates session/instance bytes. */
30
+ export const make = Effect.fnUntraced(function* (
31
+ channel: ByteChannel,
32
+ ): Effect.fn.Return<Peer, never, import("effect").Scope.Scope> {
33
+ const group = yield* FailureGroup.make<TransportError>()
34
+ const incoming = {
35
+ 0: yield* Queue.unbounded<Uint8Array>(),
36
+ 1: yield* Queue.unbounded<Uint8Array>(),
37
+ }
38
+ const outgoing = {
39
+ 0: yield* TxQueue.unbounded<Uint8Array, Cause.Done>(),
40
+ 1: yield* TxQueue.unbounded<Uint8Array, Cause.Done>(),
41
+ }
42
+ const next = Effect.tx(
43
+ Effect.gen(function* () {
44
+ const session = yield* TxQueue.poll(outgoing[0])
45
+ if (Option.isSome(session)) return session.value
46
+ const instance = yield* TxQueue.poll(outgoing[1])
47
+ if (Option.isSome(instance)) return instance.value
48
+ if (
49
+ (yield* TxQueue.isDone(outgoing[0])) &&
50
+ (yield* TxQueue.isDone(outgoing[1]))
51
+ )
52
+ return yield* Cause.done()
53
+ return yield* Effect.txRetry
54
+ }),
55
+ )
56
+ const writing = yield* group.run(
57
+ Stream.fromEffectRepeat(next).pipe(
58
+ Stream.run(channel.output),
59
+ Effect.asVoid,
60
+ ),
61
+ )
62
+ const decoder = Framing.decoder()
63
+ yield* group.run(
64
+ channel.input.pipe(
65
+ Stream.runForEach((bytes) =>
66
+ Effect.fromResult(decoder.decode(bytes)).pipe(
67
+ Effect.flatMap((frames) =>
68
+ Effect.forEach(
69
+ frames,
70
+ (frame) => Queue.offer(incoming[frame.channel], frame.payload),
71
+ { discard: true },
72
+ ),
73
+ ),
74
+ ),
75
+ ),
76
+ Effect.andThen(decoder.finish),
77
+ Effect.andThen(Effect.fail(Framing.EndOfStream.make({}))),
78
+ Effect.mapError((error) =>
79
+ error._tag === "TransportError"
80
+ ? error
81
+ : TransportError.make({ cause: Cause.fail(error) }),
82
+ ),
83
+ ),
84
+ )
85
+ return {
86
+ await: group.await,
87
+ fail: group.fail,
88
+ end: Effect.tx(
89
+ TxQueue.end(outgoing[0]).pipe(Effect.andThen(TxQueue.end(outgoing[1]))),
90
+ ).pipe(Effect.andThen(Fiber.join(writing))),
91
+ send: (id, payload) =>
92
+ group.race(
93
+ Framing.encode({ channel: id, payload }).pipe(
94
+ Effect.flatMap((bytes) => TxQueue.offer(outgoing[id], bytes)),
95
+ Effect.asVoid,
96
+ ),
97
+ ),
98
+ take: (id) => group.race(Queue.take(incoming[id])),
99
+ }
100
+ })
101
+ export const fromSocket = Effect.fnUntraced(function* (socket: Socket.Socket) {
102
+ const reader = yield* socket.reader
103
+ const writer = yield* socket.writer
104
+ return yield* make({
105
+ input: Stream.fromEffectRepeat(reader.pull).pipe(
106
+ Stream.flattenIterable,
107
+ Stream.map((bytes) =>
108
+ typeof bytes === "string" ? new TextEncoder().encode(bytes) : bytes,
109
+ ),
110
+ Stream.mapError((error) =>
111
+ TransportError.make({ cause: Cause.fail(error) }),
112
+ ),
113
+ ),
114
+ output: Sink.forEach((bytes: Uint8Array) => writer.write(bytes)).pipe(
115
+ Sink.mapError((error) =>
116
+ TransportError.make({ cause: Cause.fail(error) }),
117
+ ),
118
+ ),
119
+ })
120
+ })
@@ -0,0 +1,178 @@
1
+ import {
2
+ Array,
3
+ Cause,
4
+ Effect,
5
+ FileSystem,
6
+ Order,
7
+ Path,
8
+ Schema,
9
+ Stream,
10
+ String,
11
+ } from "effect"
12
+ import type { PlatformError } from "effect"
13
+ import { ChildProcess, ChildProcessSpawner } from "effect/process"
14
+ // @effect-diagnostics-next-line nodeBuiltinImport:off -- WebCrypto has no incremental digest API; package files are hashed as streams without buffering the directory.
15
+ import { createHash } from "node:crypto"
16
+ import process from "node:process"
17
+ import { fileURLToPath } from "node:url"
18
+ import { PackageError, type CodeIdentity } from "./model"
19
+
20
+ const Manifest = Schema.Struct({ name: Schema.String, version: Schema.String })
21
+ export interface Expected {
22
+ readonly version?: string
23
+ readonly digest?: string
24
+ }
25
+ export const verify = (actual: CodeIdentity, expected: Expected = {}) =>
26
+ expected.version !== undefined && actual.version !== expected.version
27
+ ? Effect.fail(
28
+ PackageError.make({
29
+ detail: `Package version mismatch: expected ${expected.version}, received ${actual.version}`,
30
+ }),
31
+ )
32
+ : expected.digest !== undefined && actual.digest !== expected.digest
33
+ ? Effect.fail(
34
+ PackageError.make({
35
+ detail: `Package digest mismatch: expected ${expected.digest}, received ${actual.digest}`,
36
+ }),
37
+ )
38
+ : Effect.void
39
+
40
+ /** A path-sensitive SHA-256 of sorted entries and bytes, excluding every node_modules subtree. */
41
+ export const digest = Effect.fnUntraced(function* (directory: string) {
42
+ const fs = yield* FileSystem.FileSystem
43
+ const path = yield* Path.Path
44
+ const hash = yield* Effect.sync(() =>
45
+ createHash("sha256").update("graft-package-sha256-v1\0"),
46
+ )
47
+ const visit = (
48
+ relative: string,
49
+ ): Effect.Effect<void, PackageError | PlatformError.PlatformError> =>
50
+ Effect.gen(function* () {
51
+ const filename = path.join(directory, relative)
52
+ const info = yield* fs.stat(filename)
53
+ if (info.type !== "File" && info.type !== "Directory")
54
+ return yield* PackageError.make({
55
+ detail: `Unsupported package entry: ${relative}`,
56
+ })
57
+ const name = new TextEncoder().encode(relative)
58
+ yield* Effect.sync(() => {
59
+ hash.update(
60
+ `${info.type}:${name.byteLength}:${info.type === "File" ? info.size : 0}:`,
61
+ )
62
+ hash.update(name)
63
+ })
64
+ if (info.type === "File") {
65
+ yield* fs.stream(filename).pipe(
66
+ Stream.runForEach((bytes) =>
67
+ Effect.sync(() => {
68
+ hash.update(bytes)
69
+ }),
70
+ ),
71
+ )
72
+ } else {
73
+ const entries = yield* fs.readDirectory(filename)
74
+ for (const entry of Array.sort(entries, Order.String)) {
75
+ if (entry === "node_modules") continue
76
+ yield* visit(relative === "" ? entry : `${relative}/${entry}`)
77
+ }
78
+ }
79
+ })
80
+ yield* visit("")
81
+ return yield* Effect.sync(() => hash.digest("hex"))
82
+ })
83
+
84
+ /**
85
+ * Resolve using Node's import conditions without importing executable package code.
86
+ * The helper's cwd is the installation root and it inherits no NODE_OPTIONS/loaders.
87
+ * The installation directory and its package exports are trusted.
88
+ */
89
+ export const resolve = Effect.fnUntraced(
90
+ function* (root: string, specifier: string, includeDigest: boolean = false) {
91
+ const segments = String.split(specifier, "/")
92
+ const scoped = String.startsWith("@")(specifier)
93
+ const name = Array.join(Array.take(segments, scoped ? 2 : 1), "/")
94
+ const fs = yield* FileSystem.FileSystem
95
+ const path = yield* Path.Path
96
+ const installation = yield* fs.realPath(root)
97
+ const directory = yield* fs.realPath(
98
+ path.join(installation, "node_modules", name),
99
+ )
100
+ const manifest = yield* fs
101
+ .readFileString(path.join(directory, "package.json"))
102
+ .pipe(
103
+ Effect.flatMap(Schema.decodeEffect(Schema.fromJsonString(Manifest))),
104
+ )
105
+ const resolved = yield* resolveEntry(installation, specifier)
106
+ const filename = yield* Effect.try({
107
+ try: () => fileURLToPath(resolved),
108
+ catch: (error) =>
109
+ PackageError.make({
110
+ detail: "The package export is not a file URL",
111
+ cause: Cause.die(error),
112
+ }),
113
+ })
114
+ const entry = yield* fs.realPath(filename)
115
+ const identity: CodeIdentity = {
116
+ ...manifest,
117
+ ...(includeDigest ? { digest: yield* digest(directory) } : {}),
118
+ }
119
+ return { directory, entry, identity }
120
+ },
121
+ Effect.catchTags({
122
+ PlatformError: (error) =>
123
+ Effect.fail(
124
+ PackageError.make({
125
+ detail: "Reading the installed package failed",
126
+ cause: Cause.fail(error),
127
+ }),
128
+ ),
129
+ SchemaError: (error) =>
130
+ Effect.fail(
131
+ PackageError.make({
132
+ detail: "Reading the package manifest failed",
133
+ cause: Cause.fail(error),
134
+ }),
135
+ ),
136
+ }),
137
+ )
138
+
139
+ export const resolveEntry = (installation: string, specifier: string) =>
140
+ Effect.gen(function* () {
141
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
142
+ return yield* Effect.scoped(
143
+ Effect.gen(function* () {
144
+ const child = yield* spawner.spawn(
145
+ ChildProcess.make(
146
+ process.execPath,
147
+ [
148
+ "--input-type=module",
149
+ "--eval",
150
+ "process.stdout.write(import.meta.resolve(process.argv[1]))",
151
+ "--",
152
+ specifier,
153
+ ],
154
+ {
155
+ cwd: installation,
156
+ env: {},
157
+ stdin: "ignore",
158
+ stdout: "pipe",
159
+ stderr: "pipe",
160
+ },
161
+ ),
162
+ )
163
+ const [code, stdout, stderr] = yield* Effect.all(
164
+ [
165
+ child.exitCode,
166
+ child.stdout.pipe(Stream.decodeText(), Stream.mkString),
167
+ child.stderr.pipe(Stream.decodeText(), Stream.mkString),
168
+ ],
169
+ { concurrency: "unbounded" },
170
+ )
171
+ if (code !== 0)
172
+ return yield* PackageError.make({
173
+ detail: `Package resolution failed: ${stderr}`,
174
+ })
175
+ return stdout
176
+ }),
177
+ )
178
+ })
@@ -0,0 +1,63 @@
1
+ import {
2
+ Array,
3
+ Cause,
4
+ Effect,
5
+ Exit,
6
+ Fiber,
7
+ Ref,
8
+ Schedule,
9
+ Stream,
10
+ String,
11
+ } from "effect"
12
+ import type { PlatformError } from "effect"
13
+ import type { ChildProcessSpawner } from "effect/process"
14
+ import * as FailureGroup from "../FailureGroup"
15
+
16
+ /** Time allowed for a direct execution unit or launcher to exit after input EOF. */
17
+ export const stdinExitTimeout = "1 second"
18
+
19
+ /** Readers outlive the failure monitor so forced termination still captures its diagnostic tail. */
20
+ export const observe = Effect.fnUntraced(function* (
21
+ child: ChildProcessSpawner.ChildProcessHandle,
22
+ options: { readonly drainStdout?: boolean } = {},
23
+ ) {
24
+ const failures = yield* FailureGroup.make<PlatformError.PlatformError>()
25
+ const tail = yield* Ref.make("")
26
+ // Command transports own stdout as a protocol stream.
27
+ const stdout = yield* (
28
+ options.drainStdout === false ? Effect.void : Stream.runDrain(child.stdout)
29
+ ).pipe(Effect.forkScoped)
30
+ const stderr = yield* child.stderr.pipe(
31
+ Stream.decodeText(),
32
+ Stream.runForEach((text) =>
33
+ Ref.update(tail, (old) => String.takeRight(old + text, 8192)),
34
+ ),
35
+ Effect.forkScoped,
36
+ )
37
+ yield* failures.run(Fiber.join(stdout))
38
+ yield* failures.run(Fiber.join(stderr))
39
+ const exited = yield* Effect.gen(function* () {
40
+ const result = yield* Effect.exit(child.exitCode)
41
+ // exitCode can fail before exit on an input error; isRunning follows Node's exit event.
42
+ yield* child.isRunning.pipe(
43
+ Effect.repeat({
44
+ schedule: Schedule.spaced("25 millis"),
45
+ while: (running) => running,
46
+ }),
47
+ )
48
+ const err = yield* Fiber.await(stderr)
49
+ const out = yield* Fiber.await(stdout)
50
+ return {
51
+ code: Exit.isSuccess(result) ? result.value : null,
52
+ signal: null,
53
+ stderr: yield* Ref.get(tail),
54
+ cause: Array.reduce(
55
+ [Exit.asVoid(result), err, out],
56
+ Cause.empty,
57
+ (cause: Cause.Cause<PlatformError.PlatformError>, exit) =>
58
+ Exit.isFailure(exit) ? Cause.combine(cause, exit.cause) : cause,
59
+ ),
60
+ }
61
+ }).pipe(Effect.forkScoped)
62
+ return { exited: Fiber.join(exited), failure: failures.await }
63
+ })
@@ -0,0 +1,109 @@
1
+ import { Cause, Effect, Option, Schedule, Stream, String } from "effect"
2
+ import { ChildProcess, ChildProcessSpawner } from "effect/process"
3
+ import process from "node:process"
4
+ import {
5
+ ExecutionError,
6
+ TerminationUnconfirmed,
7
+ type ProcessIdentity,
8
+ type Termination,
9
+ } from "./model"
10
+
11
+ const inspect = (pid: number) =>
12
+ Effect.scoped(
13
+ Effect.gen(function* () {
14
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
15
+ const child = yield* spawner.spawn(
16
+ ChildProcess.make(
17
+ "ps",
18
+ ["-p", `${pid}`, "-o", "lstart=", "-o", "stat="],
19
+ {
20
+ env: { ...process.env, LC_ALL: "C" },
21
+ stdin: "ignore",
22
+ },
23
+ ),
24
+ )
25
+ const [code, output, stderr] = yield* Effect.all(
26
+ [
27
+ child.exitCode,
28
+ child.stdout.pipe(Stream.decodeText(), Stream.mkString),
29
+ child.stderr.pipe(Stream.decodeText(), Stream.mkString),
30
+ ],
31
+ { concurrency: "unbounded" },
32
+ )
33
+ if (code === 1 && String.trim(output) === "") return Option.none()
34
+ const [, born, status] =
35
+ /^(.{24})\s+(\S+)$/m.exec(String.trim(output)) ?? []
36
+ if (code !== 0 || born === undefined || status === undefined)
37
+ return yield* ExecutionError.make({
38
+ detail: "Cannot inspect process identity: " + stderr,
39
+ })
40
+ if (String.startsWith("Z")(status)) return Option.none()
41
+ return Option.some({ born })
42
+ }),
43
+ ).pipe(
44
+ Effect.mapError((error) =>
45
+ error._tag === "ExecutionError"
46
+ ? error
47
+ : ExecutionError.make({
48
+ detail: "Inspecting process identity failed",
49
+ cause: Cause.fail(error),
50
+ }),
51
+ ),
52
+ )
53
+
54
+ export const identity = (pid: number) =>
55
+ Effect.gen(function* () {
56
+ const current = yield* inspect(pid)
57
+ if (Option.isNone(current))
58
+ return yield* ExecutionError.make({
59
+ detail: "The child exited before its identity could be recorded",
60
+ })
61
+ return { pid, start: current.value }
62
+ })
63
+
64
+ // The OS may discard argv before reporting a zombie; PID and start time remain the identity.
65
+ export const matches = (child: ProcessIdentity) =>
66
+ Effect.gen(function* () {
67
+ const current = yield* inspect(child.pid)
68
+ if (Option.isNone(current) || current.value.born !== child.start.born)
69
+ return false
70
+ return true
71
+ })
72
+
73
+ export const recover = (child: ProcessIdentity) =>
74
+ Effect.gen(function* () {
75
+ if (!(yield* matches(child)))
76
+ return {
77
+ kind: "Exited",
78
+ exit: { code: null, signal: null },
79
+ cause: Cause.empty,
80
+ } satisfies Termination
81
+ // The PID can still be reused between this final check and kill; an external supervisor covers descendants.
82
+ const sent = yield* Effect.exit(
83
+ Effect.try({
84
+ try: () => process.kill(child.pid, "SIGKILL"),
85
+ catch: (cause) =>
86
+ ExecutionError.make({
87
+ detail: "Signaling the orphan failed",
88
+ cause: Cause.die(cause),
89
+ }),
90
+ }),
91
+ )
92
+ const confirmed = yield* matches(child).pipe(
93
+ Effect.repeat({
94
+ schedule: Schedule.spaced("50 millis"),
95
+ while: (value) => value,
96
+ }),
97
+ Effect.timeoutOption("10 seconds"),
98
+ )
99
+ if (Option.isNone(confirmed))
100
+ return yield* TerminationUnconfirmed.make({
101
+ detail: "The orphan did not exit after recovery",
102
+ cause: sent._tag === "Failure" ? sent.cause : Cause.empty,
103
+ })
104
+ return {
105
+ kind: "Killed",
106
+ exit: { code: null, signal: "SIGKILL" },
107
+ cause: sent._tag === "Failure" ? sent.cause : Cause.empty,
108
+ } satisfies Termination
109
+ })
@@ -0,0 +1,49 @@
1
+ import { Array, HashMap, Option } from "effect"
2
+ import { keyOf, type SessionKey, type SessionRecord } from "./model"
3
+
4
+ /** A terminal high-water record fences every older Open, even after its request id is forgotten. */
5
+ export const retain = (
6
+ records: ReadonlyArray<SessionRecord>,
7
+ ): ReadonlyArray<SessionRecord> => {
8
+ const highWater = Array.reduce(
9
+ records,
10
+ HashMap.empty<SessionKey, number>(),
11
+ (water, record) =>
12
+ HashMap.set(
13
+ water,
14
+ keyOf(record.handle.key),
15
+ Math.max(
16
+ Option.getOrElse(
17
+ HashMap.get(water, keyOf(record.handle.key)),
18
+ () => 0,
19
+ ),
20
+ record.handle.generation,
21
+ ),
22
+ ),
23
+ )
24
+ return Array.filter(
25
+ records,
26
+ (record) =>
27
+ record.phase !== "Stopped" ||
28
+ record.handle.generation ===
29
+ Option.getOrUndefined(HashMap.get(highWater, keyOf(record.handle.key))),
30
+ )
31
+ }
32
+ /** Apply the same retention rule to both in-memory stores. */
33
+ export const save = (
34
+ records: HashMap.HashMap<string, SessionRecord>,
35
+ record: SessionRecord,
36
+ ) =>
37
+ HashMap.fromIterable(
38
+ Array.map(
39
+ retain(
40
+ Array.fromIterable(
41
+ HashMap.values(HashMap.set(records, record.handle.token, record)),
42
+ ),
43
+ ),
44
+ (record): readonly [string, SessionRecord] => [
45
+ record.handle.token,
46
+ record,
47
+ ],
48
+ ),
49
+ )
@@ -0,0 +1,160 @@
1
+ import {
2
+ Array,
3
+ Cause,
4
+ Layer,
5
+ Effect,
6
+ FileSystem,
7
+ HashMap,
8
+ HashSet,
9
+ Path,
10
+ Ref,
11
+ Schema,
12
+ Semaphore,
13
+ String,
14
+ type PlatformError,
15
+ } from "effect"
16
+ import { Digest, SecureRandom } from "effect/crypto"
17
+ import { Key, SessionRecord, Store, StateStorageError } from "./model"
18
+ import * as Retention from "./Retention"
19
+
20
+ /** Injectable store used by deterministic supervisor tests. */
21
+ export const memory = Effect.gen(function* () {
22
+ const records = yield* Ref.make(HashMap.empty<string, SessionRecord>())
23
+ return Store.of({
24
+ list: Ref.get(records).pipe(
25
+ Effect.map((records) => Array.fromIterable(HashMap.values(records))),
26
+ ),
27
+ save: (record) => Ref.update(records, (all) => Retention.save(all, record)),
28
+ })
29
+ })
30
+
31
+ /**
32
+ * Atomically replaced records retain unfinished sessions and each key's high-water mark.
33
+ * Older terminal request ids expire; Open fences their retries with expectedGeneration.
34
+ * Requires exclusive directory ownership; it is not a multi-writer database.
35
+ */
36
+ export const directory = (root: string) =>
37
+ Effect.gen(function* () {
38
+ const fs = yield* FileSystem.FileSystem
39
+ const path = yield* Path.Path
40
+ const digest = yield* Digest.Digest
41
+ const json = Schema.fromJsonString(Schema.toCodecJson(SessionRecord))
42
+ const random = yield* SecureRandom.SecureRandom
43
+ const storage = <A, R>(
44
+ effect: Effect.Effect<
45
+ A,
46
+ PlatformError.PlatformError | Schema.SchemaError | StateStorageError,
47
+ R
48
+ >,
49
+ ) =>
50
+ effect.pipe(
51
+ Effect.mapError((error) =>
52
+ error._tag === "StateStorageError"
53
+ ? error
54
+ : StateStorageError.make({
55
+ detail: "Runner state storage failed",
56
+ cause: Cause.fail(error),
57
+ }),
58
+ ),
59
+ )
60
+ yield* storage(
61
+ fs.makeDirectory(root, { recursive: true }).pipe(Effect.uninterruptible),
62
+ )
63
+ const mutex = yield* Semaphore.make(1)
64
+ const read = Effect.gen(function* () {
65
+ const files = yield* fs.readDirectory(root)
66
+ const rows = yield* Effect.forEach(
67
+ Array.filter(files, String.endsWith(".json")),
68
+ (file) =>
69
+ fs.readFileString(path.join(root, file)).pipe(
70
+ Effect.flatMap(Schema.decodeEffect(json)),
71
+ Effect.map((record) => ({ file, record })),
72
+ ),
73
+ )
74
+ return rows
75
+ })
76
+ const compact = Effect.scoped(
77
+ Effect.gen(function* () {
78
+ const rows = yield* read
79
+ const retained = Retention.retain(Array.map(rows, (row) => row.record))
80
+ const tokens = HashSet.fromIterable(
81
+ Array.map(retained, (record) => record.handle.token),
82
+ )
83
+ const obsolete = Array.filter(
84
+ rows,
85
+ (row) => !HashSet.has(tokens, row.record.handle.token),
86
+ )
87
+ yield* Effect.forEach(
88
+ obsolete,
89
+ (row) =>
90
+ fs.remove(path.join(root, row.file)).pipe(Effect.uninterruptible),
91
+ { discard: true },
92
+ )
93
+ if (obsolete.length > 0) {
94
+ const directory = yield* fs.open(root, { flag: "r" })
95
+ yield* directory.sync.pipe(Effect.uninterruptible)
96
+ }
97
+ }),
98
+ )
99
+ yield* storage(compact)
100
+ return Store.of({
101
+ list: storage(
102
+ mutex.withPermit(
103
+ read.pipe(Effect.map((rows) => Array.map(rows, (row) => row.record))),
104
+ ),
105
+ ),
106
+ save: (record) =>
107
+ storage(
108
+ mutex.withPermit(
109
+ Effect.scoped(
110
+ Effect.gen(function* () {
111
+ const encoded = yield* Schema.encodeEffect(json)(record)
112
+ const address = yield* Schema.encodeEffect(
113
+ Schema.fromJsonString(
114
+ Schema.Struct({ key: Key, generation: Schema.Int }),
115
+ ),
116
+ )({
117
+ key: record.handle.key,
118
+ generation: record.handle.generation,
119
+ })
120
+ const name = yield* digest.digestHex(
121
+ Digest.sha256,
122
+ new TextEncoder().encode(address),
123
+ )
124
+ const nonce = yield* random.uuidV4()
125
+ const temporary = path.join(root, `.${name}.${nonce}.tmp`)
126
+ const destination = path.join(root, name + ".json")
127
+ yield* Effect.acquireRelease(
128
+ fs.open(temporary, { flag: "wx", mode: 0o600 }),
129
+ () =>
130
+ fs.remove(temporary, { force: true }).pipe(Effect.orDie),
131
+ ).pipe(
132
+ Effect.flatMap((file) =>
133
+ file
134
+ .writeAll(new TextEncoder().encode(encoded))
135
+ .pipe(
136
+ Effect.uninterruptible,
137
+ Effect.andThen(file.sync.pipe(Effect.uninterruptible)),
138
+ ),
139
+ ),
140
+ )
141
+ // Keep rename and directory synchronization together if the caller is canceled.
142
+ yield* Effect.uninterruptible(
143
+ Effect.gen(function* () {
144
+ yield* fs.rename(temporary, destination)
145
+ const directory = yield* fs.open(root, { flag: "r" })
146
+ yield* directory.sync.pipe(Effect.uninterruptible)
147
+ }),
148
+ )
149
+ // The new high-water file is durable before any old record is removed.
150
+ yield* compact
151
+ }),
152
+ ),
153
+ ),
154
+ ),
155
+ })
156
+ })
157
+
158
+ export const layerMemory = Layer.effect(Store, memory)
159
+ export const layerDirectory = (root: string) =>
160
+ Layer.effect(Store, directory(root))