@graftland/plugin-remote 0.3.1 → 0.3.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.
- package/dist/Auth.d.ts +2 -2
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js.map +1 -1
- package/dist/{Bootstrap-Dr6sX7el.js → Bootstrap-H9gDsgsC.js} +2 -2
- package/dist/{Contract-DL2mHvaT.js → Contract-DsJtisvL.js} +2 -2
- package/dist/Contract.js +1 -1
- package/dist/{Errors-BMKmu5Y7.js → Errors-DYhsGZcZ.js} +3 -1
- package/dist/Errors.d.ts +7 -0
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js +3 -1
- package/dist/Errors.js.map +1 -1
- package/dist/{FailureGroup-BcH0XOBi.js → FailureGroup-BgT73AaR.js} +14 -4
- package/dist/{Framing-zaYdOJnT.js → Framing-G9eSaeLb.js} +1 -1
- package/dist/{Graft-CVyueNOf.js → Graft-B71CPA2Y.js} +20 -16
- package/dist/{Packages-JNL34JpS.js → Packages-AgoCGotL.js} +23 -26
- package/dist/{Peer-BT7eAGmh.js → Peer-DXeVrGBh.js} +5 -5
- package/dist/{ProcessObservation-DEGrEMfP.js → ProcessObservation-gLgGirYv.js} +1 -1
- package/dist/{ServeLifecycle-CJM0gG5B.js → ServeLifecycle-Bd1FPJ6e.js} +1 -1
- package/dist/Transport.d.ts +2 -2
- package/dist/Transport.d.ts.map +1 -1
- package/dist/Transport.js.map +1 -1
- package/dist/bin.js +48 -47
- package/dist/bin.js.map +1 -1
- package/dist/{childRuntime-An0HsIzl.js → childRuntime-Bm3iSg_N.js} +29 -26
- package/dist/{connectionEnded-DCpFCjMX.js → connectionEnded-BwcxQ7W8.js} +4 -4
- package/dist/{entry-B89sepMU.js → entry-psOpX3Bj.js} +72 -35
- package/dist/host/auth/bearer.js +1 -1
- package/dist/host/auth/jwt.js +1 -1
- package/dist/host/auth/mtls.js +2 -2
- package/dist/host/auth/none.js +1 -1
- package/dist/host/command.js +4 -4
- package/dist/host/local.js +3 -3
- package/dist/host/unix.js +3 -3
- package/dist/host/websocket.js +3 -3
- package/dist/host/worker.js +4 -5
- package/dist/{importer-Bk6U_sn4.js → importer-Cvf88eAY.js} +5 -8
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/internal/Certificates.js +4 -4
- package/dist/internal/Certificates.js.map +1 -1
- package/dist/internal/FailureGroup.js +3 -2
- package/dist/internal/FailureGroup.js.map +1 -1
- package/dist/internal/assembly.js +9 -2
- package/dist/internal/assembly.js.map +1 -1
- package/dist/internal/auth/mtls.js +1 -1
- package/dist/internal/auth/mtls.js.map +1 -1
- package/dist/internal/child.js +20 -17
- package/dist/internal/child.js.map +1 -1
- package/dist/internal/childRuntime.js +4 -4
- package/dist/internal/childRuntime.js.map +1 -1
- package/dist/internal/directTransport.d.ts +1 -1
- package/dist/internal/entry.d.ts.map +1 -1
- package/dist/internal/entry.js +1 -1
- package/dist/internal/entry.js.map +1 -1
- package/dist/internal/execution.js +40 -5
- package/dist/internal/execution.js.map +1 -1
- package/dist/internal/host/runner.js +7 -6
- package/dist/internal/host/runner.js.map +1 -1
- package/dist/internal/host.js +5 -5
- package/dist/internal/host.js.map +1 -1
- package/dist/internal/port.js +5 -5
- package/dist/internal/port.js.map +1 -1
- package/dist/internal/release.js +1 -1
- package/dist/internal/release.js.map +1 -1
- package/dist/internal/runner/Connection.d.ts +1 -1
- package/dist/internal/runner/Connection.js +4 -4
- package/dist/internal/runner/Connection.js.map +1 -1
- package/dist/internal/runner/Execution.js +3 -3
- package/dist/internal/runner/Execution.js.map +1 -1
- package/dist/internal/runner/Framing.js +1 -1
- package/dist/internal/runner/Framing.js.map +1 -1
- package/dist/internal/runner/Local.js +1 -1
- package/dist/internal/runner/Local.js.map +1 -1
- package/dist/internal/runner/Lock.js +1 -1
- package/dist/internal/runner/Lock.js.map +1 -1
- package/dist/internal/runner/Packages.d.ts +1 -1
- package/dist/internal/runner/Packages.js +22 -25
- package/dist/internal/runner/Packages.js.map +1 -1
- package/dist/internal/runner/Processes.js +7 -9
- package/dist/internal/runner/Processes.js.map +1 -1
- package/dist/internal/runner/Store.js +3 -3
- package/dist/internal/runner/Store.js.map +1 -1
- package/dist/internal/runner/Supervisor.js +46 -47
- package/dist/internal/runner/Supervisor.js.map +1 -1
- package/dist/internal/runner/accept.js +3 -3
- package/dist/internal/runner/accept.js.map +1 -1
- package/dist/internal/runner/model.js +1 -1
- package/dist/internal/runner/model.js.map +1 -1
- package/dist/internal/serve.js +1 -1
- package/dist/internal/serve.js.map +1 -1
- package/dist/internal/supervisorPlugin.js +1 -1
- package/dist/internal/watchdogMain.js +5 -5
- package/dist/internal/watchdogMain.js.map +1 -1
- package/dist/internal/websocketServer.js +3 -1
- package/dist/internal/websocketServer.js.map +1 -1
- package/dist/internal/workerMain.js +3 -3
- package/dist/{port-DSVUY8Bq.js → port--3x2zJ4D.js} +8 -8
- package/dist/{release-BY4Mlluy.js → release-DfZPuIcK.js} +1 -1
- package/dist/runner/auth/bearer.js +2 -2
- package/dist/runner/auth/jwt.js +4 -4
- package/dist/runner/auth/jwt.js.map +1 -1
- package/dist/runner/auth/mtls.js +3 -3
- package/dist/runner/auth/none.js +1 -1
- package/dist/runner/index.js +5 -5
- package/dist/runner/stdio.js +3 -3
- package/dist/runner/unix.js +3 -3
- package/dist/runner/websocket.js +4 -4
- package/dist/{socketChannel-C_ppdSzz.js → socketChannel-CJvL2DiB.js} +2 -2
- package/dist/{supervisorPlugin-CivhM7x5.js → supervisorPlugin-t6Z6PrhD.js} +72 -76
- package/dist/{token-Cc_1CTbE.js → token-CYBNNlhS.js} +1 -1
- package/dist/{tokenCredentials-CI6mMRRd.js → tokenCredentials-CbCuk-Rt.js} +3 -3
- package/dist/{websocketServer-D2Hk7wsA.js → websocketServer-NQhODlEt.js} +5 -3
- package/dist/{workerChannel-cmLc13vm.js → workerChannel-C8hhBJzA.js} +1 -1
- package/package.json +3 -3
- package/src/Auth.ts +9 -2
- package/src/Errors.ts +8 -0
- package/src/Transport.ts +6 -2
- package/src/bin.ts +28 -30
- package/src/index.ts +5 -3
- package/src/internal/Certificates.ts +10 -13
- package/src/internal/FailureGroup.ts +128 -121
- package/src/internal/assembly.ts +19 -10
- package/src/internal/auth/mtls.ts +19 -20
- package/src/internal/child.ts +248 -239
- package/src/internal/childRuntime.ts +81 -80
- package/src/internal/entry.ts +10 -11
- package/src/internal/execution.ts +69 -12
- package/src/internal/host/runner.ts +153 -153
- package/src/internal/host.ts +116 -120
- package/src/internal/port.ts +100 -103
- package/src/internal/release.ts +3 -2
- package/src/internal/runner/Connection.ts +52 -60
- package/src/internal/runner/Execution.ts +163 -164
- package/src/internal/runner/Framing.ts +9 -10
- package/src/internal/runner/Local.ts +26 -27
- package/src/internal/runner/Lock.ts +23 -25
- package/src/internal/runner/Packages.ts +67 -70
- package/src/internal/runner/Processes.ts +89 -92
- package/src/internal/runner/Store.ts +110 -114
- package/src/internal/runner/Supervisor.ts +392 -405
- package/src/internal/runner/accept.ts +76 -84
- package/src/internal/runner/model.ts +20 -21
- package/src/internal/serve.ts +15 -13
- package/src/internal/watchdogMain.ts +16 -11
- package/src/internal/websocketServer.ts +18 -3
- package/src/runner/auth/jwt.ts +10 -6
- package/dist/cleanup-CXLa1Wd9.js +0 -13
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { a as provide, l as make$2, o as fork, u as optional } from "./Graft-
|
|
2
|
-
import { a as PositiveDuration, i as Supervisor$1, t as resolve } from "./Packages-
|
|
1
|
+
import { a as provide, l as make$2, o as fork, u as optional } from "./Graft-B71CPA2Y.js";
|
|
2
|
+
import { a as PositiveDuration, i as Supervisor$1, t as resolve } from "./Packages-AgoCGotL.js";
|
|
3
3
|
import { t as ConfigDirectory } from "./ConfigDirectory-BCC6q2R4.js";
|
|
4
|
-
import { C as negotiate, E as make$3, S as keyOf, T as stoppingRecord, _ as StateStorageError, a as ExecutionError, d as SessionAccessDenied, f as SessionConflict, g as StateDirectoryLocked, h as StaleSession, i as Execution, m as SessionStopped, n as Session$1, o as Key, p as SessionRecord, r as channel, s as LeaseExpired, t as Peer, u as RunnerClosing, v as Store, w as stoppedRecord, x as childOf, y as TerminationUnconfirmed } from "./Peer-
|
|
5
|
-
import { t as observe } from "./ProcessObservation-
|
|
6
|
-
import { t as make$4 } from "./FailureGroup-
|
|
4
|
+
import { C as negotiate, E as make$3, S as keyOf, T as stoppingRecord, _ as StateStorageError, a as ExecutionError, d as SessionAccessDenied, f as SessionConflict, g as StateDirectoryLocked, h as StaleSession, i as Execution, m as SessionStopped, n as Session$1, o as Key, p as SessionRecord, r as channel, s as LeaseExpired, t as Peer, u as RunnerClosing, v as Store, w as stoppedRecord, x as childOf, y as TerminationUnconfirmed } from "./Peer-DXeVrGBh.js";
|
|
5
|
+
import { t as observe } from "./ProcessObservation-gLgGirYv.js";
|
|
6
|
+
import { r as cleanupCause, t as make$4 } from "./FailureGroup-BgT73AaR.js";
|
|
7
7
|
import { t as CommandJson } from "./WatchdogProtocol-BZmVxrBP.js";
|
|
8
|
-
import {
|
|
9
|
-
import { t as Bootstrap } from "./Bootstrap-
|
|
8
|
+
import { u as TransportError } from "./Errors-DYhsGZcZ.js";
|
|
9
|
+
import { t as Bootstrap } from "./Bootstrap-H9gDsgsC.js";
|
|
10
10
|
import { t as command } from "./command-9zrHdbwT.js";
|
|
11
|
-
import { n as close } from "./release-
|
|
12
|
-
import { n as
|
|
13
|
-
import {
|
|
14
|
-
import { i as resources, t as ServeLifecycle } from "./ServeLifecycle-CJM0gG5B.js";
|
|
11
|
+
import { n as close } from "./release-DfZPuIcK.js";
|
|
12
|
+
import { n as make$5, o as defaults } from "./port--3x2zJ4D.js";
|
|
13
|
+
import { i as resources, t as ServeLifecycle } from "./ServeLifecycle-Bd1FPJ6e.js";
|
|
15
14
|
import { Array, Cause, Clock, Context, Data, Deferred, Duration, Effect, Equal, Exit, FiberHandle, FiberSet, FileSystem, HashMap, HashSet, Layer, Option, Path, Queue, RcMap, Ref, Result, Schedule, Schema, Scope, Semaphore, Sink, Stream, String, SynchronizedRef } from "effect";
|
|
16
15
|
import process from "node:process";
|
|
17
16
|
import { Digest, SecureRandom } from "effect/crypto";
|
|
@@ -19,7 +18,7 @@ import { RpcServer } from "effect/rpc";
|
|
|
19
18
|
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
20
19
|
// packages/remote/src/internal/runner/Lock.ts
|
|
21
20
|
/** SQLite owns the local directory lock for the enclosing scope, including failed startup. */
|
|
22
|
-
const acquire =
|
|
21
|
+
const acquire = Effect.fnUntraced(function* (directory) {
|
|
23
22
|
const fs = yield* FileSystem.FileSystem;
|
|
24
23
|
const path = yield* Path.Path;
|
|
25
24
|
yield* fs.makeDirectory(directory, { recursive: true }).pipe(Effect.uninterruptible);
|
|
@@ -59,7 +58,7 @@ const memory = Effect.gen(function* () {
|
|
|
59
58
|
* Older terminal request ids expire; Open fences their retries with expectedGeneration.
|
|
60
59
|
* Requires exclusive directory ownership; it is not a multi-writer database.
|
|
61
60
|
*/
|
|
62
|
-
const directory =
|
|
61
|
+
const directory = Effect.fnUntraced(function* (root) {
|
|
63
62
|
const fs = yield* FileSystem.FileSystem;
|
|
64
63
|
const path = yield* Path.Path;
|
|
65
64
|
const digest = yield* Digest.Digest;
|
|
@@ -89,7 +88,7 @@ const directory = (root) => Effect.gen(function* () {
|
|
|
89
88
|
yield* storage(compact);
|
|
90
89
|
return Store.of({
|
|
91
90
|
list: storage(mutex.withPermit(read.pipe(Effect.map((rows) => Array.map(rows, (row) => row.record))))),
|
|
92
|
-
save:
|
|
91
|
+
save: Effect.fnUntraced(function* (record) {
|
|
93
92
|
const encoded = yield* Schema.encodeEffect(json)(record);
|
|
94
93
|
const address = yield* Schema.encodeEffect(Schema.fromJsonString(Schema.Struct({
|
|
95
94
|
key: Key,
|
|
@@ -111,13 +110,13 @@ const directory = (root) => Effect.gen(function* () {
|
|
|
111
110
|
yield* (yield* fs.open(root, { flag: "r" })).sync.pipe(Effect.uninterruptible);
|
|
112
111
|
}));
|
|
113
112
|
yield* compact;
|
|
114
|
-
})
|
|
113
|
+
}, Effect.scoped, mutex.withPermit, storage)
|
|
115
114
|
});
|
|
116
115
|
});
|
|
117
116
|
Layer.effect(Store, memory);
|
|
118
117
|
const layerDirectory = (root) => Layer.effect(Store, directory(root));
|
|
119
118
|
// packages/remote/src/internal/runner/Processes.ts
|
|
120
|
-
const inspect =
|
|
119
|
+
const inspect = Effect.fnUntraced(function* (pid) {
|
|
121
120
|
const child = yield* (yield* ChildProcessSpawner.ChildProcessSpawner).spawn(ChildProcess.make("ps", [
|
|
122
121
|
"-p",
|
|
123
122
|
`${pid}`,
|
|
@@ -126,10 +125,8 @@ const inspect = (pid) => Effect.scoped(Effect.gen(function* () {
|
|
|
126
125
|
"-o",
|
|
127
126
|
"stat="
|
|
128
127
|
], {
|
|
129
|
-
env: {
|
|
130
|
-
|
|
131
|
-
LC_ALL: "C"
|
|
132
|
-
},
|
|
128
|
+
env: { LC_ALL: "C" },
|
|
129
|
+
extendEnv: true,
|
|
133
130
|
stdin: "ignore"
|
|
134
131
|
}));
|
|
135
132
|
const [code, output, stderr] = yield* Effect.all([
|
|
@@ -142,11 +139,11 @@ const inspect = (pid) => Effect.scoped(Effect.gen(function* () {
|
|
|
142
139
|
if (code !== 0 || born === void 0 || status === void 0) return yield* ExecutionError.make({ detail: "Cannot inspect process identity: " + stderr });
|
|
143
140
|
if (String.startsWith("Z")(status)) return Option.none();
|
|
144
141
|
return Option.some({ born });
|
|
145
|
-
}
|
|
142
|
+
}, Effect.scoped, Effect.mapError((error) => error._tag === "ExecutionError" ? error : ExecutionError.make({
|
|
146
143
|
detail: "Inspecting process identity failed",
|
|
147
144
|
cause: Cause.fail(error)
|
|
148
145
|
})));
|
|
149
|
-
const identity =
|
|
146
|
+
const identity = Effect.fnUntraced(function* (pid) {
|
|
150
147
|
const current = yield* inspect(pid);
|
|
151
148
|
if (Option.isNone(current)) return yield* ExecutionError.make({ detail: "The child exited before its identity could be recorded" });
|
|
152
149
|
return {
|
|
@@ -154,12 +151,12 @@ const identity = (pid) => Effect.gen(function* () {
|
|
|
154
151
|
start: current.value
|
|
155
152
|
};
|
|
156
153
|
});
|
|
157
|
-
const matches =
|
|
154
|
+
const matches = Effect.fnUntraced(function* (child) {
|
|
158
155
|
const current = yield* inspect(child.pid);
|
|
159
156
|
if (Option.isNone(current) || current.value.born !== child.start.born) return false;
|
|
160
157
|
return true;
|
|
161
158
|
});
|
|
162
|
-
const recover$1 =
|
|
159
|
+
const recover$1 = Effect.fnUntraced(function* (child) {
|
|
163
160
|
if (!(yield* matches(child))) return {
|
|
164
161
|
kind: "Exited",
|
|
165
162
|
exit: {
|
|
@@ -194,7 +191,7 @@ const recover$1 = (child) => Effect.gen(function* () {
|
|
|
194
191
|
});
|
|
195
192
|
// packages/remote/src/internal/runner/Execution.ts
|
|
196
193
|
var Channels = class extends Context.Service()("@graftland/plugin-remote/internal/runner/Execution/Channels") {};
|
|
197
|
-
const make$1 =
|
|
194
|
+
const make$1 = Effect.fnUntraced(function* (root) {
|
|
198
195
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
199
196
|
const fs = yield* FileSystem.FileSystem;
|
|
200
197
|
const path = yield* Path.Path;
|
|
@@ -204,7 +201,7 @@ const make$1 = (root) => Effect.gen(function* () {
|
|
|
204
201
|
return {
|
|
205
202
|
driver: Execution.of({
|
|
206
203
|
recover: (child) => recover$1(child).pipe(Effect.provideContext(platform)),
|
|
207
|
-
spawn: (handle, request, limits)
|
|
204
|
+
spawn: Effect.fnUntraced(function* (handle, request, limits) {
|
|
208
205
|
const resolved = yield* resolve(root, request.specifier, request.digest);
|
|
209
206
|
const argv = yield* command();
|
|
210
207
|
const child = yield* spawner.spawn(ChildProcess.make(argv[0], [
|
|
@@ -270,7 +267,7 @@ const make$1 = (root) => Effect.gen(function* () {
|
|
|
270
267
|
millis
|
|
271
268
|
})
|
|
272
269
|
};
|
|
273
|
-
}
|
|
270
|
+
}, Effect.provideContext(platform), Effect.catchTags({
|
|
274
271
|
PlatformError: (error) => Effect.fail(ExecutionError.make({
|
|
275
272
|
detail: "Starting the child failed",
|
|
276
273
|
cause: Cause.fail(error)
|
|
@@ -369,34 +366,32 @@ const emptyTermination = {
|
|
|
369
366
|
};
|
|
370
367
|
const exitCause = (exit) => Exit.isFailure(exit) ? exit.cause : Cause.empty;
|
|
371
368
|
/** A signal is a request; only the exited effect confirms that the execution has stopped. */
|
|
372
|
-
const terminate = (execution, grace, confirmation)
|
|
373
|
-
if (execution._tag === "Absent") return
|
|
374
|
-
if (execution._tag === "Exited") return
|
|
369
|
+
const terminate = Effect.fnUntraced(function* (execution, grace, confirmation) {
|
|
370
|
+
if (execution._tag === "Absent") return emptyTermination;
|
|
371
|
+
if (execution._tag === "Exited") return {
|
|
375
372
|
...emptyTermination,
|
|
376
373
|
exit: execution.exit
|
|
377
|
-
}
|
|
374
|
+
};
|
|
378
375
|
const child = execution.unit;
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
cause
|
|
391
|
-
});
|
|
392
|
-
return {
|
|
393
|
-
kind: "Killed",
|
|
394
|
-
exit: forced.value.value,
|
|
395
|
-
cause
|
|
396
|
-
};
|
|
376
|
+
const graceful = yield* child.interrupt.pipe(Effect.andThen(child.exited), Effect.timeoutOption(grace), Effect.exit);
|
|
377
|
+
if (Exit.isSuccess(graceful) && Option.isSome(graceful.value)) return {
|
|
378
|
+
...emptyTermination,
|
|
379
|
+
exit: graceful.value.value
|
|
380
|
+
};
|
|
381
|
+
const killed = yield* Effect.exit(child.kill);
|
|
382
|
+
const forced = yield* child.exited.pipe(Effect.timeoutOption(confirmation), Effect.exit);
|
|
383
|
+
const cause = Cause.combine(Cause.combine(exitCause(graceful), exitCause(killed)), exitCause(forced));
|
|
384
|
+
if (Exit.isFailure(forced) || Option.isNone(forced.value)) return yield* TerminationUnconfirmed.make({
|
|
385
|
+
detail: "The child exit could not be confirmed",
|
|
386
|
+
cause
|
|
397
387
|
});
|
|
398
|
-
|
|
399
|
-
|
|
388
|
+
return {
|
|
389
|
+
kind: "Killed",
|
|
390
|
+
exit: forced.value.value,
|
|
391
|
+
cause
|
|
392
|
+
};
|
|
393
|
+
});
|
|
394
|
+
const initialize = Effect.fnUntraced(function* (options = {}) {
|
|
400
395
|
const store = yield* Store;
|
|
401
396
|
const execution = yield* Execution;
|
|
402
397
|
const random = yield* SecureRandom.SecureRandom;
|
|
@@ -432,19 +427,19 @@ const operations = (runtime) => {
|
|
|
432
427
|
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" }));
|
|
433
428
|
}));
|
|
434
429
|
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)));
|
|
435
|
-
const entryFor =
|
|
430
|
+
const entryFor = Effect.fnUntraced(function* (handle) {
|
|
436
431
|
yield* status(handle);
|
|
437
432
|
const all = yield* Ref.get(entries);
|
|
438
433
|
const found = HashMap.get(all, handle.token);
|
|
439
434
|
if (Option.isNone(found)) return yield* SessionStopped.make({ detail: "The session was retired during recovery" });
|
|
440
435
|
return found.value;
|
|
441
436
|
});
|
|
442
|
-
const commit = (entry, transition) => SynchronizedRef.updateEffect(entry.state,
|
|
437
|
+
const commit = (entry, transition) => SynchronizedRef.updateEffect(entry.state, Effect.fnUntraced(function* (state) {
|
|
443
438
|
const next = yield* Effect.fromResult(transition(state));
|
|
444
439
|
yield* persist(snapshot(next));
|
|
445
440
|
return next;
|
|
446
441
|
}));
|
|
447
|
-
const finishStop = (entry, state, saved)
|
|
442
|
+
const finishStop = Effect.fnUntraced(function* (entry, state, saved) {
|
|
448
443
|
yield* FiberHandle.clear(entry.loading);
|
|
449
444
|
const result = yield* terminate(state.execution, grace, confirmation);
|
|
450
445
|
const closed = yield* Effect.exit(close(entry.unitScope, Exit.void));
|
|
@@ -461,7 +456,7 @@ const operations = (runtime) => {
|
|
|
461
456
|
return termination;
|
|
462
457
|
});
|
|
463
458
|
/** Called with the session ref locked; the worker starts after its transition is published. */
|
|
464
|
-
const stopLocked = (entry, state, reason, exit)
|
|
459
|
+
const stopLocked = Effect.fnUntraced(function* (entry, state, reason, exit) {
|
|
465
460
|
if (state._tag === "Stopping" || state._tag === "Stopped") return [state.reply, state];
|
|
466
461
|
const reply = yield* Deferred.make();
|
|
467
462
|
const next = beginStop(state, reason, reply, exit);
|
|
@@ -478,7 +473,7 @@ const operations = (runtime) => {
|
|
|
478
473
|
return stopLocked(entry, state, { _tag: "Expired" }, Option.none()).pipe(Effect.map(([, next]) => next));
|
|
479
474
|
});
|
|
480
475
|
})), { startImmediately: false });
|
|
481
|
-
const register = (entry, unit) => SynchronizedRef.updateEffect(entry.state,
|
|
476
|
+
const register = (entry, unit) => SynchronizedRef.updateEffect(entry.state, Effect.fnUntraced(function* (state) {
|
|
482
477
|
const now = yield* Clock.monotonicTimeNanos;
|
|
483
478
|
const current = yield* Effect.fromResult(live(state, now));
|
|
484
479
|
const next = yield* Effect.fromResult(registerUnit(current, unit));
|
|
@@ -487,7 +482,7 @@ const operations = (runtime) => {
|
|
|
487
482
|
yield* FiberSet.run(workers, observe(unit.exited.pipe(Effect.flatMap((exit) => stop(entry, { _tag: "Exited" }, Option.some(exit))))));
|
|
488
483
|
return next;
|
|
489
484
|
})).pipe(Effect.uninterruptible);
|
|
490
|
-
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(
|
|
485
|
+
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(Effect.fnUntraced(function* (result) {
|
|
491
486
|
if (Exit.isSuccess(result)) {
|
|
492
487
|
yield* Deferred.done(state.reply, result);
|
|
493
488
|
return;
|
|
@@ -510,7 +505,7 @@ const operations = (runtime) => {
|
|
|
510
505
|
healthy
|
|
511
506
|
};
|
|
512
507
|
};
|
|
513
|
-
const recover =
|
|
508
|
+
const recover = Effect.fnUntraced(function* (runtime, actions) {
|
|
514
509
|
const { store, execution, confirmation, records } = runtime;
|
|
515
510
|
const { persist } = actions;
|
|
516
511
|
const stored = yield* store.list;
|
|
@@ -531,10 +526,10 @@ const recover = (runtime, actions) => Effect.gen(function* () {
|
|
|
531
526
|
yield* persist(stoppedRecord(record.phase === "Stopping" ? record.previous : record, { _tag: "Recovery" }, termination));
|
|
532
527
|
}
|
|
533
528
|
});
|
|
534
|
-
const ownShutdown =
|
|
529
|
+
const ownShutdown = Effect.fnUntraced(function* (runtime, actions) {
|
|
535
530
|
const { entries, health, closing } = runtime;
|
|
536
531
|
const { stop } = actions;
|
|
537
|
-
yield* Effect.addFinalizer(
|
|
532
|
+
yield* Effect.addFinalizer(Effect.fnUntraced(function* () {
|
|
538
533
|
yield* Ref.set(closing, true);
|
|
539
534
|
const all = yield* Ref.get(entries);
|
|
540
535
|
const exits = yield* Effect.forEach(HashMap.values(all), (entry) => stop(entry, { _tag: "Shutdown" }).pipe(Effect.flatMap(Deferred.await), Effect.exit));
|
|
@@ -543,18 +538,19 @@ const ownShutdown = (runtime, actions) => Effect.gen(function* () {
|
|
|
543
538
|
if (cause.reasons.length > 0) return yield* Effect.failCause(cleanupCause(cause));
|
|
544
539
|
}));
|
|
545
540
|
});
|
|
546
|
-
const protocol =
|
|
541
|
+
const protocol = Effect.fnUntraced(function* (runtime, actions) {
|
|
547
542
|
const { random, owner, locks, lease, limits, records, entries, health } = runtime;
|
|
548
543
|
const { persist, status, latest, entryFor, stop, scheduleLease, runLoad, healthy } = actions;
|
|
549
544
|
return Supervisor.of({
|
|
550
545
|
await: health.await,
|
|
551
546
|
status,
|
|
552
547
|
highWater: (key) => latest(key).pipe(Effect.map((value) => value === 0 ? null : value)),
|
|
553
|
-
open:
|
|
548
|
+
open: Effect.fnUntraced(function* (request) {
|
|
554
549
|
yield* healthy;
|
|
555
550
|
const leaseMillis = Duration.toMillis(request.lease ?? lease);
|
|
556
551
|
const negotiated = negotiate(limits, request.limits ?? defaults);
|
|
557
|
-
|
|
552
|
+
const lock = yield* RcMap.get(locks, keyOf(request.key));
|
|
553
|
+
return yield* Effect.gen(function* () {
|
|
558
554
|
yield* healthy;
|
|
559
555
|
const allRecords = yield* Ref.get(records);
|
|
560
556
|
const same = Array.filter(Array.fromIterable(HashMap.values(allRecords)), (row) => Equal.equals(keyOf(row.handle.key), keyOf(request.key)));
|
|
@@ -605,28 +601,28 @@ const protocol = (runtime, actions) => Effect.gen(function* () {
|
|
|
605
601
|
yield* scheduleLease(entry, deadline);
|
|
606
602
|
return record;
|
|
607
603
|
}));
|
|
608
|
-
}));
|
|
609
|
-
})
|
|
610
|
-
renew:
|
|
604
|
+
}).pipe(lock.withPermit);
|
|
605
|
+
}, Effect.scoped),
|
|
606
|
+
renew: Effect.fnUntraced(function* (handle) {
|
|
611
607
|
yield* healthy;
|
|
612
608
|
const entry = yield* entryFor(handle);
|
|
613
|
-
return yield* SynchronizedRef.modifyEffect(entry.state,
|
|
609
|
+
return yield* Effect.uninterruptibleMask((restore) => SynchronizedRef.modifyEffect(entry.state, Effect.fnUntraced(function* (state) {
|
|
614
610
|
const now = yield* Clock.monotonicTimeNanos;
|
|
615
611
|
const current = yield* Effect.fromResult(live(state, now));
|
|
616
612
|
const running = executionOf(current);
|
|
617
|
-
if (running._tag === "Running") yield* running.unit.renew(current.record.leaseMillis);
|
|
613
|
+
if (running._tag === "Running") yield* restore(running.unit.renew(current.record.leaseMillis));
|
|
618
614
|
const deadline = now + nanos(current.record.leaseMillis);
|
|
619
615
|
yield* scheduleLease(entry, deadline);
|
|
620
616
|
return [current.record.leaseMillis, {
|
|
621
617
|
...current,
|
|
622
618
|
deadline
|
|
623
619
|
}];
|
|
624
|
-
}));
|
|
620
|
+
})));
|
|
625
621
|
}),
|
|
626
|
-
load:
|
|
622
|
+
load: Effect.fnUntraced(function* (handle, request) {
|
|
627
623
|
yield* healthy;
|
|
628
624
|
const entry = yield* entryFor(handle);
|
|
629
|
-
return yield* yield* SynchronizedRef.modifyEffect(entry.state,
|
|
625
|
+
return yield* yield* SynchronizedRef.modifyEffect(entry.state, Effect.fnUntraced(function* (state) {
|
|
630
626
|
const now = yield* Clock.monotonicTimeNanos;
|
|
631
627
|
const current = yield* Effect.fromResult(live(state, now));
|
|
632
628
|
if (current._tag !== "Open") {
|
|
@@ -640,7 +636,7 @@ const protocol = (runtime, actions) => Effect.gen(function* () {
|
|
|
640
636
|
return [Deferred.await(done), next];
|
|
641
637
|
})).pipe(Effect.uninterruptible);
|
|
642
638
|
}),
|
|
643
|
-
dispose:
|
|
639
|
+
dispose: Effect.fnUntraced(function* (handle) {
|
|
644
640
|
const record = yield* status(handle);
|
|
645
641
|
if (record.phase === "Stopped") return record.termination;
|
|
646
642
|
const entry = yield* entryFor(handle);
|
|
@@ -648,7 +644,7 @@ const protocol = (runtime, actions) => Effect.gen(function* () {
|
|
|
648
644
|
})
|
|
649
645
|
});
|
|
650
646
|
});
|
|
651
|
-
const make = (options = {})
|
|
647
|
+
const make = Effect.fnUntraced(function* (options = {}) {
|
|
652
648
|
const runtime = yield* initialize(options);
|
|
653
649
|
const actions = operations(runtime);
|
|
654
650
|
yield* recover(runtime, actions);
|
|
@@ -657,7 +653,7 @@ const make = (options = {}) => Effect.gen(function* () {
|
|
|
657
653
|
});
|
|
658
654
|
const layer = (options = {}) => Layer.effect(Supervisor, make(options));
|
|
659
655
|
// packages/remote/src/internal/runner/accept.ts
|
|
660
|
-
const accept = (supervisor, execution, channel$1)
|
|
656
|
+
const accept = Effect.fnUntraced(function* (supervisor, execution, channel$1) {
|
|
661
657
|
const identity = yield* Peer;
|
|
662
658
|
const scope = yield* Effect.scope;
|
|
663
659
|
const mux = yield* make$3(channel$1);
|
|
@@ -684,7 +680,7 @@ const accept = (supervisor, execution, channel$1) => Effect.gen(function* () {
|
|
|
684
680
|
...leaseMillis === void 0 ? {} : { lease: leaseMillis },
|
|
685
681
|
limits
|
|
686
682
|
}),
|
|
687
|
-
Load: ({ handle, ...request })
|
|
683
|
+
Load: Effect.fnUntraced(function* ({ handle, ...request }) {
|
|
688
684
|
yield* authorize(handle);
|
|
689
685
|
const attachment = yield* Ref.get(attached);
|
|
690
686
|
if (Option.isSome(attachment) && attachment.value !== handle.token) return yield* SessionConflict.make({ detail: "A connection can attach only one execution" });
|
|
@@ -695,7 +691,7 @@ const accept = (supervisor, execution, channel$1) => Effect.gen(function* () {
|
|
|
695
691
|
yield* Effect.all([Effect.forever(Effect.flatMap(mux.take(1), (bytes) => child.send(1, bytes))), Effect.forever(Effect.flatMap(child.take(1), (bytes) => mux.send(1, bytes)))], { concurrency: "unbounded" }).pipe(Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : child.fail(TransportError.make({ cause }))), Effect.forkIn(scope));
|
|
696
692
|
}
|
|
697
693
|
return code;
|
|
698
|
-
}
|
|
694
|
+
}, loading.withPermit),
|
|
699
695
|
Renew: (handle) => authorize(handle).pipe(Effect.andThen(supervisor.renew(handle))),
|
|
700
696
|
Dispose: (handle) => authorize(handle).pipe(Effect.andThen(supervisor.dispose(handle))),
|
|
701
697
|
Status: (handle) => authorize(handle).pipe(Effect.andThen(supervisor.status(handle)))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AuthenticationFailed } from "./Errors-
|
|
1
|
+
import { t as AuthenticationFailed } from "./Errors-DYhsGZcZ.js";
|
|
2
2
|
import { Effect, Option, Redacted } from "effect";
|
|
3
3
|
// packages/remote/src/internal/auth/token.ts
|
|
4
4
|
const invalid = () => AuthenticationFailed.make({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as provide, l as make } from "./Graft-
|
|
1
|
+
import { a as provide, l as make } from "./Graft-B71CPA2Y.js";
|
|
2
2
|
import { t as ConfigDirectory } from "./ConfigDirectory-BCC6q2R4.js";
|
|
3
3
|
import { n as Credentials } from "./Auth-BElTC9_X.js";
|
|
4
|
-
import {
|
|
5
|
-
import { n as prepare } from "./token-
|
|
4
|
+
import { r as CredentialsError } from "./Errors-DYhsGZcZ.js";
|
|
5
|
+
import { n as prepare } from "./token-CYBNNlhS.js";
|
|
6
6
|
import { Cause, Effect, FileSystem, Option, Path, Redacted, Schema } from "effect";
|
|
7
7
|
// packages/remote/src/internal/auth/tokenCredentials.ts
|
|
8
8
|
const Config$1 = Schema.Struct({ token: Schema.Union([Schema.RedactedFromValue(Schema.String), Schema.Struct({ file: Schema.String })]) });
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as payloadLimit, s as protocol, t as fromSocket } from "./socketChannel-
|
|
1
|
+
import { u as TransportError } from "./Errors-DYhsGZcZ.js";
|
|
2
|
+
import { a as payloadLimit, s as protocol, t as fromSocket } from "./socketChannel-CJvL2DiB.js";
|
|
3
3
|
import { Array, Cause, Deferred, Effect, Option, Redacted, Scope, String } from "effect";
|
|
4
4
|
import { NodeHttpServer, NodeHttpServerRequest } from "@effect/platform-node";
|
|
5
5
|
import { HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
6
6
|
import { TLSSocket } from "node:tls";
|
|
7
7
|
// packages/remote/src/internal/websocketServer.ts
|
|
8
|
-
const rejection = (error) =>
|
|
8
|
+
const rejection = (error) => error._tag === "AuthenticatorUnavailable" ? unavailable(error) : unauthorized(error);
|
|
9
|
+
const unavailable = (error) => Effect.logError("Remote host authenticator is unavailable", error.cause).pipe(Effect.as(HttpServerResponse.empty({ status: 503 })));
|
|
10
|
+
const unauthorized = (error) => Effect.logWarning("Remote host authentication failed", { reason: error.reason }, ...error.cause === void 0 ? [] : [error.cause]).pipe(Effect.as(HttpServerResponse.empty({
|
|
9
11
|
status: 401,
|
|
10
12
|
headers: error.challenge === void 0 ? {} : { "www-authenticate": error.challenge }
|
|
11
13
|
})));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as TransportError } from "./Errors-DYhsGZcZ.js";
|
|
2
2
|
import { Cause, Effect, FiberSet, Queue, Schema, Sink, Stream } from "effect";
|
|
3
3
|
// packages/remote/src/internal/workerBootstrap.ts
|
|
4
4
|
const Bootstrap = Schema.Struct({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graftland/plugin-remote",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local and authenticated network execution for Graft plugins",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"effect": "4.1.*"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@graftland/graft": "0.3.
|
|
52
|
+
"@graftland/graft": "0.3.2",
|
|
53
53
|
"@effect/platform-node": "4.1.2",
|
|
54
|
-
"@graftland/loader": "0.3.
|
|
54
|
+
"@graftland/loader": "0.3.2",
|
|
55
55
|
"pkijs": "4.0.1",
|
|
56
56
|
"asn1js": "4.0.0",
|
|
57
57
|
"ws": "8.22.1"
|
package/src/Auth.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/** Credentials and authenticated identities shared by transport plugins. */
|
|
2
2
|
import { Context } from "effect"
|
|
3
3
|
import type { Effect, Redacted, Option, Scope } from "effect"
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
AuthenticationFailed,
|
|
6
|
+
AuthenticatorUnavailable,
|
|
7
|
+
CredentialsError,
|
|
8
|
+
} from "./Errors"
|
|
5
9
|
|
|
6
10
|
export interface ClientCertificate {
|
|
7
11
|
readonly cert: string
|
|
@@ -42,7 +46,10 @@ export type AuthenticatorApi =
|
|
|
42
46
|
readonly issuer?: string
|
|
43
47
|
readonly authenticate: (
|
|
44
48
|
header: Option.Option<Redacted.Redacted<string>>,
|
|
45
|
-
) => Effect.Effect<
|
|
49
|
+
) => Effect.Effect<
|
|
50
|
+
string,
|
|
51
|
+
AuthenticationFailed | AuthenticatorUnavailable
|
|
52
|
+
>
|
|
46
53
|
}
|
|
47
54
|
| {
|
|
48
55
|
readonly _tag: "Mtls"
|
package/src/Errors.ts
CHANGED
|
@@ -81,6 +81,14 @@ export class AuthenticationFailed extends Schema.TaggedError<
|
|
|
81
81
|
cause: Schema.optionalKey(Schema.Cause(Schema.Unknown, Schema.Unknown)),
|
|
82
82
|
}) {}
|
|
83
83
|
|
|
84
|
+
/** The authenticator could not reach what it needs to decide, such as its key set; the credential may still be valid. */
|
|
85
|
+
export class AuthenticatorUnavailable extends Schema.TaggedError<
|
|
86
|
+
AuthenticatorUnavailable,
|
|
87
|
+
{ readonly brand: unique symbol }
|
|
88
|
+
>()("AuthenticatorUnavailable", {
|
|
89
|
+
cause: Schema.Cause(Schema.Unknown, Schema.Unknown),
|
|
90
|
+
}) {}
|
|
91
|
+
|
|
84
92
|
/** A remote entry could not be resolved or configured at the indicated field. */
|
|
85
93
|
export class RemoteEntryError extends Schema.TaggedError<
|
|
86
94
|
RemoteEntryError,
|
package/src/Transport.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/** Execution and byte-channel capabilities; implementations live in host plugins. */
|
|
2
2
|
import { Context } from "effect"
|
|
3
3
|
import type { Effect, Option, Scope, Stream, Sink, Redacted } from "effect"
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
AuthenticationFailed,
|
|
6
|
+
AuthenticatorUnavailable,
|
|
7
|
+
TransportError,
|
|
8
|
+
} from "./Errors"
|
|
5
9
|
import type { Prepared, VerifiedCertificate, TlsPolicy } from "./Auth"
|
|
6
10
|
/** Ordered reliable bytes. Chunk boundaries have no meaning; EOF is not exit confirmation. */
|
|
7
11
|
export interface Channel {
|
|
@@ -24,7 +28,7 @@ export type Session = (
|
|
|
24
28
|
) => Effect.Effect<void, TransportError, Scope.Scope>
|
|
25
29
|
export type Accept = (
|
|
26
30
|
handshake: Handshake,
|
|
27
|
-
) => Effect.Effect<Session, AuthenticationFailed>
|
|
31
|
+
) => Effect.Effect<Session, AuthenticationFailed | AuthenticatorUnavailable>
|
|
28
32
|
export interface Serving {
|
|
29
33
|
/** Completes after serve has registered its accept loop, not merely after bind. */
|
|
30
34
|
readonly ready: Effect.Effect<void>
|
package/src/bin.ts
CHANGED
|
@@ -68,24 +68,23 @@ const child = Command.make(
|
|
|
68
68
|
Argument.withSchema(Schema.fromJsonString(Bootstrap)),
|
|
69
69
|
),
|
|
70
70
|
},
|
|
71
|
-
({ contract, session, bootstrap })
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}),
|
|
71
|
+
Effect.fnUntraced(function* ({ contract, session, bootstrap }) {
|
|
72
|
+
const watchdog = yield* Watchdog.start
|
|
73
|
+
// The executable owns stdin; it must not retain the process after a supervisor stop.
|
|
74
|
+
yield* Effect.addFinalizer(() =>
|
|
75
|
+
Effect.sync(() => {
|
|
76
|
+
process.stdin.destroy()
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
const begin = yield* Effect.raceFirst(
|
|
80
|
+
watchdog.begin.pipe(Effect.as(true)),
|
|
81
|
+
watchdog.stop.pipe(Effect.as(false)),
|
|
82
|
+
)
|
|
83
|
+
if (!begin) return
|
|
84
|
+
const definition = yield* load(pathToFileURL(contract).href)
|
|
85
|
+
const channel = yield* bytes
|
|
86
|
+
return yield* run(definition, channel, session, bootstrap, watchdog.stop)
|
|
87
|
+
}),
|
|
89
88
|
)
|
|
90
89
|
const cli = Command.make(
|
|
91
90
|
"graft-remote",
|
|
@@ -93,18 +92,17 @@ const cli = Command.make(
|
|
|
93
92
|
contract: Argument.String("contract").pipe(Argument.optional),
|
|
94
93
|
session: Argument.String("session").pipe(Argument.withDefault("local")),
|
|
95
94
|
},
|
|
96
|
-
({ contract, session })
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}),
|
|
95
|
+
Effect.fnUntraced(function* ({ contract, session }) {
|
|
96
|
+
if (Option.isNone(contract))
|
|
97
|
+
return yield* CliError.UserError.make({
|
|
98
|
+
cause: "Missing contract module",
|
|
99
|
+
userMessage:
|
|
100
|
+
"A contract module or the child/serve/certificates subcommand is required",
|
|
101
|
+
})
|
|
102
|
+
const definition = yield* load(contract.value)
|
|
103
|
+
const channel = yield* bytes
|
|
104
|
+
return yield* run(definition, channel, session)
|
|
105
|
+
}),
|
|
108
106
|
).pipe(Command.withSubcommands([child, serve, certificates]))
|
|
109
107
|
|
|
110
108
|
NodeRuntime.runMain(
|
package/src/index.ts
CHANGED
|
@@ -92,8 +92,8 @@ export const plugin = <
|
|
|
92
92
|
ChildProcessSpawner.ChildProcessSpawner,
|
|
93
93
|
],
|
|
94
94
|
retry: options.retry,
|
|
95
|
-
apply: (
|
|
96
|
-
|
|
95
|
+
apply: Effect.fnUntraced(
|
|
96
|
+
function* () {
|
|
97
97
|
const input = yield* Schema.decodeUnknownEffect(Configuration.Host)({
|
|
98
98
|
contract: options.contractModule,
|
|
99
99
|
connect: options.connect,
|
|
@@ -112,6 +112,8 @@ export const plugin = <
|
|
|
112
112
|
yield* follow(child, (cause) =>
|
|
113
113
|
Effect.failCause(publicCause(contract.error, cause)),
|
|
114
114
|
)
|
|
115
|
-
}
|
|
115
|
+
},
|
|
116
|
+
Effect.mapError((error) => publicError(contract.error, error)),
|
|
117
|
+
),
|
|
116
118
|
})
|
|
117
119
|
export { host as default } from "./internal/entry"
|
|
@@ -241,20 +241,17 @@ export const write = Effect.fn("Certificates.write")(function* (
|
|
|
241
241
|
force: boolean = false,
|
|
242
242
|
) {
|
|
243
243
|
const fs = yield* FileSystem.FileSystem
|
|
244
|
-
yield* fs
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
})
|
|
249
|
-
.pipe(Effect.uninterruptible)
|
|
244
|
+
yield* fs.writeFileString(base + ".key", Redacted.value(pair.privateKey), {
|
|
245
|
+
flag: force ? "w" : "wx",
|
|
246
|
+
mode: 0o600,
|
|
247
|
+
})
|
|
250
248
|
// Opening an existing file does not change its permissions when renewing it.
|
|
251
|
-
yield* fs.chmod(base + ".key", 0o600)
|
|
252
|
-
yield* fs
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
})
|
|
249
|
+
yield* fs.chmod(base + ".key", 0o600)
|
|
250
|
+
yield* fs.writeFileString(base + ".crt", pair.certificate, {
|
|
251
|
+
flag: force ? "w" : "wx",
|
|
252
|
+
})
|
|
253
|
+
// One region for the pair: an interruption between the files would leave a key without its certificate.
|
|
254
|
+
}, Effect.uninterruptible)
|
|
258
255
|
|
|
259
256
|
export interface Options {
|
|
260
257
|
readonly out: string
|