@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
@@ -0,0 +1,985 @@
1
+ import { Array, Cause, Context, Data, Deferred, Duration, Effect, Equal, Exit, Fiber, FiberSet, HashMap, HashSet, Layer, Logger, Option, Order, Predicate, PubSub, Pull, Record, Ref, References, Result, Schedule, Schema, Scope, Stream, TxRef, TxSubscriptionRef } from "effect";
2
+ import { identity } from "effect/Function";
3
+ // packages/core/src/Fork.ts
4
+ const ForkState = Data.taggedEnum();
5
+ /** A disposal failure retains the original typed errors, defects, and interruption reasons. */
6
+ var CleanupError = class extends Schema.TaggedError()("CleanupError", { cause: Schema.Cause(Schema.Unknown, Schema.Unknown) }) {
7
+ get message() {
8
+ return "Plugin cleanup failed";
9
+ }
10
+ };
11
+ // packages/core/src/internal/dependencies.ts
12
+ /** The exact dependency snapshot must still be valid when plugin code publishes. */
13
+ const resolutionChanged = Effect.fnUntraced(function* (resolution) {
14
+ for (const provision of resolution.provisions) {
15
+ const current = yield* TxRef.get(provision.slot.provision);
16
+ if (!Option.exists(current, (current) => current === provision)) return true;
17
+ }
18
+ for (const slot of HashMap.values(resolution.watch)) {
19
+ const current = yield* TxRef.get(slot.provision);
20
+ if (Option.isSome(current)) return true;
21
+ }
22
+ return false;
23
+ });
24
+ /** Reverse reachability reads only nodes that can affect this publisher. Call within a transaction. */
25
+ const publicationCycle = Effect.fnUntraced(function* (publisher, key, candidate) {
26
+ let pending = {
27
+ node: publisher,
28
+ next: void 0
29
+ };
30
+ let seen = HashSet.empty();
31
+ while (pending !== void 0) {
32
+ const node = pending.node;
33
+ pending = pending.next;
34
+ if (HashSet.has(seen, node.id)) continue;
35
+ seen = HashSet.add(seen, node.id);
36
+ const state = yield* TxRef.get(node.state);
37
+ if (!state.live) continue;
38
+ const resolution = node === publisher && candidate !== void 0 ? candidate : state.resolution;
39
+ if (resolution !== void 0) {
40
+ if (HashMap.has(resolution.watch, key)) return true;
41
+ for (const provision of resolution.provisions) pending = {
42
+ node: provision.node,
43
+ next: pending
44
+ };
45
+ }
46
+ if (node.parent !== void 0) pending = {
47
+ node: node.parent,
48
+ next: pending
49
+ };
50
+ }
51
+ return false;
52
+ });
53
+ // packages/core/src/internal/slots.ts
54
+ /** Call inside a transaction before waiting; the directory must stay out of waiting read sets. */
55
+ const retain = Effect.fnUntraced(function* (runtime, key) {
56
+ const directory = yield* TxRef.get(runtime.slots);
57
+ const existing = HashMap.get(directory, key);
58
+ if (Option.isSome(existing)) {
59
+ yield* TxRef.update(existing.value.holders, (count) => count + 1);
60
+ return existing.value;
61
+ }
62
+ const slot = {
63
+ key,
64
+ provision: TxRef.makeUnsafe(Option.none()),
65
+ holders: TxRef.makeUnsafe(1)
66
+ };
67
+ yield* TxRef.set(runtime.slots, HashMap.set(directory, key, slot));
68
+ return slot;
69
+ });
70
+ /** Every holder, including a publisher, releases in the same transaction as its last use. */
71
+ const release = Effect.fnUntraced(function* (runtime, slot) {
72
+ const count = yield* TxRef.get(slot.holders);
73
+ yield* TxRef.set(slot.holders, count - 1);
74
+ if (count === 1) {
75
+ const provision = yield* TxRef.get(slot.provision);
76
+ if (Option.isNone(provision)) yield* TxRef.update(runtime.slots, HashMap.remove(slot.key));
77
+ }
78
+ });
79
+ // packages/core/src/internal/aliases.ts
80
+ /** Weak keys are necessary: an obsolete plugin must not be retained by the alias registry. */
81
+ const make$3 = () => ({ identities: /* @__PURE__ */ new WeakMap() });
82
+ const makeGroup = (target) => ({ state: TxRef.makeUnsafe({
83
+ _tag: "Root",
84
+ target,
85
+ rank: 0
86
+ }) });
87
+ const identity$1 = (aliases, plugin) => {
88
+ const existing = aliases.identities.get(plugin);
89
+ if (existing !== void 0) return existing;
90
+ const cell = TxRef.makeUnsafe(makeGroup(plugin));
91
+ aliases.identities.set(plugin, cell);
92
+ return cell;
93
+ };
94
+ const resolve$1 = Effect.fnUntraced(function* (aliases, plugin) {
95
+ let group = yield* TxRef.get(identity$1(aliases, plugin));
96
+ while (true) {
97
+ const state = yield* TxRef.get(group.state);
98
+ if (state._tag === "Root") return state.target;
99
+ group = state.group;
100
+ }
101
+ });
102
+ /**
103
+ * Stages a flat-alias transition before touching transaction state. A caller may
104
+ * catch a conflict inside an outer transaction without accidentally committing
105
+ * the rejected aliases. Successful writes share the caller's transaction.
106
+ */
107
+ const replace$1 = Effect.fnUntraced(function* (aliases, pairs) {
108
+ let cells = HashMap.empty();
109
+ let groups = HashMap.empty();
110
+ const readCell = (cell) => Option.match(HashMap.get(cells, cell), {
111
+ onNone: () => TxRef.get(cell),
112
+ onSome: Effect.succeed
113
+ });
114
+ const readGroup = (group) => Option.match(HashMap.get(groups, group), {
115
+ onNone: () => TxRef.get(group.state),
116
+ onSome: Effect.succeed
117
+ });
118
+ const root = Effect.fnUntraced(function* (cell) {
119
+ let group = yield* readCell(cell);
120
+ while (true) {
121
+ const state = yield* readGroup(group);
122
+ if (state._tag === "Root") return {
123
+ group,
124
+ state
125
+ };
126
+ group = state.group;
127
+ }
128
+ });
129
+ const current = yield* Effect.forEach(pairs, ([from]) => resolve$1(aliases, from));
130
+ for (const [from, to] of pairs) {
131
+ const targetCell = identity$1(aliases, to);
132
+ let target = yield* root(targetCell);
133
+ if (target.state.target !== to) {
134
+ const group = makeGroup(to);
135
+ cells = HashMap.set(cells, targetCell, group);
136
+ target = yield* root(targetCell);
137
+ }
138
+ if (from === to) continue;
139
+ const sourceCell = identity$1(aliases, from);
140
+ const source = yield* root(sourceCell);
141
+ if (source.state.target !== from) cells = HashMap.set(cells, sourceCell, target.group);
142
+ else if (source.group !== target.group) {
143
+ const winner = source.state.rank > target.state.rank ? source : target;
144
+ const loser = winner === source ? target : source;
145
+ groups = HashMap.set(groups, loser.group, {
146
+ _tag: "Link",
147
+ group: winner.group
148
+ });
149
+ groups = HashMap.set(groups, winner.group, {
150
+ _tag: "Root",
151
+ target: to,
152
+ rank: winner.state.rank + (source.state.rank === target.state.rank ? 1 : 0)
153
+ });
154
+ }
155
+ }
156
+ const checks = yield* Effect.forEach(pairs, ([from, to], index) => Effect.gen(function* () {
157
+ const overlap = from !== to && Array.some(pairs, ([other, target]) => other !== target && (to === other || from === target));
158
+ const source = yield* root(identity$1(aliases, from));
159
+ const previous = yield* root(identity$1(aliases, current[index]));
160
+ const target = yield* root(identity$1(aliases, to));
161
+ return overlap || source.state.target !== to || previous.state.target !== to || target.state.target !== to ? Option.some(index) : Option.none();
162
+ }));
163
+ const conflicts = Array.getSomes(checks);
164
+ if (conflicts.length > 0) return conflicts;
165
+ for (const [cell, group] of cells) yield* TxRef.set(cell, group);
166
+ for (const [group, state] of groups) yield* TxRef.set(group.state, state);
167
+ return conflicts;
168
+ });
169
+ // packages/core/src/internal/release.ts
170
+ /** Resource release was interrupted, rather than successfully cancelled. */
171
+ var ReleaseInterrupted = class extends Schema.TaggedError()("ReleaseInterrupted", { cause: Schema.Cause(Schema.Never, Schema.Unknown) }) {
172
+ get message() {
173
+ return "Resource release was interrupted";
174
+ }
175
+ };
176
+ /** Keep a known release failure distinguishable from cancellation through enclosing scopes. */
177
+ const close = (scope, exit) => Effect.uninterruptible(Scope.close(scope, exit).pipe(Effect.catchCauseIf(Cause.hasInterruptsOnly, (cause) => Effect.gen(function* () {
178
+ const pending = yield* Effect.exit(Effect.interruptible(Effect.void));
179
+ const [cancelled, interrupted] = Array.partition(cause.reasons, (reason) => Exit.isFailure(pending) && Array.some(pending.cause.reasons, (external) => reason._tag === "Interrupt" && external._tag === "Interrupt" && reason.fiberId === external.fiberId) ? Result.succeed(reason) : Result.fail(reason));
180
+ if (interrupted.length === 0) return yield* Effect.failCause(cause);
181
+ return yield* Effect.failCause(Cause.combine(Cause.fromReasons(cancelled), Cause.die(ReleaseInterrupted.make({ cause: Cause.fromReasons(interrupted) }))));
182
+ }))));
183
+ // packages/core/src/internal/scope.ts
184
+ /** Keep ownership until cleanup finishes, even if a dispose caller is cancelled. */
185
+ const ownedScope = Effect.fnUntraced(function* (parent, afterClose = Effect.void) {
186
+ const link = yield* Scope.fork(parent);
187
+ const scope = yield* Scope.make();
188
+ const workers = yield* Scope.make();
189
+ const started = yield* Deferred.make();
190
+ const ready = yield* Deferred.make();
191
+ const completed = yield* Deferred.make();
192
+ const start = (exit) => Effect.gen(function* () {
193
+ if (!(yield* Deferred.succeed(started, void 0))) return;
194
+ yield* Effect.gen(function* () {
195
+ const result = yield* Effect.exit(Effect.gen(function* () {
196
+ const closed = yield* Effect.exit(close(scope, exit));
197
+ const observed = yield* Effect.exit(afterClose);
198
+ if (Exit.isFailure(closed)) return yield* Effect.failCause(Exit.isFailure(observed) ? Cause.combine(closed.cause, observed.cause) : closed.cause);
199
+ if (Exit.isFailure(observed)) return yield* Effect.failCause(observed.cause);
200
+ }));
201
+ yield* Deferred.done(ready, result);
202
+ yield* close(link, exit).pipe(Effect.catchCause((cause) => Effect.logError("Closing fork ownership failed", cause)));
203
+ yield* Deferred.done(completed, result);
204
+ }).pipe(Effect.forkIn(workers, {
205
+ uninterruptible: true,
206
+ startImmediately: false
207
+ }));
208
+ });
209
+ const close$1 = (exit) => Effect.uninterruptibleMask((restore) => start(exit).pipe(Effect.andThen(restore(Deferred.await(completed)))));
210
+ yield* Scope.addFinalizerExit(link, (exit) => start(exit).pipe(Effect.andThen(Deferred.await(ready)), Effect.orDie, Effect.ensuring(close(workers, exit))));
211
+ return {
212
+ scope,
213
+ close: close$1
214
+ };
215
+ });
216
+ // packages/core/src/internal/forkState.ts
217
+ /** Update ancestors in the same transaction as the state or topology change. */
218
+ const adjustLoading = Effect.fnUntraced(function* (status, delta) {
219
+ if (delta === 0) return;
220
+ for (let current = status; current !== void 0; current = current.parent) {
221
+ if ((yield* TxSubscriptionRef.get(current.snapshot)).disposed) return;
222
+ yield* TxRef.update(current.loading, (count) => count + delta);
223
+ }
224
+ });
225
+ /** Called inside the fork registration transaction. */
226
+ const make$2 = Effect.fnUntraced(function* (parent, spec) {
227
+ const status = {
228
+ parent,
229
+ loading: yield* TxRef.make(0),
230
+ snapshot: yield* TxSubscriptionRef.make({
231
+ state: ForkState.Loading(),
232
+ accepted: void 0,
233
+ name: spec.plugin.name,
234
+ input: spec.input,
235
+ disposed: false
236
+ })
237
+ };
238
+ yield* adjustLoading(status, 1);
239
+ return status;
240
+ });
241
+ const setState = (runtime, id, status, state, spec) => Effect.tx(Effect.gen(function* () {
242
+ const current = yield* TxSubscriptionRef.get(status.snapshot);
243
+ if (current.disposed) return;
244
+ const next = {
245
+ state,
246
+ accepted: spec,
247
+ name: spec.plugin.name,
248
+ input: spec.input,
249
+ disposed: false
250
+ };
251
+ yield* adjustLoading(status, Number(state._tag === "Loading") - Number(current.state._tag === "Loading"));
252
+ yield* TxSubscriptionRef.set(status.snapshot, next);
253
+ yield* TxSubscriptionRef.update(runtime.forks, (forks) => HashMap.modify(forks, id, (entry) => ({
254
+ ...entry,
255
+ ...next
256
+ })));
257
+ }));
258
+ /** Called inside the removal transaction, after supervisor cleanup. */
259
+ const dispose = Effect.fnUntraced(function* (runtime, id, status) {
260
+ const current = yield* TxSubscriptionRef.get(status.snapshot);
261
+ if (current.disposed) return;
262
+ const loading = yield* TxRef.get(status.loading);
263
+ yield* adjustLoading(status.parent, -loading);
264
+ yield* TxRef.set(status.loading, 0);
265
+ yield* TxSubscriptionRef.set(status.snapshot, {
266
+ ...current,
267
+ state: ForkState.Disposed(),
268
+ disposed: true
269
+ });
270
+ yield* TxSubscriptionRef.update(runtime.forks, HashMap.remove(id));
271
+ });
272
+ /** Only the subtree's own counter belongs to this waiting transaction's read set. */
273
+ const stable = (status) => Effect.tx(Effect.gen(function* () {
274
+ if ((yield* TxRef.get(status.loading)) > 0) return yield* Effect.txRetry;
275
+ }));
276
+ // packages/core/src/internal/context.ts
277
+ /** Strip provision-sourced values before child intercepts read or transform the fallback. */
278
+ const inheritContext = (parent, inherited) => Context.makeUnsafe(new Map([...Array.filter(parent.fallback.mapUnsafe, ([key]) => HashSet.has(parent.provisionKeys, key)), ...Array.filter(inherited.mapUnsafe, ([key]) => !HashSet.has(parent.provisionKeys, key))]));
279
+ // packages/core/src/internal/tasks.ts
280
+ /** One activation owns both the workers and every failure they finish with. */
281
+ const make$1 = Effect.gen(function* () {
282
+ const scope = yield* Scope.make();
283
+ return {
284
+ scope,
285
+ fibers: yield* FiberSet.make().pipe(Scope.provide(scope)),
286
+ failures: yield* Ref.make(Cause.empty)
287
+ };
288
+ });
289
+ const run = (group, effect) => FiberSet.run(group.fibers, Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
290
+ const scope = yield* Scope.make();
291
+ const body = yield* Effect.exit(restore(Scope.provide(scope)(effect)));
292
+ const closed = yield* Effect.exit(close(scope, body));
293
+ const failure = Cause.combine(Exit.isFailure(body) && !Cause.hasInterruptsOnly(body.cause) ? body.cause : Cause.empty, Exit.isFailure(closed) && !Cause.hasInterruptsOnly(closed.cause) ? closed.cause : Cause.empty);
294
+ if (failure.reasons.length > 0) {
295
+ yield* Ref.update(group.failures, (cause) => Cause.combine(cause, failure));
296
+ yield* Deferred.failCause(group.fibers.deferred, failure);
297
+ yield* Effect.logError("The plugin's background task failed", failure);
298
+ }
299
+ if (Exit.isFailure(closed)) return yield* Effect.failCause(Exit.isFailure(body) ? Cause.combine(body.cause, closed.cause) : closed.cause);
300
+ return yield* body;
301
+ })), { startImmediately: false });
302
+ // packages/core/src/Plugin.ts
303
+ const TypeId = "~@graftland/graft/Plugin";
304
+ const Contract = "~@graftland/graft/Plugin/Contract";
305
+ /**
306
+ * Marks a dependency as optional: the plugin starts without it and restarts
307
+ * whenever it appears or disappears. Read it with `Effect.serviceOption`.
308
+ */
309
+ var Optional = class extends Data.TaggedClass("Optional") {};
310
+ /** Starts an activation-owned worker. Its unhandled errors belong to the plugin, not the launch operation. */
311
+ const fork = (effect) => Effect.gen(function* () {
312
+ const { activation } = yield* Graft;
313
+ if (Option.isNone(activation.tasks)) return yield* Effect.die(/* @__PURE__ */ new Error("Plugin.fork requires a plugin activation"));
314
+ return yield* run(activation.tasks.value, effect);
315
+ });
316
+ const isPlugin = (u) => Predicate.hasProperty(u, TypeId);
317
+ /** The plugin a module exports: its default export, or else an export named `plugin`. */
318
+ const fromModule = (module) => Array.findFirst([Predicate.hasProperty(module, "default") ? module.default : void 0, Predicate.hasProperty(module, "plugin") ? module.plugin : void 0], isPlugin);
319
+ const optional = (key) => new Optional({ key });
320
+ const isOptional = (dependency) => "_tag" in dependency && dependency._tag === "Optional";
321
+ /**
322
+ * Defines a plugin. `apply` may only require what `inject` declares as
323
+ * required; anything else is a type error.
324
+ */
325
+ const make = (options) => {
326
+ const schema = options.config;
327
+ return Equal.byReference({
328
+ [TypeId]: TypeId,
329
+ [Contract]: {
330
+ input: identity,
331
+ error: identity
332
+ },
333
+ name: options.name,
334
+ inject: options.inject ?? [],
335
+ retry: options.retry,
336
+ decode: schema === void 0 ? Effect.succeed : Schema.decodeUnknownEffect(schema),
337
+ apply: options.apply
338
+ });
339
+ };
340
+ /** A plugin that builds one service with a scoped effect and publishes it. */
341
+ const service = (key, build, options) => make({
342
+ ...options,
343
+ apply: () => Effect.flatMap(build, (value) => provide(key, value))
344
+ });
345
+ // packages/core/src/internal/runtime.ts
346
+ /** Maps a service key to the realm it resolves in. Absent keys use the root realm. */
347
+ const Realms = Context.Reference("@graftland/graft/Realms", { defaultValue: () => HashMap.empty() });
348
+ /** The realm a key resolves in; the root realm is the empty string. */
349
+ const realmOf = (realms, key) => Option.getOrElse(HashMap.get(realms, key), () => "");
350
+ /** The single constructor used by publication, resolution, and failed-publication retries. */
351
+ const realmKey = (realm, service) => `${realm.length}:${realm}${service}`;
352
+ // packages/core/src/internal/activation.ts
353
+ /**
354
+ * The supervision loop of a single fork.
355
+ *
356
+ * Each iteration acquires the fork's dependencies, runs `apply` in a fresh
357
+ * activation, waits until the specification or a dependency changes, and
358
+ * tears the activation down. Teardown follows a fixed order instead of
359
+ * relying on finalizer registration order:
360
+ *
361
+ * 1. stop `apply` if it is still running;
362
+ * 2. withdraw everything the activation published and close it to further
363
+ * publishing, so nobody new can lease it;
364
+ * 3. wait until every consumer has released those provisions;
365
+ * 4. stop supervised tasks and close their scopes, waiting for cleanup;
366
+ * 5. close the activation scope (child forks, resources, handlers);
367
+ * 6. release the leases the activation itself holds, whatever happened before.
368
+ *
369
+ * All phases contribute to one cleanup Exit. Failed state or fork disposal owns
370
+ * that result; logging it is never a substitute for handing it to the caller.
371
+ */
372
+ const interruptedBy = (cause, id) => Array.every(cause.reasons, (reason) => reason._tag === "Interrupt" && reason.fiberId === id);
373
+ /** Observe cancellation without losing the child's final Exit at an interruption boundary. */
374
+ const cancelOnChange = (operation, changed, handoff, observe = () => Effect.void) => Effect.scoped(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
375
+ const id = yield* Effect.withFiber((self) => Effect.succeed(self.id));
376
+ const worker = yield* Effect.forkScoped(restore(operation));
377
+ const raced = yield* Effect.exit(restore(Effect.raceFirst(Effect.as(changed, true), Effect.as(Fiber.await(worker), false))));
378
+ yield* Fiber.interrupt(worker);
379
+ const result = yield* Fiber.await(worker);
380
+ yield* observe(result);
381
+ return yield* handoff(result, yield* Effect.exit(restore(raced)), restore, (cause) => interruptedBy(cause, id));
382
+ })));
383
+ /** How long teardown waits for consumers before warning about a possible cycle. */
384
+ const drainWarning = Duration.seconds(10);
385
+ const Outcome = Data.taggedEnum();
386
+ const Acquired = Data.taggedEnum();
387
+ /** A schedule belongs to one spec and the exact provisions that attempt used. */
388
+ const sameAttempt = (left, right) => left.spec === right.spec && left.provisions.length === right.provisions.length && Array.every(left.provisions, (provision, index) => provision === right.provisions[index]) && Equal.equals(left.unprovided, right.unprovided);
389
+ const restart = Outcome.Restart();
390
+ const resolve = Effect.fnUntraced(function* (spec, prepared) {
391
+ const lookups = yield* Effect.forEach(prepared.lookups, (lookup) => Effect.map(TxRef.get(lookup.slot.provision), (found) => ({
392
+ ...lookup,
393
+ found,
394
+ ambient: Option.isSome(found) ? Option.none() : lookup.ambient()
395
+ })));
396
+ const unresolved = Array.filter(lookups, (lookup) => Option.isNone(lookup.found));
397
+ const absent = Array.filter(unresolved, (lookup) => Option.isNone(lookup.ambient));
398
+ return {
399
+ prepared,
400
+ watch: HashMap.fromIterable(Array.map(unresolved, (lookup) => [lookup.qualified, lookup.slot])),
401
+ spec,
402
+ provisions: Array.getSomes(Array.map(lookups, (lookup) => lookup.found)),
403
+ ambient: Array.getSomes(Array.map(unresolved, (lookup) => Option.map(lookup.ambient, (value) => [lookup.service, value]))),
404
+ missing: Array.map(Array.filter(absent, (lookup) => !lookup.optional), (lookup) => lookup.service),
405
+ unprovided: Array.map(unresolved, (lookup) => lookup.qualified)
406
+ };
407
+ });
408
+ const waitDrained = (published) => Effect.tx(Effect.gen(function* () {
409
+ for (const provision of published) {
410
+ const consumers = yield* TxRef.get(provision.consumers);
411
+ if (HashSet.size(consumers) > 0) return yield* Effect.txRetry;
412
+ }
413
+ }));
414
+ /**
415
+ * Withdraws what an activation published, closes it to further publishing,
416
+ * and waits until no consumer holds a lease on any of it.
417
+ */
418
+ const withdraw = Effect.fnUntraced(function* (runtime, activation) {
419
+ const published = yield* Effect.tx(Effect.gen(function* () {
420
+ const current = yield* TxRef.get(activation.published);
421
+ const published = Option.getOrElse(current, () => []);
422
+ yield* TxRef.set(activation.published, Option.none());
423
+ yield* TxRef.update(activation.node.state, (state) => ({
424
+ ...state,
425
+ resolution: state.resolution === void 0 ? void 0 : {
426
+ ...state.resolution,
427
+ watch: HashMap.empty()
428
+ }
429
+ }));
430
+ for (const provision of published) {
431
+ const current = yield* TxRef.get(provision.slot.provision);
432
+ if (Option.exists(current, (current) => current === provision)) yield* TxRef.set(provision.slot.provision, Option.none());
433
+ yield* release(runtime, provision.slot);
434
+ }
435
+ return published;
436
+ }));
437
+ const drained = yield* Effect.timeoutOption(waitDrained(published), drainWarning);
438
+ if (Option.isNone(drained)) {
439
+ const services = Array.join(Array.map(published, (provision) => provision.service), ", ");
440
+ yield* Effect.logWarning(`Still waiting for consumers of ${services}; a teardown cycle may be holding them`);
441
+ yield* waitDrained(published);
442
+ }
443
+ });
444
+ const reportFailure = (message, exit) => Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause) ? Effect.logError(message, exit.cause) : Effect.void;
445
+ const supervise = Effect.fnUntraced(function* (runtime, id, specRef, processing, node, status, completion) {
446
+ const cleanup = completion ?? (yield* Ref.make(Exit.void));
447
+ const realms = yield* Realms;
448
+ /** What the fork inherits from where it was loaded: references and ambient services. */
449
+ const inherited = yield* Effect.context();
450
+ const references = Context.merge(runtime.ambient, inherited);
451
+ const held = yield* TxRef.make(void 0);
452
+ const prepare = Effect.gen(function* () {
453
+ const spec = yield* TxRef.get(specRef);
454
+ const previous = yield* TxRef.get(held);
455
+ if (previous?.plugin === spec.plugin) return previous;
456
+ let slots = HashMap.empty();
457
+ const lookups = yield* Effect.forEach(spec.plugin.inject, (dependency) => Effect.gen(function* () {
458
+ const key = isOptional(dependency) ? dependency.key : dependency;
459
+ const qualified = realmKey(realmOf(realms, key.key), key.key);
460
+ const existing = HashMap.get(slots, qualified);
461
+ const slot = Option.isSome(existing) ? existing.value : yield* retain(runtime, qualified);
462
+ slots = HashMap.set(slots, qualified, slot);
463
+ return {
464
+ optional: isOptional(dependency),
465
+ service: key.key,
466
+ qualified,
467
+ slot,
468
+ ambient: () => Context.getOption(Context.isReference(key) ? references : runtime.ambient, key)
469
+ };
470
+ }));
471
+ if (previous !== void 0) for (const slot of HashMap.values(previous.slots)) yield* release(runtime, slot);
472
+ const prepared = {
473
+ plugin: spec.plugin,
474
+ slots,
475
+ lookups
476
+ };
477
+ yield* TxRef.set(held, prepared);
478
+ return prepared;
479
+ });
480
+ const resolveCurrent = (prepared) => Effect.flatMap(TxRef.get(specRef), (spec) => resolve(spec, prepared));
481
+ /** Resolves to the new spec if the spec changed, or `None` if a dependency changed. */
482
+ const waitChange = (resolution) => Effect.tx(Effect.gen(function* () {
483
+ const current = yield* TxRef.get(specRef);
484
+ if (current !== resolution.spec) return Option.some(current);
485
+ if (resolution.provisions.length === 0 && resolution.unprovided.length === 0) return yield* Effect.txRetry;
486
+ return (yield* resolutionChanged(resolution)) ? Option.none() : yield* Effect.txRetry;
487
+ }));
488
+ const acquire = Effect.gen(function* () {
489
+ const resolution = yield* Effect.tx(Effect.gen(function* () {
490
+ const prepared = yield* prepare;
491
+ const resolution = yield* resolveCurrent(prepared);
492
+ yield* TxRef.set(processing, resolution.spec);
493
+ if (resolution.missing.length === 0) {
494
+ for (const provision of resolution.provisions) yield* TxRef.update(provision.consumers, HashSet.add(id));
495
+ yield* TxRef.update(node.state, (state) => ({
496
+ ...state,
497
+ resolution: {
498
+ watch: resolution.watch,
499
+ provisions: resolution.provisions
500
+ }
501
+ }));
502
+ }
503
+ return resolution;
504
+ }));
505
+ if (resolution.missing.length > 0) return Acquired.Missing({ resolution });
506
+ const scope = yield* Scope.make();
507
+ const tasks = yield* make$1;
508
+ const published = yield* TxRef.make(Option.some([]));
509
+ const activation = {
510
+ fork: id,
511
+ node,
512
+ status,
513
+ tasks: Option.some(tasks),
514
+ published,
515
+ fallback: references,
516
+ provisionKeys: HashSet.fromIterable(Array.map(resolution.provisions, (provision) => provision.service))
517
+ };
518
+ const context = Context.makeUnsafe(new Map([
519
+ ...inherited.mapUnsafe,
520
+ ...resolution.ambient,
521
+ ...Array.map(resolution.provisions, (provision) => [provision.service, provision.value]),
522
+ [Scope.Scope.key, scope],
523
+ [Graft.key, {
524
+ runtime,
525
+ activation
526
+ }]
527
+ ]));
528
+ const spec = resolution.spec;
529
+ yield* setState(runtime, id, status, ForkState.Loading(), spec);
530
+ const fiber = yield* Effect.suspend(() => spec.plugin.decode(spec.input)).pipe(Effect.flatMap((config) => spec.plugin.apply(config)), Effect.withSpan(`graft.plugin ${spec.plugin.name}`), inActivation(context, spec), Effect.forkIn(scope));
531
+ const running = {
532
+ updateCleanup: yield* Ref.make(Cause.empty),
533
+ resolution,
534
+ tasks,
535
+ activation,
536
+ scope,
537
+ context,
538
+ fiber
539
+ };
540
+ return Acquired.Running({ running });
541
+ });
542
+ const pending = Effect.fnUntraced(function* (resolution) {
543
+ yield* setState(runtime, id, status, ForkState.Pending({ missing: resolution.missing }), resolution.spec);
544
+ yield* Effect.tx(Effect.gen(function* () {
545
+ if ((yield* TxRef.get(specRef)) !== resolution.spec) return;
546
+ const next = yield* resolveCurrent(resolution.prepared);
547
+ if (next.spec === resolution.spec && Equal.equals(next.missing, resolution.missing)) return yield* Effect.txRetry;
548
+ }));
549
+ return restart;
550
+ });
551
+ /** Runs plugin code with the activation's context, which discharges whatever it requires. */
552
+ const inActivation = (context, spec) => (effect) => Effect.updateContext(Effect.annotateLogs(effect, {
553
+ "graft.fork": id,
554
+ "graft.plugin": spec.plugin.name
555
+ }), () => context);
556
+ const run = Effect.fnUntraced(function* (running) {
557
+ const { resolution } = running;
558
+ let spec = resolution.spec;
559
+ const fiber = running.fiber;
560
+ const first = yield* Effect.raceFirst(Effect.asSome(Fiber.await(fiber)), Effect.as(waitChange(resolution), Option.none()));
561
+ if (Option.isNone(first)) return restart;
562
+ const exit = first.value;
563
+ if (exit._tag === "Failure") return Outcome.Failed({
564
+ resolution,
565
+ cause: exit.cause
566
+ });
567
+ yield* setState(runtime, id, status, ForkState.Active(), spec);
568
+ const update = exit.value;
569
+ while (true) {
570
+ const next = yield* waitChange({
571
+ ...resolution,
572
+ spec
573
+ });
574
+ if (Option.isNone(next) || update === void 0) return restart;
575
+ const candidate = next.value;
576
+ if (candidate.plugin !== spec.plugin || candidate.revision !== spec.revision) return restart;
577
+ yield* TxRef.set(processing, candidate);
578
+ const operation = Effect.suspend(() => spec.plugin.decode(candidate.input)).pipe(Effect.flatMap(update), inActivation(running.context, spec));
579
+ if (!(yield* cancelOnChange(operation, waitChange({
580
+ ...resolution,
581
+ spec: candidate
582
+ }), (result, settled, _restore, expectedCancellation) => Effect.gen(function* () {
583
+ if (Exit.isFailure(result)) {
584
+ if (!expectedCancellation(result.cause) && (Exit.isFailure(settled) || Cause.hasInterrupts(result.cause))) yield* Ref.update(running.updateCleanup, (cause) => Cause.combine(cause, result.cause));
585
+ if (!expectedCancellation(result.cause) || Exit.isSuccess(settled) && !settled.value) yield* Effect.logWarning("Updating in place failed; restarting instead", result.cause).pipe(Effect.annotateLogs({
586
+ "graft.fork": id,
587
+ "graft.plugin": spec.plugin.name
588
+ }));
589
+ }
590
+ if (Exit.isFailure(settled)) return yield* Effect.failCause(settled.cause);
591
+ return !settled.value && Exit.isSuccess(result) && result.value;
592
+ })))) return restart;
593
+ spec = candidate;
594
+ yield* setState(runtime, id, status, ForkState.Active(), spec);
595
+ }
596
+ });
597
+ /** Every phase finishes before the immutable result is handed to state or disposal. */
598
+ const teardown = (running, exit) => Effect.gen(function* () {
599
+ const closer = yield* Effect.withFiber((self) => Effect.succeed(self.id));
600
+ yield* Fiber.interrupt(running.fiber);
601
+ const stopped = yield* Fiber.await(running.fiber);
602
+ const withdrawn = yield* Effect.exit(withdraw(runtime, running.activation));
603
+ const tasksClosed = yield* close(running.tasks.scope, exit).pipe(Effect.catchCauseIf(Cause.hasInterruptsOnly, () => Effect.void), Effect.exit);
604
+ const closed = yield* close(running.scope, exit).pipe(Effect.catchCauseIf(Cause.hasInterruptsOnly, () => Effect.void), Effect.exit);
605
+ const released = yield* Effect.exit(Effect.tx(Effect.gen(function* () {
606
+ for (const provision of running.resolution.provisions) yield* TxRef.update(provision.consumers, HashSet.remove(id));
607
+ yield* TxRef.update(node.state, (state) => ({
608
+ ...state,
609
+ resolution: void 0
610
+ }));
611
+ })));
612
+ const tasks = yield* Ref.get(running.tasks.failures);
613
+ const updates = yield* Ref.get(running.updateCleanup);
614
+ const stoppedCause = Exit.isFailure(stopped) && !interruptedBy(stopped.cause, closer) ? stopped.cause : Cause.empty;
615
+ const cause = Array.reduce([
616
+ withdrawn,
617
+ tasksClosed,
618
+ closed,
619
+ released
620
+ ], Cause.combine(Cause.combine(tasks, updates), stoppedCause), (cause, result) => Exit.isFailure(result) ? Cause.combine(cause, result.cause) : cause);
621
+ if (Exit.isFailure(closed)) yield* Effect.logError("Releasing the plugin's resources failed", closed.cause);
622
+ yield* reportFailure(`Plugin "${running.resolution.spec.plugin.name}" failed`, stopped);
623
+ return cause.reasons.length === 0 ? Exit.void : Exit.failCause(cause);
624
+ }).pipe(Effect.annotateLogs({
625
+ "graft.fork": id,
626
+ "graft.plugin": running.resolution.spec.plugin.name
627
+ }));
628
+ const waitRetry = Effect.fnUntraced(function* (outcome, previous) {
629
+ const { spec } = outcome.resolution;
630
+ yield* Effect.uninterruptible(setState(runtime, id, status, ForkState.Failed({ cause: outcome.cause }), spec).pipe(Effect.andThen(Ref.set(cleanup, Exit.void))));
631
+ const changed = Effect.asVoid(waitChange(outcome.resolution));
632
+ const blocked = Array.flatMap(outcome.cause.reasons, (reason) => reason._tag === "Fail" && Schema.is(ServiceConflict)(reason.error) && reason.error.fork === id && (reason.error.reason === "SelfDependency" || reason.error.reason === "DependencyCycle") ? [realmKey(reason.error.realm ?? "", reason.error.service)] : []);
633
+ if (blocked.length > 0) {
634
+ yield* Effect.acquireUseRelease(Effect.tx(Effect.forEach(blocked, (key) => retain(runtime, key))), (slots) => {
635
+ const publishable = Effect.tx(Effect.gen(function* () {
636
+ if ((yield* TxRef.get(specRef)) !== spec) return;
637
+ const resolution = yield* resolveCurrent(outcome.resolution.prepared);
638
+ if (resolution.missing.length > 0) return yield* Effect.txRetry;
639
+ const candidate = {
640
+ watch: resolution.watch,
641
+ provisions: resolution.provisions
642
+ };
643
+ for (const slot of slots) if ((yield* TxRef.get(slot.provision))._tag === "Some" || (yield* publicationCycle(node, slot.key, candidate))) return yield* Effect.txRetry;
644
+ }));
645
+ return Effect.raceFirst(changed, publishable);
646
+ }, (slots) => Effect.tx(Effect.forEach(slots, (slot) => release(runtime, slot), { discard: true })));
647
+ return Option.none();
648
+ }
649
+ if (spec.plugin.retry === void 0) {
650
+ yield* changed;
651
+ return Option.none();
652
+ }
653
+ const schedule = spec.plugin.retry;
654
+ const operation = Effect.gen(function* () {
655
+ const step = Option.isSome(previous) && sameAttempt(previous.value.resolution, outcome.resolution) ? previous.value.step : yield* Schedule.toStepWithSleep(schedule);
656
+ return yield* step(outcome.cause).pipe(Effect.as(Option.some({
657
+ resolution: outcome.resolution,
658
+ step
659
+ })), Pull.catchDone(() => Effect.succeedNone));
660
+ });
661
+ return yield* cancelOnChange(operation, changed, (result, settled, restore, expectedCancellation) => Effect.gen(function* () {
662
+ if (Exit.isFailure(settled)) {
663
+ if (Exit.isFailure(result) && !expectedCancellation(result.cause)) yield* Ref.set(cleanup, result);
664
+ return yield* Effect.failCause(settled.cause);
665
+ }
666
+ if (Exit.isFailure(result) && (!settled.value || !expectedCancellation(result.cause))) yield* setState(runtime, id, status, ForkState.Failed({ cause: Cause.combine(outcome.cause, result.cause) }), spec);
667
+ if (settled.value) return Option.none();
668
+ if (Exit.isSuccess(result) && Option.isSome(result.value)) return result.value;
669
+ yield* restore(changed);
670
+ return Option.none();
671
+ }), (result) => reportFailure("The plugin's retry schedule failed", result).pipe(Effect.annotateLogs({
672
+ "graft.fork": id,
673
+ "graft.plugin": spec.plugin.name
674
+ })));
675
+ });
676
+ const cycle = Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
677
+ const acquired = yield* acquire;
678
+ if (acquired._tag === "Missing") return yield* restore(pending(acquired.resolution));
679
+ const running = acquired.running;
680
+ const used = yield* Effect.exit(restore(Effect.raceFirst(run(running), FiberSet.join(running.tasks.fibers).pipe(Effect.andThen(Effect.never), Effect.catchCause((cause) => Effect.gen(function* () {
681
+ const spec = yield* TxRef.get(processing);
682
+ return Outcome.Failed({
683
+ resolution: {
684
+ ...running.resolution,
685
+ spec
686
+ },
687
+ cause
688
+ });
689
+ }))))));
690
+ const cleaned = yield* teardown(running, Exit.isSuccess(used) && used.value._tag === "Failed" ? Exit.failCause(used.value.cause) : used);
691
+ const closed = Exit.isSuccess(used) && used.value._tag === "Failed" && Cause.hasInterruptsOnly(used.value.cause) && Exit.isFailure(cleaned) ? Exit.failCause(Cause.combine(used.value.cause, cleaned.cause)) : cleaned;
692
+ yield* Ref.set(cleanup, closed);
693
+ if (Exit.isFailure(used)) return yield* Effect.failCause(used.cause);
694
+ if (Exit.isFailure(closed)) {
695
+ const spec = yield* TxRef.get(processing);
696
+ return Outcome.Failed({
697
+ resolution: {
698
+ ...running.resolution,
699
+ spec
700
+ },
701
+ cause: closed.cause
702
+ });
703
+ }
704
+ return used.value;
705
+ }));
706
+ const loop = (previous) => cycle.pipe(Effect.flatMap((outcome) => outcome._tag === "Failed" ? waitRetry(outcome, previous) : Effect.succeedNone), Effect.flatMap(loop));
707
+ yield* loop(Option.none()).pipe(Effect.ensuring(Effect.tx(Effect.gen(function* () {
708
+ const remaining = yield* TxRef.get(held);
709
+ if (remaining === void 0) return;
710
+ for (const slot of HashMap.values(remaining.slots)) yield* release(runtime, slot);
711
+ }))));
712
+ });
713
+ // packages/core/src/Graft.ts
714
+ /**
715
+ * The graft runtime: loading plugins, publishing services, replacing
716
+ * plugins at runtime, and observing the fork tree and its logs.
717
+ */
718
+ /**
719
+ * The graft a piece of code runs in: the shared runtime plus the activation
720
+ * that owns anything it publishes.
721
+ */
722
+ var Graft = class extends Context.Service()("@graftland/graft/Graft") {};
723
+ var ServiceConflict = class extends Schema.TaggedError()("ServiceConflict", {
724
+ service: Schema.String,
725
+ /** Absent for an existing provision; otherwise explains why this activation cannot publish. */
726
+ reason: Schema.optionalKey(Schema.Literals([
727
+ "SelfDependency",
728
+ "DependencyCycle",
729
+ "Invalidated"
730
+ ])),
731
+ realm: Schema.optionalKey(Schema.String),
732
+ fork: Schema.optionalKey(Schema.Finite)
733
+ }) {
734
+ get message() {
735
+ return this.reason === void 0 ? `Service "${this.service}" is already provided in this realm` : this.reason === "Invalidated" ? `Cannot provide "${this.service}": the provider's dependencies have changed` : `Cannot provide "${this.service}": publication would restart its own provider`;
736
+ }
737
+ };
738
+ /**
739
+ * Publishes a service into the current realm. It stays available until the
740
+ * activation that published it is torn down, which first waits for every
741
+ * consumer to let go of it.
742
+ */
743
+ const provide = Effect.fnUntraced(function* (key, value) {
744
+ const { runtime, activation } = yield* Graft;
745
+ const realms = yield* Realms;
746
+ const qualified = realmKey(realmOf(realms, key.key), key.key);
747
+ yield* Effect.tx(Effect.gen(function* () {
748
+ const published = yield* TxRef.get(activation.published);
749
+ if (Option.isNone(published)) return yield* Effect.die(/* @__PURE__ */ new Error(`Cannot provide "${key.key}": the plugin providing it is being torn down`));
750
+ const { resolution } = yield* TxRef.get(activation.node.state);
751
+ if (resolution !== void 0 && (yield* resolutionChanged(resolution))) return yield* ServiceConflict.make({
752
+ service: key.key,
753
+ reason: "Invalidated"
754
+ });
755
+ const directory = yield* TxRef.get(runtime.slots);
756
+ const existing = HashMap.get(directory, qualified);
757
+ if (Option.isSome(existing) && (yield* TxRef.get(existing.value.provision))._tag === "Some") return yield* ServiceConflict.make({ service: key.key });
758
+ if (yield* publicationCycle(activation.node, qualified)) {
759
+ const direct = resolution !== void 0 && HashMap.has(resolution.watch, qualified);
760
+ return yield* ServiceConflict.make({
761
+ service: key.key,
762
+ realm: realmOf(realms, key.key),
763
+ fork: activation.fork,
764
+ reason: direct ? "SelfDependency" : "DependencyCycle"
765
+ });
766
+ }
767
+ const slot = yield* retain(runtime, qualified);
768
+ const provision = {
769
+ key: qualified,
770
+ service: key.key,
771
+ value,
772
+ owner: activation.fork,
773
+ node: activation.node,
774
+ slot,
775
+ consumers: TxRef.makeUnsafe(HashSet.empty())
776
+ };
777
+ yield* TxRef.set(slot.provision, Option.some(provision));
778
+ yield* TxRef.set(activation.published, Option.some(Array.append(published.value, provision)));
779
+ }));
780
+ });
781
+ /** How many log entries new subscribers of `logs` receive from the past. */
782
+ const logReplay = 1e3;
783
+ const runtimeLayer = Layer.effect(Graft, Effect.gen(function* () {
784
+ const ambient = yield* Effect.context();
785
+ const runtime = {
786
+ ambient,
787
+ slots: yield* TxRef.make(HashMap.empty()),
788
+ forks: yield* TxSubscriptionRef.make(HashMap.empty()),
789
+ aliases: make$3(),
790
+ events: yield* TxRef.make(HashMap.empty()),
791
+ ids: yield* TxRef.make(1),
792
+ logs: yield* PubSub.sliding({
793
+ capacity: logReplay,
794
+ replay: logReplay
795
+ })
796
+ };
797
+ const published = yield* TxRef.make(Option.some([]));
798
+ const activation = {
799
+ fork: 0,
800
+ node: {
801
+ id: 0,
802
+ parent: void 0,
803
+ state: TxRef.makeUnsafe({
804
+ live: true,
805
+ resolution: void 0
806
+ })
807
+ },
808
+ status: void 0,
809
+ tasks: Option.none(),
810
+ published,
811
+ provisionKeys: HashSet.empty(),
812
+ fallback: ambient
813
+ };
814
+ yield* Effect.addFinalizer(() => withdraw(runtime, activation));
815
+ return {
816
+ runtime,
817
+ activation
818
+ };
819
+ }));
820
+ /** Copies every log entry into the runtime, so `logs` can replay recent history. */
821
+ const loggerLayer = Logger.layer([Effect.map(Graft, ({ runtime }) => Logger.make((options) => {
822
+ PubSub.publishUnsafe(runtime.logs, {
823
+ date: options.date,
824
+ level: options.logLevel,
825
+ message: options.message,
826
+ cause: options.cause,
827
+ annotations: options.fiber.getRef(References.CurrentLogAnnotations)
828
+ });
829
+ }))], { mergeWithExisting: true });
830
+ /** The root graft. Services provided at the root are withdrawn when the layer closes. */
831
+ const layer = Layer.provideMerge(loggerLayer, runtimeLayer);
832
+ const intercept = (reference, f) => ({ apply: (effect) => Effect.updateService(effect, reference, f) });
833
+ const isolation = (id) => (entry) => "key" in entry ? [entry.key, `#${id}`] : [entry[0].key, `@${entry[1]}`];
834
+ /**
835
+ * Changes a fork's spec and waits until its supervisor has acted on it:
836
+ * updated in place, or begun restarting. A later change also counts.
837
+ */
838
+ const accept = (status, spec, f) => Effect.gen(function* () {
839
+ const next = yield* TxRef.modify(spec, (current) => {
840
+ const next = f(current);
841
+ return [next, next];
842
+ });
843
+ yield* Effect.tx(Effect.gen(function* () {
844
+ const snapshot = yield* TxSubscriptionRef.get(status.snapshot);
845
+ if (snapshot.disposed || snapshot.accepted === next) return;
846
+ if ((yield* TxRef.get(spec)) !== next) return;
847
+ return yield* Effect.txRetry;
848
+ }));
849
+ });
850
+ const makeFork = (status, id, spec, dispose) => {
851
+ const state = TxSubscriptionRef.changesStream(status.snapshot).pipe(Stream.map((snapshot) => snapshot.state), Stream.changes, Stream.takeUntil(ForkState.$is("Disposed")));
852
+ return {
853
+ id,
854
+ state,
855
+ await: state.pipe(Stream.filter((state) => !ForkState.$is("Loading")(state)), Stream.runHead, Effect.flatMap((state) => Option.isSome(state) && state.value._tag === "Failed" ? Effect.failCause(state.value.cause) : Effect.void)),
856
+ stable: stable(status),
857
+ update: (input) => accept(status, spec, (current) => ({
858
+ ...current,
859
+ input
860
+ })),
861
+ restart: accept(status, spec, (current) => ({
862
+ ...current,
863
+ revision: current.revision + 1
864
+ })),
865
+ dispose
866
+ };
867
+ };
868
+ /** Loads a plugin under the current scope. Closing that scope unloads it. */
869
+ const plugin = Effect.fnUntraced(function* (plugin, input, options) {
870
+ return yield* Effect.uninterruptible(Effect.gen(function* () {
871
+ const { runtime, activation } = yield* Graft;
872
+ const scope = yield* Effect.scope;
873
+ const termination = yield* Ref.make(Exit.void);
874
+ const owned = yield* ownedScope(scope, Effect.flatMap(Ref.get(termination), (exit) => Exit.isFailure(exit) ? Effect.fail(CleanupError.make({ cause: exit.cause })) : Effect.void));
875
+ const forkScope = owned.scope;
876
+ const { id, spec, node, status } = yield* Effect.acquireRelease(Effect.tx(Effect.gen(function* () {
877
+ const id = yield* TxRef.get(runtime.ids);
878
+ yield* TxRef.set(runtime.ids, id + 1);
879
+ const resolved = yield* resolve$1(runtime.aliases, plugin);
880
+ const spec = TxRef.makeUnsafe({
881
+ plugin: resolved,
882
+ input,
883
+ revision: 0
884
+ });
885
+ const node = {
886
+ id,
887
+ parent: activation.node.id === 0 ? void 0 : activation.node,
888
+ state: TxRef.makeUnsafe({
889
+ live: true,
890
+ resolution: void 0
891
+ })
892
+ };
893
+ const initialSpec = yield* TxRef.get(spec);
894
+ const status = yield* make$2(activation.status, initialSpec);
895
+ const entry = {
896
+ id,
897
+ node,
898
+ status,
899
+ parent: activation.fork === 0 ? void 0 : activation.fork,
900
+ spec,
901
+ accepted: void 0,
902
+ name: resolved.name,
903
+ input,
904
+ state: ForkState.Loading()
905
+ };
906
+ yield* TxSubscriptionRef.update(runtime.forks, HashMap.set(id, entry));
907
+ return {
908
+ id,
909
+ spec,
910
+ node,
911
+ status
912
+ };
913
+ })), ({ id, node, status }) => Effect.tx(Effect.gen(function* () {
914
+ yield* TxRef.set(node.state, {
915
+ live: false,
916
+ resolution: void 0
917
+ });
918
+ yield* dispose(runtime, id, status);
919
+ }))).pipe(Scope.provide(forkScope));
920
+ const realms = HashMap.fromIterable(Array.map(options?.isolate ?? [], isolation(id)));
921
+ const inherited = yield* Effect.context();
922
+ const context = inheritContext(activation, inherited);
923
+ const supervisor = Effect.forever(Effect.gen(function* () {
924
+ const initial = yield* TxRef.get(spec);
925
+ const processing = yield* TxRef.make(initial);
926
+ yield* Effect.suspend(() => Array.reduce(options?.intercept ?? [], supervise(runtime, id, spec, processing, node, status, termination).pipe(Effect.updateService(Realms, (outer) => HashMap.union(outer, realms))), (effect, entry) => entry.apply(effect))).pipe(Effect.andThen(Effect.die(/* @__PURE__ */ new Error("The plugin supervisor stopped unexpectedly"))), Effect.catchCause((cause) => Effect.gen(function* () {
927
+ if (forkScope.state._tag === "Closed") return yield* Effect.failCause(cause);
928
+ const cleanup = yield* Ref.get(termination);
929
+ const completeCause = Exit.isFailure(cleanup) ? Cause.combine(cause, cleanup.cause) : cause;
930
+ const attempted = yield* TxRef.get(processing);
931
+ yield* Effect.logError("The plugin supervisor failed", cause).pipe(Effect.annotateLogs({
932
+ "graft.fork": id,
933
+ "graft.plugin": attempted.plugin.name
934
+ }));
935
+ yield* Effect.uninterruptible(setState(runtime, id, status, ForkState.Failed({ cause: completeCause }), attempted).pipe(Effect.andThen(Ref.set(termination, Exit.void))));
936
+ yield* Effect.tx(Effect.gen(function* () {
937
+ if ((yield* TxRef.get(spec)) === attempted) return yield* Effect.txRetry;
938
+ }));
939
+ })));
940
+ })).pipe(Effect.updateContext(() => context));
941
+ yield* Effect.acquireRelease(Effect.forkIn(supervisor, forkScope), (fiber) => Effect.gen(function* () {
942
+ const closer = yield* Effect.withFiber((self) => Effect.succeed(self.id));
943
+ yield* Fiber.interrupt(fiber);
944
+ const exit = yield* Fiber.await(fiber);
945
+ return yield* Exit.isFailure(exit) && !Array.every(exit.cause.reasons, (reason) => reason._tag === "Interrupt" && reason.fiberId === closer) ? Ref.update(termination, (cleanup) => Exit.failCause(Exit.isFailure(cleanup) ? Cause.combine(cleanup.cause, exit.cause) : exit.cause)).pipe(Effect.andThen(Effect.logError("Stopping the plugin supervisor failed", exit.cause).pipe(Effect.annotateLogs({ "graft.fork": id })))) : Effect.void;
946
+ })).pipe(Scope.provide(forkScope));
947
+ return makeFork(status, id, spec, owned.close(Exit.void));
948
+ }));
949
+ });
950
+ /** The requested identities cannot be represented by the runtime's flat aliases. */
951
+ var ReplacementConflict = class extends Schema.TaggedError()("ReplacementConflict", { indices: Schema.Array(Schema.Int) }) {};
952
+ Effect.fnUntraced(function* (pairs) {
953
+ const { runtime } = yield* Graft;
954
+ yield* Effect.tx(Effect.gen(function* () {
955
+ const conflicts = yield* replace$1(runtime.aliases, pairs);
956
+ if (conflicts.length > 0) return yield* ReplacementConflict.make({ indices: conflicts });
957
+ const forks = yield* TxSubscriptionRef.get(runtime.forks);
958
+ for (const entry of HashMap.values(forks)) {
959
+ const spec = yield* TxRef.get(entry.spec);
960
+ const next = yield* resolve$1(runtime.aliases, spec.plugin);
961
+ if (next !== spec.plugin) yield* TxRef.set(entry.spec, {
962
+ ...spec,
963
+ plugin: next,
964
+ revision: spec.revision + 1
965
+ });
966
+ }
967
+ }));
968
+ });
969
+ const byId = Order.mapInput(Order.Number, (entry) => entry.id);
970
+ const buildTree = (forks) => {
971
+ const key = (parent) => parent === void 0 ? "" : `${parent}`;
972
+ const byParent = Array.groupBy(Array.sort(HashMap.toValues(forks), byId), (entry) => key(entry.parent));
973
+ const children = (parent) => Array.map(Record.get(byParent, key(parent)).pipe(Option.getOrElse(() => [])), (entry) => ({
974
+ id: entry.id,
975
+ name: entry.name,
976
+ input: entry.input,
977
+ state: entry.state,
978
+ children: children(entry.id)
979
+ }));
980
+ return children(void 0);
981
+ };
982
+ /** The fork tree, emitted again on every change. */
983
+ const forks = Stream.unwrap(Effect.map(Graft, ({ runtime }) => TxSubscriptionRef.changesStream(runtime.forks).pipe(Stream.map(buildTree))));
984
+ Stream.unwrap(Effect.map(Graft, ({ runtime }) => Stream.fromPubSub(runtime.logs)));
985
+ export { provide as a, isPlugin as c, service as d, CleanupError as f, plugin as i, make as l, intercept as n, fork as o, layer as r, fromModule as s, forks as t, optional as u };