@graftland/plugin-remote 0.3.1 → 0.3.3

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 (184) hide show
  1. package/dist/Auth.d.ts +2 -2
  2. package/dist/Auth.d.ts.map +1 -1
  3. package/dist/Auth.js.map +1 -1
  4. package/dist/{Bootstrap-Dr6sX7el.js → Bootstrap-H9gDsgsC.js} +2 -2
  5. package/dist/{Contract-DL2mHvaT.js → Contract-DsJtisvL.js} +2 -2
  6. package/dist/Contract.js +1 -1
  7. package/dist/{Errors-BMKmu5Y7.js → Errors-DYhsGZcZ.js} +3 -1
  8. package/dist/Errors.d.ts +7 -0
  9. package/dist/Errors.d.ts.map +1 -1
  10. package/dist/Errors.js +3 -1
  11. package/dist/Errors.js.map +1 -1
  12. package/dist/{FailureGroup-BcH0XOBi.js → FailureGroup-BgT73AaR.js} +14 -4
  13. package/dist/{Framing-zaYdOJnT.js → Framing-G9eSaeLb.js} +1 -1
  14. package/dist/{Graft-CVyueNOf.js → Graft-B71CPA2Y.js} +20 -16
  15. package/dist/{Packages-JNL34JpS.js → Packages-AgoCGotL.js} +23 -26
  16. package/dist/{Peer-BT7eAGmh.js → Peer-DXeVrGBh.js} +5 -5
  17. package/dist/{ProcessObservation-DEGrEMfP.js → ProcessObservation-gLgGirYv.js} +1 -1
  18. package/dist/{ServeLifecycle-CJM0gG5B.js → ServeLifecycle-Bd1FPJ6e.js} +1 -1
  19. package/dist/Transport.d.ts +2 -2
  20. package/dist/Transport.d.ts.map +1 -1
  21. package/dist/Transport.js.map +1 -1
  22. package/dist/bin.js +48 -47
  23. package/dist/bin.js.map +1 -1
  24. package/dist/{childRuntime-An0HsIzl.js → childRuntime-Bm3iSg_N.js} +29 -26
  25. package/dist/{connectionEnded-DCpFCjMX.js → connectionEnded-BwcxQ7W8.js} +4 -4
  26. package/dist/{entry-B89sepMU.js → entry-psOpX3Bj.js} +72 -35
  27. package/dist/host/auth/bearer.d.ts +9 -1
  28. package/dist/host/auth/bearer.d.ts.map +1 -1
  29. package/dist/host/auth/bearer.js +1 -1
  30. package/dist/host/auth/jwt.d.ts +9 -1
  31. package/dist/host/auth/jwt.d.ts.map +1 -1
  32. package/dist/host/auth/jwt.js +1 -1
  33. package/dist/host/auth/mtls.d.ts +8 -1
  34. package/dist/host/auth/mtls.d.ts.map +1 -1
  35. package/dist/host/auth/mtls.js +2 -2
  36. package/dist/host/auth/none.d.ts +3 -1
  37. package/dist/host/auth/none.js +1 -1
  38. package/dist/host/command.d.ts +14 -1
  39. package/dist/host/command.d.ts.map +1 -1
  40. package/dist/host/command.js +4 -4
  41. package/dist/host/local.d.ts +2 -1
  42. package/dist/host/local.d.ts.map +1 -1
  43. package/dist/host/local.js +3 -3
  44. package/dist/host/unix.d.ts +6 -1
  45. package/dist/host/unix.d.ts.map +1 -1
  46. package/dist/host/unix.js +3 -3
  47. package/dist/host/websocket.d.ts +10 -1
  48. package/dist/host/websocket.d.ts.map +1 -1
  49. package/dist/host/websocket.js +3 -3
  50. package/dist/host/worker.d.ts +3 -1
  51. package/dist/host/worker.d.ts.map +1 -1
  52. package/dist/host/worker.js +4 -5
  53. package/dist/{importer-Bk6U_sn4.js → importer-Cvf88eAY.js} +5 -8
  54. package/dist/index.js +9 -9
  55. package/dist/index.js.map +1 -1
  56. package/dist/internal/Certificates.js +4 -4
  57. package/dist/internal/Certificates.js.map +1 -1
  58. package/dist/internal/FailureGroup.js +3 -2
  59. package/dist/internal/FailureGroup.js.map +1 -1
  60. package/dist/internal/assembly.d.ts +2 -1
  61. package/dist/internal/assembly.js +9 -2
  62. package/dist/internal/assembly.js.map +1 -1
  63. package/dist/internal/auth/mtls.js +1 -1
  64. package/dist/internal/auth/mtls.js.map +1 -1
  65. package/dist/internal/auth/tokenCredentials.d.ts +2 -1
  66. package/dist/internal/auth/tokenCredentials.d.ts.map +1 -1
  67. package/dist/internal/child.js +20 -17
  68. package/dist/internal/child.js.map +1 -1
  69. package/dist/internal/childRuntime.js +4 -4
  70. package/dist/internal/childRuntime.js.map +1 -1
  71. package/dist/internal/credentials.d.ts +1 -1
  72. package/dist/internal/directTransport.d.ts +1 -1
  73. package/dist/internal/entry.d.ts +415 -3
  74. package/dist/internal/entry.d.ts.map +1 -1
  75. package/dist/internal/entry.js +1 -1
  76. package/dist/internal/entry.js.map +1 -1
  77. package/dist/internal/execution.js +40 -5
  78. package/dist/internal/execution.js.map +1 -1
  79. package/dist/internal/host/runner.js +7 -6
  80. package/dist/internal/host/runner.js.map +1 -1
  81. package/dist/internal/host.js +5 -5
  82. package/dist/internal/host.js.map +1 -1
  83. package/dist/internal/port.js +5 -5
  84. package/dist/internal/port.js.map +1 -1
  85. package/dist/internal/release.js +1 -1
  86. package/dist/internal/release.js.map +1 -1
  87. package/dist/internal/runner/Connection.d.ts +1 -1
  88. package/dist/internal/runner/Connection.js +4 -4
  89. package/dist/internal/runner/Connection.js.map +1 -1
  90. package/dist/internal/runner/Execution.js +3 -3
  91. package/dist/internal/runner/Execution.js.map +1 -1
  92. package/dist/internal/runner/Framing.js +1 -1
  93. package/dist/internal/runner/Framing.js.map +1 -1
  94. package/dist/internal/runner/Local.js +1 -1
  95. package/dist/internal/runner/Local.js.map +1 -1
  96. package/dist/internal/runner/Lock.js +1 -1
  97. package/dist/internal/runner/Lock.js.map +1 -1
  98. package/dist/internal/runner/Packages.d.ts +1 -1
  99. package/dist/internal/runner/Packages.js +22 -25
  100. package/dist/internal/runner/Packages.js.map +1 -1
  101. package/dist/internal/runner/Processes.js +7 -9
  102. package/dist/internal/runner/Processes.js.map +1 -1
  103. package/dist/internal/runner/Store.js +3 -3
  104. package/dist/internal/runner/Store.js.map +1 -1
  105. package/dist/internal/runner/Supervisor.js +46 -47
  106. package/dist/internal/runner/Supervisor.js.map +1 -1
  107. package/dist/internal/runner/accept.js +3 -3
  108. package/dist/internal/runner/accept.js.map +1 -1
  109. package/dist/internal/runner/model.js +1 -1
  110. package/dist/internal/runner/model.js.map +1 -1
  111. package/dist/internal/serve.js +1 -1
  112. package/dist/internal/serve.js.map +1 -1
  113. package/dist/internal/supervisorPlugin.js +1 -1
  114. package/dist/internal/watchdogMain.js +5 -5
  115. package/dist/internal/watchdogMain.js.map +1 -1
  116. package/dist/internal/websocketServer.js +3 -1
  117. package/dist/internal/websocketServer.js.map +1 -1
  118. package/dist/internal/workerMain.js +3 -3
  119. package/dist/{port-DSVUY8Bq.js → port--3x2zJ4D.js} +8 -8
  120. package/dist/{release-BY4Mlluy.js → release-DfZPuIcK.js} +1 -1
  121. package/dist/runner/auth/bearer.d.ts +6 -1
  122. package/dist/runner/auth/bearer.d.ts.map +1 -1
  123. package/dist/runner/auth/bearer.js +2 -2
  124. package/dist/runner/auth/jwt.d.ts +29 -2
  125. package/dist/runner/auth/jwt.d.ts.map +1 -1
  126. package/dist/runner/auth/jwt.js +4 -4
  127. package/dist/runner/auth/jwt.js.map +1 -1
  128. package/dist/runner/auth/mtls.d.ts +6 -1
  129. package/dist/runner/auth/mtls.d.ts.map +1 -1
  130. package/dist/runner/auth/mtls.js +3 -3
  131. package/dist/runner/auth/none.d.ts +7 -1
  132. package/dist/runner/auth/none.js +1 -1
  133. package/dist/runner/index.d.ts +310 -1
  134. package/dist/runner/index.d.ts.map +1 -1
  135. package/dist/runner/index.js +5 -5
  136. package/dist/runner/stdio.d.ts +6 -1
  137. package/dist/runner/stdio.d.ts.map +1 -1
  138. package/dist/runner/stdio.js +3 -3
  139. package/dist/runner/unix.d.ts +6 -1
  140. package/dist/runner/unix.d.ts.map +1 -1
  141. package/dist/runner/unix.js +3 -3
  142. package/dist/runner/websocket.d.ts +24 -1
  143. package/dist/runner/websocket.d.ts.map +1 -1
  144. package/dist/runner/websocket.js +4 -4
  145. package/dist/{socketChannel-C_ppdSzz.js → socketChannel-CJvL2DiB.js} +2 -2
  146. package/dist/{supervisorPlugin-CivhM7x5.js → supervisorPlugin-t6Z6PrhD.js} +72 -76
  147. package/dist/{token-Cc_1CTbE.js → token-CYBNNlhS.js} +1 -1
  148. package/dist/{tokenCredentials-CI6mMRRd.js → tokenCredentials-CbCuk-Rt.js} +3 -3
  149. package/dist/{websocketServer-D2Hk7wsA.js → websocketServer-NQhODlEt.js} +5 -3
  150. package/dist/{workerChannel-cmLc13vm.js → workerChannel-C8hhBJzA.js} +1 -1
  151. package/package.json +4 -4
  152. package/src/Auth.ts +9 -2
  153. package/src/Errors.ts +8 -0
  154. package/src/Transport.ts +6 -2
  155. package/src/bin.ts +28 -30
  156. package/src/index.ts +5 -3
  157. package/src/internal/Certificates.ts +10 -13
  158. package/src/internal/FailureGroup.ts +128 -121
  159. package/src/internal/assembly.ts +19 -10
  160. package/src/internal/auth/mtls.ts +19 -20
  161. package/src/internal/child.ts +248 -239
  162. package/src/internal/childRuntime.ts +81 -80
  163. package/src/internal/entry.ts +10 -11
  164. package/src/internal/execution.ts +69 -12
  165. package/src/internal/host/runner.ts +153 -153
  166. package/src/internal/host.ts +116 -120
  167. package/src/internal/port.ts +100 -103
  168. package/src/internal/release.ts +3 -2
  169. package/src/internal/runner/Connection.ts +52 -60
  170. package/src/internal/runner/Execution.ts +163 -164
  171. package/src/internal/runner/Framing.ts +9 -10
  172. package/src/internal/runner/Local.ts +26 -27
  173. package/src/internal/runner/Lock.ts +23 -25
  174. package/src/internal/runner/Packages.ts +67 -70
  175. package/src/internal/runner/Processes.ts +89 -92
  176. package/src/internal/runner/Store.ts +110 -114
  177. package/src/internal/runner/Supervisor.ts +392 -405
  178. package/src/internal/runner/accept.ts +76 -84
  179. package/src/internal/runner/model.ts +20 -21
  180. package/src/internal/serve.ts +15 -13
  181. package/src/internal/watchdogMain.ts +16 -11
  182. package/src/internal/websocketServer.ts +18 -3
  183. package/src/runner/auth/jwt.ts +10 -6
  184. 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-CVyueNOf.js";
2
- import { a as PositiveDuration, i as Supervisor$1, t as resolve } from "./Packages-JNL34JpS.js";
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-BT7eAGmh.js";
5
- import { t as observe } from "./ProcessObservation-DEGrEMfP.js";
6
- import { t as make$4 } from "./FailureGroup-BcH0XOBi.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-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 { l as TransportError } from "./Errors-BMKmu5Y7.js";
9
- import { t as Bootstrap } from "./Bootstrap-Dr6sX7el.js";
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-BY4Mlluy.js";
12
- import { n as cleanupCause } from "./cleanup-CXLa1Wd9.js";
13
- import { n as make$5, o as defaults } from "./port-DSVUY8Bq.js";
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 = (directory) => Effect.gen(function* () {
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 = (root) => Effect.gen(function* () {
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: (record) => storage(mutex.withPermit(Effect.scoped(Effect.gen(function* () {
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 = (pid) => Effect.scoped(Effect.gen(function* () {
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
- ...process.env,
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
- })).pipe(Effect.mapError((error) => error._tag === "ExecutionError" ? error : ExecutionError.make({
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 = (pid) => Effect.gen(function* () {
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 = (child) => Effect.gen(function* () {
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 = (child) => Effect.gen(function* () {
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 = (root) => Effect.gen(function* () {
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) => Effect.gen(function* () {
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
- }).pipe(Effect.provideContext(platform), Effect.catchTags({
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 Effect.succeed(emptyTermination);
374
- if (execution._tag === "Exited") return Effect.succeed({
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
- return Effect.gen(function* () {
380
- const graceful = yield* child.interrupt.pipe(Effect.andThen(child.exited), Effect.timeoutOption(grace), Effect.exit);
381
- if (Exit.isSuccess(graceful) && Option.isSome(graceful.value)) return {
382
- ...emptyTermination,
383
- exit: graceful.value.value
384
- };
385
- const killed = yield* Effect.exit(child.kill);
386
- const forced = yield* child.exited.pipe(Effect.timeoutOption(confirmation), Effect.exit);
387
- const cause = Cause.combine(Cause.combine(exitCause(graceful), exitCause(killed)), exitCause(forced));
388
- if (Exit.isFailure(forced) || Option.isNone(forced.value)) return yield* TerminationUnconfirmed.make({
389
- detail: "The child exit could not be confirmed",
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
- const initialize = (options = {}) => Effect.gen(function* () {
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 = (handle) => Effect.gen(function* () {
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, (state) => Effect.gen(function* () {
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) => Effect.gen(function* () {
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) => Effect.gen(function* () {
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, (state) => Effect.gen(function* () {
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((result) => Effect.gen(function* () {
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 = (runtime, actions) => Effect.gen(function* () {
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 = (runtime, actions) => Effect.gen(function* () {
529
+ const ownShutdown = Effect.fnUntraced(function* (runtime, actions) {
535
530
  const { entries, health, closing } = runtime;
536
531
  const { stop } = actions;
537
- yield* Effect.addFinalizer(() => Effect.gen(function* () {
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 = (runtime, actions) => Effect.gen(function* () {
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: (request) => Effect.scoped(Effect.gen(function* () {
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
- return yield* (yield* RcMap.get(locks, keyOf(request.key))).withPermit(Effect.gen(function* () {
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: (handle) => Effect.gen(function* () {
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, (state) => Effect.gen(function* () {
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: (handle, request) => Effect.gen(function* () {
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, (state) => Effect.gen(function* () {
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: (handle) => Effect.gen(function* () {
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 = {}) => Effect.gen(function* () {
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) => Effect.gen(function* () {
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 }) => Effect.gen(function* () {
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
- }).pipe(loading.withPermit),
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-BMKmu5Y7.js";
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-CVyueNOf.js";
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 { n as CredentialsError } from "./Errors-BMKmu5Y7.js";
5
- import { n as prepare } from "./token-Cc_1CTbE.js";
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 { l as TransportError } from "./Errors-BMKmu5Y7.js";
2
- import { a as payloadLimit, s as protocol, t as fromSocket } from "./socketChannel-C_ppdSzz.js";
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) => Effect.logWarning("Remote host authentication failed", { reason: error.reason }, ...error.cause === void 0 ? [] : [error.cause]).pipe(Effect.as(HttpServerResponse.empty({
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 { l as TransportError } from "./Errors-BMKmu5Y7.js";
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.1",
3
+ "version": "0.3.3",
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.1",
52
+ "@graftland/graft": "0.3.3",
53
53
  "@effect/platform-node": "4.1.2",
54
- "@graftland/loader": "0.3.1",
54
+ "@graftland/loader": "0.3.3",
55
55
  "pkijs": "4.0.1",
56
56
  "asn1js": "4.0.0",
57
57
  "ws": "8.22.1"
@@ -66,7 +66,7 @@
66
66
  "graft-remote": "./dist/bin.js"
67
67
  },
68
68
  "scripts": {
69
- "build": "tsdown",
69
+ "build": "tsc -b && tsdown",
70
70
  "test": "vitest run"
71
71
  }
72
72
  }
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 { AuthenticationFailed, CredentialsError } from "./Errors"
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<string, AuthenticationFailed>
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 { AuthenticationFailed, TransportError } from "./Errors"
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
- Effect.gen(function* () {
73
- const watchdog = yield* Watchdog.start
74
- // The executable owns stdin; it must not retain the process after a supervisor stop.
75
- yield* Effect.addFinalizer(() =>
76
- Effect.sync(() => {
77
- process.stdin.destroy()
78
- }),
79
- )
80
- const begin = yield* Effect.raceFirst(
81
- watchdog.begin.pipe(Effect.as(true)),
82
- watchdog.stop.pipe(Effect.as(false)),
83
- )
84
- if (!begin) return
85
- const definition = yield* load(pathToFileURL(contract).href)
86
- const channel = yield* bytes
87
- return yield* run(definition, channel, session, bootstrap, watchdog.stop)
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
- Effect.gen(function* () {
98
- if (Option.isNone(contract))
99
- return yield* CliError.UserError.make({
100
- cause: "Missing contract module",
101
- userMessage:
102
- "A contract module or the child/serve/certificates subcommand is required",
103
- })
104
- const definition = yield* load(contract.value)
105
- const channel = yield* bytes
106
- return yield* run(definition, channel, session)
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
- Effect.gen(function* () {
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
- }).pipe(Effect.mapError((error) => publicError(contract.error, error))),
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
- .writeFileString(base + ".key", Redacted.value(pair.privateKey), {
246
- flag: force ? "w" : "wx",
247
- mode: 0o600,
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).pipe(Effect.uninterruptible)
252
- yield* fs
253
- .writeFileString(base + ".crt", pair.certificate, {
254
- flag: force ? "w" : "wx",
255
- })
256
- .pipe(Effect.uninterruptible)
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