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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +76 -2
  3. package/README.zh-CN.md +71 -0
  4. package/README.zh-TW.md +71 -0
  5. package/dist/Auth-BElTC9_X.js +6 -0
  6. package/dist/Auth.d.ts +49 -0
  7. package/dist/Auth.d.ts.map +1 -0
  8. package/dist/Auth.js +8 -0
  9. package/dist/Auth.js.map +1 -0
  10. package/dist/Bootstrap-MCwivGN1.js +9 -0
  11. package/dist/ConfigDirectory-BCC6q2R4.js +5 -0
  12. package/dist/Contract-CcpSIJm4.js +121 -0
  13. package/dist/Contract.d.ts +71 -0
  14. package/dist/Contract.d.ts.map +1 -0
  15. package/dist/Contract.js +1 -0
  16. package/dist/Contract.js.map +1 -0
  17. package/dist/Errors-oPsTLY7l.js +45 -0
  18. package/dist/Errors.d.ts +67 -0
  19. package/dist/Errors.d.ts.map +1 -0
  20. package/dist/Errors.js +47 -0
  21. package/dist/Errors.js.map +1 -0
  22. package/dist/FailureGroup-BcH0XOBi.js +53 -0
  23. package/dist/Framing-zaYdOJnT.js +61 -0
  24. package/dist/Graft-BsYq3F-J.js +985 -0
  25. package/dist/Instance.d.ts +7 -0
  26. package/dist/Instance.d.ts.map +1 -0
  27. package/dist/Instance.js +14 -0
  28. package/dist/Instance.js.map +1 -0
  29. package/dist/Packages-B1TPk8pa.js +111 -0
  30. package/dist/Peer-IJgFK6mD.js +342 -0
  31. package/dist/ProcessObservation-DEGrEMfP.js +38 -0
  32. package/dist/ServeLifecycle-CJM0gG5B.js +24 -0
  33. package/dist/Testing.d.ts +26 -0
  34. package/dist/Testing.d.ts.map +1 -0
  35. package/dist/Testing.js +69 -0
  36. package/dist/Testing.js.map +1 -0
  37. package/dist/Transport-DULzpsgR.js +6 -0
  38. package/dist/Transport.d.ts +39 -0
  39. package/dist/Transport.d.ts.map +1 -0
  40. package/dist/Transport.js +8 -0
  41. package/dist/Transport.js.map +1 -0
  42. package/dist/WatchdogProtocol-BZmVxrBP.js +17 -0
  43. package/dist/_virtual/_rolldown/runtime.js +12 -0
  44. package/dist/bin.d.ts +1 -0
  45. package/dist/bin.js +28275 -0
  46. package/dist/bin.js.map +1 -0
  47. package/dist/childRuntime-DSqtFN9o.js +188 -0
  48. package/dist/cleanup-BPWr-5U9.js +13 -0
  49. package/dist/command-9zrHdbwT.js +7 -0
  50. package/dist/connectionEnded-DUgcobEd.js +9 -0
  51. package/dist/directTransport-DrexuPSm.js +5 -0
  52. package/dist/entry-SYsx9VNb.js +708 -0
  53. package/dist/host/auth/bearer.d.ts +5 -0
  54. package/dist/host/auth/bearer.d.ts.map +1 -0
  55. package/dist/host/auth/bearer.js +4 -0
  56. package/dist/host/auth/bearer.js.map +1 -0
  57. package/dist/host/auth/jwt.d.ts +5 -0
  58. package/dist/host/auth/jwt.d.ts.map +1 -0
  59. package/dist/host/auth/jwt.js +4 -0
  60. package/dist/host/auth/jwt.js.map +1 -0
  61. package/dist/host/auth/mtls.d.ts +8 -0
  62. package/dist/host/auth/mtls.d.ts.map +1 -0
  63. package/dist/host/auth/mtls.js +34 -0
  64. package/dist/host/auth/mtls.js.map +1 -0
  65. package/dist/host/auth/none.d.ts +3 -0
  66. package/dist/host/auth/none.d.ts.map +1 -0
  67. package/dist/host/auth/none.js +13 -0
  68. package/dist/host/auth/none.js.map +1 -0
  69. package/dist/host/command.d.ts +22 -0
  70. package/dist/host/command.d.ts.map +1 -0
  71. package/dist/host/command.js +61 -0
  72. package/dist/host/command.js.map +1 -0
  73. package/dist/host/local.d.ts +4 -0
  74. package/dist/host/local.d.ts.map +1 -0
  75. package/dist/host/local.js +52 -0
  76. package/dist/host/local.js.map +1 -0
  77. package/dist/host/unix.d.ts +11 -0
  78. package/dist/host/unix.d.ts.map +1 -0
  79. package/dist/host/unix.js +39 -0
  80. package/dist/host/unix.js.map +1 -0
  81. package/dist/host/websocket.d.ts +13 -0
  82. package/dist/host/websocket.d.ts.map +1 -0
  83. package/dist/host/websocket.js +36 -0
  84. package/dist/host/websocket.js.map +1 -0
  85. package/dist/host/worker.d.ts +4 -0
  86. package/dist/host/worker.d.ts.map +1 -0
  87. package/dist/host/worker.js +52 -0
  88. package/dist/host/worker.js.map +1 -0
  89. package/dist/importer-D7zSgqxq.js +347 -0
  90. package/dist/index.d.ts +29 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +86 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/internal/Certificates.js +182 -0
  95. package/dist/internal/Certificates.js.map +1 -0
  96. package/dist/internal/FailureGroup.js +55 -0
  97. package/dist/internal/FailureGroup.js.map +1 -0
  98. package/dist/internal/Limits.d.ts +1 -0
  99. package/dist/internal/Limits.js +17 -0
  100. package/dist/internal/Limits.js.map +1 -0
  101. package/dist/internal/Peer.js +6 -0
  102. package/dist/internal/Peer.js.map +1 -0
  103. package/dist/internal/ServeLifecycle.js +26 -0
  104. package/dist/internal/ServeLifecycle.js.map +1 -0
  105. package/dist/internal/Supervisor.js +7 -0
  106. package/dist/internal/Supervisor.js.map +1 -0
  107. package/dist/internal/assembly.d.ts +5 -0
  108. package/dist/internal/assembly.js +138 -0
  109. package/dist/internal/assembly.js.map +1 -0
  110. package/dist/internal/auth/mtls.js +23 -0
  111. package/dist/internal/auth/mtls.js.map +1 -0
  112. package/dist/internal/auth/token.js +19 -0
  113. package/dist/internal/auth/token.js.map +1 -0
  114. package/dist/internal/auth/tokenCredentials.d.ts +8 -0
  115. package/dist/internal/auth/tokenCredentials.d.ts.map +1 -0
  116. package/dist/internal/auth/tokenCredentials.js +33 -0
  117. package/dist/internal/auth/tokenCredentials.js.map +1 -0
  118. package/dist/internal/child.js +125 -0
  119. package/dist/internal/child.js.map +1 -0
  120. package/dist/internal/childErrors.d.ts +33 -0
  121. package/dist/internal/childErrors.d.ts.map +1 -0
  122. package/dist/internal/childErrors.js +29 -0
  123. package/dist/internal/childErrors.js.map +1 -0
  124. package/dist/internal/childRuntime.js +59 -0
  125. package/dist/internal/childRuntime.js.map +1 -0
  126. package/dist/internal/cleanup.js +15 -0
  127. package/dist/internal/cleanup.js.map +1 -0
  128. package/dist/internal/config.js +6 -0
  129. package/dist/internal/config.js.map +1 -0
  130. package/dist/internal/control.js +42 -0
  131. package/dist/internal/control.js.map +1 -0
  132. package/dist/internal/credentials.d.ts +44 -0
  133. package/dist/internal/credentials.d.ts.map +1 -0
  134. package/dist/internal/credentials.js +54 -0
  135. package/dist/internal/credentials.js.map +1 -0
  136. package/dist/internal/directTransport.d.ts +3 -0
  137. package/dist/internal/directTransport.js +7 -0
  138. package/dist/internal/directTransport.js.map +1 -0
  139. package/dist/internal/entry.d.ts +9 -0
  140. package/dist/internal/entry.d.ts.map +1 -0
  141. package/dist/internal/entry.js +144 -0
  142. package/dist/internal/entry.js.map +1 -0
  143. package/dist/internal/entryConfig.d.ts +202 -0
  144. package/dist/internal/entryConfig.d.ts.map +1 -0
  145. package/dist/internal/entryConfig.js +176 -0
  146. package/dist/internal/entryConfig.js.map +1 -0
  147. package/dist/internal/execution.d.ts +5 -0
  148. package/dist/internal/execution.js +43 -0
  149. package/dist/internal/execution.js.map +1 -0
  150. package/dist/internal/follow.js +11 -0
  151. package/dist/internal/follow.js.map +1 -0
  152. package/dist/internal/forkTree.js +7 -0
  153. package/dist/internal/forkTree.js.map +1 -0
  154. package/dist/internal/host/local.js +28 -0
  155. package/dist/internal/host/local.js.map +1 -0
  156. package/dist/internal/host/runner.js +100 -0
  157. package/dist/internal/host/runner.js.map +1 -0
  158. package/dist/internal/host.js +71 -0
  159. package/dist/internal/host.js.map +1 -0
  160. package/dist/internal/importer.js +18 -0
  161. package/dist/internal/importer.js.map +1 -0
  162. package/dist/internal/listenerStartup.js +17 -0
  163. package/dist/internal/listenerStartup.js.map +1 -0
  164. package/dist/internal/loadModule.js +20 -0
  165. package/dist/internal/loadModule.js.map +1 -0
  166. package/dist/internal/platform.js +9 -0
  167. package/dist/internal/platform.js.map +1 -0
  168. package/dist/internal/port.d.ts +13 -0
  169. package/dist/internal/port.d.ts.map +1 -0
  170. package/dist/internal/port.js +275 -0
  171. package/dist/internal/port.js.map +1 -0
  172. package/dist/internal/release.js +25 -0
  173. package/dist/internal/release.js.map +1 -0
  174. package/dist/internal/runner/Bootstrap.js +11 -0
  175. package/dist/internal/runner/Bootstrap.js.map +1 -0
  176. package/dist/internal/runner/Connection.d.ts +11 -0
  177. package/dist/internal/runner/Connection.js +56 -0
  178. package/dist/internal/runner/Connection.js.map +1 -0
  179. package/dist/internal/runner/Execution.js +115 -0
  180. package/dist/internal/runner/Execution.js.map +1 -0
  181. package/dist/internal/runner/Framing.d.ts +11 -0
  182. package/dist/internal/runner/Framing.d.ts.map +1 -0
  183. package/dist/internal/runner/Framing.js +63 -0
  184. package/dist/internal/runner/Framing.js.map +1 -0
  185. package/dist/internal/runner/Local.js +46 -0
  186. package/dist/internal/runner/Local.js.map +1 -0
  187. package/dist/internal/runner/Lock.js +25 -0
  188. package/dist/internal/runner/Lock.js.map +1 -0
  189. package/dist/internal/runner/Multiplex.d.ts +5 -0
  190. package/dist/internal/runner/Multiplex.js +49 -0
  191. package/dist/internal/runner/Multiplex.js.map +1 -0
  192. package/dist/internal/runner/Packages.d.ts +3 -0
  193. package/dist/internal/runner/Packages.js +108 -0
  194. package/dist/internal/runner/Packages.js.map +1 -0
  195. package/dist/internal/runner/ProcessObservation.js +40 -0
  196. package/dist/internal/runner/ProcessObservation.js.map +1 -0
  197. package/dist/internal/runner/Processes.js +83 -0
  198. package/dist/internal/runner/Processes.js.map +1 -0
  199. package/dist/internal/runner/Retention.js +13 -0
  200. package/dist/internal/runner/Retention.js.map +1 -0
  201. package/dist/internal/runner/Store.js +78 -0
  202. package/dist/internal/runner/Store.js.map +1 -0
  203. package/dist/internal/runner/Supervisor.js +375 -0
  204. package/dist/internal/runner/Supervisor.js.map +1 -0
  205. package/dist/internal/runner/Watchdog.js +47 -0
  206. package/dist/internal/runner/Watchdog.js.map +1 -0
  207. package/dist/internal/runner/WatchdogProtocol.js +19 -0
  208. package/dist/internal/runner/WatchdogProtocol.js.map +1 -0
  209. package/dist/internal/runner/Wire.d.ts +5 -0
  210. package/dist/internal/runner/Wire.js +64 -0
  211. package/dist/internal/runner/Wire.js.map +1 -0
  212. package/dist/internal/runner/accept.js +57 -0
  213. package/dist/internal/runner/accept.js.map +1 -0
  214. package/dist/internal/runner/command.js +9 -0
  215. package/dist/internal/runner/command.js.map +1 -0
  216. package/dist/internal/runner/connectionEnded.js +11 -0
  217. package/dist/internal/runner/connectionEnded.js.map +1 -0
  218. package/dist/internal/runner/model.d.ts +17 -0
  219. package/dist/internal/runner/model.d.ts.map +1 -0
  220. package/dist/internal/runner/model.js +231 -0
  221. package/dist/internal/runner/model.js.map +1 -0
  222. package/dist/internal/serve.js +60 -0
  223. package/dist/internal/serve.js.map +1 -0
  224. package/dist/internal/services.d.ts +18 -0
  225. package/dist/internal/services.d.ts.map +1 -0
  226. package/dist/internal/services.js +22 -0
  227. package/dist/internal/services.js.map +1 -0
  228. package/dist/internal/socketChannel.js +24 -0
  229. package/dist/internal/socketChannel.js.map +1 -0
  230. package/dist/internal/stdioChannel.js +23 -0
  231. package/dist/internal/stdioChannel.js.map +1 -0
  232. package/dist/internal/supervisorPlugin.js +1 -0
  233. package/dist/internal/supervisorPlugin.js.map +1 -0
  234. package/dist/internal/transportOptions.d.ts +18 -0
  235. package/dist/internal/transportOptions.d.ts.map +1 -0
  236. package/dist/internal/watchdogMain.d.ts +1 -0
  237. package/dist/internal/watchdogMain.js +55 -0
  238. package/dist/internal/watchdogMain.js.map +1 -0
  239. package/dist/internal/websocket.js +46 -0
  240. package/dist/internal/websocket.js.map +1 -0
  241. package/dist/internal/websocketServer.js +61 -0
  242. package/dist/internal/websocketServer.js.map +1 -0
  243. package/dist/internal/workerBootstrap.js +9 -0
  244. package/dist/internal/workerBootstrap.js.map +1 -0
  245. package/dist/internal/workerChannel.js +24 -0
  246. package/dist/internal/workerChannel.js.map +1 -0
  247. package/dist/internal/workerMain.d.ts +1 -0
  248. package/dist/internal/workerMain.js +18 -0
  249. package/dist/internal/workerMain.js.map +1 -0
  250. package/dist/port-Blbh8tms.js +285 -0
  251. package/dist/release-BY4Mlluy.js +23 -0
  252. package/dist/rolldown-runtime-DYf_mQCB.js +34 -0
  253. package/dist/runner/auth/bearer.d.ts +7 -0
  254. package/dist/runner/auth/bearer.d.ts.map +1 -0
  255. package/dist/runner/auth/bearer.js +42 -0
  256. package/dist/runner/auth/bearer.js.map +1 -0
  257. package/dist/runner/auth/jwt.d.ts +19 -0
  258. package/dist/runner/auth/jwt.d.ts.map +1 -0
  259. package/dist/runner/auth/jwt.js +65 -0
  260. package/dist/runner/auth/jwt.js.map +1 -0
  261. package/dist/runner/auth/mtls.d.ts +11 -0
  262. package/dist/runner/auth/mtls.d.ts.map +1 -0
  263. package/dist/runner/auth/mtls.js +48 -0
  264. package/dist/runner/auth/mtls.js.map +1 -0
  265. package/dist/runner/auth/none.d.ts +3 -0
  266. package/dist/runner/auth/none.d.ts.map +1 -0
  267. package/dist/runner/auth/none.js +13 -0
  268. package/dist/runner/auth/none.js.map +1 -0
  269. package/dist/runner/index.d.ts +3 -0
  270. package/dist/runner/index.d.ts.map +1 -0
  271. package/dist/runner/index.js +71 -0
  272. package/dist/runner/index.js.map +1 -0
  273. package/dist/runner/stdio.d.ts +7 -0
  274. package/dist/runner/stdio.d.ts.map +1 -0
  275. package/dist/runner/stdio.js +39 -0
  276. package/dist/runner/stdio.js.map +1 -0
  277. package/dist/runner/unix.d.ts +7 -0
  278. package/dist/runner/unix.d.ts.map +1 -0
  279. package/dist/runner/unix.js +42 -0
  280. package/dist/runner/unix.js.map +1 -0
  281. package/dist/runner/websocket.d.ts +28 -0
  282. package/dist/runner/websocket.d.ts.map +1 -0
  283. package/dist/runner/websocket.js +77 -0
  284. package/dist/runner/websocket.js.map +1 -0
  285. package/dist/socketChannel-KmtzF-9G.js +3658 -0
  286. package/dist/supervisorPlugin-Inb1S5IV.js +737 -0
  287. package/dist/token-v5ne2I0-.js +17 -0
  288. package/dist/tokenCredentials-WUJm2AKm.js +31 -0
  289. package/dist/websocketServer-MXcCJx0v.js +58 -0
  290. package/dist/workerChannel-P82YdNjh.js +27 -0
  291. package/package.json +69 -3
  292. package/src/Auth.ts +62 -0
  293. package/src/Contract.ts +100 -0
  294. package/src/Errors.ts +82 -0
  295. package/src/Instance.ts +12 -0
  296. package/src/Testing.ts +135 -0
  297. package/src/Transport.ts +52 -0
  298. package/src/bin.ts +145 -0
  299. package/src/host/auth/bearer.ts +10 -0
  300. package/src/host/auth/jwt.ts +10 -0
  301. package/src/host/auth/mtls.ts +48 -0
  302. package/src/host/auth/none.ts +13 -0
  303. package/src/host/command.ts +131 -0
  304. package/src/host/local.ts +41 -0
  305. package/src/host/unix.ts +65 -0
  306. package/src/host/websocket.ts +66 -0
  307. package/src/host/worker.ts +90 -0
  308. package/src/index.ts +115 -0
  309. package/src/internal/Certificates.ts +330 -0
  310. package/src/internal/FailureGroup.ts +176 -0
  311. package/src/internal/Limits.ts +12 -0
  312. package/src/internal/Peer.ts +4 -0
  313. package/src/internal/ServeLifecycle.ts +53 -0
  314. package/src/internal/Supervisor.ts +14 -0
  315. package/src/internal/assembly.ts +337 -0
  316. package/src/internal/auth/mtls.ts +40 -0
  317. package/src/internal/auth/token.ts +26 -0
  318. package/src/internal/auth/tokenCredentials.ts +65 -0
  319. package/src/internal/child.ts +323 -0
  320. package/src/internal/childErrors.ts +44 -0
  321. package/src/internal/childRuntime.ts +111 -0
  322. package/src/internal/cleanup.ts +34 -0
  323. package/src/internal/config.ts +8 -0
  324. package/src/internal/control.ts +49 -0
  325. package/src/internal/credentials.ts +112 -0
  326. package/src/internal/directTransport.ts +38 -0
  327. package/src/internal/entry.ts +288 -0
  328. package/src/internal/entryConfig.ts +190 -0
  329. package/src/internal/execution.ts +121 -0
  330. package/src/internal/follow.ts +17 -0
  331. package/src/internal/forkTree.ts +13 -0
  332. package/src/internal/host/local.ts +53 -0
  333. package/src/internal/host/runner.ts +187 -0
  334. package/src/internal/host.ts +209 -0
  335. package/src/internal/importer.ts +27 -0
  336. package/src/internal/listenerStartup.ts +55 -0
  337. package/src/internal/loadModule.ts +23 -0
  338. package/src/internal/platform.ts +12 -0
  339. package/src/internal/port.ts +623 -0
  340. package/src/internal/release.ts +71 -0
  341. package/src/internal/runner/Bootstrap.ts +9 -0
  342. package/src/internal/runner/Connection.ts +184 -0
  343. package/src/internal/runner/Execution.ts +244 -0
  344. package/src/internal/runner/Framing.ts +122 -0
  345. package/src/internal/runner/Local.ts +73 -0
  346. package/src/internal/runner/Lock.ts +29 -0
  347. package/src/internal/runner/Multiplex.ts +120 -0
  348. package/src/internal/runner/Packages.ts +178 -0
  349. package/src/internal/runner/ProcessObservation.ts +63 -0
  350. package/src/internal/runner/Processes.ts +109 -0
  351. package/src/internal/runner/Retention.ts +49 -0
  352. package/src/internal/runner/Store.ts +160 -0
  353. package/src/internal/runner/Supervisor.ts +901 -0
  354. package/src/internal/runner/Watchdog.ts +83 -0
  355. package/src/internal/runner/WatchdogProtocol.ts +12 -0
  356. package/src/internal/runner/Wire.ts +99 -0
  357. package/src/internal/runner/accept.ts +103 -0
  358. package/src/internal/runner/command.ts +15 -0
  359. package/src/internal/runner/connectionEnded.ts +28 -0
  360. package/src/internal/runner/model.ts +364 -0
  361. package/src/internal/serve.ts +117 -0
  362. package/src/internal/services.ts +74 -0
  363. package/src/internal/socketChannel.ts +64 -0
  364. package/src/internal/stdioChannel.ts +25 -0
  365. package/src/internal/supervisorPlugin.ts +67 -0
  366. package/src/internal/transportOptions.ts +17 -0
  367. package/src/internal/watchdogMain.ts +72 -0
  368. package/src/internal/websocket.ts +81 -0
  369. package/src/internal/websocketServer.ts +152 -0
  370. package/src/internal/workerBootstrap.ts +6 -0
  371. package/src/internal/workerChannel.ts +54 -0
  372. package/src/internal/workerMain.ts +23 -0
  373. package/src/runner/auth/bearer.ts +66 -0
  374. package/src/runner/auth/jwt.ts +114 -0
  375. package/src/runner/auth/mtls.ts +37 -0
  376. package/src/runner/auth/none.ts +13 -0
  377. package/src/runner/index.ts +97 -0
  378. package/src/runner/stdio.ts +76 -0
  379. package/src/runner/unix.ts +53 -0
  380. package/src/runner/websocket.ts +143 -0
@@ -0,0 +1,78 @@
1
+ import { Key, SessionRecord, StateStorageError, Store } from "./model.js";
2
+ import { retain, save } from "./Retention.js";
3
+ import { Array, Cause, Effect, FileSystem, HashMap, HashSet, Layer, Path, Ref, Schema, Semaphore, String } from "effect";
4
+ import { Digest, SecureRandom } from "effect/crypto";
5
+ // src/internal/runner/Store.ts
6
+ /** Injectable store used by deterministic supervisor tests. */
7
+ const memory = Effect.gen(function* () {
8
+ const records = yield* Ref.make(HashMap.empty());
9
+ return Store.of({
10
+ list: Ref.get(records).pipe(Effect.map((records) => Array.fromIterable(HashMap.values(records)))),
11
+ save: (record) => Ref.update(records, (all) => save(all, record))
12
+ });
13
+ });
14
+ /**
15
+ * Atomically replaced records retain unfinished sessions and each key's high-water mark.
16
+ * Older terminal request ids expire; Open fences their retries with expectedGeneration.
17
+ * Requires exclusive directory ownership; it is not a multi-writer database.
18
+ */
19
+ const directory = (root) => Effect.gen(function* () {
20
+ const fs = yield* FileSystem.FileSystem;
21
+ const path = yield* Path.Path;
22
+ const digest = yield* Digest.Digest;
23
+ const json = Schema.fromJsonString(Schema.toCodecJson(SessionRecord));
24
+ const random = yield* SecureRandom.SecureRandom;
25
+ const storage = (effect) => effect.pipe(Effect.mapError((error) => error._tag === "StateStorageError" ? error : StateStorageError.make({
26
+ detail: "Runner state storage failed",
27
+ cause: Cause.fail(error)
28
+ })));
29
+ yield* storage(fs.makeDirectory(root, { recursive: true }).pipe(Effect.uninterruptible));
30
+ const mutex = yield* Semaphore.make(1);
31
+ const read = Effect.gen(function* () {
32
+ const files = yield* fs.readDirectory(root);
33
+ return yield* Effect.forEach(Array.filter(files, String.endsWith(".json")), (file) => fs.readFileString(path.join(root, file)).pipe(Effect.flatMap(Schema.decodeEffect(json)), Effect.map((record) => ({
34
+ file,
35
+ record
36
+ }))));
37
+ });
38
+ const compact = Effect.scoped(Effect.gen(function* () {
39
+ const rows = yield* read;
40
+ const retained = retain(Array.map(rows, (row) => row.record));
41
+ const tokens = HashSet.fromIterable(Array.map(retained, (record) => record.handle.token));
42
+ const obsolete = Array.filter(rows, (row) => !HashSet.has(tokens, row.record.handle.token));
43
+ yield* Effect.forEach(obsolete, (row) => fs.remove(path.join(root, row.file)).pipe(Effect.uninterruptible), { discard: true });
44
+ if (obsolete.length > 0) yield* (yield* fs.open(root, { flag: "r" })).sync.pipe(Effect.uninterruptible);
45
+ }));
46
+ yield* storage(compact);
47
+ return Store.of({
48
+ list: storage(mutex.withPermit(read.pipe(Effect.map((rows) => Array.map(rows, (row) => row.record))))),
49
+ save: (record) => storage(mutex.withPermit(Effect.scoped(Effect.gen(function* () {
50
+ const encoded = yield* Schema.encodeEffect(json)(record);
51
+ const address = yield* Schema.encodeEffect(Schema.fromJsonString(Schema.Struct({
52
+ key: Key,
53
+ generation: Schema.Int
54
+ })))({
55
+ key: record.handle.key,
56
+ generation: record.handle.generation
57
+ });
58
+ const name = yield* digest.digestHex(Digest.sha256, new TextEncoder().encode(address));
59
+ const nonce = yield* random.uuidV4();
60
+ const temporary = path.join(root, `.${name}.${nonce}.tmp`);
61
+ const destination = path.join(root, name + ".json");
62
+ yield* Effect.acquireRelease(fs.open(temporary, {
63
+ flag: "wx",
64
+ mode: 384
65
+ }), () => fs.remove(temporary, { force: true }).pipe(Effect.orDie)).pipe(Effect.flatMap((file) => file.writeAll(new TextEncoder().encode(encoded)).pipe(Effect.uninterruptible, Effect.andThen(file.sync.pipe(Effect.uninterruptible)))));
66
+ yield* Effect.uninterruptible(Effect.gen(function* () {
67
+ yield* fs.rename(temporary, destination);
68
+ yield* (yield* fs.open(root, { flag: "r" })).sync.pipe(Effect.uninterruptible);
69
+ }));
70
+ yield* compact;
71
+ }))))
72
+ });
73
+ });
74
+ Layer.effect(Store, memory);
75
+ const layerDirectory = (root) => Layer.effect(Store, directory(root));
76
+ export { directory, layerDirectory, memory };
77
+
78
+ //# sourceMappingURL=Store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store.js","names":["Retention.save","Retention.retain"],"sources":["../../../src/internal/runner/Store.ts"],"sourcesContent":["import {\n\tArray,\n\tCause,\n\tLayer,\n\tEffect,\n\tFileSystem,\n\tHashMap,\n\tHashSet,\n\tPath,\n\tRef,\n\tSchema,\n\tSemaphore,\n\tString,\n\ttype PlatformError,\n} from \"effect\"\nimport { Digest, SecureRandom } from \"effect/crypto\"\nimport { Key, SessionRecord, Store, StateStorageError } from \"./model\"\nimport * as Retention from \"./Retention\"\n\n/** Injectable store used by deterministic supervisor tests. */\nexport const memory = Effect.gen(function* () {\n\tconst records = yield* Ref.make(HashMap.empty<string, SessionRecord>())\n\treturn Store.of({\n\t\tlist: Ref.get(records).pipe(\n\t\t\tEffect.map((records) => Array.fromIterable(HashMap.values(records))),\n\t\t),\n\t\tsave: (record) => Ref.update(records, (all) => Retention.save(all, record)),\n\t})\n})\n\n/**\n * Atomically replaced records retain unfinished sessions and each key's high-water mark.\n * Older terminal request ids expire; Open fences their retries with expectedGeneration.\n * Requires exclusive directory ownership; it is not a multi-writer database.\n */\nexport const directory = (root: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem\n\t\tconst path = yield* Path.Path\n\t\tconst digest = yield* Digest.Digest\n\t\tconst json = Schema.fromJsonString(Schema.toCodecJson(SessionRecord))\n\t\tconst random = yield* SecureRandom.SecureRandom\n\t\tconst storage = <A, R>(\n\t\t\teffect: Effect.Effect<\n\t\t\t\tA,\n\t\t\t\tPlatformError.PlatformError | Schema.SchemaError | StateStorageError,\n\t\t\t\tR\n\t\t\t>,\n\t\t) =>\n\t\t\teffect.pipe(\n\t\t\t\tEffect.mapError((error) =>\n\t\t\t\t\terror._tag === \"StateStorageError\"\n\t\t\t\t\t\t? error\n\t\t\t\t\t\t: StateStorageError.make({\n\t\t\t\t\t\t\t\tdetail: \"Runner state storage failed\",\n\t\t\t\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)\n\t\tyield* storage(\n\t\t\tfs.makeDirectory(root, { recursive: true }).pipe(Effect.uninterruptible),\n\t\t)\n\t\tconst mutex = yield* Semaphore.make(1)\n\t\tconst read = Effect.gen(function* () {\n\t\t\tconst files = yield* fs.readDirectory(root)\n\t\t\tconst rows = yield* Effect.forEach(\n\t\t\t\tArray.filter(files, String.endsWith(\".json\")),\n\t\t\t\t(file) =>\n\t\t\t\t\tfs.readFileString(path.join(root, file)).pipe(\n\t\t\t\t\t\tEffect.flatMap(Schema.decodeEffect(json)),\n\t\t\t\t\t\tEffect.map((record) => ({ file, record })),\n\t\t\t\t\t),\n\t\t\t)\n\t\t\treturn rows\n\t\t})\n\t\tconst compact = Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst rows = yield* read\n\t\t\t\tconst retained = Retention.retain(Array.map(rows, (row) => row.record))\n\t\t\t\tconst tokens = HashSet.fromIterable(\n\t\t\t\t\tArray.map(retained, (record) => record.handle.token),\n\t\t\t\t)\n\t\t\t\tconst obsolete = Array.filter(\n\t\t\t\t\trows,\n\t\t\t\t\t(row) => !HashSet.has(tokens, row.record.handle.token),\n\t\t\t\t)\n\t\t\t\tyield* Effect.forEach(\n\t\t\t\t\tobsolete,\n\t\t\t\t\t(row) =>\n\t\t\t\t\t\tfs.remove(path.join(root, row.file)).pipe(Effect.uninterruptible),\n\t\t\t\t\t{ discard: true },\n\t\t\t\t)\n\t\t\t\tif (obsolete.length > 0) {\n\t\t\t\t\tconst directory = yield* fs.open(root, { flag: \"r\" })\n\t\t\t\t\tyield* directory.sync.pipe(Effect.uninterruptible)\n\t\t\t\t}\n\t\t\t}),\n\t\t)\n\t\tyield* storage(compact)\n\t\treturn Store.of({\n\t\t\tlist: storage(\n\t\t\t\tmutex.withPermit(\n\t\t\t\t\tread.pipe(Effect.map((rows) => Array.map(rows, (row) => row.record))),\n\t\t\t\t),\n\t\t\t),\n\t\t\tsave: (record) =>\n\t\t\t\tstorage(\n\t\t\t\t\tmutex.withPermit(\n\t\t\t\t\t\tEffect.scoped(\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tconst encoded = yield* Schema.encodeEffect(json)(record)\n\t\t\t\t\t\t\t\tconst address = yield* Schema.encodeEffect(\n\t\t\t\t\t\t\t\t\tSchema.fromJsonString(\n\t\t\t\t\t\t\t\t\t\tSchema.Struct({ key: Key, generation: Schema.Int }),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)({\n\t\t\t\t\t\t\t\t\tkey: record.handle.key,\n\t\t\t\t\t\t\t\t\tgeneration: record.handle.generation,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\tconst name = yield* digest.digestHex(\n\t\t\t\t\t\t\t\t\tDigest.sha256,\n\t\t\t\t\t\t\t\t\tnew TextEncoder().encode(address),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst nonce = yield* random.uuidV4()\n\t\t\t\t\t\t\t\tconst temporary = path.join(root, `.${name}.${nonce}.tmp`)\n\t\t\t\t\t\t\t\tconst destination = path.join(root, name + \".json\")\n\t\t\t\t\t\t\t\tyield* Effect.acquireRelease(\n\t\t\t\t\t\t\t\t\tfs.open(temporary, { flag: \"wx\", mode: 0o600 }),\n\t\t\t\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\t\t\t\tfs.remove(temporary, { force: true }).pipe(Effect.orDie),\n\t\t\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\t\t\tEffect.flatMap((file) =>\n\t\t\t\t\t\t\t\t\t\tfile\n\t\t\t\t\t\t\t\t\t\t\t.writeAll(new TextEncoder().encode(encoded))\n\t\t\t\t\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\t\t\t\t\tEffect.uninterruptible,\n\t\t\t\t\t\t\t\t\t\t\t\tEffect.andThen(file.sync.pipe(Effect.uninterruptible)),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t// Keep rename and directory synchronization together if the caller is canceled.\n\t\t\t\t\t\t\t\tyield* Effect.uninterruptible(\n\t\t\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\t\t\tyield* fs.rename(temporary, destination)\n\t\t\t\t\t\t\t\t\t\tconst directory = yield* fs.open(root, { flag: \"r\" })\n\t\t\t\t\t\t\t\t\t\tyield* directory.sync.pipe(Effect.uninterruptible)\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t// The new high-water file is durable before any old record is removed.\n\t\t\t\t\t\t\t\tyield* compact\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t})\n\t})\n\nexport const layerMemory = Layer.effect(Store, memory)\nexport const layerDirectory = (root: string) =>\n\tLayer.effect(Store, directory(root))\n"],"mappings":"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"}
@@ -0,0 +1,375 @@
1
+ import { make as make$1 } from "../FailureGroup.js";
2
+ import { close } from "../release.js";
3
+ import { defaults } from "../Limits.js";
4
+ import { save } from "./Retention.js";
5
+ import { cleanupCause } from "../cleanup.js";
6
+ import { Execution, ExecutionError, LeaseExpired, RunnerClosing, SessionConflict, SessionStopped, StaleSession, Store, TerminationUnconfirmed, childOf, keyOf, negotiate, stoppedRecord, stoppingRecord } from "./model.js";
7
+ import { Array, Cause, Clock, Context, Data, Deferred, Duration, Effect, Equal, Exit, FiberHandle, FiberSet, HashMap, Layer, Option, RcMap, Ref, Result, Scope, Semaphore, SynchronizedRef } from "effect";
8
+ import { SecureRandom } from "effect/crypto";
9
+ // src/internal/runner/Supervisor.ts
10
+ var Supervisor = class extends Context.Service()("@graftland/plugin-remote/internal/runner/Supervisor") {};
11
+ const Launch = Data.taggedEnum();
12
+ const ExecutionState = Data.taggedEnum();
13
+ const Session = Data.taggedEnum();
14
+ function snapshot(state) {
15
+ return state._tag === "Loading" ? {
16
+ ...state.record,
17
+ phase: "Loading",
18
+ load: state.request,
19
+ launch: state.launch._tag === "Starting" ? { _tag: "Starting" } : {
20
+ _tag: "Registered",
21
+ child: state.launch.unit.identity
22
+ }
23
+ } : state.record;
24
+ }
25
+ const live = (state, now) => {
26
+ if (state._tag === "Stopping" || state._tag === "Stopped") return Result.fail(state.record.reason._tag === "Expired" ? LeaseExpired.make({ detail: "The session lease has expired" }) : SessionStopped.make({ detail: "The session is stopping or stopped" }));
27
+ return now >= state.deadline ? Result.fail(LeaseExpired.make({ detail: "The session lease has expired" })) : Result.succeed(state);
28
+ };
29
+ const executionOf = (state) => {
30
+ switch (state._tag) {
31
+ case "Open": return ExecutionState.Absent();
32
+ case "Loading": return state.launch._tag === "Registered" ? ExecutionState.Running({ unit: state.launch.unit }) : ExecutionState.Absent();
33
+ case "Loaded": return ExecutionState.Running({ unit: state.unit });
34
+ }
35
+ };
36
+ /** All state transitions are pure; the caller serializes persistence and publication. */
37
+ const beginLoad = (state, request, reply) => Session.Loading({
38
+ record: state.record,
39
+ deadline: state.deadline,
40
+ request,
41
+ reply,
42
+ launch: Launch.Starting()
43
+ });
44
+ const registerUnit = (state, unit) => {
45
+ if (state._tag !== "Loading") return Result.fail(SessionStopped.make({ detail: "The session is stopping or stopped" }));
46
+ if (state.launch._tag === "Registered") return Result.fail(ExecutionError.make({ detail: "An execution adapter registered more than one child" }));
47
+ return Result.succeed(Session.Loading({
48
+ ...state,
49
+ launch: Launch.Registered({ unit })
50
+ }));
51
+ };
52
+ const loaded = (state, code) => {
53
+ if (state._tag !== "Loading") return Result.fail(SessionStopped.make({ detail: "The session is stopping or stopped" }));
54
+ if (state.launch._tag !== "Registered") return Result.fail(ExecutionError.make({ detail: "Execution adapter returned without registering its child" }));
55
+ return Result.succeed(Session.Loaded({
56
+ deadline: state.deadline,
57
+ unit: state.launch.unit,
58
+ record: {
59
+ ...state.record,
60
+ phase: "Loaded",
61
+ load: state.request,
62
+ code,
63
+ child: state.launch.unit.identity
64
+ }
65
+ }));
66
+ };
67
+ const beginStop = (state, reason, reply, exit) => Session.Stopping({
68
+ record: stoppingRecord(snapshot(state), reason),
69
+ reply,
70
+ execution: Option.match(exit, {
71
+ onNone: () => executionOf(state),
72
+ onSome: (exit) => ExecutionState.Exited({ exit })
73
+ })
74
+ });
75
+ const nanos = (millis) => BigInt(Math.ceil(millis * 1e6));
76
+ const emptyTermination = {
77
+ kind: "Exited",
78
+ exit: {
79
+ code: 0,
80
+ signal: null
81
+ },
82
+ cause: Cause.empty
83
+ };
84
+ const exitCause = (exit) => Exit.isFailure(exit) ? exit.cause : Cause.empty;
85
+ /** A signal is a request; only the exited effect confirms that the execution has stopped. */
86
+ const terminate = (execution, grace, confirmation) => {
87
+ if (execution._tag === "Absent") return Effect.succeed(emptyTermination);
88
+ if (execution._tag === "Exited") return Effect.succeed({
89
+ ...emptyTermination,
90
+ exit: execution.exit
91
+ });
92
+ const child = execution.unit;
93
+ return Effect.gen(function* () {
94
+ const graceful = yield* child.interrupt.pipe(Effect.andThen(child.exited), Effect.timeoutOption(grace), Effect.exit);
95
+ if (Exit.isSuccess(graceful) && Option.isSome(graceful.value)) return {
96
+ ...emptyTermination,
97
+ exit: graceful.value.value
98
+ };
99
+ const killed = yield* Effect.exit(child.kill);
100
+ const forced = yield* child.exited.pipe(Effect.timeoutOption(confirmation), Effect.exit);
101
+ const cause = Cause.combine(Cause.combine(exitCause(graceful), exitCause(killed)), exitCause(forced));
102
+ if (Exit.isFailure(forced) || Option.isNone(forced.value)) return yield* TerminationUnconfirmed.make({
103
+ detail: "The child exit could not be confirmed",
104
+ cause
105
+ });
106
+ return {
107
+ kind: "Killed",
108
+ exit: forced.value.value,
109
+ cause
110
+ };
111
+ });
112
+ };
113
+ const initialize = (options = {}) => Effect.gen(function* () {
114
+ const store = yield* Store;
115
+ const execution = yield* Execution;
116
+ const random = yield* SecureRandom.SecureRandom;
117
+ const parent = yield* Effect.scope;
118
+ const owner = yield* Scope.fork(parent);
119
+ return {
120
+ store,
121
+ execution,
122
+ random,
123
+ owner,
124
+ workers: yield* FiberSet.make().pipe(Scope.provide(owner)),
125
+ locks: yield* RcMap.make({ lookup: (_key) => Semaphore.make(1) }).pipe(Scope.provide(owner)),
126
+ lease: Duration.toMillis(options.lease ?? "15 seconds"),
127
+ grace: Duration.toMillis(options.grace ?? "5 seconds"),
128
+ confirmation: Duration.toMillis(options.confirmationTimeout ?? "5 seconds"),
129
+ limits: options.limits ?? defaults,
130
+ records: yield* Ref.make(HashMap.empty()),
131
+ entries: yield* Ref.make(HashMap.empty()),
132
+ health: yield* make$1().pipe(Scope.provide(owner)),
133
+ closing: yield* Ref.make(false)
134
+ };
135
+ });
136
+ const operations = (runtime) => {
137
+ const { store, execution, workers, grace, confirmation, records, entries, health, closing } = runtime;
138
+ const poison = health.failCause;
139
+ const observe = (effect) => effect.pipe(Effect.asVoid, Effect.catchCause(poison));
140
+ const healthy = health.check.pipe(Effect.andThen(Effect.gen(function* () {
141
+ if (yield* Ref.get(closing)) return yield* RunnerClosing.make({ detail: "The runner is closing" });
142
+ })));
143
+ const persist = (record) => store.save(record).pipe(Effect.tapCause(poison), Effect.andThen(Ref.update(records, (all) => save(all, record))));
144
+ const status = (handle) => Ref.get(records).pipe(Effect.flatMap((all) => {
145
+ const found = HashMap.get(all, handle.token);
146
+ return Option.isSome(found) && Equal.equals(keyOf(found.value.handle.key), keyOf(handle.key)) && found.value.handle.generation === handle.generation ? Effect.succeed(found.value) : Effect.fail(StaleSession.make({ detail: "Unknown session or generation" }));
147
+ }));
148
+ const latest = (key) => Ref.get(records).pipe(Effect.map((all) => Array.reduce(Array.fromIterable(HashMap.values(all)), 0, (value, record) => Equal.equals(keyOf(record.handle.key), keyOf(key)) ? Math.max(value, record.handle.generation) : value)));
149
+ const entryFor = (handle) => Effect.gen(function* () {
150
+ yield* status(handle);
151
+ const all = yield* Ref.get(entries);
152
+ const found = HashMap.get(all, handle.token);
153
+ if (Option.isNone(found)) return yield* SessionStopped.make({ detail: "The session was retired during recovery" });
154
+ return found.value;
155
+ });
156
+ const commit = (entry, transition) => SynchronizedRef.updateEffect(entry.state, (state) => Effect.gen(function* () {
157
+ const next = yield* Effect.fromResult(transition(state));
158
+ yield* persist(snapshot(next));
159
+ return next;
160
+ }));
161
+ const finishStop = (entry, state, saved) => Effect.gen(function* () {
162
+ yield* FiberHandle.clear(entry.loading);
163
+ const result = yield* terminate(state.execution, grace, confirmation);
164
+ const closed = yield* Effect.exit(close(entry.unitScope, Exit.void));
165
+ const termination = {
166
+ ...result,
167
+ cause: Cause.combine(result.cause, exitCause(closed))
168
+ };
169
+ const record = stoppedRecord(state.record.previous, state.record.reason, termination);
170
+ yield* SynchronizedRef.updateEffect(entry.state, () => persist(record).pipe(Effect.as(Session.Stopped({
171
+ record,
172
+ reply: state.reply
173
+ }))));
174
+ if (Exit.isFailure(saved)) return yield* Effect.failCause(saved.cause);
175
+ return termination;
176
+ });
177
+ /** Called with the session ref locked; the worker starts after its transition is published. */
178
+ const stopLocked = (entry, state, reason, exit) => Effect.gen(function* () {
179
+ if (state._tag === "Stopping" || state._tag === "Stopped") return [state.reply, state];
180
+ const reply = yield* Deferred.make();
181
+ const next = beginStop(state, reason, reply, exit);
182
+ const saved = yield* Effect.exit(persist(next.record));
183
+ yield* FiberSet.run(workers, finishStop(entry, next, saved).pipe(Effect.onExit((result) => Deferred.done(reply, result)), observe), { startImmediately: false });
184
+ return [reply, next];
185
+ });
186
+ const stop = (entry, reason, exit = Option.none()) => SynchronizedRef.modifyEffect(entry.state, (state) => stopLocked(entry, state, reason, exit)).pipe(Effect.uninterruptible);
187
+ const scheduleLease = (entry, deadline) => FiberHandle.run(entry.timer, observe(Effect.gen(function* () {
188
+ const now = yield* Clock.monotonicTimeNanos;
189
+ yield* Effect.sleep(Duration.nanos(deadline > now ? deadline - now : 0n));
190
+ yield* SynchronizedRef.updateEffect(entry.state, (state) => {
191
+ if (state._tag === "Stopping" || state._tag === "Stopped" || state.deadline !== deadline) return Effect.succeed(state);
192
+ return stopLocked(entry, state, { _tag: "Expired" }, Option.none()).pipe(Effect.map(([, next]) => next));
193
+ });
194
+ })), { startImmediately: false });
195
+ const register = (entry, unit) => SynchronizedRef.updateEffect(entry.state, (state) => Effect.gen(function* () {
196
+ const now = yield* Clock.monotonicTimeNanos;
197
+ const current = yield* Effect.fromResult(live(state, now));
198
+ const next = yield* Effect.fromResult(registerUnit(current, unit));
199
+ yield* unit.renew(Number(current.deadline - (yield* Clock.monotonicTimeNanos)) / 1e6);
200
+ yield* persist(snapshot(next));
201
+ yield* FiberSet.run(workers, observe(unit.exited.pipe(Effect.flatMap((exit) => stop(entry, { _tag: "Exited" }, Option.some(exit))))));
202
+ return next;
203
+ })).pipe(Effect.uninterruptible);
204
+ const runLoad = (entry, state) => execution.spawn(state.record.handle, state.request, state.record.limits).pipe(Scope.provide(entry.unitScope), Effect.flatMap((unit) => register(entry, unit).pipe(Effect.andThen(unit.start), Effect.as(unit.code))), Effect.tap((code) => commit(entry, (current) => loaded(current, code))), Effect.onExit((result) => Effect.gen(function* () {
205
+ if (Exit.isSuccess(result)) {
206
+ yield* Deferred.done(state.reply, result);
207
+ return;
208
+ }
209
+ if ((yield* SynchronizedRef.get(entry.state))._tag === "Loading") yield* stop(entry, {
210
+ _tag: "LoadFailed",
211
+ cause: result.cause
212
+ });
213
+ const healthCause = yield* health.cause;
214
+ yield* Deferred.failCause(state.reply, Cause.combine(result.cause, healthCause));
215
+ })), Effect.exit, Effect.asVoid);
216
+ return {
217
+ persist,
218
+ status,
219
+ latest,
220
+ entryFor,
221
+ stop,
222
+ scheduleLease,
223
+ runLoad,
224
+ healthy
225
+ };
226
+ };
227
+ const recover = (runtime, actions) => Effect.gen(function* () {
228
+ const { store, execution, confirmation, records } = runtime;
229
+ const { persist } = actions;
230
+ const stored = yield* store.list;
231
+ yield* Ref.set(records, HashMap.fromIterable(Array.map(stored, (record) => [record.handle.token, record])));
232
+ for (const record of stored) {
233
+ if (record.phase === "Stopped") continue;
234
+ const child = childOf(record);
235
+ const termination = Option.isNone(child) ? emptyTermination : yield* execution.recover(child.value).pipe(Effect.timeout(confirmation), Effect.catchTags({
236
+ ExecutionError: (error) => Effect.fail(TerminationUnconfirmed.make({
237
+ detail: "Orphan recovery did not confirm exit",
238
+ cause: Cause.fail(error)
239
+ })),
240
+ TimeoutError: (error) => Effect.fail(TerminationUnconfirmed.make({
241
+ detail: "Orphan recovery did not confirm exit",
242
+ cause: Cause.fail(error)
243
+ }))
244
+ }));
245
+ yield* persist(stoppedRecord(record.phase === "Stopping" ? record.previous : record, { _tag: "Recovery" }, termination));
246
+ }
247
+ });
248
+ const ownShutdown = (runtime, actions) => Effect.gen(function* () {
249
+ const { entries, health, closing } = runtime;
250
+ const { stop } = actions;
251
+ yield* Effect.addFinalizer(() => Effect.gen(function* () {
252
+ yield* Ref.set(closing, true);
253
+ const all = yield* Ref.get(entries);
254
+ const exits = yield* Effect.forEach(HashMap.values(all), (entry) => stop(entry, { _tag: "Shutdown" }).pipe(Effect.flatMap(Deferred.await), Effect.exit));
255
+ const initial = yield* health.cause;
256
+ const cause = Array.reduce(exits, initial, (cause, exit) => Cause.combine(cause, Exit.isFailure(exit) ? exit.cause : exit.value.cause));
257
+ if (cause.reasons.length > 0) return yield* Effect.failCause(cleanupCause(cause));
258
+ }));
259
+ });
260
+ const protocol = (runtime, actions) => Effect.gen(function* () {
261
+ const { random, owner, locks, lease, limits, records, entries, health } = runtime;
262
+ const { persist, status, latest, entryFor, stop, scheduleLease, runLoad, healthy } = actions;
263
+ return Supervisor.of({
264
+ await: health.await,
265
+ status,
266
+ highWater: (key) => latest(key).pipe(Effect.map((value) => value === 0 ? null : value)),
267
+ open: (request) => Effect.scoped(Effect.gen(function* () {
268
+ yield* healthy;
269
+ const leaseMillis = Duration.toMillis(request.lease ?? lease);
270
+ const negotiated = negotiate(limits, request.limits ?? defaults);
271
+ return yield* (yield* RcMap.get(locks, keyOf(request.key))).withPermit(Effect.gen(function* () {
272
+ yield* healthy;
273
+ const allRecords = yield* Ref.get(records);
274
+ const same = Array.filter(Array.fromIterable(HashMap.values(allRecords)), (row) => Equal.equals(keyOf(row.handle.key), keyOf(request.key)));
275
+ const prior = Array.findFirst(same, (row) => row.requestId === request.requestId);
276
+ if (Option.isSome(prior)) return prior.value;
277
+ const generation = yield* latest(request.key);
278
+ if (generation !== (request.expectedGeneration ?? 0)) return yield* StaleSession.make({ detail: "Open expectedGeneration does not match the generation high-water mark" });
279
+ for (const record of same) {
280
+ const allEntries = yield* Ref.get(entries);
281
+ const entry = HashMap.get(allEntries, record.handle.token);
282
+ if (Option.isSome(entry)) yield* stop(entry.value, { _tag: "Superseded" }).pipe(Effect.flatMap(Deferred.await), Effect.tap((result) => result.cause.reasons.length === 0 ? Effect.void : Effect.logWarning("Superseded remote execution cleanup failed", result.cause).pipe(Effect.annotateLogs({
283
+ "remote.identity": record.handle.key.identity,
284
+ "remote.instance": record.handle.key.instance,
285
+ "remote.generation": record.handle.generation
286
+ }))));
287
+ }
288
+ yield* healthy;
289
+ const token = yield* random.uuidV4();
290
+ const record = {
291
+ version: 1,
292
+ phase: "Open",
293
+ handle: {
294
+ key: request.key,
295
+ token,
296
+ generation: generation + 1
297
+ },
298
+ requestId: request.requestId,
299
+ leaseMillis,
300
+ limits: negotiated
301
+ };
302
+ return yield* Effect.uninterruptible(Effect.gen(function* () {
303
+ yield* persist(record);
304
+ const deadline = (yield* Clock.monotonicTimeNanos) + nanos(leaseMillis);
305
+ const scope = yield* Scope.fork(owner);
306
+ const entry = {
307
+ state: yield* SynchronizedRef.make(Session.Open({
308
+ record,
309
+ deadline
310
+ })),
311
+ scope,
312
+ unitScope: yield* Scope.fork(scope),
313
+ timer: yield* FiberHandle.make().pipe(Scope.provide(scope)),
314
+ loading: yield* FiberHandle.make().pipe(Scope.provide(scope))
315
+ };
316
+ const retained = yield* Ref.get(records);
317
+ const old = yield* Ref.modify(entries, (all) => [Array.filter(Array.fromIterable(HashMap.entries(all)), ([key]) => !HashMap.has(retained, key)), HashMap.set(HashMap.filter(all, (_, key) => HashMap.has(retained, key)), token, entry)]);
318
+ for (const [, retired] of old) yield* close(retired.scope, Exit.void);
319
+ yield* scheduleLease(entry, deadline);
320
+ return record;
321
+ }));
322
+ }));
323
+ })),
324
+ renew: (handle) => Effect.gen(function* () {
325
+ yield* healthy;
326
+ const entry = yield* entryFor(handle);
327
+ return yield* SynchronizedRef.modifyEffect(entry.state, (state) => Effect.gen(function* () {
328
+ const now = yield* Clock.monotonicTimeNanos;
329
+ const current = yield* Effect.fromResult(live(state, now));
330
+ const running = executionOf(current);
331
+ if (running._tag === "Running") yield* running.unit.renew(current.record.leaseMillis);
332
+ const deadline = now + nanos(current.record.leaseMillis);
333
+ yield* scheduleLease(entry, deadline);
334
+ return [current.record.leaseMillis, {
335
+ ...current,
336
+ deadline
337
+ }];
338
+ }));
339
+ }),
340
+ load: (handle, request) => Effect.gen(function* () {
341
+ yield* healthy;
342
+ const entry = yield* entryFor(handle);
343
+ return yield* yield* SynchronizedRef.modifyEffect(entry.state, (state) => Effect.gen(function* () {
344
+ const now = yield* Clock.monotonicTimeNanos;
345
+ const current = yield* Effect.fromResult(live(state, now));
346
+ if (current._tag !== "Open") {
347
+ if ((current._tag === "Loading" ? current.request : current.record.load).specifier !== request.specifier) return yield* SessionConflict.make({ detail: "Load was already requested with a different specifier" });
348
+ return [current._tag === "Loading" ? Deferred.await(current.reply) : Effect.succeed(current.record.code), current];
349
+ }
350
+ const done = yield* Deferred.make();
351
+ const next = beginLoad(current, request, done);
352
+ yield* persist(snapshot(next));
353
+ if (next._tag === "Loading") yield* FiberHandle.run(entry.loading, runLoad(entry, next), { startImmediately: false });
354
+ return [Deferred.await(done), next];
355
+ })).pipe(Effect.uninterruptible);
356
+ }),
357
+ dispose: (handle) => Effect.gen(function* () {
358
+ const record = yield* status(handle);
359
+ if (record.phase === "Stopped") return record.termination;
360
+ const entry = yield* entryFor(handle);
361
+ return yield* stop(entry, { _tag: "Disposed" }).pipe(Effect.flatMap(Deferred.await));
362
+ })
363
+ });
364
+ });
365
+ const make = (options = {}) => Effect.gen(function* () {
366
+ const runtime = yield* initialize(options);
367
+ const actions = operations(runtime);
368
+ yield* recover(runtime, actions);
369
+ yield* ownShutdown(runtime, actions);
370
+ return yield* protocol(runtime, actions);
371
+ });
372
+ const layer = (options = {}) => Layer.effect(Supervisor, make(options));
373
+ export { Supervisor, layer, make };
374
+
375
+ //# sourceMappingURL=Supervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Supervisor.js","names":["FailureGroup.make","Retention.save","Release.close"],"sources":["../../../src/internal/runner/Supervisor.ts"],"sourcesContent":["import * as FailureGroup from \"../FailureGroup\"\nimport {\n\tArray,\n\tCause,\n\tClock,\n\tContext,\n\tData,\n\tDeferred,\n\tDuration,\n\tEffect,\n\tEqual,\n\tExit,\n\tFiberHandle,\n\tFiberSet,\n\tHashMap,\n\tLayer,\n\tOption,\n\tRcMap,\n\tRef,\n\tResult,\n\tScope,\n\tSemaphore,\n\tSynchronizedRef,\n} from \"effect\"\nimport * as Release from \"../release\"\nimport { SecureRandom } from \"effect/crypto\"\nimport * as Retention from \"./Retention\"\nimport { cleanupCause } from \"../cleanup\"\nimport {\n\tExecution,\n\tStore,\n\tStaleSession,\n\tLeaseExpired,\n\tSessionStopped,\n\tSessionConflict,\n\tStateStorageError,\n\tExecutionError,\n\tPackageError,\n\tTerminationUnconfirmed,\n\tRunnerClosing,\n\tchildOf,\n\tdefaults,\n\tkeyOf,\n\tnegotiate,\n\tstoppingRecord,\n\tstoppedRecord,\n\ttype ActiveRecord,\n\ttype CodeIdentity,\n\ttype ExitStatus,\n\ttype Handle,\n\ttype Key,\n\ttype Limits,\n\ttype Load,\n\ttype SessionRecord,\n\ttype SessionKey,\n\ttype StopReason,\n\ttype Termination,\n\ttype Unit,\n\ttype OpenRecord,\n\ttype LoadedRecord,\n\ttype StoppingRecord,\n\ttype StoppedRecord,\n} from \"./model\"\n\nexport type SupervisorError =\n\t| StaleSession\n\t| LeaseExpired\n\t| SessionStopped\n\t| SessionConflict\n\t| StateStorageError\n\t| ExecutionError\n\t| PackageError\n\t| TerminationUnconfirmed\n\t| RunnerClosing\nexport interface Options {\n\treadonly lease?: Duration.Input\n\treadonly grace?: Duration.Input\n\treadonly confirmationTimeout?: Duration.Input\n\treadonly limits?: Limits\n}\nexport interface Open {\n\treadonly key: Key\n\treadonly requestId: string\n\treadonly expectedGeneration?: number | null\n\treadonly lease?: Duration.Input\n\treadonly limits?: Limits\n}\nexport class Supervisor extends Context.Service<\n\tSupervisor,\n\t{\n\t\treadonly await: Effect.Effect<never, SupervisorError>\n\t\treadonly status: (\n\t\t\thandle: Handle,\n\t\t) => Effect.Effect<SessionRecord, StaleSession>\n\t\treadonly highWater: (key: Key) => Effect.Effect<number | null>\n\t\treadonly open: (\n\t\t\trequest: Open,\n\t\t) => Effect.Effect<SessionRecord, SupervisorError>\n\t\treadonly renew: (handle: Handle) => Effect.Effect<number, SupervisorError>\n\t\treadonly load: (\n\t\t\thandle: Handle,\n\t\t\trequest: Load,\n\t\t) => Effect.Effect<CodeIdentity, SupervisorError>\n\t\treadonly dispose: (\n\t\t\thandle: Handle,\n\t\t) => Effect.Effect<Termination, SupervisorError>\n\t}\n>()(\"@graftland/plugin-remote/internal/runner/Supervisor\") {}\n\ntype Launch = Data.TaggedEnum<{\n\tStarting: {}\n\tRegistered: { readonly unit: Unit }\n}>\nconst Launch = Data.taggedEnum<Launch>()\ntype ExecutionState = Data.TaggedEnum<{\n\tAbsent: {}\n\tRunning: { readonly unit: Unit }\n\tExited: { readonly exit: ExitStatus }\n}>\nconst ExecutionState = Data.taggedEnum<ExecutionState>()\ntype LoadReply = Deferred.Deferred<CodeIdentity, SupervisorError>\ntype StopReply = Deferred.Deferred<Termination, SupervisorError>\ntype Session = Data.TaggedEnum<{\n\tOpen: { readonly record: typeof OpenRecord.Type; readonly deadline: bigint }\n\tLoading: {\n\t\treadonly record: typeof OpenRecord.Type\n\t\treadonly request: Load\n\t\treadonly launch: Launch\n\t\treadonly reply: LoadReply\n\t\treadonly deadline: bigint\n\t}\n\tLoaded: {\n\t\treadonly record: typeof LoadedRecord.Type\n\t\treadonly unit: Unit\n\t\treadonly deadline: bigint\n\t}\n\tStopping: {\n\t\treadonly record: typeof StoppingRecord.Type\n\t\treadonly execution: ExecutionState\n\t\treadonly reply: StopReply\n\t}\n\tStopped: {\n\t\treadonly record: typeof StoppedRecord.Type\n\t\treadonly reply: StopReply\n\t}\n}>\nconst Session = Data.taggedEnum<Session>()\ntype Live = Extract<Session, { readonly _tag: \"Open\" | \"Loading\" | \"Loaded\" }>\ntype Loading = Extract<Session, { readonly _tag: \"Loading\" }>\ntype Stopping = Extract<Session, { readonly _tag: \"Stopping\" }>\ninterface Entry {\n\treadonly state: SynchronizedRef.SynchronizedRef<Session>\n\treadonly timer: FiberHandle.FiberHandle<void, never>\n\treadonly loading: FiberHandle.FiberHandle<void, never>\n\treadonly scope: Scope.Closeable\n\treadonly unitScope: Scope.Closeable\n}\nfunction snapshot(state: Live): ActiveRecord\nfunction snapshot(state: Session): SessionRecord\nfunction snapshot(state: Session): SessionRecord {\n\treturn state._tag === \"Loading\"\n\t\t? {\n\t\t\t\t...state.record,\n\t\t\t\tphase: \"Loading\",\n\t\t\t\tload: state.request,\n\t\t\t\tlaunch:\n\t\t\t\t\tstate.launch._tag === \"Starting\"\n\t\t\t\t\t\t? { _tag: \"Starting\" }\n\t\t\t\t\t\t: { _tag: \"Registered\", child: state.launch.unit.identity },\n\t\t\t}\n\t\t: state.record\n}\nconst live = (\n\tstate: Session,\n\tnow: bigint,\n): Result.Result<Live, LeaseExpired | SessionStopped> => {\n\tif (state._tag === \"Stopping\" || state._tag === \"Stopped\")\n\t\treturn Result.fail(\n\t\t\tstate.record.reason._tag === \"Expired\"\n\t\t\t\t? LeaseExpired.make({\n\t\t\t\t\t\tdetail: \"The session lease has expired\",\n\t\t\t\t\t})\n\t\t\t\t: SessionStopped.make({\n\t\t\t\t\t\tdetail: \"The session is stopping or stopped\",\n\t\t\t\t\t}),\n\t\t)\n\treturn now >= state.deadline\n\t\t? Result.fail(\n\t\t\t\tLeaseExpired.make({\n\t\t\t\t\tdetail: \"The session lease has expired\",\n\t\t\t\t}),\n\t\t\t)\n\t\t: Result.succeed(state)\n}\nconst executionOf = (state: Live): ExecutionState => {\n\tswitch (state._tag) {\n\t\tcase \"Open\":\n\t\t\treturn ExecutionState.Absent()\n\t\tcase \"Loading\":\n\t\t\treturn state.launch._tag === \"Registered\"\n\t\t\t\t? ExecutionState.Running({ unit: state.launch.unit })\n\t\t\t\t: ExecutionState.Absent()\n\t\tcase \"Loaded\":\n\t\t\treturn ExecutionState.Running({ unit: state.unit })\n\t}\n}\n/** All state transitions are pure; the caller serializes persistence and publication. */\nconst beginLoad = (\n\tstate: Extract<Session, { _tag: \"Open\" }>,\n\trequest: Load,\n\treply: LoadReply,\n): Loading =>\n\tSession.Loading({\n\t\trecord: state.record,\n\t\tdeadline: state.deadline,\n\t\trequest,\n\t\treply,\n\t\tlaunch: Launch.Starting(),\n\t})\nconst registerUnit = (\n\tstate: Session,\n\tunit: Unit,\n): Result.Result<Session, SessionStopped | ExecutionError> => {\n\tif (state._tag !== \"Loading\")\n\t\treturn Result.fail(\n\t\t\tSessionStopped.make({\n\t\t\t\tdetail: \"The session is stopping or stopped\",\n\t\t\t}),\n\t\t)\n\tif (state.launch._tag === \"Registered\")\n\t\treturn Result.fail(\n\t\t\tExecutionError.make({\n\t\t\t\tdetail: \"An execution adapter registered more than one child\",\n\t\t\t}),\n\t\t)\n\treturn Result.succeed(\n\t\tSession.Loading({ ...state, launch: Launch.Registered({ unit }) }),\n\t)\n}\nconst loaded = (\n\tstate: Session,\n\tcode: CodeIdentity,\n): Result.Result<Session, SessionStopped | ExecutionError> => {\n\tif (state._tag !== \"Loading\")\n\t\treturn Result.fail(\n\t\t\tSessionStopped.make({\n\t\t\t\tdetail: \"The session is stopping or stopped\",\n\t\t\t}),\n\t\t)\n\tif (state.launch._tag !== \"Registered\")\n\t\treturn Result.fail(\n\t\t\tExecutionError.make({\n\t\t\t\tdetail: \"Execution adapter returned without registering its child\",\n\t\t\t}),\n\t\t)\n\treturn Result.succeed(\n\t\tSession.Loaded({\n\t\t\tdeadline: state.deadline,\n\t\t\tunit: state.launch.unit,\n\t\t\trecord: {\n\t\t\t\t...state.record,\n\t\t\t\tphase: \"Loaded\",\n\t\t\t\tload: state.request,\n\t\t\t\tcode,\n\t\t\t\tchild: state.launch.unit.identity,\n\t\t\t},\n\t\t}),\n\t)\n}\nconst beginStop = (\n\tstate: Live,\n\treason: StopReason,\n\treply: StopReply,\n\texit: Option.Option<ExitStatus>,\n): Stopping =>\n\tSession.Stopping({\n\t\trecord: stoppingRecord(snapshot(state), reason),\n\t\treply,\n\t\texecution: Option.match(exit, {\n\t\t\tonNone: () => executionOf(state),\n\t\t\tonSome: (exit) => ExecutionState.Exited({ exit }),\n\t\t}),\n\t})\nconst nanos = (millis: number) => BigInt(Math.ceil(millis * 1_000_000))\nconst emptyTermination: Termination = {\n\tkind: \"Exited\",\n\texit: { code: 0, signal: null },\n\tcause: Cause.empty,\n}\nconst exitCause = <A, E>(exit: Exit.Exit<A, E>) =>\n\tExit.isFailure(exit) ? exit.cause : Cause.empty\n\n/** A signal is a request; only the exited effect confirms that the execution has stopped. */\nconst terminate = (\n\texecution: ExecutionState,\n\tgrace: number,\n\tconfirmation: number,\n): Effect.Effect<Termination, TerminationUnconfirmed> => {\n\tif (execution._tag === \"Absent\") return Effect.succeed(emptyTermination)\n\tif (execution._tag === \"Exited\")\n\t\treturn Effect.succeed({ ...emptyTermination, exit: execution.exit })\n\tconst child = execution.unit\n\treturn Effect.gen(function* () {\n\t\tconst graceful = yield* child.interrupt.pipe(\n\t\t\tEffect.andThen(child.exited),\n\t\t\tEffect.timeoutOption(grace),\n\t\t\tEffect.exit,\n\t\t)\n\t\tif (Exit.isSuccess(graceful) && Option.isSome(graceful.value))\n\t\t\treturn { ...emptyTermination, exit: graceful.value.value }\n\t\tconst killed = yield* Effect.exit(child.kill)\n\t\tconst forced = yield* child.exited.pipe(\n\t\t\tEffect.timeoutOption(confirmation),\n\t\t\tEffect.exit,\n\t\t)\n\t\tconst cause = Cause.combine(\n\t\t\tCause.combine(exitCause(graceful), exitCause(killed)),\n\t\t\texitCause(forced),\n\t\t)\n\t\tif (Exit.isFailure(forced) || Option.isNone(forced.value))\n\t\t\treturn yield* TerminationUnconfirmed.make({\n\t\t\t\tdetail: \"The child exit could not be confirmed\",\n\t\t\t\tcause,\n\t\t\t})\n\t\treturn {\n\t\t\tkind: \"Killed\",\n\t\t\texit: forced.value.value,\n\t\t\tcause,\n\t\t} satisfies Termination\n\t})\n}\n\nconst initialize = (options: Options = {}) =>\n\tEffect.gen(function* () {\n\t\tconst store = yield* Store\n\t\tconst execution = yield* Execution\n\t\tconst random = yield* SecureRandom.SecureRandom\n\t\tconst parent = yield* Effect.scope\n\t\tconst owner = yield* Scope.fork(parent)\n\t\t// Cleanup must continue after a health failure so every registered process is reaped.\n\t\tconst workers = yield* FiberSet.make<void, never>().pipe(\n\t\t\tScope.provide(owner),\n\t\t)\n\t\tconst locks = yield* RcMap.make({\n\t\t\tlookup: (_key: SessionKey) => Semaphore.make(1),\n\t\t}).pipe(Scope.provide(owner))\n\t\tconst lease = Duration.toMillis(options.lease ?? \"15 seconds\")\n\t\tconst grace = Duration.toMillis(options.grace ?? \"5 seconds\")\n\t\tconst confirmation = Duration.toMillis(\n\t\t\toptions.confirmationTimeout ?? \"5 seconds\",\n\t\t)\n\t\tconst limits = options.limits ?? defaults\n\t\tconst records = yield* Ref.make(HashMap.empty<string, SessionRecord>())\n\t\tconst entries = yield* Ref.make(HashMap.empty<string, Entry>())\n\t\tconst health = yield* FailureGroup.make<SupervisorError>().pipe(\n\t\t\tScope.provide(owner),\n\t\t)\n\t\tconst closing = yield* Ref.make(false)\n\t\treturn {\n\t\t\tstore,\n\t\t\texecution,\n\t\t\trandom,\n\t\t\towner,\n\t\t\tworkers,\n\t\t\tlocks,\n\t\t\tlease,\n\t\t\tgrace,\n\t\t\tconfirmation,\n\t\t\tlimits,\n\t\t\trecords,\n\t\t\tentries,\n\t\t\thealth,\n\t\t\tclosing,\n\t\t}\n\t})\ntype Runtime = Effect.Success<ReturnType<typeof initialize>>\nconst operations = (runtime: Runtime) => {\n\tconst {\n\t\tstore,\n\t\texecution,\n\t\tworkers,\n\t\tgrace,\n\t\tconfirmation,\n\t\trecords,\n\t\tentries,\n\t\thealth,\n\t\tclosing,\n\t} = runtime\n\n\tconst poison = health.failCause\n\tconst observe = <A>(effect: Effect.Effect<A, SupervisorError>) =>\n\t\teffect.pipe(Effect.asVoid, Effect.catchCause(poison))\n\tconst healthy = health.check.pipe(\n\t\tEffect.andThen(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tif (yield* Ref.get(closing))\n\t\t\t\t\treturn yield* RunnerClosing.make({ detail: \"The runner is closing\" })\n\t\t\t}),\n\t\t),\n\t)\n\tconst persist = (record: SessionRecord) =>\n\t\tstore\n\t\t\t.save(record)\n\t\t\t.pipe(\n\t\t\t\tEffect.tapCause(poison),\n\t\t\t\tEffect.andThen(\n\t\t\t\t\tRef.update(records, (all) => Retention.save(all, record)),\n\t\t\t\t),\n\t\t\t)\n\tconst status = (handle: Handle) =>\n\t\tRef.get(records).pipe(\n\t\t\tEffect.flatMap((all) => {\n\t\t\t\tconst found = HashMap.get(all, handle.token)\n\t\t\t\treturn Option.isSome(found) &&\n\t\t\t\t\tEqual.equals(keyOf(found.value.handle.key), keyOf(handle.key)) &&\n\t\t\t\t\tfound.value.handle.generation === handle.generation\n\t\t\t\t\t? Effect.succeed(found.value)\n\t\t\t\t\t: Effect.fail(\n\t\t\t\t\t\t\tStaleSession.make({\n\t\t\t\t\t\t\t\tdetail: \"Unknown session or generation\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t}),\n\t\t)\n\tconst latest = (key: Key) =>\n\t\tRef.get(records).pipe(\n\t\t\tEffect.map((all) =>\n\t\t\t\tArray.reduce(\n\t\t\t\t\tArray.fromIterable(HashMap.values(all)),\n\t\t\t\t\t0,\n\t\t\t\t\t(value, record) =>\n\t\t\t\t\t\tEqual.equals(keyOf(record.handle.key), keyOf(key))\n\t\t\t\t\t\t\t? Math.max(value, record.handle.generation)\n\t\t\t\t\t\t\t: value,\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\tconst entryFor = (handle: Handle) =>\n\t\tEffect.gen(function* () {\n\t\t\tyield* status(handle)\n\t\t\tconst all = yield* Ref.get(entries)\n\t\t\tconst found = HashMap.get(all, handle.token)\n\t\t\tif (Option.isNone(found))\n\t\t\t\treturn yield* SessionStopped.make({\n\t\t\t\t\tdetail: \"The session was retired during recovery\",\n\t\t\t\t})\n\t\t\treturn found.value\n\t\t})\n\tconst commit = (\n\t\tentry: Entry,\n\t\ttransition: (\n\t\t\tstate: Session,\n\t\t) => Result.Result<Session, ExecutionError | SessionStopped>,\n\t) =>\n\t\tSynchronizedRef.updateEffect(entry.state, (state) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst next = yield* Effect.fromResult(transition(state))\n\t\t\t\tyield* persist(snapshot(next))\n\t\t\t\treturn next\n\t\t\t}),\n\t\t)\n\tconst finishStop = (\n\t\tentry: Entry,\n\t\tstate: Stopping,\n\t\tsaved: Exit.Exit<void, StateStorageError>,\n\t) =>\n\t\tEffect.gen(function* () {\n\t\t\tyield* FiberHandle.clear(entry.loading)\n\t\t\tconst result = yield* terminate(state.execution, grace, confirmation)\n\t\t\tconst closed = yield* Effect.exit(\n\t\t\t\tRelease.close(entry.unitScope, Exit.void),\n\t\t\t)\n\t\t\tconst termination: Termination = {\n\t\t\t\t...result,\n\t\t\t\tcause: Cause.combine(result.cause, exitCause(closed)),\n\t\t\t}\n\t\t\tconst record = stoppedRecord(\n\t\t\t\tstate.record.previous,\n\t\t\t\tstate.record.reason,\n\t\t\t\ttermination,\n\t\t\t)\n\t\t\tyield* SynchronizedRef.updateEffect(entry.state, () =>\n\t\t\t\tpersist(record).pipe(\n\t\t\t\t\tEffect.as(Session.Stopped({ record, reply: state.reply })),\n\t\t\t\t),\n\t\t\t)\n\t\t\tif (Exit.isFailure(saved)) return yield* Effect.failCause(saved.cause)\n\t\t\treturn termination\n\t\t})\n\t/** Called with the session ref locked; the worker starts after its transition is published. */\n\tconst stopLocked = (\n\t\tentry: Entry,\n\t\tstate: Session,\n\t\treason: StopReason,\n\t\texit: Option.Option<ExitStatus>,\n\t): Effect.Effect<readonly [StopReply, Session]> =>\n\t\tEffect.gen(function* () {\n\t\t\tif (state._tag === \"Stopping\" || state._tag === \"Stopped\")\n\t\t\t\treturn [state.reply, state]\n\t\t\tconst reply = yield* Deferred.make<Termination, SupervisorError>()\n\t\t\tconst next = beginStop(state, reason, reply, exit)\n\t\t\t// Fence in memory even when the journal cannot acknowledge the transition.\n\t\t\tconst saved = yield* Effect.exit(persist(next.record))\n\t\t\tyield* FiberSet.run(\n\t\t\t\tworkers,\n\t\t\t\tfinishStop(entry, next, saved).pipe(\n\t\t\t\t\tEffect.onExit((result) => Deferred.done(reply, result)),\n\t\t\t\t\tobserve,\n\t\t\t\t),\n\t\t\t\t{ startImmediately: false },\n\t\t\t)\n\t\t\treturn [reply, next]\n\t\t})\n\tconst stop = (\n\t\tentry: Entry,\n\t\treason: StopReason,\n\t\texit: Option.Option<ExitStatus> = Option.none(),\n\t) =>\n\t\tSynchronizedRef.modifyEffect(entry.state, (state) =>\n\t\t\tstopLocked(entry, state, reason, exit),\n\t\t).pipe(Effect.uninterruptible)\n\tconst scheduleLease = (entry: Entry, deadline: bigint) =>\n\t\tFiberHandle.run(\n\t\t\tentry.timer,\n\t\t\tobserve(\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst now = yield* Clock.monotonicTimeNanos\n\t\t\t\t\tyield* Effect.sleep(\n\t\t\t\t\t\tDuration.nanos(deadline > now ? deadline - now : 0n),\n\t\t\t\t\t)\n\t\t\t\t\tyield* SynchronizedRef.updateEffect(entry.state, (state) => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstate._tag === \"Stopping\" ||\n\t\t\t\t\t\t\tstate._tag === \"Stopped\" ||\n\t\t\t\t\t\t\tstate.deadline !== deadline\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn Effect.succeed(state)\n\t\t\t\t\t\treturn stopLocked(\n\t\t\t\t\t\t\tentry,\n\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\t{ _tag: \"Expired\" },\n\t\t\t\t\t\t\tOption.none(),\n\t\t\t\t\t\t).pipe(Effect.map(([, next]) => next))\n\t\t\t\t\t})\n\t\t\t\t}),\n\t\t\t),\n\t\t\t{ startImmediately: false },\n\t\t)\n\tconst register = (entry: Entry, unit: Unit) =>\n\t\tSynchronizedRef.updateEffect(entry.state, (state) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst now = yield* Clock.monotonicTimeNanos\n\t\t\t\tconst current = yield* Effect.fromResult(live(state, now))\n\t\t\t\tconst next = yield* Effect.fromResult(registerUnit(current, unit))\n\t\t\t\tyield* unit.renew(\n\t\t\t\t\tNumber(current.deadline - (yield* Clock.monotonicTimeNanos)) /\n\t\t\t\t\t\t1_000_000,\n\t\t\t\t)\n\t\t\t\tyield* persist(snapshot(next))\n\t\t\t\tyield* FiberSet.run(\n\t\t\t\t\tworkers,\n\t\t\t\t\tobserve(\n\t\t\t\t\t\tunit.exited.pipe(\n\t\t\t\t\t\t\tEffect.flatMap((exit) =>\n\t\t\t\t\t\t\t\tstop(entry, { _tag: \"Exited\" }, Option.some(exit)),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\treturn next\n\t\t\t}),\n\t\t).pipe(Effect.uninterruptible)\n\tconst runLoad = (entry: Entry, state: Loading) =>\n\t\texecution\n\t\t\t.spawn(state.record.handle, state.request, state.record.limits)\n\t\t\t.pipe(\n\t\t\t\tScope.provide(entry.unitScope),\n\t\t\t\tEffect.flatMap((unit) =>\n\t\t\t\t\tregister(entry, unit).pipe(\n\t\t\t\t\t\tEffect.andThen(unit.start),\n\t\t\t\t\t\tEffect.as(unit.code),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tEffect.tap((code) => commit(entry, (current) => loaded(current, code))),\n\t\t\t\tEffect.onExit((result) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tif (Exit.isSuccess(result)) {\n\t\t\t\t\t\t\tyield* Deferred.done(state.reply, result)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst current = yield* SynchronizedRef.get(entry.state)\n\t\t\t\t\t\tif (current._tag === \"Loading\")\n\t\t\t\t\t\t\tyield* stop(entry, { _tag: \"LoadFailed\", cause: result.cause })\n\t\t\t\t\t\tconst healthCause = yield* health.cause\n\t\t\t\t\t\tyield* Deferred.failCause(\n\t\t\t\t\t\t\tstate.reply,\n\t\t\t\t\t\t\tCause.combine(result.cause, healthCause),\n\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\t// Load's caller observes its complete exit through the reply, including cancellation.\n\t\t\t\tEffect.exit,\n\t\t\t\tEffect.asVoid,\n\t\t\t)\n\n\treturn {\n\t\tpersist,\n\t\tstatus,\n\t\tlatest,\n\t\tentryFor,\n\t\tstop,\n\t\tscheduleLease,\n\t\trunLoad,\n\t\thealthy,\n\t}\n}\ntype Operations = ReturnType<typeof operations>\nconst recover = (runtime: Runtime, actions: Operations) =>\n\tEffect.gen(function* () {\n\t\tconst { store, execution, confirmation, records } = runtime\n\t\tconst { persist } = actions\n\t\t// Recover before the service is published. Construction does not resume old leases.\n\t\tconst stored = yield* store.list\n\t\tyield* Ref.set(\n\t\t\trecords,\n\t\t\tHashMap.fromIterable(\n\t\t\t\tArray.map(stored, (record) => [record.handle.token, record] as const),\n\t\t\t),\n\t\t)\n\t\tfor (const record of stored) {\n\t\t\tif (record.phase === \"Stopped\") continue\n\t\t\tconst child = childOf(record)\n\t\t\tconst termination = Option.isNone(child)\n\t\t\t\t? emptyTermination\n\t\t\t\t: yield* execution.recover(child.value).pipe(\n\t\t\t\t\t\tEffect.timeout(confirmation),\n\t\t\t\t\t\tEffect.catchTags({\n\t\t\t\t\t\t\tExecutionError: (error) =>\n\t\t\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\t\t\tTerminationUnconfirmed.make({\n\t\t\t\t\t\t\t\t\t\tdetail: \"Orphan recovery did not confirm exit\",\n\t\t\t\t\t\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tTimeoutError: (error) =>\n\t\t\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\t\t\tTerminationUnconfirmed.make({\n\t\t\t\t\t\t\t\t\t\tdetail: \"Orphan recovery did not confirm exit\",\n\t\t\t\t\t\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\tyield* persist(\n\t\t\t\tstoppedRecord(\n\t\t\t\t\trecord.phase === \"Stopping\" ? record.previous : record,\n\t\t\t\t\t{ _tag: \"Recovery\" },\n\t\t\t\t\ttermination,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t})\nconst ownShutdown = (runtime: Runtime, actions: Operations) =>\n\tEffect.gen(function* () {\n\t\tconst { entries, health, closing } = runtime\n\t\tconst { stop } = actions\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tyield* Ref.set(closing, true)\n\t\t\t\tconst all = yield* Ref.get(entries)\n\t\t\t\tconst exits = yield* Effect.forEach(HashMap.values(all), (entry) =>\n\t\t\t\t\tstop(entry, { _tag: \"Shutdown\" }).pipe(\n\t\t\t\t\t\tEffect.flatMap(Deferred.await),\n\t\t\t\t\t\tEffect.exit,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tconst initial: Cause.Cause<unknown> = yield* health.cause\n\t\t\t\tconst cause = Array.reduce(exits, initial, (cause, exit) =>\n\t\t\t\t\tCause.combine(\n\t\t\t\t\t\tcause,\n\t\t\t\t\t\tExit.isFailure(exit) ? exit.cause : exit.value.cause,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif (cause.reasons.length > 0)\n\t\t\t\t\treturn yield* Effect.failCause(cleanupCause(cause))\n\t\t\t}),\n\t\t)\n\t})\nconst protocol = (runtime: Runtime, actions: Operations) =>\n\tEffect.gen(function* () {\n\t\tconst { random, owner, locks, lease, limits, records, entries, health } =\n\t\t\truntime\n\t\tconst {\n\t\t\tpersist,\n\t\t\tstatus,\n\t\t\tlatest,\n\t\t\tentryFor,\n\t\t\tstop,\n\t\t\tscheduleLease,\n\t\t\trunLoad,\n\t\t\thealthy,\n\t\t} = actions\n\t\treturn Supervisor.of({\n\t\t\tawait: health.await,\n\t\t\tstatus,\n\t\t\thighWater: (key) =>\n\t\t\t\tlatest(key).pipe(Effect.map((value) => (value === 0 ? null : value))),\n\t\t\topen: (request) =>\n\t\t\t\tEffect.scoped(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* healthy\n\t\t\t\t\t\tconst leaseMillis = Duration.toMillis(request.lease ?? lease)\n\t\t\t\t\t\tconst negotiated = negotiate(limits, request.limits ?? defaults)\n\t\t\t\t\t\tconst lock = yield* RcMap.get(locks, keyOf(request.key))\n\t\t\t\t\t\treturn yield* lock.withPermit(\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* healthy\n\t\t\t\t\t\t\t\tconst allRecords = yield* Ref.get(records)\n\t\t\t\t\t\t\t\tconst same = Array.filter(\n\t\t\t\t\t\t\t\t\tArray.fromIterable(HashMap.values(allRecords)),\n\t\t\t\t\t\t\t\t\t(row) =>\n\t\t\t\t\t\t\t\t\t\tEqual.equals(keyOf(row.handle.key), keyOf(request.key)),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst prior = Array.findFirst(\n\t\t\t\t\t\t\t\t\tsame,\n\t\t\t\t\t\t\t\t\t(row) => row.requestId === request.requestId,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tif (Option.isSome(prior)) return prior.value\n\t\t\t\t\t\t\t\tconst generation = yield* latest(request.key)\n\t\t\t\t\t\t\t\tif (generation !== (request.expectedGeneration ?? 0))\n\t\t\t\t\t\t\t\t\treturn yield* StaleSession.make({\n\t\t\t\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\t\t\t\"Open expectedGeneration does not match the generation high-water mark\",\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\tfor (const record of same) {\n\t\t\t\t\t\t\t\t\tconst allEntries = yield* Ref.get(entries)\n\t\t\t\t\t\t\t\t\tconst entry = HashMap.get(allEntries, record.handle.token)\n\t\t\t\t\t\t\t\t\tif (Option.isSome(entry))\n\t\t\t\t\t\t\t\t\t\tyield* stop(entry.value, { _tag: \"Superseded\" }).pipe(\n\t\t\t\t\t\t\t\t\t\t\tEffect.flatMap(Deferred.await),\n\t\t\t\t\t\t\t\t\t\t\tEffect.tap((result) =>\n\t\t\t\t\t\t\t\t\t\t\t\tresult.cause.reasons.length === 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t? Effect.void\n\t\t\t\t\t\t\t\t\t\t\t\t\t: Effect.logWarning(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"Superseded remote execution cleanup failed\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tresult.cause,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"remote.identity\": record.handle.key.identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"remote.instance\": record.handle.key.instance,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"remote.generation\": record.handle.generation,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tyield* healthy\n\t\t\t\t\t\t\t\tconst token = yield* random.uuidV4()\n\t\t\t\t\t\t\t\tconst record: typeof OpenRecord.Type = {\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\tphase: \"Open\",\n\t\t\t\t\t\t\t\t\thandle: {\n\t\t\t\t\t\t\t\t\t\tkey: request.key,\n\t\t\t\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t\t\t\t\tgeneration: generation + 1,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequestId: request.requestId,\n\t\t\t\t\t\t\t\t\tleaseMillis,\n\t\t\t\t\t\t\t\t\tlimits: negotiated,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn yield* Effect.uninterruptible(\n\t\t\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\t\t\tyield* persist(record)\n\t\t\t\t\t\t\t\t\t\tconst deadline =\n\t\t\t\t\t\t\t\t\t\t\t(yield* Clock.monotonicTimeNanos) + nanos(leaseMillis)\n\t\t\t\t\t\t\t\t\t\tconst scope = yield* Scope.fork(owner)\n\t\t\t\t\t\t\t\t\t\tconst entry: Entry = {\n\t\t\t\t\t\t\t\t\t\t\tstate: yield* SynchronizedRef.make<Session>(\n\t\t\t\t\t\t\t\t\t\t\t\tSession.Open({ record, deadline }),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\tscope,\n\t\t\t\t\t\t\t\t\t\t\tunitScope: yield* Scope.fork(scope),\n\t\t\t\t\t\t\t\t\t\t\ttimer: yield* FiberHandle.make<void, never>().pipe(\n\t\t\t\t\t\t\t\t\t\t\t\tScope.provide(scope),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\tloading: yield* FiberHandle.make<void, never>().pipe(\n\t\t\t\t\t\t\t\t\t\t\t\tScope.provide(scope),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t// The store's retention policy is also the in-memory eviction policy.\n\t\t\t\t\t\t\t\t\t\tconst retained = yield* Ref.get(records)\n\t\t\t\t\t\t\t\t\t\tconst old = yield* Ref.modify(\n\t\t\t\t\t\t\t\t\t\t\tentries,\n\t\t\t\t\t\t\t\t\t\t\t(all) =>\n\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\tArray.filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tArray.fromIterable(HashMap.entries(all)),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t([key]) => !HashMap.has(retained, key),\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.filter(all, (_, key) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tHashMap.has(retained, key),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tentry,\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t] as const,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\tfor (const [, retired] of old)\n\t\t\t\t\t\t\t\t\t\t\tyield* Release.close(retired.scope, Exit.void)\n\t\t\t\t\t\t\t\t\t\tyield* scheduleLease(entry, deadline)\n\t\t\t\t\t\t\t\t\t\treturn record\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\trenew: (handle) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tyield* healthy\n\t\t\t\t\tconst entry = yield* entryFor(handle)\n\t\t\t\t\treturn yield* SynchronizedRef.modifyEffect(entry.state, (state) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst now = yield* Clock.monotonicTimeNanos\n\t\t\t\t\t\t\tconst current = yield* Effect.fromResult(live(state, now))\n\t\t\t\t\t\t\tconst running = executionOf(current)\n\t\t\t\t\t\t\tif (running._tag === \"Running\")\n\t\t\t\t\t\t\t\tyield* running.unit.renew(current.record.leaseMillis)\n\t\t\t\t\t\t\tconst deadline = now + nanos(current.record.leaseMillis)\n\t\t\t\t\t\t\tyield* scheduleLease(entry, deadline)\n\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\tcurrent.record.leaseMillis,\n\t\t\t\t\t\t\t\t{ ...current, deadline },\n\t\t\t\t\t\t\t] as const\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}),\n\t\t\tload: (handle, request) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tyield* healthy\n\t\t\t\t\tconst entry = yield* entryFor(handle)\n\t\t\t\t\tconst reply = yield* SynchronizedRef.modifyEffect(\n\t\t\t\t\t\tentry.state,\n\t\t\t\t\t\t(state) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tconst now = yield* Clock.monotonicTimeNanos\n\t\t\t\t\t\t\t\tconst current = yield* Effect.fromResult(live(state, now))\n\t\t\t\t\t\t\t\tif (current._tag !== \"Open\") {\n\t\t\t\t\t\t\t\t\tconst before =\n\t\t\t\t\t\t\t\t\t\tcurrent._tag === \"Loading\"\n\t\t\t\t\t\t\t\t\t\t\t? current.request\n\t\t\t\t\t\t\t\t\t\t\t: current.record.load\n\t\t\t\t\t\t\t\t\tif (before.specifier !== request.specifier)\n\t\t\t\t\t\t\t\t\t\treturn yield* SessionConflict.make({\n\t\t\t\t\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Load was already requested with a different specifier\",\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\t\tcurrent._tag === \"Loading\"\n\t\t\t\t\t\t\t\t\t\t\t? Deferred.await(current.reply)\n\t\t\t\t\t\t\t\t\t\t\t: Effect.succeed(current.record.code),\n\t\t\t\t\t\t\t\t\t\tcurrent,\n\t\t\t\t\t\t\t\t\t] as const\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst done = yield* Deferred.make<\n\t\t\t\t\t\t\t\t\tCodeIdentity,\n\t\t\t\t\t\t\t\t\tSupervisorError\n\t\t\t\t\t\t\t\t>()\n\t\t\t\t\t\t\t\tconst next = beginLoad(current, request, done)\n\t\t\t\t\t\t\t\tyield* persist(snapshot(next))\n\t\t\t\t\t\t\t\tif (next._tag === \"Loading\")\n\t\t\t\t\t\t\t\t\tyield* FiberHandle.run(entry.loading, runLoad(entry, next), {\n\t\t\t\t\t\t\t\t\t\tstartImmediately: false,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\treturn [Deferred.await(done), next] as const\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t).pipe(Effect.uninterruptible)\n\t\t\t\t\treturn yield* reply\n\t\t\t\t}),\n\t\t\tdispose: (handle) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst record = yield* status(handle)\n\t\t\t\t\tif (record.phase === \"Stopped\") return record.termination\n\t\t\t\t\tconst entry = yield* entryFor(handle)\n\t\t\t\t\treturn yield* stop(entry, { _tag: \"Disposed\" }).pipe(\n\t\t\t\t\t\tEffect.flatMap(Deferred.await),\n\t\t\t\t\t)\n\t\t\t\t}),\n\t\t})\n\t})\nexport const make = (options: Options = {}) =>\n\tEffect.gen(function* () {\n\t\tconst runtime = yield* initialize(options)\n\t\tconst actions = operations(runtime)\n\t\tyield* recover(runtime, actions)\n\t\tyield* ownShutdown(runtime, actions)\n\t\treturn yield* protocol(runtime, actions)\n\t})\nexport const layer = (options: Options = {}) =>\n\tLayer.effect(Supervisor, make(options))\n"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { make } from "../FailureGroup.js";
2
+ import { ExecutionError } from "./model.js";
3
+ import { Notice } from "./WatchdogProtocol.js";
4
+ import { Cause, Deferred, Effect, Schema } from "effect";
5
+ import { Worker } from "node:worker_threads";
6
+ // src/internal/runner/Watchdog.ts
7
+ const start = Effect.gen(function* () {
8
+ const ready = yield* Deferred.make();
9
+ const begin = yield* Deferred.make();
10
+ const stop = yield* Deferred.make();
11
+ const worker = yield* Effect.acquireRelease(Effect.try({
12
+ try: () => new Worker(new URL(import.meta.resolve("@graftland/plugin-remote/internal/watchdog"))),
13
+ catch: (cause) => ExecutionError.make({
14
+ detail: "Starting the child watchdog failed",
15
+ cause: Cause.die(cause)
16
+ })
17
+ }), (worker) => Effect.promise(() => worker.terminate()).pipe(Effect.asVoid));
18
+ const listeners = yield* make();
19
+ const run = yield* listeners.runtime();
20
+ const message = (value) => run(Schema.decodeUnknownEffect(Notice)(value).pipe(Effect.mapError((error) => ExecutionError.make({
21
+ detail: "Invalid watchdog notice",
22
+ cause: Cause.fail(error)
23
+ })), Effect.flatMap((notice) => Deferred.succeed(notice === "ready" ? ready : notice === "start" ? begin : stop, void 0)), Effect.asVoid));
24
+ const error = (error) => run(Effect.fail(ExecutionError.make({
25
+ detail: "Child watchdog failed",
26
+ cause: Cause.die(error)
27
+ })));
28
+ const exit = (code) => run(Effect.fail(ExecutionError.make({ detail: "Child watchdog exited: " + code })));
29
+ yield* Effect.acquireRelease(Effect.sync(() => {
30
+ worker.on("message", message);
31
+ worker.on("error", error);
32
+ worker.on("exit", exit);
33
+ }), () => Effect.sync(() => {
34
+ worker.off("message", message);
35
+ worker.off("error", error);
36
+ worker.off("exit", exit);
37
+ }));
38
+ const failure = listeners.await;
39
+ yield* Effect.raceFirst(Deferred.await(ready), failure);
40
+ return {
41
+ begin: Effect.raceFirst(Deferred.await(begin), failure),
42
+ stop: Effect.raceFirst(Deferred.await(stop), failure)
43
+ };
44
+ });
45
+ export { start };
46
+
47
+ //# sourceMappingURL=Watchdog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Watchdog.js","names":["FailureGroup.make"],"sources":["../../../src/internal/runner/Watchdog.ts"],"sourcesContent":["import { Cause, Deferred, Effect, Schema } from \"effect\"\nimport * as FailureGroup from \"../FailureGroup\"\nimport { Worker } from \"node:worker_threads\"\nimport { ExecutionError } from \"./model\"\nimport { Notice } from \"./WatchdogProtocol\"\n\nexport const start = Effect.gen(function* () {\n\tconst ready = yield* Deferred.make<void>()\n\tconst begin = yield* Deferred.make<void>()\n\tconst stop = yield* Deferred.make<void>()\n\tconst worker = yield* Effect.acquireRelease(\n\t\tEffect.try({\n\t\t\ttry: () =>\n\t\t\t\tnew Worker(\n\t\t\t\t\tnew URL(\n\t\t\t\t\t\timport.meta.resolve(\"@graftland/plugin-remote/internal/watchdog\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tcatch: (cause) =>\n\t\t\t\tExecutionError.make({\n\t\t\t\t\tdetail: \"Starting the child watchdog failed\",\n\t\t\t\t\tcause: Cause.die(cause),\n\t\t\t\t}),\n\t\t}),\n\t\t(worker) => Effect.promise(() => worker.terminate()).pipe(Effect.asVoid),\n\t)\n\tconst listeners = yield* FailureGroup.make<ExecutionError>()\n\tconst run = yield* listeners.runtime<never>()\n\tconst message = (value: unknown) =>\n\t\trun(\n\t\t\tSchema.decodeUnknownEffect(Notice)(value).pipe(\n\t\t\t\tEffect.mapError((error) =>\n\t\t\t\t\tExecutionError.make({\n\t\t\t\t\t\tdetail: \"Invalid watchdog notice\",\n\t\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tEffect.flatMap((notice) =>\n\t\t\t\t\tDeferred.succeed(\n\t\t\t\t\t\tnotice === \"ready\" ? ready : notice === \"start\" ? begin : stop,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tEffect.asVoid,\n\t\t\t),\n\t\t)\n\tconst error = (error: Error) =>\n\t\trun(\n\t\t\tEffect.fail(\n\t\t\t\tExecutionError.make({\n\t\t\t\t\tdetail: \"Child watchdog failed\",\n\t\t\t\t\tcause: Cause.die(error),\n\t\t\t\t}),\n\t\t\t),\n\t\t)\n\tconst exit = (code: number) =>\n\t\trun(\n\t\t\tEffect.fail(\n\t\t\t\tExecutionError.make({\n\t\t\t\t\tdetail: \"Child watchdog exited: \" + code,\n\t\t\t\t}),\n\t\t\t),\n\t\t)\n\tyield* Effect.acquireRelease(\n\t\tEffect.sync(() => {\n\t\t\tworker.on(\"message\", message)\n\t\t\tworker.on(\"error\", error)\n\t\t\tworker.on(\"exit\", exit)\n\t\t}),\n\t\t() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tworker.off(\"message\", message)\n\t\t\t\tworker.off(\"error\", error)\n\t\t\t\tworker.off(\"exit\", exit)\n\t\t\t}),\n\t)\n\tconst failure = listeners.await\n\tyield* Effect.raceFirst(Deferred.await(ready), failure)\n\treturn {\n\t\tbegin: Effect.raceFirst(Deferred.await(begin), failure),\n\t\tstop: Effect.raceFirst(Deferred.await(stop), failure),\n\t}\n})\n"],"mappings":";;;;;;AAMA,MAAa,QAAQ,OAAO,IAAI,aAAa;CAC5C,MAAM,QAAQ,OAAO,SAAS,KAAW;CACzC,MAAM,QAAQ,OAAO,SAAS,KAAW;CACzC,MAAM,OAAO,OAAO,SAAS,KAAW;CACxC,MAAM,SAAS,OAAO,OAAO,eAC5B,OAAO,IAAI;EACV,WACC,IAAI,OACH,IAAI,IACH,YAAY,QAAQ,4CAA4C,CACjE,CACD;EACD,QAAQ,UACP,eAAe,KAAK;GACnB,QAAQ;GACR,OAAO,MAAM,IAAI,KAAK;EACvB,CAAC;CACH,CAAC,IACA,WAAW,OAAO,cAAc,OAAO,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM,CACxE;CACA,MAAM,YAAY,OAAOA,KAAkC;CAC3D,MAAM,MAAM,OAAO,UAAU,QAAe;CAC5C,MAAM,WAAW,UAChB,IACC,OAAO,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KACzC,OAAO,UAAU,UAChB,eAAe,KAAK;EACnB,QAAQ;EACR,OAAO,MAAM,KAAK,KAAK;CACxB,CAAC,CACF,GACA,OAAO,SAAS,WACf,SAAS,QACR,WAAW,UAAU,QAAQ,WAAW,UAAU,QAAQ,MAC1D,KAAA,CACD,CACD,GACA,OAAO,MACR,CACD;CACD,MAAM,SAAS,UACd,IACC,OAAO,KACN,eAAe,KAAK;EACnB,QAAQ;EACR,OAAO,MAAM,IAAI,KAAK;CACvB,CAAC,CACF,CACD;CACD,MAAM,QAAQ,SACb,IACC,OAAO,KACN,eAAe,KAAK,EACnB,QAAQ,4BAA4B,KACrC,CAAC,CACF,CACD;CACD,OAAO,OAAO,eACb,OAAO,WAAW;EACjB,OAAO,GAAG,WAAW,OAAO;EAC5B,OAAO,GAAG,SAAS,KAAK;EACxB,OAAO,GAAG,QAAQ,IAAI;CACvB,CAAC,SAEA,OAAO,WAAW;EACjB,OAAO,IAAI,WAAW,OAAO;EAC7B,OAAO,IAAI,SAAS,KAAK;EACzB,OAAO,IAAI,QAAQ,IAAI;CACxB,CAAC,CACH;CACA,MAAM,UAAU,UAAU;CAC1B,OAAO,OAAO,UAAU,SAAS,MAAM,KAAK,GAAG,OAAO;CACtD,OAAO;EACN,OAAO,OAAO,UAAU,SAAS,MAAM,KAAK,GAAG,OAAO;EACtD,MAAM,OAAO,UAAU,SAAS,MAAM,IAAI,GAAG,OAAO;CACrD;AACD,CAAC"}