@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.
- package/LICENSE +202 -0
- package/README.md +76 -2
- package/README.zh-CN.md +71 -0
- package/README.zh-TW.md +71 -0
- package/dist/Auth-BElTC9_X.js +6 -0
- package/dist/Auth.d.ts +49 -0
- package/dist/Auth.d.ts.map +1 -0
- package/dist/Auth.js +8 -0
- package/dist/Auth.js.map +1 -0
- package/dist/Bootstrap-MCwivGN1.js +9 -0
- package/dist/ConfigDirectory-BCC6q2R4.js +5 -0
- package/dist/Contract-CcpSIJm4.js +121 -0
- package/dist/Contract.d.ts +71 -0
- package/dist/Contract.d.ts.map +1 -0
- package/dist/Contract.js +1 -0
- package/dist/Contract.js.map +1 -0
- package/dist/Errors-oPsTLY7l.js +45 -0
- package/dist/Errors.d.ts +67 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Errors.js +47 -0
- package/dist/Errors.js.map +1 -0
- package/dist/FailureGroup-BcH0XOBi.js +53 -0
- package/dist/Framing-zaYdOJnT.js +61 -0
- package/dist/Graft-BsYq3F-J.js +985 -0
- package/dist/Instance.d.ts +7 -0
- package/dist/Instance.d.ts.map +1 -0
- package/dist/Instance.js +14 -0
- package/dist/Instance.js.map +1 -0
- package/dist/Packages-B1TPk8pa.js +111 -0
- package/dist/Peer-IJgFK6mD.js +342 -0
- package/dist/ProcessObservation-DEGrEMfP.js +38 -0
- package/dist/ServeLifecycle-CJM0gG5B.js +24 -0
- package/dist/Testing.d.ts +26 -0
- package/dist/Testing.d.ts.map +1 -0
- package/dist/Testing.js +69 -0
- package/dist/Testing.js.map +1 -0
- package/dist/Transport-DULzpsgR.js +6 -0
- package/dist/Transport.d.ts +39 -0
- package/dist/Transport.d.ts.map +1 -0
- package/dist/Transport.js +8 -0
- package/dist/Transport.js.map +1 -0
- package/dist/WatchdogProtocol-BZmVxrBP.js +17 -0
- package/dist/_virtual/_rolldown/runtime.js +12 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +28275 -0
- package/dist/bin.js.map +1 -0
- package/dist/childRuntime-DSqtFN9o.js +188 -0
- package/dist/cleanup-BPWr-5U9.js +13 -0
- package/dist/command-9zrHdbwT.js +7 -0
- package/dist/connectionEnded-DUgcobEd.js +9 -0
- package/dist/directTransport-DrexuPSm.js +5 -0
- package/dist/entry-SYsx9VNb.js +708 -0
- package/dist/host/auth/bearer.d.ts +5 -0
- package/dist/host/auth/bearer.d.ts.map +1 -0
- package/dist/host/auth/bearer.js +4 -0
- package/dist/host/auth/bearer.js.map +1 -0
- package/dist/host/auth/jwt.d.ts +5 -0
- package/dist/host/auth/jwt.d.ts.map +1 -0
- package/dist/host/auth/jwt.js +4 -0
- package/dist/host/auth/jwt.js.map +1 -0
- package/dist/host/auth/mtls.d.ts +8 -0
- package/dist/host/auth/mtls.d.ts.map +1 -0
- package/dist/host/auth/mtls.js +34 -0
- package/dist/host/auth/mtls.js.map +1 -0
- package/dist/host/auth/none.d.ts +3 -0
- package/dist/host/auth/none.d.ts.map +1 -0
- package/dist/host/auth/none.js +13 -0
- package/dist/host/auth/none.js.map +1 -0
- package/dist/host/command.d.ts +22 -0
- package/dist/host/command.d.ts.map +1 -0
- package/dist/host/command.js +61 -0
- package/dist/host/command.js.map +1 -0
- package/dist/host/local.d.ts +4 -0
- package/dist/host/local.d.ts.map +1 -0
- package/dist/host/local.js +52 -0
- package/dist/host/local.js.map +1 -0
- package/dist/host/unix.d.ts +11 -0
- package/dist/host/unix.d.ts.map +1 -0
- package/dist/host/unix.js +39 -0
- package/dist/host/unix.js.map +1 -0
- package/dist/host/websocket.d.ts +13 -0
- package/dist/host/websocket.d.ts.map +1 -0
- package/dist/host/websocket.js +36 -0
- package/dist/host/websocket.js.map +1 -0
- package/dist/host/worker.d.ts +4 -0
- package/dist/host/worker.d.ts.map +1 -0
- package/dist/host/worker.js +52 -0
- package/dist/host/worker.js.map +1 -0
- package/dist/importer-D7zSgqxq.js +347 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/Certificates.js +182 -0
- package/dist/internal/Certificates.js.map +1 -0
- package/dist/internal/FailureGroup.js +55 -0
- package/dist/internal/FailureGroup.js.map +1 -0
- package/dist/internal/Limits.d.ts +1 -0
- package/dist/internal/Limits.js +17 -0
- package/dist/internal/Limits.js.map +1 -0
- package/dist/internal/Peer.js +6 -0
- package/dist/internal/Peer.js.map +1 -0
- package/dist/internal/ServeLifecycle.js +26 -0
- package/dist/internal/ServeLifecycle.js.map +1 -0
- package/dist/internal/Supervisor.js +7 -0
- package/dist/internal/Supervisor.js.map +1 -0
- package/dist/internal/assembly.d.ts +5 -0
- package/dist/internal/assembly.js +138 -0
- package/dist/internal/assembly.js.map +1 -0
- package/dist/internal/auth/mtls.js +23 -0
- package/dist/internal/auth/mtls.js.map +1 -0
- package/dist/internal/auth/token.js +19 -0
- package/dist/internal/auth/token.js.map +1 -0
- package/dist/internal/auth/tokenCredentials.d.ts +8 -0
- package/dist/internal/auth/tokenCredentials.d.ts.map +1 -0
- package/dist/internal/auth/tokenCredentials.js +33 -0
- package/dist/internal/auth/tokenCredentials.js.map +1 -0
- package/dist/internal/child.js +125 -0
- package/dist/internal/child.js.map +1 -0
- package/dist/internal/childErrors.d.ts +33 -0
- package/dist/internal/childErrors.d.ts.map +1 -0
- package/dist/internal/childErrors.js +29 -0
- package/dist/internal/childErrors.js.map +1 -0
- package/dist/internal/childRuntime.js +59 -0
- package/dist/internal/childRuntime.js.map +1 -0
- package/dist/internal/cleanup.js +15 -0
- package/dist/internal/cleanup.js.map +1 -0
- package/dist/internal/config.js +6 -0
- package/dist/internal/config.js.map +1 -0
- package/dist/internal/control.js +42 -0
- package/dist/internal/control.js.map +1 -0
- package/dist/internal/credentials.d.ts +44 -0
- package/dist/internal/credentials.d.ts.map +1 -0
- package/dist/internal/credentials.js +54 -0
- package/dist/internal/credentials.js.map +1 -0
- package/dist/internal/directTransport.d.ts +3 -0
- package/dist/internal/directTransport.js +7 -0
- package/dist/internal/directTransport.js.map +1 -0
- package/dist/internal/entry.d.ts +9 -0
- package/dist/internal/entry.d.ts.map +1 -0
- package/dist/internal/entry.js +144 -0
- package/dist/internal/entry.js.map +1 -0
- package/dist/internal/entryConfig.d.ts +202 -0
- package/dist/internal/entryConfig.d.ts.map +1 -0
- package/dist/internal/entryConfig.js +176 -0
- package/dist/internal/entryConfig.js.map +1 -0
- package/dist/internal/execution.d.ts +5 -0
- package/dist/internal/execution.js +43 -0
- package/dist/internal/execution.js.map +1 -0
- package/dist/internal/follow.js +11 -0
- package/dist/internal/follow.js.map +1 -0
- package/dist/internal/forkTree.js +7 -0
- package/dist/internal/forkTree.js.map +1 -0
- package/dist/internal/host/local.js +28 -0
- package/dist/internal/host/local.js.map +1 -0
- package/dist/internal/host/runner.js +100 -0
- package/dist/internal/host/runner.js.map +1 -0
- package/dist/internal/host.js +71 -0
- package/dist/internal/host.js.map +1 -0
- package/dist/internal/importer.js +18 -0
- package/dist/internal/importer.js.map +1 -0
- package/dist/internal/listenerStartup.js +17 -0
- package/dist/internal/listenerStartup.js.map +1 -0
- package/dist/internal/loadModule.js +20 -0
- package/dist/internal/loadModule.js.map +1 -0
- package/dist/internal/platform.js +9 -0
- package/dist/internal/platform.js.map +1 -0
- package/dist/internal/port.d.ts +13 -0
- package/dist/internal/port.d.ts.map +1 -0
- package/dist/internal/port.js +275 -0
- package/dist/internal/port.js.map +1 -0
- package/dist/internal/release.js +25 -0
- package/dist/internal/release.js.map +1 -0
- package/dist/internal/runner/Bootstrap.js +11 -0
- package/dist/internal/runner/Bootstrap.js.map +1 -0
- package/dist/internal/runner/Connection.d.ts +11 -0
- package/dist/internal/runner/Connection.js +56 -0
- package/dist/internal/runner/Connection.js.map +1 -0
- package/dist/internal/runner/Execution.js +115 -0
- package/dist/internal/runner/Execution.js.map +1 -0
- package/dist/internal/runner/Framing.d.ts +11 -0
- package/dist/internal/runner/Framing.d.ts.map +1 -0
- package/dist/internal/runner/Framing.js +63 -0
- package/dist/internal/runner/Framing.js.map +1 -0
- package/dist/internal/runner/Local.js +46 -0
- package/dist/internal/runner/Local.js.map +1 -0
- package/dist/internal/runner/Lock.js +25 -0
- package/dist/internal/runner/Lock.js.map +1 -0
- package/dist/internal/runner/Multiplex.d.ts +5 -0
- package/dist/internal/runner/Multiplex.js +49 -0
- package/dist/internal/runner/Multiplex.js.map +1 -0
- package/dist/internal/runner/Packages.d.ts +3 -0
- package/dist/internal/runner/Packages.js +108 -0
- package/dist/internal/runner/Packages.js.map +1 -0
- package/dist/internal/runner/ProcessObservation.js +40 -0
- package/dist/internal/runner/ProcessObservation.js.map +1 -0
- package/dist/internal/runner/Processes.js +83 -0
- package/dist/internal/runner/Processes.js.map +1 -0
- package/dist/internal/runner/Retention.js +13 -0
- package/dist/internal/runner/Retention.js.map +1 -0
- package/dist/internal/runner/Store.js +78 -0
- package/dist/internal/runner/Store.js.map +1 -0
- package/dist/internal/runner/Supervisor.js +375 -0
- package/dist/internal/runner/Supervisor.js.map +1 -0
- package/dist/internal/runner/Watchdog.js +47 -0
- package/dist/internal/runner/Watchdog.js.map +1 -0
- package/dist/internal/runner/WatchdogProtocol.js +19 -0
- package/dist/internal/runner/WatchdogProtocol.js.map +1 -0
- package/dist/internal/runner/Wire.d.ts +5 -0
- package/dist/internal/runner/Wire.js +64 -0
- package/dist/internal/runner/Wire.js.map +1 -0
- package/dist/internal/runner/accept.js +57 -0
- package/dist/internal/runner/accept.js.map +1 -0
- package/dist/internal/runner/command.js +9 -0
- package/dist/internal/runner/command.js.map +1 -0
- package/dist/internal/runner/connectionEnded.js +11 -0
- package/dist/internal/runner/connectionEnded.js.map +1 -0
- package/dist/internal/runner/model.d.ts +17 -0
- package/dist/internal/runner/model.d.ts.map +1 -0
- package/dist/internal/runner/model.js +231 -0
- package/dist/internal/runner/model.js.map +1 -0
- package/dist/internal/serve.js +60 -0
- package/dist/internal/serve.js.map +1 -0
- package/dist/internal/services.d.ts +18 -0
- package/dist/internal/services.d.ts.map +1 -0
- package/dist/internal/services.js +22 -0
- package/dist/internal/services.js.map +1 -0
- package/dist/internal/socketChannel.js +24 -0
- package/dist/internal/socketChannel.js.map +1 -0
- package/dist/internal/stdioChannel.js +23 -0
- package/dist/internal/stdioChannel.js.map +1 -0
- package/dist/internal/supervisorPlugin.js +1 -0
- package/dist/internal/supervisorPlugin.js.map +1 -0
- package/dist/internal/transportOptions.d.ts +18 -0
- package/dist/internal/transportOptions.d.ts.map +1 -0
- package/dist/internal/watchdogMain.d.ts +1 -0
- package/dist/internal/watchdogMain.js +55 -0
- package/dist/internal/watchdogMain.js.map +1 -0
- package/dist/internal/websocket.js +46 -0
- package/dist/internal/websocket.js.map +1 -0
- package/dist/internal/websocketServer.js +61 -0
- package/dist/internal/websocketServer.js.map +1 -0
- package/dist/internal/workerBootstrap.js +9 -0
- package/dist/internal/workerBootstrap.js.map +1 -0
- package/dist/internal/workerChannel.js +24 -0
- package/dist/internal/workerChannel.js.map +1 -0
- package/dist/internal/workerMain.d.ts +1 -0
- package/dist/internal/workerMain.js +18 -0
- package/dist/internal/workerMain.js.map +1 -0
- package/dist/port-Blbh8tms.js +285 -0
- package/dist/release-BY4Mlluy.js +23 -0
- package/dist/rolldown-runtime-DYf_mQCB.js +34 -0
- package/dist/runner/auth/bearer.d.ts +7 -0
- package/dist/runner/auth/bearer.d.ts.map +1 -0
- package/dist/runner/auth/bearer.js +42 -0
- package/dist/runner/auth/bearer.js.map +1 -0
- package/dist/runner/auth/jwt.d.ts +19 -0
- package/dist/runner/auth/jwt.d.ts.map +1 -0
- package/dist/runner/auth/jwt.js +65 -0
- package/dist/runner/auth/jwt.js.map +1 -0
- package/dist/runner/auth/mtls.d.ts +11 -0
- package/dist/runner/auth/mtls.d.ts.map +1 -0
- package/dist/runner/auth/mtls.js +48 -0
- package/dist/runner/auth/mtls.js.map +1 -0
- package/dist/runner/auth/none.d.ts +3 -0
- package/dist/runner/auth/none.d.ts.map +1 -0
- package/dist/runner/auth/none.js +13 -0
- package/dist/runner/auth/none.js.map +1 -0
- package/dist/runner/index.d.ts +3 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +71 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/stdio.d.ts +7 -0
- package/dist/runner/stdio.d.ts.map +1 -0
- package/dist/runner/stdio.js +39 -0
- package/dist/runner/stdio.js.map +1 -0
- package/dist/runner/unix.d.ts +7 -0
- package/dist/runner/unix.d.ts.map +1 -0
- package/dist/runner/unix.js +42 -0
- package/dist/runner/unix.js.map +1 -0
- package/dist/runner/websocket.d.ts +28 -0
- package/dist/runner/websocket.d.ts.map +1 -0
- package/dist/runner/websocket.js +77 -0
- package/dist/runner/websocket.js.map +1 -0
- package/dist/socketChannel-KmtzF-9G.js +3658 -0
- package/dist/supervisorPlugin-Inb1S5IV.js +737 -0
- package/dist/token-v5ne2I0-.js +17 -0
- package/dist/tokenCredentials-WUJm2AKm.js +31 -0
- package/dist/websocketServer-MXcCJx0v.js +58 -0
- package/dist/workerChannel-P82YdNjh.js +27 -0
- package/package.json +69 -3
- package/src/Auth.ts +62 -0
- package/src/Contract.ts +100 -0
- package/src/Errors.ts +82 -0
- package/src/Instance.ts +12 -0
- package/src/Testing.ts +135 -0
- package/src/Transport.ts +52 -0
- package/src/bin.ts +145 -0
- package/src/host/auth/bearer.ts +10 -0
- package/src/host/auth/jwt.ts +10 -0
- package/src/host/auth/mtls.ts +48 -0
- package/src/host/auth/none.ts +13 -0
- package/src/host/command.ts +131 -0
- package/src/host/local.ts +41 -0
- package/src/host/unix.ts +65 -0
- package/src/host/websocket.ts +66 -0
- package/src/host/worker.ts +90 -0
- package/src/index.ts +115 -0
- package/src/internal/Certificates.ts +330 -0
- package/src/internal/FailureGroup.ts +176 -0
- package/src/internal/Limits.ts +12 -0
- package/src/internal/Peer.ts +4 -0
- package/src/internal/ServeLifecycle.ts +53 -0
- package/src/internal/Supervisor.ts +14 -0
- package/src/internal/assembly.ts +337 -0
- package/src/internal/auth/mtls.ts +40 -0
- package/src/internal/auth/token.ts +26 -0
- package/src/internal/auth/tokenCredentials.ts +65 -0
- package/src/internal/child.ts +323 -0
- package/src/internal/childErrors.ts +44 -0
- package/src/internal/childRuntime.ts +111 -0
- package/src/internal/cleanup.ts +34 -0
- package/src/internal/config.ts +8 -0
- package/src/internal/control.ts +49 -0
- package/src/internal/credentials.ts +112 -0
- package/src/internal/directTransport.ts +38 -0
- package/src/internal/entry.ts +288 -0
- package/src/internal/entryConfig.ts +190 -0
- package/src/internal/execution.ts +121 -0
- package/src/internal/follow.ts +17 -0
- package/src/internal/forkTree.ts +13 -0
- package/src/internal/host/local.ts +53 -0
- package/src/internal/host/runner.ts +187 -0
- package/src/internal/host.ts +209 -0
- package/src/internal/importer.ts +27 -0
- package/src/internal/listenerStartup.ts +55 -0
- package/src/internal/loadModule.ts +23 -0
- package/src/internal/platform.ts +12 -0
- package/src/internal/port.ts +623 -0
- package/src/internal/release.ts +71 -0
- package/src/internal/runner/Bootstrap.ts +9 -0
- package/src/internal/runner/Connection.ts +184 -0
- package/src/internal/runner/Execution.ts +244 -0
- package/src/internal/runner/Framing.ts +122 -0
- package/src/internal/runner/Local.ts +73 -0
- package/src/internal/runner/Lock.ts +29 -0
- package/src/internal/runner/Multiplex.ts +120 -0
- package/src/internal/runner/Packages.ts +178 -0
- package/src/internal/runner/ProcessObservation.ts +63 -0
- package/src/internal/runner/Processes.ts +109 -0
- package/src/internal/runner/Retention.ts +49 -0
- package/src/internal/runner/Store.ts +160 -0
- package/src/internal/runner/Supervisor.ts +901 -0
- package/src/internal/runner/Watchdog.ts +83 -0
- package/src/internal/runner/WatchdogProtocol.ts +12 -0
- package/src/internal/runner/Wire.ts +99 -0
- package/src/internal/runner/accept.ts +103 -0
- package/src/internal/runner/command.ts +15 -0
- package/src/internal/runner/connectionEnded.ts +28 -0
- package/src/internal/runner/model.ts +364 -0
- package/src/internal/serve.ts +117 -0
- package/src/internal/services.ts +74 -0
- package/src/internal/socketChannel.ts +64 -0
- package/src/internal/stdioChannel.ts +25 -0
- package/src/internal/supervisorPlugin.ts +67 -0
- package/src/internal/transportOptions.ts +17 -0
- package/src/internal/watchdogMain.ts +72 -0
- package/src/internal/websocket.ts +81 -0
- package/src/internal/websocketServer.ts +152 -0
- package/src/internal/workerBootstrap.ts +6 -0
- package/src/internal/workerChannel.ts +54 -0
- package/src/internal/workerMain.ts +23 -0
- package/src/runner/auth/bearer.ts +66 -0
- package/src/runner/auth/jwt.ts +114 -0
- package/src/runner/auth/mtls.ts +37 -0
- package/src/runner/auth/none.ts +13 -0
- package/src/runner/index.ts +97 -0
- package/src/runner/stdio.ts +76 -0
- package/src/runner/unix.ts +53 -0
- package/src/runner/websocket.ts +143 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Cause, Deferred, Effect, Schema } from "effect"
|
|
2
|
+
import * as FailureGroup from "../FailureGroup"
|
|
3
|
+
import { Worker } from "node:worker_threads"
|
|
4
|
+
import { ExecutionError } from "./model"
|
|
5
|
+
import { Notice } from "./WatchdogProtocol"
|
|
6
|
+
|
|
7
|
+
export const start = Effect.gen(function* () {
|
|
8
|
+
const ready = yield* Deferred.make<void>()
|
|
9
|
+
const begin = yield* Deferred.make<void>()
|
|
10
|
+
const stop = yield* Deferred.make<void>()
|
|
11
|
+
const worker = yield* Effect.acquireRelease(
|
|
12
|
+
Effect.try({
|
|
13
|
+
try: () =>
|
|
14
|
+
new Worker(
|
|
15
|
+
new URL(
|
|
16
|
+
import.meta.resolve("@graftland/plugin-remote/internal/watchdog"),
|
|
17
|
+
),
|
|
18
|
+
),
|
|
19
|
+
catch: (cause) =>
|
|
20
|
+
ExecutionError.make({
|
|
21
|
+
detail: "Starting the child watchdog failed",
|
|
22
|
+
cause: Cause.die(cause),
|
|
23
|
+
}),
|
|
24
|
+
}),
|
|
25
|
+
(worker) => Effect.promise(() => worker.terminate()).pipe(Effect.asVoid),
|
|
26
|
+
)
|
|
27
|
+
const listeners = yield* FailureGroup.make<ExecutionError>()
|
|
28
|
+
const run = yield* listeners.runtime<never>()
|
|
29
|
+
const message = (value: unknown) =>
|
|
30
|
+
run(
|
|
31
|
+
Schema.decodeUnknownEffect(Notice)(value).pipe(
|
|
32
|
+
Effect.mapError((error) =>
|
|
33
|
+
ExecutionError.make({
|
|
34
|
+
detail: "Invalid watchdog notice",
|
|
35
|
+
cause: Cause.fail(error),
|
|
36
|
+
}),
|
|
37
|
+
),
|
|
38
|
+
Effect.flatMap((notice) =>
|
|
39
|
+
Deferred.succeed(
|
|
40
|
+
notice === "ready" ? ready : notice === "start" ? begin : stop,
|
|
41
|
+
undefined,
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
Effect.asVoid,
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
const error = (error: Error) =>
|
|
48
|
+
run(
|
|
49
|
+
Effect.fail(
|
|
50
|
+
ExecutionError.make({
|
|
51
|
+
detail: "Child watchdog failed",
|
|
52
|
+
cause: Cause.die(error),
|
|
53
|
+
}),
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
const exit = (code: number) =>
|
|
57
|
+
run(
|
|
58
|
+
Effect.fail(
|
|
59
|
+
ExecutionError.make({
|
|
60
|
+
detail: "Child watchdog exited: " + code,
|
|
61
|
+
}),
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
yield* Effect.acquireRelease(
|
|
65
|
+
Effect.sync(() => {
|
|
66
|
+
worker.on("message", message)
|
|
67
|
+
worker.on("error", error)
|
|
68
|
+
worker.on("exit", exit)
|
|
69
|
+
}),
|
|
70
|
+
() =>
|
|
71
|
+
Effect.sync(() => {
|
|
72
|
+
worker.off("message", message)
|
|
73
|
+
worker.off("error", error)
|
|
74
|
+
worker.off("exit", exit)
|
|
75
|
+
}),
|
|
76
|
+
)
|
|
77
|
+
const failure = listeners.await
|
|
78
|
+
yield* Effect.raceFirst(Deferred.await(ready), failure)
|
|
79
|
+
return {
|
|
80
|
+
begin: Effect.raceFirst(Deferred.await(begin), failure),
|
|
81
|
+
stop: Effect.raceFirst(Deferred.await(stop), failure),
|
|
82
|
+
}
|
|
83
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Schema } from "effect"
|
|
2
|
+
|
|
3
|
+
export const Command = Schema.Union([
|
|
4
|
+
Schema.Struct({
|
|
5
|
+
kind: Schema.Literal("renew"),
|
|
6
|
+
millis: Schema.Finite.check(Schema.isGreaterThan(0)),
|
|
7
|
+
}),
|
|
8
|
+
Schema.Struct({ kind: Schema.Literal("start") }),
|
|
9
|
+
Schema.Struct({ kind: Schema.Literal("stop") }),
|
|
10
|
+
])
|
|
11
|
+
export const CommandJson = Schema.fromJsonString(Command)
|
|
12
|
+
export const Notice = Schema.Literals(["ready", "start", "stop"])
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Cause, Effect, Sink, Stream, Schema } from "effect"
|
|
2
|
+
import { Rpc, RpcGroup } from "effect/rpc"
|
|
3
|
+
import { TransportError } from "../../Errors"
|
|
4
|
+
import * as Port from "../port"
|
|
5
|
+
import type * as Multiplex from "./Multiplex"
|
|
6
|
+
import {
|
|
7
|
+
CodeIdentity,
|
|
8
|
+
Handle,
|
|
9
|
+
Limits,
|
|
10
|
+
PositiveInt,
|
|
11
|
+
PositiveFinite,
|
|
12
|
+
SessionRecord,
|
|
13
|
+
SessionAccessDenied,
|
|
14
|
+
StaleSession,
|
|
15
|
+
LeaseExpired,
|
|
16
|
+
SessionStopped,
|
|
17
|
+
SessionConflict,
|
|
18
|
+
StateStorageError,
|
|
19
|
+
ExecutionError,
|
|
20
|
+
PackageError,
|
|
21
|
+
TerminationUnconfirmed,
|
|
22
|
+
RunnerClosing,
|
|
23
|
+
StateDirectoryLocked,
|
|
24
|
+
Termination,
|
|
25
|
+
} from "./model"
|
|
26
|
+
|
|
27
|
+
/** The RPC boundary is the only place that assembles the runner's error schema. */
|
|
28
|
+
export const SessionError = Schema.Union([
|
|
29
|
+
SessionAccessDenied,
|
|
30
|
+
StaleSession,
|
|
31
|
+
LeaseExpired,
|
|
32
|
+
SessionStopped,
|
|
33
|
+
SessionConflict,
|
|
34
|
+
StateStorageError,
|
|
35
|
+
ExecutionError,
|
|
36
|
+
PackageError,
|
|
37
|
+
TerminationUnconfirmed,
|
|
38
|
+
RunnerClosing,
|
|
39
|
+
StateDirectoryLocked,
|
|
40
|
+
])
|
|
41
|
+
export type SessionError = typeof SessionError.Type
|
|
42
|
+
|
|
43
|
+
export const Session = RpcGroup.make(
|
|
44
|
+
Rpc.make("HighWater", {
|
|
45
|
+
payload: { instance: Schema.NonEmptyString },
|
|
46
|
+
success: Schema.NullOr(PositiveInt),
|
|
47
|
+
error: SessionError,
|
|
48
|
+
}),
|
|
49
|
+
Rpc.make("Open", {
|
|
50
|
+
payload: {
|
|
51
|
+
instance: Schema.NonEmptyString,
|
|
52
|
+
requestId: Schema.NonEmptyString,
|
|
53
|
+
expectedGeneration: Schema.NullOr(PositiveInt),
|
|
54
|
+
leaseMillis: Schema.optionalKey(PositiveFinite),
|
|
55
|
+
limits: Limits,
|
|
56
|
+
},
|
|
57
|
+
success: SessionRecord,
|
|
58
|
+
error: SessionError,
|
|
59
|
+
}),
|
|
60
|
+
Rpc.make("Load", {
|
|
61
|
+
payload: {
|
|
62
|
+
handle: Handle,
|
|
63
|
+
specifier: Schema.NonEmptyString,
|
|
64
|
+
digest: Schema.optionalKey(Schema.Boolean),
|
|
65
|
+
},
|
|
66
|
+
success: CodeIdentity,
|
|
67
|
+
error: SessionError,
|
|
68
|
+
}),
|
|
69
|
+
Rpc.make("Renew", {
|
|
70
|
+
payload: Handle,
|
|
71
|
+
success: Schema.Finite,
|
|
72
|
+
error: SessionError,
|
|
73
|
+
}),
|
|
74
|
+
Rpc.make("Dispose", {
|
|
75
|
+
payload: Handle,
|
|
76
|
+
success: Termination,
|
|
77
|
+
error: SessionError,
|
|
78
|
+
}),
|
|
79
|
+
Rpc.make("Status", {
|
|
80
|
+
payload: Handle,
|
|
81
|
+
success: SessionRecord,
|
|
82
|
+
error: SessionError,
|
|
83
|
+
}),
|
|
84
|
+
).annotateRpcs(Port.Priority, "control")
|
|
85
|
+
|
|
86
|
+
export type Peer = Multiplex.Peer
|
|
87
|
+
/** Preserve the port writer order within each byte channel. */
|
|
88
|
+
export const channel = (peer: Peer, id: 0 | 1): Port.Channel => ({
|
|
89
|
+
input: Stream.fromEffectRepeat(peer.take(id)),
|
|
90
|
+
output: Sink.forEach((bytes: Uint8Array) =>
|
|
91
|
+
peer
|
|
92
|
+
.send(id, bytes)
|
|
93
|
+
.pipe(
|
|
94
|
+
Effect.mapError((error) =>
|
|
95
|
+
TransportError.make({ cause: Cause.fail(error) }),
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
),
|
|
99
|
+
})
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Cause, Effect, Ref, Option, Scope, Semaphore } from "effect"
|
|
2
|
+
import { RpcServer } from "effect/rpc"
|
|
3
|
+
import { Peer } from "../Peer"
|
|
4
|
+
import { TransportError } from "../../Errors"
|
|
5
|
+
import type { Channel } from "../../Transport"
|
|
6
|
+
import type { Supervisor } from "./Supervisor"
|
|
7
|
+
import type { Channels } from "./Execution"
|
|
8
|
+
import * as Port from "../port"
|
|
9
|
+
import * as Multiplex from "./Multiplex"
|
|
10
|
+
import * as Wire from "./Wire"
|
|
11
|
+
import { SessionAccessDenied, SessionConflict, type Handle } from "./model"
|
|
12
|
+
|
|
13
|
+
export const accept = (
|
|
14
|
+
supervisor: typeof Supervisor.Service,
|
|
15
|
+
execution: typeof Channels.Service,
|
|
16
|
+
channel: Channel,
|
|
17
|
+
) =>
|
|
18
|
+
Effect.gen(function* () {
|
|
19
|
+
const identity = yield* Peer
|
|
20
|
+
const scope = yield* Effect.scope
|
|
21
|
+
const mux = yield* Multiplex.make(channel)
|
|
22
|
+
const peer = yield* Port.make(Wire.channel(mux, 0), {
|
|
23
|
+
session: "session-v1",
|
|
24
|
+
serve: { session: Wire.Session },
|
|
25
|
+
call: {},
|
|
26
|
+
})
|
|
27
|
+
const attached = yield* Ref.make(Option.none<string>())
|
|
28
|
+
const loading = yield* Semaphore.make(1)
|
|
29
|
+
const authorize = (handle: Handle) =>
|
|
30
|
+
handle.key.identity === identity
|
|
31
|
+
? Effect.void
|
|
32
|
+
: Effect.fail(
|
|
33
|
+
SessionAccessDenied.make({
|
|
34
|
+
detail: "The session belongs to another authenticated identity",
|
|
35
|
+
}),
|
|
36
|
+
)
|
|
37
|
+
const handlers = yield* Wire.Session.toHandlers({
|
|
38
|
+
HighWater: ({ instance }) => supervisor.highWater({ identity, instance }),
|
|
39
|
+
Open: ({
|
|
40
|
+
instance,
|
|
41
|
+
requestId,
|
|
42
|
+
expectedGeneration,
|
|
43
|
+
leaseMillis,
|
|
44
|
+
limits,
|
|
45
|
+
}) =>
|
|
46
|
+
supervisor.open({
|
|
47
|
+
key: { identity, instance },
|
|
48
|
+
requestId,
|
|
49
|
+
expectedGeneration,
|
|
50
|
+
...(leaseMillis === undefined ? {} : { lease: leaseMillis }),
|
|
51
|
+
limits,
|
|
52
|
+
}),
|
|
53
|
+
Load: ({ handle, ...request }) =>
|
|
54
|
+
Effect.gen(function* () {
|
|
55
|
+
yield* authorize(handle)
|
|
56
|
+
const attachment = yield* Ref.get(attached)
|
|
57
|
+
if (Option.isSome(attachment) && attachment.value !== handle.token)
|
|
58
|
+
return yield* SessionConflict.make({
|
|
59
|
+
detail: "A connection can attach only one execution",
|
|
60
|
+
})
|
|
61
|
+
const code = yield* supervisor.load(handle, request)
|
|
62
|
+
if (Option.isNone(attachment)) {
|
|
63
|
+
const child = yield* execution
|
|
64
|
+
.peer(handle.token)
|
|
65
|
+
.pipe(Scope.provide(scope))
|
|
66
|
+
yield* Ref.set(attached, Option.some(handle.token))
|
|
67
|
+
// A child EOF must not destroy the session channel before Dispose can acknowledge exit.
|
|
68
|
+
yield* Effect.all(
|
|
69
|
+
[
|
|
70
|
+
Effect.forever(
|
|
71
|
+
Effect.flatMap(mux.take(1), (bytes) => child.send(1, bytes)),
|
|
72
|
+
),
|
|
73
|
+
Effect.forever(
|
|
74
|
+
Effect.flatMap(child.take(1), (bytes) => mux.send(1, bytes)),
|
|
75
|
+
),
|
|
76
|
+
],
|
|
77
|
+
{ concurrency: "unbounded" },
|
|
78
|
+
).pipe(
|
|
79
|
+
Effect.catchCause((cause) =>
|
|
80
|
+
Cause.hasInterruptsOnly(cause)
|
|
81
|
+
? Effect.void
|
|
82
|
+
: child.fail(TransportError.make({ cause })),
|
|
83
|
+
),
|
|
84
|
+
Effect.forkIn(scope),
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
return code
|
|
88
|
+
}).pipe(loading.withPermit),
|
|
89
|
+
Renew: (handle) =>
|
|
90
|
+
authorize(handle).pipe(Effect.andThen(supervisor.renew(handle))),
|
|
91
|
+
Dispose: (handle) =>
|
|
92
|
+
authorize(handle).pipe(Effect.andThen(supervisor.dispose(handle))),
|
|
93
|
+
Status: (handle) =>
|
|
94
|
+
authorize(handle).pipe(Effect.andThen(supervisor.status(handle))),
|
|
95
|
+
})
|
|
96
|
+
return yield* RpcServer.make(Wire.Session, {
|
|
97
|
+
disableFatalDefects: true,
|
|
98
|
+
}).pipe(
|
|
99
|
+
Effect.provideContext(handlers),
|
|
100
|
+
Effect.provideService(RpcServer.Protocol, peer.serverProtocol("session")),
|
|
101
|
+
Effect.raceFirst(mux.await),
|
|
102
|
+
)
|
|
103
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect } from "effect"
|
|
2
|
+
import process from "node:process"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
|
|
5
|
+
/** Resolve the executable through the installed package export, never a relative dist path. */
|
|
6
|
+
export const command = (override?: readonly [string, ...string[]]) =>
|
|
7
|
+
Effect.sync(
|
|
8
|
+
(): readonly [string, ...string[]] =>
|
|
9
|
+
override ?? [
|
|
10
|
+
process.execPath,
|
|
11
|
+
fileURLToPath(
|
|
12
|
+
import.meta.resolve("@graftland/plugin-remote/internal/bin"),
|
|
13
|
+
),
|
|
14
|
+
],
|
|
15
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Array, Cause, Effect, Schema } from "effect"
|
|
2
|
+
import { Socket } from "effect/socket"
|
|
3
|
+
import { TransportError } from "../../Errors"
|
|
4
|
+
import { EndOfStream } from "./Framing"
|
|
5
|
+
import { Peer } from "../Peer"
|
|
6
|
+
|
|
7
|
+
// Multiplex preserves the socket reason inside TransportError; only an entirely normal close is silent.
|
|
8
|
+
export const closedNormally = (cause: Cause.Cause<unknown>): boolean =>
|
|
9
|
+
cause.reasons.length > 0 &&
|
|
10
|
+
Array.every(
|
|
11
|
+
cause.reasons,
|
|
12
|
+
(reason) =>
|
|
13
|
+
reason._tag === "Fail" &&
|
|
14
|
+
(Schema.is(TransportError)(reason.error)
|
|
15
|
+
? closedNormally(reason.error.cause)
|
|
16
|
+
: Schema.is(EndOfStream)(reason.error) ||
|
|
17
|
+
(Socket.isSocketError(reason.error) &&
|
|
18
|
+
reason.error.reason._tag === "SocketCloseError" &&
|
|
19
|
+
reason.error.reason.code === 1000)),
|
|
20
|
+
)
|
|
21
|
+
export const connectionEnded = (cause: Cause.Cause<unknown>) =>
|
|
22
|
+
Cause.hasInterruptsOnly(cause) || closedNormally(cause)
|
|
23
|
+
? Effect.void
|
|
24
|
+
: Effect.flatMap(Peer, (identity) =>
|
|
25
|
+
Effect.logWarning("Remote host connection failed", cause).pipe(
|
|
26
|
+
Effect.annotateLogs({ "remote.peer": identity }),
|
|
27
|
+
),
|
|
28
|
+
)
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { Limits, PositiveInt } from "../Limits"
|
|
2
|
+
export { Limits, PositiveInt, PositiveFinite, defaults } from "../Limits"
|
|
3
|
+
import {
|
|
4
|
+
Array,
|
|
5
|
+
Cause,
|
|
6
|
+
Context,
|
|
7
|
+
Data,
|
|
8
|
+
Duration,
|
|
9
|
+
Effect,
|
|
10
|
+
Option,
|
|
11
|
+
Schema,
|
|
12
|
+
} from "effect"
|
|
13
|
+
import type { Scope } from "effect"
|
|
14
|
+
|
|
15
|
+
const diagnosticCause = Schema.Cause(
|
|
16
|
+
Schema.Defect({ includeStack: true }),
|
|
17
|
+
Schema.Defect({ includeStack: true }),
|
|
18
|
+
)
|
|
19
|
+
export class PackageError extends Schema.TaggedError<
|
|
20
|
+
PackageError,
|
|
21
|
+
{ readonly brand: unique symbol }
|
|
22
|
+
>()("PackageError", {
|
|
23
|
+
detail: Schema.String,
|
|
24
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
25
|
+
}) {
|
|
26
|
+
override get message() {
|
|
27
|
+
return this.detail
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class SessionAccessDenied extends Schema.TaggedError<
|
|
31
|
+
SessionAccessDenied,
|
|
32
|
+
{ readonly brand: unique symbol }
|
|
33
|
+
>()("SessionAccessDenied", {
|
|
34
|
+
detail: Schema.String,
|
|
35
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
36
|
+
}) {
|
|
37
|
+
override get message() {
|
|
38
|
+
return this.detail
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class StaleSession extends Schema.TaggedError<
|
|
42
|
+
StaleSession,
|
|
43
|
+
{ readonly brand: unique symbol }
|
|
44
|
+
>()("StaleSession", {
|
|
45
|
+
detail: Schema.String,
|
|
46
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
47
|
+
}) {
|
|
48
|
+
override get message() {
|
|
49
|
+
return this.detail
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export class LeaseExpired extends Schema.TaggedError<
|
|
53
|
+
LeaseExpired,
|
|
54
|
+
{ readonly brand: unique symbol }
|
|
55
|
+
>()("LeaseExpired", {
|
|
56
|
+
detail: Schema.String,
|
|
57
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
58
|
+
}) {
|
|
59
|
+
override get message() {
|
|
60
|
+
return this.detail
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export class SessionStopped extends Schema.TaggedError<
|
|
64
|
+
SessionStopped,
|
|
65
|
+
{ readonly brand: unique symbol }
|
|
66
|
+
>()("SessionStopped", {
|
|
67
|
+
detail: Schema.String,
|
|
68
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
69
|
+
}) {
|
|
70
|
+
override get message() {
|
|
71
|
+
return this.detail
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export class SessionConflict extends Schema.TaggedError<
|
|
75
|
+
SessionConflict,
|
|
76
|
+
{ readonly brand: unique symbol }
|
|
77
|
+
>()("SessionConflict", {
|
|
78
|
+
detail: Schema.String,
|
|
79
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
80
|
+
}) {
|
|
81
|
+
override get message() {
|
|
82
|
+
return this.detail
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export class StateStorageError extends Schema.TaggedError<
|
|
86
|
+
StateStorageError,
|
|
87
|
+
{ readonly brand: unique symbol }
|
|
88
|
+
>()("StateStorageError", {
|
|
89
|
+
detail: Schema.String,
|
|
90
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
91
|
+
}) {
|
|
92
|
+
override get message() {
|
|
93
|
+
return this.detail
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export class ExecutionError extends Schema.TaggedError<
|
|
97
|
+
ExecutionError,
|
|
98
|
+
{ readonly brand: unique symbol }
|
|
99
|
+
>()("ExecutionError", {
|
|
100
|
+
detail: Schema.String,
|
|
101
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
102
|
+
}) {
|
|
103
|
+
override get message() {
|
|
104
|
+
return this.detail
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export class TerminationUnconfirmed extends Schema.TaggedError<
|
|
108
|
+
TerminationUnconfirmed,
|
|
109
|
+
{ readonly brand: unique symbol }
|
|
110
|
+
>()("TerminationUnconfirmed", {
|
|
111
|
+
detail: Schema.String,
|
|
112
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
113
|
+
}) {
|
|
114
|
+
override get message() {
|
|
115
|
+
return this.detail
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export class RunnerClosing extends Schema.TaggedError<
|
|
119
|
+
RunnerClosing,
|
|
120
|
+
{ readonly brand: unique symbol }
|
|
121
|
+
>()("RunnerClosing", {
|
|
122
|
+
detail: Schema.String,
|
|
123
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
124
|
+
}) {
|
|
125
|
+
override get message() {
|
|
126
|
+
return this.detail
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export class StateDirectoryLocked extends Schema.TaggedError<
|
|
130
|
+
StateDirectoryLocked,
|
|
131
|
+
{ readonly brand: unique symbol }
|
|
132
|
+
>()("StateDirectoryLocked", {
|
|
133
|
+
detail: Schema.String,
|
|
134
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
135
|
+
}) {
|
|
136
|
+
override get message() {
|
|
137
|
+
return this.detail
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export const Key = Schema.Struct({
|
|
141
|
+
identity: Schema.NonEmptyString,
|
|
142
|
+
instance: Schema.NonEmptyString,
|
|
143
|
+
})
|
|
144
|
+
export type Key = typeof Key.Type
|
|
145
|
+
/** Structural keys keep identity namespaces separate without delimiter conventions. */
|
|
146
|
+
export class SessionKey extends Data.Class<Key> {}
|
|
147
|
+
export const keyOf = (key: Key) => new SessionKey(key)
|
|
148
|
+
export const negotiate = (local: Limits, peer: Limits): Limits => ({
|
|
149
|
+
control: Math.min(local.control, peer.control),
|
|
150
|
+
data: Math.min(local.data, peer.data),
|
|
151
|
+
log: Math.min(local.log, peer.log),
|
|
152
|
+
})
|
|
153
|
+
export const Handle = Schema.Struct({
|
|
154
|
+
key: Key,
|
|
155
|
+
token: Schema.NonEmptyString,
|
|
156
|
+
generation: PositiveInt,
|
|
157
|
+
})
|
|
158
|
+
export type Handle = typeof Handle.Type
|
|
159
|
+
export const ProcessIdentity = Schema.Struct({
|
|
160
|
+
pid: Schema.Int,
|
|
161
|
+
start: Schema.Struct({ born: Schema.String }),
|
|
162
|
+
})
|
|
163
|
+
export type ProcessIdentity = typeof ProcessIdentity.Type
|
|
164
|
+
export const ExitStatus = Schema.Struct({
|
|
165
|
+
stderr: Schema.optionalKey(Schema.String),
|
|
166
|
+
cause: Schema.optionalKey(diagnosticCause),
|
|
167
|
+
code: Schema.NullOr(Schema.Int),
|
|
168
|
+
signal: Schema.NullOr(Schema.String),
|
|
169
|
+
})
|
|
170
|
+
export type ExitStatus = typeof ExitStatus.Type
|
|
171
|
+
export const CodeIdentity = Schema.Struct({
|
|
172
|
+
name: Schema.String,
|
|
173
|
+
version: Schema.String,
|
|
174
|
+
digest: Schema.optionalKey(Schema.String),
|
|
175
|
+
})
|
|
176
|
+
export type CodeIdentity = typeof CodeIdentity.Type
|
|
177
|
+
export const Load = Schema.Struct({
|
|
178
|
+
specifier: Schema.String,
|
|
179
|
+
digest: Schema.optionalKey(Schema.Boolean),
|
|
180
|
+
})
|
|
181
|
+
export type Load = typeof Load.Type
|
|
182
|
+
export const Termination = Schema.Struct({
|
|
183
|
+
kind: Schema.Literals(["Exited", "Killed"]),
|
|
184
|
+
exit: ExitStatus,
|
|
185
|
+
cause: diagnosticCause,
|
|
186
|
+
})
|
|
187
|
+
export type Termination = typeof Termination.Type
|
|
188
|
+
const Fields = {
|
|
189
|
+
version: Schema.Literal(1),
|
|
190
|
+
handle: Handle,
|
|
191
|
+
requestId: Schema.String,
|
|
192
|
+
leaseMillis: Schema.Finite,
|
|
193
|
+
limits: Limits,
|
|
194
|
+
}
|
|
195
|
+
export const OpenRecord = Schema.Struct({
|
|
196
|
+
...Fields,
|
|
197
|
+
phase: Schema.Literal("Open"),
|
|
198
|
+
})
|
|
199
|
+
export const Launch = Schema.Union([
|
|
200
|
+
Schema.TaggedStruct("Starting", {}),
|
|
201
|
+
Schema.TaggedStruct("Registered", { child: ProcessIdentity }),
|
|
202
|
+
])
|
|
203
|
+
export const LoadingRecord = Schema.Struct({
|
|
204
|
+
...Fields,
|
|
205
|
+
phase: Schema.Literal("Loading"),
|
|
206
|
+
load: Load,
|
|
207
|
+
launch: Launch,
|
|
208
|
+
})
|
|
209
|
+
export const LoadedRecord = Schema.Struct({
|
|
210
|
+
...Fields,
|
|
211
|
+
phase: Schema.Literal("Loaded"),
|
|
212
|
+
load: Load,
|
|
213
|
+
child: ProcessIdentity,
|
|
214
|
+
code: CodeIdentity,
|
|
215
|
+
})
|
|
216
|
+
export const ActiveRecord = Schema.Union([
|
|
217
|
+
OpenRecord,
|
|
218
|
+
LoadingRecord,
|
|
219
|
+
LoadedRecord,
|
|
220
|
+
])
|
|
221
|
+
export type ActiveRecord = typeof ActiveRecord.Type
|
|
222
|
+
export const StopReason = Schema.Union([
|
|
223
|
+
...Array.map(
|
|
224
|
+
[
|
|
225
|
+
"Disposed",
|
|
226
|
+
"Expired",
|
|
227
|
+
"Superseded",
|
|
228
|
+
"Recovery",
|
|
229
|
+
"Shutdown",
|
|
230
|
+
"Exited",
|
|
231
|
+
] as const,
|
|
232
|
+
(tag) => Schema.TaggedStruct(tag, {}),
|
|
233
|
+
),
|
|
234
|
+
Schema.TaggedStruct("LoadFailed", { cause: diagnosticCause }),
|
|
235
|
+
])
|
|
236
|
+
export type StopReason = typeof StopReason.Type
|
|
237
|
+
export const StoppingRecord = Schema.Struct({
|
|
238
|
+
...Fields,
|
|
239
|
+
phase: Schema.Literal("Stopping"),
|
|
240
|
+
previous: ActiveRecord,
|
|
241
|
+
reason: StopReason,
|
|
242
|
+
})
|
|
243
|
+
export const StoppedRecord = Schema.Struct({
|
|
244
|
+
...Fields,
|
|
245
|
+
phase: Schema.Literal("Stopped"),
|
|
246
|
+
previous: ActiveRecord,
|
|
247
|
+
reason: StopReason,
|
|
248
|
+
termination: Termination,
|
|
249
|
+
})
|
|
250
|
+
export const SessionRecord = Schema.Union([
|
|
251
|
+
OpenRecord,
|
|
252
|
+
LoadingRecord,
|
|
253
|
+
LoadedRecord,
|
|
254
|
+
StoppingRecord,
|
|
255
|
+
StoppedRecord,
|
|
256
|
+
])
|
|
257
|
+
export type SessionRecord = typeof SessionRecord.Type
|
|
258
|
+
export const childOf = (
|
|
259
|
+
record: SessionRecord,
|
|
260
|
+
): Option.Option<ProcessIdentity> => {
|
|
261
|
+
switch (record.phase) {
|
|
262
|
+
case "Open":
|
|
263
|
+
return Option.none()
|
|
264
|
+
case "Loading":
|
|
265
|
+
return record.launch._tag === "Registered"
|
|
266
|
+
? Option.some(record.launch.child)
|
|
267
|
+
: Option.none()
|
|
268
|
+
case "Loaded":
|
|
269
|
+
return Option.some(record.child)
|
|
270
|
+
case "Stopping":
|
|
271
|
+
case "Stopped":
|
|
272
|
+
return childOf(record.previous)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
export const stoppingRecord = (
|
|
276
|
+
previous: ActiveRecord,
|
|
277
|
+
reason: StopReason,
|
|
278
|
+
): typeof StoppingRecord.Type => ({
|
|
279
|
+
version: previous.version,
|
|
280
|
+
handle: previous.handle,
|
|
281
|
+
requestId: previous.requestId,
|
|
282
|
+
leaseMillis: previous.leaseMillis,
|
|
283
|
+
limits: previous.limits,
|
|
284
|
+
phase: "Stopping",
|
|
285
|
+
previous,
|
|
286
|
+
reason,
|
|
287
|
+
})
|
|
288
|
+
export const stoppedRecord = (
|
|
289
|
+
previous: ActiveRecord,
|
|
290
|
+
reason: StopReason,
|
|
291
|
+
termination: Termination,
|
|
292
|
+
): typeof StoppedRecord.Type => ({
|
|
293
|
+
...stoppingRecord(previous, reason),
|
|
294
|
+
phase: "Stopped",
|
|
295
|
+
termination,
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
export class Store extends Context.Service<
|
|
299
|
+
Store,
|
|
300
|
+
{
|
|
301
|
+
readonly list: Effect.Effect<
|
|
302
|
+
ReadonlyArray<SessionRecord>,
|
|
303
|
+
StateStorageError
|
|
304
|
+
>
|
|
305
|
+
readonly save: (
|
|
306
|
+
record: SessionRecord,
|
|
307
|
+
) => Effect.Effect<void, StateStorageError>
|
|
308
|
+
}
|
|
309
|
+
>()("@graftland/plugin-remote/internal/runner/model/Store") {}
|
|
310
|
+
export type ExecutionFailure =
|
|
311
|
+
ExecutionError | PackageError | TerminationUnconfirmed
|
|
312
|
+
export interface Unit {
|
|
313
|
+
readonly code: CodeIdentity
|
|
314
|
+
/** The supervisor persists identity and renews the lease before releasing the child startup gate. */
|
|
315
|
+
readonly start: Effect.Effect<void, ExecutionFailure>
|
|
316
|
+
readonly identity: ProcessIdentity
|
|
317
|
+
readonly exited: Effect.Effect<ExitStatus, ExecutionFailure>
|
|
318
|
+
readonly interrupt: Effect.Effect<void, ExecutionFailure>
|
|
319
|
+
readonly kill: Effect.Effect<void, ExecutionFailure>
|
|
320
|
+
readonly renew: (millis: number) => Effect.Effect<void, ExecutionFailure>
|
|
321
|
+
}
|
|
322
|
+
export class Execution extends Context.Service<
|
|
323
|
+
Execution,
|
|
324
|
+
{
|
|
325
|
+
readonly spawn: (
|
|
326
|
+
handle: Handle,
|
|
327
|
+
request: Load,
|
|
328
|
+
limits: Limits,
|
|
329
|
+
) => Effect.Effect<Unit, ExecutionFailure, Scope.Scope>
|
|
330
|
+
readonly recover: (
|
|
331
|
+
child: ProcessIdentity,
|
|
332
|
+
) => Effect.Effect<Termination, ExecutionFailure>
|
|
333
|
+
}
|
|
334
|
+
>()("@graftland/plugin-remote/internal/runner/model/Execution") {}
|
|
335
|
+
export class RemoteTerminationUnconfirmed extends Schema.TaggedError<
|
|
336
|
+
RemoteTerminationUnconfirmed,
|
|
337
|
+
{ readonly brand: unique symbol }
|
|
338
|
+
>()("RemoteTerminationUnconfirmed", { handle: Handle }) {}
|
|
339
|
+
/** Losing contact never becomes a successful stop merely because a lease duration passed. */
|
|
340
|
+
export const awaitTermination = <E, R>(
|
|
341
|
+
handle: Handle,
|
|
342
|
+
confirmation: Effect.Effect<Termination, E, R>,
|
|
343
|
+
leaseMillis: number,
|
|
344
|
+
marginMillis: number,
|
|
345
|
+
) =>
|
|
346
|
+
Effect.gen(function* () {
|
|
347
|
+
const [elapsed, result] = yield* Effect.exit(
|
|
348
|
+
Effect.timeoutOption(confirmation, leaseMillis + marginMillis),
|
|
349
|
+
).pipe(Effect.timed)
|
|
350
|
+
if (result._tag === "Success") {
|
|
351
|
+
if (Option.isSome(result.value)) return result.value.value
|
|
352
|
+
return yield* RemoteTerminationUnconfirmed.make({ handle })
|
|
353
|
+
}
|
|
354
|
+
// Confirmation and the disconnected wait share one deadline.
|
|
355
|
+
yield* Effect.sleep(
|
|
356
|
+
Math.max(0, leaseMillis + marginMillis - Duration.toMillis(elapsed)),
|
|
357
|
+
)
|
|
358
|
+
return yield* Effect.failCause(
|
|
359
|
+
Cause.combine(
|
|
360
|
+
result.cause,
|
|
361
|
+
Cause.fail(RemoteTerminationUnconfirmed.make({ handle })),
|
|
362
|
+
),
|
|
363
|
+
)
|
|
364
|
+
})
|