@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.
Files changed (147) 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.js +1 -1
  28. package/dist/host/auth/jwt.js +1 -1
  29. package/dist/host/auth/mtls.js +2 -2
  30. package/dist/host/auth/none.js +1 -1
  31. package/dist/host/command.js +4 -4
  32. package/dist/host/local.js +3 -3
  33. package/dist/host/unix.js +3 -3
  34. package/dist/host/websocket.js +3 -3
  35. package/dist/host/worker.js +4 -5
  36. package/dist/{importer-Bk6U_sn4.js → importer-Cvf88eAY.js} +5 -8
  37. package/dist/index.js +9 -9
  38. package/dist/index.js.map +1 -1
  39. package/dist/internal/Certificates.js +4 -4
  40. package/dist/internal/Certificates.js.map +1 -1
  41. package/dist/internal/FailureGroup.js +3 -2
  42. package/dist/internal/FailureGroup.js.map +1 -1
  43. package/dist/internal/assembly.js +9 -2
  44. package/dist/internal/assembly.js.map +1 -1
  45. package/dist/internal/auth/mtls.js +1 -1
  46. package/dist/internal/auth/mtls.js.map +1 -1
  47. package/dist/internal/child.js +20 -17
  48. package/dist/internal/child.js.map +1 -1
  49. package/dist/internal/childRuntime.js +4 -4
  50. package/dist/internal/childRuntime.js.map +1 -1
  51. package/dist/internal/directTransport.d.ts +1 -1
  52. package/dist/internal/entry.d.ts.map +1 -1
  53. package/dist/internal/entry.js +1 -1
  54. package/dist/internal/entry.js.map +1 -1
  55. package/dist/internal/execution.js +40 -5
  56. package/dist/internal/execution.js.map +1 -1
  57. package/dist/internal/host/runner.js +7 -6
  58. package/dist/internal/host/runner.js.map +1 -1
  59. package/dist/internal/host.js +5 -5
  60. package/dist/internal/host.js.map +1 -1
  61. package/dist/internal/port.js +5 -5
  62. package/dist/internal/port.js.map +1 -1
  63. package/dist/internal/release.js +1 -1
  64. package/dist/internal/release.js.map +1 -1
  65. package/dist/internal/runner/Connection.d.ts +1 -1
  66. package/dist/internal/runner/Connection.js +4 -4
  67. package/dist/internal/runner/Connection.js.map +1 -1
  68. package/dist/internal/runner/Execution.js +3 -3
  69. package/dist/internal/runner/Execution.js.map +1 -1
  70. package/dist/internal/runner/Framing.js +1 -1
  71. package/dist/internal/runner/Framing.js.map +1 -1
  72. package/dist/internal/runner/Local.js +1 -1
  73. package/dist/internal/runner/Local.js.map +1 -1
  74. package/dist/internal/runner/Lock.js +1 -1
  75. package/dist/internal/runner/Lock.js.map +1 -1
  76. package/dist/internal/runner/Packages.d.ts +1 -1
  77. package/dist/internal/runner/Packages.js +22 -25
  78. package/dist/internal/runner/Packages.js.map +1 -1
  79. package/dist/internal/runner/Processes.js +7 -9
  80. package/dist/internal/runner/Processes.js.map +1 -1
  81. package/dist/internal/runner/Store.js +3 -3
  82. package/dist/internal/runner/Store.js.map +1 -1
  83. package/dist/internal/runner/Supervisor.js +46 -47
  84. package/dist/internal/runner/Supervisor.js.map +1 -1
  85. package/dist/internal/runner/accept.js +3 -3
  86. package/dist/internal/runner/accept.js.map +1 -1
  87. package/dist/internal/runner/model.js +1 -1
  88. package/dist/internal/runner/model.js.map +1 -1
  89. package/dist/internal/serve.js +1 -1
  90. package/dist/internal/serve.js.map +1 -1
  91. package/dist/internal/supervisorPlugin.js +1 -1
  92. package/dist/internal/watchdogMain.js +5 -5
  93. package/dist/internal/watchdogMain.js.map +1 -1
  94. package/dist/internal/websocketServer.js +3 -1
  95. package/dist/internal/websocketServer.js.map +1 -1
  96. package/dist/internal/workerMain.js +3 -3
  97. package/dist/{port-DSVUY8Bq.js → port--3x2zJ4D.js} +8 -8
  98. package/dist/{release-BY4Mlluy.js → release-DfZPuIcK.js} +1 -1
  99. package/dist/runner/auth/bearer.js +2 -2
  100. package/dist/runner/auth/jwt.js +4 -4
  101. package/dist/runner/auth/jwt.js.map +1 -1
  102. package/dist/runner/auth/mtls.js +3 -3
  103. package/dist/runner/auth/none.js +1 -1
  104. package/dist/runner/index.js +5 -5
  105. package/dist/runner/stdio.js +3 -3
  106. package/dist/runner/unix.js +3 -3
  107. package/dist/runner/websocket.js +4 -4
  108. package/dist/{socketChannel-C_ppdSzz.js → socketChannel-CJvL2DiB.js} +2 -2
  109. package/dist/{supervisorPlugin-CivhM7x5.js → supervisorPlugin-t6Z6PrhD.js} +72 -76
  110. package/dist/{token-Cc_1CTbE.js → token-CYBNNlhS.js} +1 -1
  111. package/dist/{tokenCredentials-CI6mMRRd.js → tokenCredentials-CbCuk-Rt.js} +3 -3
  112. package/dist/{websocketServer-D2Hk7wsA.js → websocketServer-NQhODlEt.js} +5 -3
  113. package/dist/{workerChannel-cmLc13vm.js → workerChannel-C8hhBJzA.js} +1 -1
  114. package/package.json +3 -3
  115. package/src/Auth.ts +9 -2
  116. package/src/Errors.ts +8 -0
  117. package/src/Transport.ts +6 -2
  118. package/src/bin.ts +28 -30
  119. package/src/index.ts +5 -3
  120. package/src/internal/Certificates.ts +10 -13
  121. package/src/internal/FailureGroup.ts +128 -121
  122. package/src/internal/assembly.ts +19 -10
  123. package/src/internal/auth/mtls.ts +19 -20
  124. package/src/internal/child.ts +248 -239
  125. package/src/internal/childRuntime.ts +81 -80
  126. package/src/internal/entry.ts +10 -11
  127. package/src/internal/execution.ts +69 -12
  128. package/src/internal/host/runner.ts +153 -153
  129. package/src/internal/host.ts +116 -120
  130. package/src/internal/port.ts +100 -103
  131. package/src/internal/release.ts +3 -2
  132. package/src/internal/runner/Connection.ts +52 -60
  133. package/src/internal/runner/Execution.ts +163 -164
  134. package/src/internal/runner/Framing.ts +9 -10
  135. package/src/internal/runner/Local.ts +26 -27
  136. package/src/internal/runner/Lock.ts +23 -25
  137. package/src/internal/runner/Packages.ts +67 -70
  138. package/src/internal/runner/Processes.ts +89 -92
  139. package/src/internal/runner/Store.ts +110 -114
  140. package/src/internal/runner/Supervisor.ts +392 -405
  141. package/src/internal/runner/accept.ts +76 -84
  142. package/src/internal/runner/model.ts +20 -21
  143. package/src/internal/serve.ts +15 -13
  144. package/src/internal/watchdogMain.ts +16 -11
  145. package/src/internal/websocketServer.ts +18 -3
  146. package/src/runner/auth/jwt.ts +10 -6
  147. package/dist/cleanup-CXLa1Wd9.js +0 -13
@@ -1,23 +1,22 @@
1
- import { c as isPlugin, i as plugin, l as make, o as fork, t as forks, u as optional } from "./Graft-CVyueNOf.js";
1
+ import { c as isPlugin, i as plugin, l as make, o as fork, t as forks, u as optional } from "./Graft-B71CPA2Y.js";
2
2
  import { t as ConfigDirectory } from "./ConfigDirectory-BCC6q2R4.js";
3
- import { i as make$2, m as isSubtreeActive, n as ModuleInvalid, o as CurrentId, p as findSubtree, r as ModuleResolver, t as make$1 } from "./importer-Bk6U_sn4.js";
4
- import { c as endpoint, n as UndeclaredFailure, o as endpoints, r as fromModule } from "./Contract-DL2mHvaT.js";
5
- import { a as ProcessExited, c as RemoteWithdrawn, i as MissingInstance, l as TransportError, o as RemoteEntryError, r as LocalTerminationTimeout, s as RemoteError, t as AuthenticationFailed } from "./Errors-BMKmu5Y7.js";
3
+ import { i as make$2, m as isSubtreeActive, n as ModuleInvalid, o as CurrentId, p as findSubtree, r as ModuleResolver, t as make$1 } from "./importer-Cvf88eAY.js";
4
+ import { c as endpoint, n as UndeclaredFailure, o as endpoints, r as fromModule } from "./Contract-DsJtisvL.js";
5
+ import { a as MissingInstance, c as RemoteError, i as LocalTerminationTimeout, l as RemoteWithdrawn, o as ProcessExited, r as CredentialsError, s as RemoteEntryError, t as AuthenticationFailed, u as TransportError } from "./Errors-DYhsGZcZ.js";
6
6
  import { n as WorkerTransport, t as LocalTransport } from "./directTransport-DrexuPSm.js";
7
- import { a as PositiveDuration, i as Supervisor, n as resolveEntry, r as verify } from "./Packages-JNL34JpS.js";
8
- import { E as make$3, b as awaitTermination, n as Session, r as channel, t as Peer, x as childOf } from "./Peer-BT7eAGmh.js";
7
+ import { a as PositiveDuration, i as Supervisor, n as resolveEntry, r as verify } from "./Packages-AgoCGotL.js";
8
+ import { E as make$3, _ as StateStorageError, a as ExecutionError, b as awaitTermination, c as PackageError, d as SessionAccessDenied, f as SessionConflict, g as StateDirectoryLocked, h as StaleSession, l as RemoteTerminationUnconfirmed, m as SessionStopped, n as Session, r as channel, s as LeaseExpired, t as Peer, u as RunnerClosing, x as childOf, y as TerminationUnconfirmed } from "./Peer-DXeVrGBh.js";
9
9
  import { n as Credentials, t as Authenticator } from "./Auth-BElTC9_X.js";
10
10
  import { n as Listener, t as Connector } from "./Transport-DULzpsgR.js";
11
- import { n as connectionEnded, r as prepare, t as closedNormally } from "./connectionEnded-DCpFCjMX.js";
12
- import { t as ServeLifecycle } from "./ServeLifecycle-CJM0gG5B.js";
13
- import { t as make$4 } from "./FailureGroup-BcH0XOBi.js";
14
- import { n as cleanupCause, t as children } from "./cleanup-CXLa1Wd9.js";
15
- import { n as make$5, o as defaults } from "./port-DSVUY8Bq.js";
16
- import { n as close } from "./release-BY4Mlluy.js";
17
- import { n as stdinExitTimeout } from "./ProcessObservation-DEGrEMfP.js";
18
- import { Array, Cause, Context, Deferred, Duration, Effect, Exit, Fiber, Option, Path, Ref, References, Schema, Scope, Stream, String } from "effect";
11
+ import { a as AlreadyLoaded, i as ActivationFailed, n as connectionEnded, o as ContractNotFound, r as prepare, s as ModuleImportFailed, t as closedNormally } from "./connectionEnded-BwcxQ7W8.js";
12
+ import { t as ServeLifecycle } from "./ServeLifecycle-Bd1FPJ6e.js";
13
+ import { n as children, r as cleanupCause, t as make$4 } from "./FailureGroup-BgT73AaR.js";
14
+ import { n as make$5, o as defaults } from "./port--3x2zJ4D.js";
15
+ import { n as close, t as ReleaseInterrupted } from "./release-DfZPuIcK.js";
16
+ import { n as stdinExitTimeout } from "./ProcessObservation-gLgGirYv.js";
17
+ import { Array, Cause, Context, Deferred, Duration, Effect, Exit, Fiber, Option, Path, PlatformError, Ref, References, Schema, Scope, Stream, String } from "effect";
19
18
  import { SecureRandom } from "effect/crypto";
20
- import { RpcClient } from "effect/rpc";
19
+ import { RpcClient, RpcClientError } from "effect/rpc";
21
20
  import { ChildProcessSpawner } from "effect/process";
22
21
  // packages/remote/src/internal/entryConfig.ts
23
22
  const Reference = Schema.Struct({
@@ -216,6 +215,13 @@ var CapabilityCombinationError = class extends Schema.TaggedError()("CapabilityC
216
215
  }
217
216
  };
218
217
  var CapabilityFailed = class extends Schema.TaggedError()("CapabilityFailed", { cause: Schema.Cause(Schema.Unknown, Schema.Unknown) }) {};
218
+ /** Every failure class assembly raises; host error classification reads this list. */
219
+ const errors = [
220
+ ListenerConfigError,
221
+ CapabilityContractError,
222
+ CapabilityCombinationError,
223
+ CapabilityFailed
224
+ ];
219
225
  const definition = Schema.declare(isPlugin);
220
226
  /** Entries resolve capability modules before assembling their private providers. */
221
227
  const Invocation = Schema.Struct({
@@ -281,7 +287,7 @@ const compatible = (properties, kind) => {
281
287
  const kind = (auth) => auth._tag === "Mtls" ? "Certificate" : auth._tag === "Header" ? "Authorization" : "None";
282
288
  const warn = (properties, credentials, side) => Effect.all([properties.network && !properties.encrypted ? Effect.logWarning(credentials === "Authorization" ? `${properties.protocol}:// ${side === "host" ? "connection" : "listener"} is unencrypted; credentials are transmitted in plaintext` : `${properties.protocol}:// ${side === "host" ? "connection" : "listener"} is unencrypted`) : Effect.void, side === "runner" && properties.network && credentials === "None" ? Effect.logWarning("WebSocket listener has no authentication") : Effect.void], { discard: true });
283
289
  const directAuth = (properties, explicit) => explicit && (properties.protocol === "stdio" || properties.protocol === "command") ? Effect.fail(CapabilityCombinationError.make({ detail: `${properties.protocol} transports do not accept auth` })) : Effect.void;
284
- const connectWith = (explicitAuth = false) => Effect.gen(function* () {
290
+ const connectWith = Effect.fnUntraced(function* (explicitAuth = false) {
285
291
  const connector = yield* Connector;
286
292
  const credentials = yield* Credentials;
287
293
  yield* directAuth(connector.properties, explicitAuth);
@@ -321,7 +327,7 @@ const makeListenerConsumer = (prepare = () => Effect.void, ready = Effect.void)
321
327
  const listenerConsumer = makeListenerConsumer();
322
328
  connectWith();
323
329
  // packages/remote/src/internal/host/runner.ts
324
- const connect$1 = (target, contractModule, options, resources, processScope) => Effect.gen(function* () {
330
+ const connect$1 = Effect.fnUntraced(function* (target, contractModule, options, resources, processScope) {
325
331
  const instance = target.instance;
326
332
  const margin = Duration.toMillis(target.margin ?? "5 seconds");
327
333
  const channel$1 = yield* connectWith(target.explicitAuth).pipe(Scope.provide(processScope));
@@ -344,7 +350,7 @@ const connect$1 = (target, contractModule, options, resources, processScope) =>
344
350
  const finishStarted = yield* Ref.make(false);
345
351
  const terminate = yield* Effect.cached(Effect.gen(function* () {
346
352
  yield* Ref.set(finishStarted, true);
347
- yield* failures.close;
353
+ const closed = yield* Effect.exit(failures.close);
348
354
  const result = yield* awaitTermination(record.handle, session.Dispose(record.handle), record.leaseMillis, margin);
349
355
  const { code, signal, stderr, cause } = result.exit;
350
356
  yield* Effect.logInfo("Remote execution terminated", {
@@ -357,7 +363,8 @@ const connect$1 = (target, contractModule, options, resources, processScope) =>
357
363
  "remote.generation": record.handle.generation,
358
364
  "remote.termination": result.kind
359
365
  }));
360
- if (result.cause.reasons.length > 0) return yield* Effect.failCause(cleanupCause(result.cause));
366
+ const failure = Exit.isFailure(closed) ? Cause.combine(closed.cause, result.cause) : result.cause;
367
+ if (failure.reasons.length > 0) return yield* Effect.failCause(cleanupCause(failure));
361
368
  }));
362
369
  yield* Scope.addFinalizer(processScope, Effect.gen(function* () {
363
370
  if (!(yield* Ref.get(finishStarted))) yield* terminate.pipe(Effect.catchCause((cause) => Effect.failCause(cleanupCause(cause))));
@@ -377,7 +384,7 @@ const connect$1 = (target, contractModule, options, resources, processScope) =>
377
384
  }).pipe(Scope.provide(resources));
378
385
  const report = (cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : failures.failCause(Cause.map(cause, (error) => TransportError.make({ cause: Cause.fail(error) })));
379
386
  yield* failures.await.pipe(Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : peer.fail(TransportError.make({ cause }))), Effect.forkIn(resources));
380
- yield* failures.run(Fiber.join(renewed).pipe(Effect.catchCause((cause) => Effect.gen(function* () {
387
+ yield* failures.run(Fiber.join(renewed).pipe(Effect.catchCause(Effect.fnUntraced(function* (cause) {
381
388
  if (Cause.hasInterruptsOnly(cause)) return;
382
389
  const status = yield* Effect.exit(session.Status(record.handle).pipe(Effect.timeout("5 seconds")));
383
390
  if (Exit.isSuccess(status) && status.value.phase === "Stopped") {
@@ -394,7 +401,7 @@ const connect$1 = (target, contractModule, options, resources, processScope) =>
394
401
  resources,
395
402
  pid: Option.map(childOf(loaded), (child) => child.pid),
396
403
  diagnostics: failures.cause,
397
- terminate: () => Effect.gen(function* () {
404
+ terminate: Effect.fnUntraced(function* () {
398
405
  yield* Fiber.interrupt(renewed);
399
406
  yield* terminate;
400
407
  }),
@@ -426,7 +433,7 @@ const connect = Effect.fnUntraced(function* (execution, options) {
426
433
  report
427
434
  },
428
435
  diagnostics: Fiber.await(exited).pipe(Effect.andThen(failures.cause)),
429
- terminate: (graceful) => Effect.gen(function* () {
436
+ terminate: Effect.fnUntraced(function* (graceful) {
430
437
  yield* failures.close;
431
438
  if (!graceful) return;
432
439
  const status = yield* peer.end.pipe(Effect.catchCauseIf(Cause.hasInterruptsOnly, () => Effect.void), Effect.andThen(Fiber.join(exited)), Effect.interruptible, Effect.timeoutOrElse({
@@ -463,17 +470,17 @@ const finish = (causes) => {
463
470
  const scopes = Effect.acquireRelease(Effect.all({
464
471
  resources: Scope.make(),
465
472
  process: Scope.make()
466
- }), (scopes, exit) => Effect.gen(function* () {
473
+ }), Effect.fnUntraced(function* (scopes, exit) {
467
474
  const process = yield* Effect.exit(close(scopes.process, exit));
468
475
  const resources = yield* Effect.exit(close(scopes.resources, exit));
469
476
  yield* finish([reason(process), reason(resources)]);
470
477
  }));
471
478
  /** Setup supplies a concrete control lifecycle; release never reads a later-installed effect. */
472
- const acquire = (target, contractModule, options, setup, dispose, timeout) => Effect.gen(function* () {
479
+ const acquire = Effect.fnUntraced(function* (target, contractModule, options, setup, dispose, timeout) {
473
480
  const owned = yield* scopes;
474
481
  const connection = yield* Effect.acquireRelease(Effect.gen(function* () {
475
482
  return target._tag === "Local" || target._tag === "Worker" ? yield* Local(target, contractModule, options, owned.resources, owned.process).pipe(Effect.map(connected)) : yield* connect$1(target, contractModule, options, owned.resources, owned.process);
476
- }).pipe(Effect.interruptible), (connection, exit) => Effect.gen(function* () {
483
+ }).pipe(Effect.interruptible), Effect.fnUntraced(function* (connection, exit) {
477
484
  const process = yield* Effect.exit(close(owned.process, exit));
478
485
  yield* connection.diagnostics;
479
486
  const resources = yield* Effect.exit(close(owned.resources, exit));
@@ -484,7 +491,7 @@ const acquire = (target, contractModule, options, setup, dispose, timeout) => Ef
484
491
  diagnostics
485
492
  ]);
486
493
  }));
487
- return yield* Effect.acquireRelease(setup.pipe(Effect.provideService(Connection, connection)), (value) => Effect.gen(function* () {
494
+ return yield* Effect.acquireRelease(setup.pipe(Effect.provideService(Connection, connection)), Effect.fnUntraced(function* (value) {
488
495
  const graceful = yield* dispose(value).pipe(Effect.interruptible, Effect.timeout(timeout), Effect.exit);
489
496
  const terminated = yield* Effect.exit(connection.terminate(Exit.isSuccess(graceful)));
490
497
  yield* finish([Exit.isSuccess(graceful) ? graceful.value : graceful.cause, reason(terminated)]);
@@ -492,7 +499,7 @@ const acquire = (target, contractModule, options, setup, dispose, timeout) => Ef
492
499
  });
493
500
  // packages/remote/src/internal/host.ts
494
501
  const race = (connection, effect) => Effect.raceFirst(effect, connection.transport.failure);
495
- const forwardEvents = (contract, client, connection) => Effect.gen(function* () {
502
+ const forwardEvents = Effect.fnUntraced(function* (contract, client, connection) {
496
503
  const stopped = yield* Deferred.make();
497
504
  const remoteFailure = yield* make$4();
498
505
  return {
@@ -507,10 +514,10 @@ const forwardEvents = (contract, client, connection) => Effect.gen(function* ()
507
514
  }))).pipe(Effect.tapCause(connection.transport.report), Effect.forkIn(connection.resources))
508
515
  };
509
516
  });
510
- const forwardLogs = (contract, client, connection) => Effect.gen(function* () {
517
+ const forwardLogs = Effect.fnUntraced(function* (contract, client, connection) {
511
518
  const logsEnded = yield* Deferred.make();
512
519
  const reportedDrops = yield* Ref.make(0);
513
- yield* race(connection, client.Logs().pipe(Stream.runForEach((event) => Effect.gen(function* () {
520
+ yield* race(connection, client.Logs().pipe(Stream.runForEach(Effect.fnUntraced(function* (event) {
514
521
  const previous = yield* Ref.getAndSet(reportedDrops, event.dropped);
515
522
  if (event.dropped > previous) yield* Effect.logWarning("Remote logs were dropped").pipe(Effect.annotateLogs({
516
523
  ...Option.isSome(connection.pid) ? { "remote.pid": connection.pid.value } : {},
@@ -531,7 +538,7 @@ const forwardLogs = (contract, client, connection) => Effect.gen(function* () {
531
538
  })))).pipe(Effect.tapCause(connection.transport.report), Effect.forkIn(connection.resources));
532
539
  return logsEnded;
533
540
  });
534
- const initialize = (contract) => Effect.gen(function* () {
541
+ const initialize = Effect.fnUntraced(function* (contract) {
535
542
  const connection = yield* Connection;
536
543
  const client = yield* RpcClient.make(contract.control).pipe(Effect.provideService(RpcClient.Protocol, connection.transport.clientProtocol(endpoint)), Scope.provide(connection.resources));
537
544
  for (const service of contract.inject) yield* service.serve(connection.transport).pipe(Effect.tapCause(connection.transport.report), Effect.forkIn(connection.resources));
@@ -545,7 +552,7 @@ const initialize = (contract) => Effect.gen(function* () {
545
552
  };
546
553
  });
547
554
  const load$1 = (active, input) => race(active.connection, Effect.raceFirst(active.client.Load({ input }).pipe(Effect.catchIf((cause) => Cause.isCause(cause), Effect.failCause)), active.remoteFailure.await));
548
- const dispose = (active) => Effect.gen(function* () {
555
+ const dispose = Effect.fnUntraced(function* (active) {
549
556
  const result = yield* race(active.connection, active.client.Dispose().pipe(Effect.catchIf(Cause.isCause, Effect.succeed)));
550
557
  const cause = Cause.isCause(result) ? result : Cause.empty;
551
558
  yield* race(active.connection, Deferred.await(active.stopped).pipe(Effect.andThen(Deferred.await(active.logsEnded)))).pipe(Effect.onError(() => Effect.failCause(cleanupCause(cause))));
@@ -562,7 +569,7 @@ const executionPlugin = (contract, options, configured, annotations = {}) => mak
562
569
  ...Array.map(contract.inject, (service) => service.key)
563
570
  ],
564
571
  config: Schema.toEncoded(contract.config),
565
- apply: (input) => Effect.gen(function* () {
572
+ apply: Effect.fnUntraced(function* (input) {
566
573
  const prepared = prepare(contract);
567
574
  const session = yield* (yield* SecureRandom.SecureRandom).uuidV4();
568
575
  const active = yield* acquire(configured, options.contractModule, {
@@ -577,9 +584,39 @@ const executionPlugin = (contract, options, configured, annotations = {}) => mak
577
584
  for (const service of contract.provides) yield* service.publish(active.connection.transport).pipe(Scope.provide(active.connection.resources));
578
585
  yield* fork(Effect.raceFirst(Fiber.join(active.events), active.remoteFailure.await).pipe(Effect.mapError((error) => publicError(contract.error, error))));
579
586
  return () => Effect.succeed(false);
580
- }).pipe(Effect.annotateLogs(annotations), Effect.mapError((error) => publicError(contract.error, error)))
587
+ }, Effect.annotateLogs(annotations), Effect.mapError((error) => publicError(contract.error, error)))
581
588
  });
582
- const publicError = (declared, error) => Schema.is(declared)(error) ? error : Schema.is(UndeclaredFailure)(error) || Schema.is(RemoteWithdrawn)(error) || Schema.is(RemoteError)(error) || Schema.is(MissingInstance)(error) ? error : RemoteError.make({ cause: Cause.fail(error) });
589
+ /** Failures raised by the host machinery; a permissive declared schema must not claim them. */
590
+ const internalErrors = [
591
+ ProcessExited,
592
+ TransportError,
593
+ LocalTerminationTimeout,
594
+ CredentialsError,
595
+ AuthenticationFailed,
596
+ RemoteEntryError,
597
+ AlreadyLoaded,
598
+ ContractNotFound,
599
+ ModuleImportFailed,
600
+ ActivationFailed,
601
+ PackageError,
602
+ SessionAccessDenied,
603
+ StaleSession,
604
+ LeaseExpired,
605
+ SessionStopped,
606
+ SessionConflict,
607
+ StateStorageError,
608
+ ExecutionError,
609
+ TerminationUnconfirmed,
610
+ RunnerClosing,
611
+ StateDirectoryLocked,
612
+ RemoteTerminationUnconfirmed,
613
+ ReleaseInterrupted,
614
+ RpcClientError.RpcClientError,
615
+ ...errors
616
+ ];
617
+ const isInternal = (error) => Schema.isSchemaError(error) || PlatformError.isPlatformError(error) || Array.some(internalErrors, (Class) => error instanceof Class);
618
+ const isPublic = (error) => Schema.is(UndeclaredFailure)(error) || Schema.is(RemoteWithdrawn)(error) || Schema.is(RemoteError)(error) || Schema.is(MissingInstance)(error);
619
+ const publicError = (declared, error) => isPublic(error) ? error : !isInternal(error) && Schema.is(declared)(error) ? error : RemoteError.make({ cause: Cause.fail(error) });
583
620
  // packages/remote/src/internal/entry.ts
584
621
  const boundary = Effect.fnUntraced(function* (field) {
585
622
  const entry = yield* CurrentId;
@@ -598,7 +635,7 @@ const resolve = Effect.fnUntraced(function* (reference, field) {
598
635
  const directory = path.resolve(Option.getOrElse(source, () => "."));
599
636
  const resolver = yield* Option.match(existing, {
600
637
  onSome: Effect.succeed,
601
- onNone: () => Effect.gen(function* () {
638
+ onNone: Effect.fnUntraced(function* () {
602
639
  const importer = yield* make$1(directory);
603
640
  return yield* make$2({
604
641
  base: directory,
@@ -1,4 +1,4 @@
1
- import { n as plugin, t as Config } from "../../tokenCredentials-CI6mMRRd.js";
1
+ import { n as plugin, t as Config } from "../../tokenCredentials-CbCuk-Rt.js";
2
2
  // packages/remote/src/host/auth/bearer.ts
3
3
  const capability = plugin("remote-bearer-credentials");
4
4
  export { Config, capability as default };
@@ -1,4 +1,4 @@
1
- import { n as plugin, t as Config } from "../../tokenCredentials-CI6mMRRd.js";
1
+ import { n as plugin, t as Config } from "../../tokenCredentials-CbCuk-Rt.js";
2
2
  // packages/remote/src/host/auth/jwt.ts
3
3
  const capability = plugin("remote-jwt-credentials");
4
4
  export { Config, capability as default };
@@ -1,5 +1,5 @@
1
- import { a as provide, l as make } from "../../Graft-CVyueNOf.js";
2
- import { n as CredentialsError } from "../../Errors-BMKmu5Y7.js";
1
+ import { a as provide, l as make } from "../../Graft-B71CPA2Y.js";
2
+ import { r as CredentialsError } from "../../Errors-DYhsGZcZ.js";
3
3
  import { t as ConfigDirectory } from "../../ConfigDirectory-BCC6q2R4.js";
4
4
  import { n as Credentials } from "../../Auth-BElTC9_X.js";
5
5
  import { Cause, Effect, FileSystem, Option, Path, Redacted, Schema } from "effect";
@@ -1,4 +1,4 @@
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 { n as Credentials } from "../../Auth-BElTC9_X.js";
3
3
  import { Effect, Schema } from "effect";
4
4
  // packages/remote/src/host/auth/none.ts
@@ -1,9 +1,9 @@
1
- import { a as provide, l as make$1 } from "../Graft-CVyueNOf.js";
1
+ import { a as provide, l as make$1 } from "../Graft-B71CPA2Y.js";
2
2
  import { t as Connector } from "../Transport-DULzpsgR.js";
3
3
  import { t as ConfigDirectory } from "../ConfigDirectory-BCC6q2R4.js";
4
- import { l as TransportError } from "../Errors-BMKmu5Y7.js";
5
- import { n as cleanupCause } from "../cleanup-CXLa1Wd9.js";
6
- import { n as stdinExitTimeout, t as observe } from "../ProcessObservation-DEGrEMfP.js";
4
+ import { u as TransportError } from "../Errors-DYhsGZcZ.js";
5
+ import { r as cleanupCause } from "../FailureGroup-BgT73AaR.js";
6
+ import { n as stdinExitTimeout, t as observe } from "../ProcessObservation-gLgGirYv.js";
7
7
  import { Array, Cause, Effect, Option, Path, Schema, Scope, Sink, Stream } from "effect";
8
8
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
9
9
  // packages/remote/src/host/command.ts
@@ -1,8 +1,8 @@
1
- import { d as service } from "../Graft-CVyueNOf.js";
1
+ import { d as service } from "../Graft-B71CPA2Y.js";
2
2
  import { t as LocalTransport } from "../directTransport-DrexuPSm.js";
3
3
  import { t as command } from "../command-9zrHdbwT.js";
4
- import { a as ProcessExited, l as TransportError } from "../Errors-BMKmu5Y7.js";
5
- import { t as observe$1 } from "../ProcessObservation-DEGrEMfP.js";
4
+ import { o as ProcessExited, u as TransportError } from "../Errors-DYhsGZcZ.js";
5
+ import { t as observe$1 } from "../ProcessObservation-gLgGirYv.js";
6
6
  import { Array, Cause, Effect, Fiber, Option, Scope, Sink, Stream } from "effect";
7
7
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
8
8
  // packages/remote/src/internal/host/local.ts
package/dist/host/unix.js CHANGED
@@ -1,8 +1,8 @@
1
- import { a as provide, l as make$1 } from "../Graft-CVyueNOf.js";
1
+ import { a as provide, l as make$1 } from "../Graft-B71CPA2Y.js";
2
2
  import { t as ConfigDirectory } from "../ConfigDirectory-BCC6q2R4.js";
3
- import { a as payloadLimit, c as wrapper_default, i as path, s as protocol, t as fromSocket } from "../socketChannel-C_ppdSzz.js";
3
+ import { a as payloadLimit, c as wrapper_default, i as path, s as protocol, t as fromSocket } from "../socketChannel-CJvL2DiB.js";
4
4
  import { t as Connector } from "../Transport-DULzpsgR.js";
5
- import { l as TransportError } from "../Errors-BMKmu5Y7.js";
5
+ import { u as TransportError } from "../Errors-DYhsGZcZ.js";
6
6
  import { Cause, Effect, Layer, Option, Path, Redacted, Schema } from "effect";
7
7
  import { Socket } from "effect/socket";
8
8
  // packages/remote/src/host/unix.ts
@@ -1,8 +1,8 @@
1
- import { a as provide, l as make$1 } from "../Graft-CVyueNOf.js";
1
+ import { a as provide, l as make$1 } from "../Graft-B71CPA2Y.js";
2
2
  import { t as Connector } from "../Transport-DULzpsgR.js";
3
- import { l as TransportError } from "../Errors-BMKmu5Y7.js";
3
+ import { u as TransportError } from "../Errors-DYhsGZcZ.js";
4
4
  import { t as ConfigDirectory } from "../ConfigDirectory-BCC6q2R4.js";
5
- import { n as Url, o as properties, r as open, t as fromSocket } from "../socketChannel-C_ppdSzz.js";
5
+ import { n as Url, o as properties, r as open, t as fromSocket } from "../socketChannel-CJvL2DiB.js";
6
6
  import { Cause, Effect, FileSystem, Option, Path, Schema } from "effect";
7
7
  // packages/remote/src/host/websocket.ts
8
8
  /** Configured Connector; certificate paths belong to the enclosing configuration. */
@@ -1,9 +1,8 @@
1
- import { d as service } from "../Graft-CVyueNOf.js";
1
+ import { d as service } from "../Graft-B71CPA2Y.js";
2
2
  import { n as WorkerTransport } from "../directTransport-DrexuPSm.js";
3
- import { a as ProcessExited, l as TransportError } from "../Errors-BMKmu5Y7.js";
4
- import { n as Bootstrap, t as make } from "../workerChannel-cmLc13vm.js";
5
- import { t as make$1 } from "../FailureGroup-BcH0XOBi.js";
6
- import { n as cleanupCause } from "../cleanup-CXLa1Wd9.js";
3
+ import { o as ProcessExited, u as TransportError } from "../Errors-DYhsGZcZ.js";
4
+ import { n as Bootstrap, t as make } from "../workerChannel-C8hhBJzA.js";
5
+ import { r as cleanupCause, t as make$1 } from "../FailureGroup-BgT73AaR.js";
7
6
  import { Cause, Deferred, Effect, FiberSet, Option, Schema } from "effect";
8
7
  import { Worker } from "node:worker_threads";
9
8
  // packages/remote/src/host/worker.ts
@@ -1,4 +1,4 @@
1
- import { s as fromModule } from "./Graft-CVyueNOf.js";
1
+ import { s as fromModule } from "./Graft-B71CPA2Y.js";
2
2
  import { t as ConfigDirectory } from "./ConfigDirectory-BCC6q2R4.js";
3
3
  import { registerHooks } from "node:module";
4
4
  import { Array, Cause, Config, Context, Data, Effect, Exit, HashMap, MutableList, Option, Path, Predicate, Record, Ref, Result, Schema, Scope, String } from "effect";
@@ -202,7 +202,7 @@ const inCandidateScope = (effect) => Effect.uninterruptibleMask((restore) => Eff
202
202
  * Importers may attach observation-only leases to the separate observationScope.
203
203
  * The caller keeps that scope through failure and closes it on retry or disposal.
204
204
  */
205
- const make$1 = (options) => Effect.gen(function* () {
205
+ const make$1 = Effect.fnUntraced(function* (options) {
206
206
  const path = yield* Path.Path;
207
207
  /** Keep the import target and Node's possible missing names in one normalization step. */
208
208
  const normalize = Effect.fnUntraced(function* (specifier) {
@@ -253,14 +253,11 @@ const make$1 = (options) => Effect.gen(function* () {
253
253
  });
254
254
  const environment = options.resolution;
255
255
  const revision = environment === void 0 ? 0 : yield* environment.revision;
256
- const cached = yield* Ref.get(plans);
257
- if (cached.revision === revision) {
258
- const found = HashMap.get(cached.entries, key);
259
- if (Option.isSome(found)) return found.value;
260
- } else yield* Ref.set(plans, {
256
+ const found = yield* Ref.modify(plans, (current) => current.revision === revision ? [HashMap.get(current.entries, key), current] : revision > current.revision ? [Option.none(), {
261
257
  revision,
262
258
  entries: HashMap.empty()
263
- });
259
+ }] : [Option.none(), current]);
260
+ if (Option.isSome(found)) return found.value;
264
261
  const normalized = yield* Effect.forEach(candidates(name), (specifier) => Effect.map(normalize(specifier), (candidate) => ({
265
262
  ...candidate,
266
263
  specifier
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { a as provide, l as make, u as optional } from "./Graft-CVyueNOf.js";
2
- import { r as ModuleResolver } from "./importer-Bk6U_sn4.js";
3
- import { a as publicError, d as follow, f as Host, n as host, r as launch, s as CapabilityFailed } from "./entry-B89sepMU.js";
1
+ import { a as provide, l as make, u as optional } from "./Graft-B71CPA2Y.js";
2
+ import { r as ModuleResolver } from "./importer-Cvf88eAY.js";
3
+ import { a as publicError, d as follow, f as Host, n as host, r as launch, s as CapabilityFailed } from "./entry-psOpX3Bj.js";
4
4
  import { n as Credentials } from "./Auth-BElTC9_X.js";
5
- import { c as RemoteWithdrawn, i as MissingInstance, n as CredentialsError, s as RemoteError } from "./Errors-BMKmu5Y7.js";
6
- import { n as prepare } from "./token-Cc_1CTbE.js";
7
- import { n as UndeclaredFailure, t as Contract_exports } from "./Contract-DL2mHvaT.js";
8
- import { O as Instance, l as RemoteTerminationUnconfirmed } from "./Peer-BT7eAGmh.js";
5
+ import { a as MissingInstance, c as RemoteError, l as RemoteWithdrawn, r as CredentialsError } from "./Errors-DYhsGZcZ.js";
6
+ import { n as prepare } from "./token-CYBNNlhS.js";
7
+ import { n as UndeclaredFailure, t as Contract_exports } from "./Contract-DsJtisvL.js";
8
+ import { O as Instance, l as RemoteTerminationUnconfirmed } from "./Peer-DXeVrGBh.js";
9
9
  import { Array, Cause, Context, Effect, Path, Schema, Scope } from "effect";
10
10
  import { SecureRandom } from "effect/crypto";
11
11
  import { ChildProcessSpawner } from "effect/process";
@@ -69,7 +69,7 @@ const plugin = (contract, options) => make({
69
69
  ChildProcessSpawner.ChildProcessSpawner
70
70
  ],
71
71
  retry: options.retry,
72
- apply: () => Effect.gen(function* () {
72
+ apply: Effect.fnUntraced(function* () {
73
73
  const input = yield* Schema.decodeUnknownEffect(Host)({
74
74
  contract: options.contractModule,
75
75
  connect: options.connect,
@@ -81,6 +81,6 @@ const plugin = (contract, options) => make({
81
81
  shutdownTimeout: options.shutdownTimeout
82
82
  }, invocation(options.connect));
83
83
  yield* follow(child, (cause) => Effect.failCause(publicCause(contract.error, cause)));
84
- }).pipe(Effect.mapError((error) => publicError(contract.error, error)))
84
+ }, Effect.mapError((error) => publicError(contract.error, error)))
85
85
  });
86
86
  export { Contract_exports as Contract, Instance, MissingInstance, RemoteError, RemoteTerminationUnconfirmed, RemoteWithdrawn, UndeclaredFailure, host as default, plugin };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Configuration.Host","Credential.invocation"],"sources":["../src/index.ts"],"sourcesContent":["import { Plugin } from \"@graftland/graft\"\nimport { ModuleResolver } from \"@graftland/loader\"\nimport { Array, Cause, Effect, Path, Schema } from \"effect\"\nimport type { Duration, Schedule } from \"effect\"\nimport { SecureRandom } from \"effect/crypto\"\nimport { ChildProcessSpawner } from \"effect/process\"\nimport { launch } from \"./internal/entry\"\nimport { follow } from \"./internal/follow\"\nimport { CapabilityFailed } from \"./internal/assembly\"\nimport { publicError } from \"./internal/execution\"\nimport * as Configuration from \"./internal/entryConfig\"\nimport * as Credential from \"./internal/credentials\"\nimport { RemoteWithdrawn, RemoteError, MissingInstance } from \"./Errors\"\nimport * as Contract from \"./Contract\"\nexport { Contract }\nexport { Instance } from \"./Instance\"\nexport { RemoteTerminationUnconfirmed } from \"./internal/runner/model\"\nexport { RemoteError, RemoteWithdrawn, MissingInstance } from \"./Errors\"\nexport { UndeclaredFailure } from \"./Contract\"\nexport type {\n\tConnect,\n\tAuthentication,\n\tToken as CredentialToken,\n\tSource as CredentialSource,\n} from \"./internal/credentials\"\n\nexport interface Options<\n\tD extends ReadonlyArray<Plugin.Dependency> = readonly [],\n> {\n\treadonly connect: Credential.Connect<D>\n\t/** Contract module resolved independently in each execution environment. */\n\treadonly contractModule: string\n\treadonly config?: Schema.Json\n\treadonly retry?: Schedule.Schedule<unknown, unknown> | undefined\n\treadonly shutdownTimeout?: Duration.Input | undefined\n}\nconst publicCause = <E extends Schema.Top>(\n\tdeclared: E,\n\tcause: Cause.Cause<unknown>,\n): Cause.Cause<\n\t| E[\"Type\"]\n\t| Contract.UndeclaredFailure\n\t| RemoteWithdrawn\n\t| RemoteError\n\t| MissingInstance\n> =>\n\tCause.fromReasons(\n\t\tArray.flatMap(cause.reasons, (reason) => {\n\t\t\tif (reason._tag !== \"Fail\") return [reason]\n\t\t\treturn Schema.is(CapabilityFailed)(reason.error)\n\t\t\t\t? Array.map(\n\t\t\t\t\t\tpublicCause(declared, reason.error.cause).reasons,\n\t\t\t\t\t\t(inner) => inner.annotate(Cause.reasonAnnotations(reason)),\n\t\t\t\t\t)\n\t\t\t\t: [\n\t\t\t\t\t\tCause.makeFailReason(publicError(declared, reason.error)).annotate(\n\t\t\t\t\t\t\tCause.reasonAnnotations(reason),\n\t\t\t\t\t\t),\n\t\t\t\t\t]\n\t\t}),\n\t)\n\nexport const plugin = <\n\tS extends Schema.Top & {\n\t\treadonly Encoded: Schema.Json\n\t\treadonly DecodingServices: never\n\t\treadonly EncodingServices: never\n\t},\n\tE extends Schema.Top & {\n\t\treadonly DecodingServices: never\n\t\treadonly EncodingServices: never\n\t},\n\tconst D extends ReadonlyArray<Plugin.Dependency> = readonly [],\n>(\n\tcontract: Contract.Contract<S, E>,\n\toptions: Options<D> & { readonly config?: S[\"Encoded\"] },\n): Plugin.Plugin<\n\tvoid,\n\tvoid,\n\t| E[\"Type\"]\n\t| Contract.UndeclaredFailure\n\t| RemoteError\n\t| RemoteWithdrawn\n\t| MissingInstance\n> =>\n\tPlugin.make({\n\t\tname: contract.name,\n\t\tinject: [\n\t\t\tPlugin.optional(ModuleResolver.ModuleResolver),\n\t\t\tPath.Path,\n\t\t\tSecureRandom.SecureRandom,\n\t\t\tChildProcessSpawner.ChildProcessSpawner,\n\t\t],\n\t\tretry: options.retry,\n\t\tapply: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst input = yield* Schema.decodeUnknownEffect(Configuration.Host)({\n\t\t\t\t\tcontract: options.contractModule,\n\t\t\t\t\tconnect: options.connect,\n\t\t\t\t\tconfig: options.config === undefined ? {} : options.config,\n\t\t\t\t})\n\t\t\t\tyield* Schema.decodeEffect(contract.config)(input.config)\n\t\t\t\tconst child = yield* launch(\n\t\t\t\t\tcontract,\n\t\t\t\t\tinput,\n\t\t\t\t\t{\n\t\t\t\t\t\tcontractModule: options.contractModule,\n\t\t\t\t\t\tshutdownTimeout: options.shutdownTimeout,\n\t\t\t\t\t},\n\t\t\t\t\tCredential.invocation(options.connect),\n\t\t\t\t)\n\t\t\t\tyield* follow(child, (cause) =>\n\t\t\t\t\tEffect.failCause(publicCause(contract.error, cause)),\n\t\t\t\t)\n\t\t\t}).pipe(Effect.mapError((error) => publicError(contract.error, error))),\n\t})\nexport { host as default } from \"./internal/entry\"\n"],"mappings":";;;;;;;;;;;;;;;;AAoCA,MAAM,eACL,UACA,UAQA,MAAM,YACL,MAAM,QAAQ,MAAM,UAAU,WAAW;CACxC,IAAI,OAAO,SAAS,QAAQ,OAAO,CAAC,MAAM;CAC1C,OAAO,OAAO,GAAG,gBAAgB,CAAC,CAAC,OAAO,KAAK,IAC5C,MAAM,IACN,YAAY,UAAU,OAAO,MAAM,KAAK,CAAC,CAAC,UACzC,UAAU,MAAM,SAAS,MAAM,kBAAkB,MAAM,CAAC,CAC1D,IACC,CACA,MAAM,eAAe,YAAY,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,SACzD,MAAM,kBAAkB,MAAM,CAC/B,CACD;AACH,CAAC,CACF;AAED,MAAa,UAYZ,UACA,YAUA,OAAO,KAAK;CACX,MAAM,SAAS;CACf,QAAQ;EACP,OAAO,SAAS,eAAe,cAAc;EAC7C,KAAK;EACL,aAAa;EACb,oBAAoB;CACrB;CACA,OAAO,QAAQ;CACf,aACC,OAAO,IAAI,aAAa;EACvB,MAAM,QAAQ,OAAO,OAAO,oBAAoBA,IAAkB,CAAC,CAAC;GACnE,UAAU,QAAQ;GAClB,SAAS,QAAQ;GACjB,QAAQ,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,QAAQ;EACrD,CAAC;EACD,OAAO,OAAO,aAAa,SAAS,MAAM,CAAC,CAAC,MAAM,MAAM;EACxD,MAAM,QAAQ,OAAO,OACpB,UACA,OACA;GACC,gBAAgB,QAAQ;GACxB,iBAAiB,QAAQ;EAC1B,GACAC,WAAsB,QAAQ,OAAO,CACtC;EACA,OAAO,OAAO,QAAQ,UACrB,OAAO,UAAU,YAAY,SAAS,OAAO,KAAK,CAAC,CACpD;CACD,CAAC,CAAC,CAAC,KAAK,OAAO,UAAU,UAAU,YAAY,SAAS,OAAO,KAAK,CAAC,CAAC;AACxE,CAAC"}
1
+ {"version":3,"file":"index.js","names":["Configuration.Host","Credential.invocation"],"sources":["../src/index.ts"],"sourcesContent":["import { Plugin } from \"@graftland/graft\"\nimport { ModuleResolver } from \"@graftland/loader\"\nimport { Array, Cause, Effect, Path, Schema } from \"effect\"\nimport type { Duration, Schedule } from \"effect\"\nimport { SecureRandom } from \"effect/crypto\"\nimport { ChildProcessSpawner } from \"effect/process\"\nimport { launch } from \"./internal/entry\"\nimport { follow } from \"./internal/follow\"\nimport { CapabilityFailed } from \"./internal/assembly\"\nimport { publicError } from \"./internal/execution\"\nimport * as Configuration from \"./internal/entryConfig\"\nimport * as Credential from \"./internal/credentials\"\nimport { RemoteWithdrawn, RemoteError, MissingInstance } from \"./Errors\"\nimport * as Contract from \"./Contract\"\nexport { Contract }\nexport { Instance } from \"./Instance\"\nexport { RemoteTerminationUnconfirmed } from \"./internal/runner/model\"\nexport { RemoteError, RemoteWithdrawn, MissingInstance } from \"./Errors\"\nexport { UndeclaredFailure } from \"./Contract\"\nexport type {\n\tConnect,\n\tAuthentication,\n\tToken as CredentialToken,\n\tSource as CredentialSource,\n} from \"./internal/credentials\"\n\nexport interface Options<\n\tD extends ReadonlyArray<Plugin.Dependency> = readonly [],\n> {\n\treadonly connect: Credential.Connect<D>\n\t/** Contract module resolved independently in each execution environment. */\n\treadonly contractModule: string\n\treadonly config?: Schema.Json\n\treadonly retry?: Schedule.Schedule<unknown, unknown> | undefined\n\treadonly shutdownTimeout?: Duration.Input | undefined\n}\nconst publicCause = <E extends Schema.Top>(\n\tdeclared: E,\n\tcause: Cause.Cause<unknown>,\n): Cause.Cause<\n\t| E[\"Type\"]\n\t| Contract.UndeclaredFailure\n\t| RemoteWithdrawn\n\t| RemoteError\n\t| MissingInstance\n> =>\n\tCause.fromReasons(\n\t\tArray.flatMap(cause.reasons, (reason) => {\n\t\t\tif (reason._tag !== \"Fail\") return [reason]\n\t\t\treturn Schema.is(CapabilityFailed)(reason.error)\n\t\t\t\t? Array.map(\n\t\t\t\t\t\tpublicCause(declared, reason.error.cause).reasons,\n\t\t\t\t\t\t(inner) => inner.annotate(Cause.reasonAnnotations(reason)),\n\t\t\t\t\t)\n\t\t\t\t: [\n\t\t\t\t\t\tCause.makeFailReason(publicError(declared, reason.error)).annotate(\n\t\t\t\t\t\t\tCause.reasonAnnotations(reason),\n\t\t\t\t\t\t),\n\t\t\t\t\t]\n\t\t}),\n\t)\n\nexport const plugin = <\n\tS extends Schema.Top & {\n\t\treadonly Encoded: Schema.Json\n\t\treadonly DecodingServices: never\n\t\treadonly EncodingServices: never\n\t},\n\tE extends Schema.Top & {\n\t\treadonly DecodingServices: never\n\t\treadonly EncodingServices: never\n\t},\n\tconst D extends ReadonlyArray<Plugin.Dependency> = readonly [],\n>(\n\tcontract: Contract.Contract<S, E>,\n\toptions: Options<D> & { readonly config?: S[\"Encoded\"] },\n): Plugin.Plugin<\n\tvoid,\n\tvoid,\n\t| E[\"Type\"]\n\t| Contract.UndeclaredFailure\n\t| RemoteError\n\t| RemoteWithdrawn\n\t| MissingInstance\n> =>\n\tPlugin.make({\n\t\tname: contract.name,\n\t\tinject: [\n\t\t\tPlugin.optional(ModuleResolver.ModuleResolver),\n\t\t\tPath.Path,\n\t\t\tSecureRandom.SecureRandom,\n\t\t\tChildProcessSpawner.ChildProcessSpawner,\n\t\t],\n\t\tretry: options.retry,\n\t\tapply: Effect.fnUntraced(\n\t\t\tfunction* () {\n\t\t\t\tconst input = yield* Schema.decodeUnknownEffect(Configuration.Host)({\n\t\t\t\t\tcontract: options.contractModule,\n\t\t\t\t\tconnect: options.connect,\n\t\t\t\t\tconfig: options.config === undefined ? {} : options.config,\n\t\t\t\t})\n\t\t\t\tyield* Schema.decodeEffect(contract.config)(input.config)\n\t\t\t\tconst child = yield* launch(\n\t\t\t\t\tcontract,\n\t\t\t\t\tinput,\n\t\t\t\t\t{\n\t\t\t\t\t\tcontractModule: options.contractModule,\n\t\t\t\t\t\tshutdownTimeout: options.shutdownTimeout,\n\t\t\t\t\t},\n\t\t\t\t\tCredential.invocation(options.connect),\n\t\t\t\t)\n\t\t\t\tyield* follow(child, (cause) =>\n\t\t\t\t\tEffect.failCause(publicCause(contract.error, cause)),\n\t\t\t\t)\n\t\t\t},\n\t\t\tEffect.mapError((error) => publicError(contract.error, error)),\n\t\t),\n\t})\nexport { host as default } from \"./internal/entry\"\n"],"mappings":";;;;;;;;;;;;;;;;AAoCA,MAAM,eACL,UACA,UAQA,MAAM,YACL,MAAM,QAAQ,MAAM,UAAU,WAAW;CACxC,IAAI,OAAO,SAAS,QAAQ,OAAO,CAAC,MAAM;CAC1C,OAAO,OAAO,GAAG,gBAAgB,CAAC,CAAC,OAAO,KAAK,IAC5C,MAAM,IACN,YAAY,UAAU,OAAO,MAAM,KAAK,CAAC,CAAC,UACzC,UAAU,MAAM,SAAS,MAAM,kBAAkB,MAAM,CAAC,CAC1D,IACC,CACA,MAAM,eAAe,YAAY,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,SACzD,MAAM,kBAAkB,MAAM,CAC/B,CACD;AACH,CAAC,CACF;AAED,MAAa,UAYZ,UACA,YAUA,OAAO,KAAK;CACX,MAAM,SAAS;CACf,QAAQ;EACP,OAAO,SAAS,eAAe,cAAc;EAC7C,KAAK;EACL,aAAa;EACb,oBAAoB;CACrB;CACA,OAAO,QAAQ;CACf,OAAO,OAAO,WACb,aAAa;EACZ,MAAM,QAAQ,OAAO,OAAO,oBAAoBA,IAAkB,CAAC,CAAC;GACnE,UAAU,QAAQ;GAClB,SAAS,QAAQ;GACjB,QAAQ,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,QAAQ;EACrD,CAAC;EACD,OAAO,OAAO,aAAa,SAAS,MAAM,CAAC,CAAC,MAAM,MAAM;EACxD,MAAM,QAAQ,OAAO,OACpB,UACA,OACA;GACC,gBAAgB,QAAQ;GACxB,iBAAiB,QAAQ;EAC1B,GACAC,WAAsB,QAAQ,OAAO,CACtC;EACA,OAAO,OAAO,QAAQ,UACrB,OAAO,UAAU,YAAY,SAAS,OAAO,KAAK,CAAC,CACpD;CACD,GACA,OAAO,UAAU,UAAU,YAAY,SAAS,OAAO,KAAK,CAAC,CAC9D;AACD,CAAC"}
@@ -137,10 +137,10 @@ const write = Effect.fn("Certificates.write")(function* (base, pair, force = fal
137
137
  yield* fs.writeFileString(base + ".key", Redacted.value(pair.privateKey), {
138
138
  flag: force ? "w" : "wx",
139
139
  mode: 384
140
- }).pipe(Effect.uninterruptible);
141
- yield* fs.chmod(base + ".key", 384).pipe(Effect.uninterruptible);
142
- yield* fs.writeFileString(base + ".crt", pair.certificate, { flag: force ? "w" : "wx" }).pipe(Effect.uninterruptible);
143
- });
140
+ });
141
+ yield* fs.chmod(base + ".key", 384);
142
+ yield* fs.writeFileString(base + ".crt", pair.certificate, { flag: force ? "w" : "wx" });
143
+ }, Effect.uninterruptible);
144
144
  /** URI-encode names so each identity has a distinct filename, including names with slashes. */
145
145
  const clientName = (identity) => `client-${encodeURIComponent(identity)}`;
146
146
  const generate = Effect.fn("Certificates.generate")(function* (options) {
@@ -1 +1 @@
1
- {"version":3,"file":"Certificates.js","names":[],"sources":["../../src/internal/Certificates.ts"],"sourcesContent":["import {\n\tArray,\n\tDateTime,\n\tEffect,\n\tFileSystem,\n\tPath,\n\tRedacted,\n\tResult,\n\tSchema,\n\tString,\n} from \"effect\"\nimport { SecureRandom, WebCrypto } from \"effect/crypto\"\nimport { Base64 } from \"effect/encoding\"\nimport { NetAddress } from \"effect/net\"\nimport * as asn1js from \"asn1js\"\nimport * as pki from \"pkijs\"\n\nexport class CertificateError extends Schema.TaggedError<\n\tCertificateError,\n\t{ readonly brand: unique symbol }\n>()(\"CertificateError\", {\n\tdetail: Schema.String,\n\tcause: Schema.optional(Schema.Defect()),\n}) {\n\toverride get message() {\n\t\treturn this.detail\n\t}\n}\n\n/** A requested output already exists and replacing it was not asked for. */\nexport class CertificateExists extends Schema.TaggedError<\n\tCertificateExists,\n\t{ readonly brand: unique symbol }\n>()(\"CertificateExists\", { file: Schema.String }) {\n\toverride get message() {\n\t\treturn `${this.file} already exists; use --force to replace the requested certificates`\n\t}\n}\n\n/** Only PEM leaves this boundary; PKI.js objects stay local to each operation. */\nexport interface Pem {\n\treadonly certificate: string\n\treadonly privateKey: Redacted.Redacted<string>\n}\nexport interface IssueOptions {\n\treadonly name: string\n\treadonly days: number\n\treadonly usage: \"ca\" | \"server\" | \"client\"\n\treadonly hosts?: ReadonlyArray<string>\n\treadonly identities?: ReadonlyArray<string>\n\treadonly issuer?: Pem\n}\nconst pem = (label: string, bytes: ArrayBuffer) =>\n\t`-----BEGIN ${label}-----\\n${String.replace(/.{64}(?=.)/g, \"$&\\n\")(Base64.encode(new Uint8Array(bytes)))}\\n-----END ${label}-----\\n`\n// WebCrypto and PKI.js take ArrayBuffer-backed bytes, so the decoded view is copied into one.\nconst der = (value: string) =>\n\tEffect.fromResult(\n\t\tBase64.decode(String.replace(/-----[^-]+-----|\\s/g, \"\")(value)),\n\t).pipe(Effect.map((bytes) => new Uint8Array(bytes)))\nconst subject = (name: string) =>\n\tnew pki.RelativeDistinguishedNames({\n\t\ttypesAndValues: [\n\t\t\tnew pki.AttributeTypeAndValue({\n\t\t\t\ttype: \"2.5.4.3\",\n\t\t\t\tvalue: new asn1js.Utf8String({ value: name }),\n\t\t\t}),\n\t\t],\n\t})\nconst hostName = (host: string) =>\n\tResult.match(NetAddress.ipFromString(host), {\n\t\tonFailure: () => new pki.GeneralName({ type: 2, value: host }),\n\t\tonSuccess: (ip) =>\n\t\t\tnew pki.GeneralName({\n\t\t\t\ttype: 7,\n\t\t\t\tvalue: new asn1js.OctetString({\n\t\t\t\t\tvalueHex: new Uint8Array(\n\t\t\t\t\t\tip._tag === \"Ipv4Address\"\n\t\t\t\t\t\t\t? NetAddress.ipv4ToOctets(ip)\n\t\t\t\t\t\t\t: NetAddress.ipv6ToOctets(ip),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t}),\n\t})\n\nexport const issue = Effect.fn(\"Certificates.issue\")(function* (\n\toptions: IssueOptions,\n) {\n\tconst random = yield* SecureRandom.SecureRandom\n\tconst serial = yield* random.randomBytes(19)\n\tconst now = yield* DateTime.now\n\tconst webcrypto = yield* WebCrypto.WebCrypto\n\tconst engine = new pki.CryptoEngine({\n\t\tname: \"Node WebCrypto\",\n\t\tcrypto: webcrypto,\n\t})\n\tconst failure = (cause: unknown) =>\n\t\tCertificateError.make({\n\t\t\tdetail: `Could not issue the certificate for ${options.name}`,\n\t\t\tcause,\n\t\t})\n\tconst keys = yield* Effect.tryPromise({\n\t\ttry: () =>\n\t\t\twebcrypto.subtle.generateKey(\n\t\t\t\t{ name: \"ECDSA\", namedCurve: \"P-256\" },\n\t\t\t\ttrue,\n\t\t\t\t[\"sign\", \"verify\"],\n\t\t\t),\n\t\tcatch: failure,\n\t})\n\t// Reused CA keys have the same P-256 / PKCS#8 format as the ones this command creates.\n\tconst authority =\n\t\toptions.issuer === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tcertificate: yield* Effect.mapError(\n\t\t\t\t\t\tder(options.issuer.certificate),\n\t\t\t\t\t\tfailure,\n\t\t\t\t\t),\n\t\t\t\t\tprivateKey: yield* Effect.mapError(\n\t\t\t\t\t\tder(Redacted.value(options.issuer.privateKey)),\n\t\t\t\t\t\tfailure,\n\t\t\t\t\t),\n\t\t\t\t}\n\tconst signingKey =\n\t\tauthority === undefined\n\t\t\t? keys.privateKey\n\t\t\t: yield* Effect.tryPromise({\n\t\t\t\t\ttry: () =>\n\t\t\t\t\t\twebcrypto.subtle.importKey(\n\t\t\t\t\t\t\t\"pkcs8\",\n\t\t\t\t\t\t\tauthority.privateKey,\n\t\t\t\t\t\t\t{ name: \"ECDSA\", namedCurve: \"P-256\" },\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\t[\"sign\"],\n\t\t\t\t\t\t),\n\t\t\t\t\tcatch: failure,\n\t\t\t\t})\n\tconst certificate = yield* Effect.try({\n\t\ttry: () => {\n\t\t\tconst issuer =\n\t\t\t\tauthority === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: pki.Certificate.fromBER(authority.certificate)\n\t\t\tconst names = [\n\t\t\t\t...Array.map(options.hosts ?? [], hostName),\n\t\t\t\t...Array.map(\n\t\t\t\t\toptions.identities ?? [],\n\t\t\t\t\t(identity) =>\n\t\t\t\t\t\tnew pki.GeneralName({ type: 6, value: `graft://${identity}` }),\n\t\t\t\t),\n\t\t\t]\n\t\t\treturn new pki.Certificate({\n\t\t\t\tversion: 2,\n\t\t\t\t// A leading nonzero byte keeps the serial positive without losing random bits.\n\t\t\t\tserialNumber: new asn1js.Integer({\n\t\t\t\t\tvalueHex: new Uint8Array([1, ...serial]),\n\t\t\t\t}),\n\t\t\t\tsubject: subject(options.name),\n\t\t\t\tissuer: issuer?.subject ?? subject(options.name),\n\t\t\t\tnotBefore: new pki.Time({ value: DateTime.toDateUtc(now) }),\n\t\t\t\tnotAfter: new pki.Time({\n\t\t\t\t\tvalue: DateTime.toDateUtc(DateTime.add(now, { days: options.days })),\n\t\t\t\t}),\n\t\t\t\textensions: [\n\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\textnID: \"2.5.29.19\",\n\t\t\t\t\t\tcritical: true,\n\t\t\t\t\t\textnValue: new pki.BasicConstraints({ cA: options.usage === \"ca\" })\n\t\t\t\t\t\t\t.toSchema()\n\t\t\t\t\t\t\t.toBER(),\n\t\t\t\t\t}),\n\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\textnID: \"2.5.29.15\",\n\t\t\t\t\t\tcritical: true,\n\t\t\t\t\t\textnValue: new asn1js.BitString({\n\t\t\t\t\t\t\tvalueHex: new Uint8Array([options.usage === \"ca\" ? 0x06 : 0x80]),\n\t\t\t\t\t\t}).toBER(),\n\t\t\t\t\t}),\n\t\t\t\t\t...(options.usage === \"ca\"\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\t\t\t\textnID: \"2.5.29.37\",\n\t\t\t\t\t\t\t\t\textnValue: new pki.ExtKeyUsage({\n\t\t\t\t\t\t\t\t\t\tkeyPurposes: [\n\t\t\t\t\t\t\t\t\t\t\toptions.usage === \"server\"\n\t\t\t\t\t\t\t\t\t\t\t\t? \"1.3.6.1.5.5.7.3.1\"\n\t\t\t\t\t\t\t\t\t\t\t\t: \"1.3.6.1.5.5.7.3.2\",\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t.toSchema()\n\t\t\t\t\t\t\t\t\t\t.toBER(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t...(names.length === 0\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\t\t\t\textnID: \"2.5.29.17\",\n\t\t\t\t\t\t\t\t\textnValue: new pki.AltName({ altNames: names })\n\t\t\t\t\t\t\t\t\t\t.toSchema()\n\t\t\t\t\t\t\t\t\t\t.toBER(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t]),\n\t\t\t\t],\n\t\t\t})\n\t\t},\n\t\tcatch: failure,\n\t})\n\tyield* Effect.tryPromise({\n\t\ttry: () =>\n\t\t\tcertificate.subjectPublicKeyInfo.importKey(keys.publicKey, engine),\n\t\tcatch: failure,\n\t})\n\tyield* Effect.tryPromise({\n\t\ttry: () => certificate.sign(signingKey, \"SHA-256\", engine),\n\t\tcatch: failure,\n\t})\n\tconst privateKey = yield* Effect.tryPromise({\n\t\ttry: () => webcrypto.subtle.exportKey(\"pkcs8\", keys.privateKey),\n\t\tcatch: failure,\n\t})\n\treturn yield* Effect.try({\n\t\ttry: () => ({\n\t\t\tcertificate: pem(\"CERTIFICATE\", certificate.toSchema().toBER()),\n\t\t\tprivateKey: Redacted.make(pem(\"PRIVATE KEY\", privateKey)),\n\t\t}),\n\t\tcatch: failure,\n\t})\n})\n\nexport const read = Effect.fn(\"Certificates.read\")(function* (base: string) {\n\tconst fs = yield* FileSystem.FileSystem\n\tconst certificate = yield* fs.readFileString(base + \".crt\")\n\tconst privateKey = yield* fs.readFileString(base + \".key\")\n\treturn { certificate, privateKey: Redacted.make(privateKey) }\n})\nexport const write = Effect.fn(\"Certificates.write\")(function* (\n\tbase: string,\n\tpair: Pem,\n\tforce: boolean = false,\n) {\n\tconst fs = yield* FileSystem.FileSystem\n\tyield* fs\n\t\t.writeFileString(base + \".key\", Redacted.value(pair.privateKey), {\n\t\t\tflag: force ? \"w\" : \"wx\",\n\t\t\tmode: 0o600,\n\t\t})\n\t\t.pipe(Effect.uninterruptible)\n\t// Opening an existing file does not change its permissions when renewing it.\n\tyield* fs.chmod(base + \".key\", 0o600).pipe(Effect.uninterruptible)\n\tyield* fs\n\t\t.writeFileString(base + \".crt\", pair.certificate, {\n\t\t\tflag: force ? \"w\" : \"wx\",\n\t\t})\n\t\t.pipe(Effect.uninterruptible)\n})\n\nexport interface Options {\n\treadonly out: string\n\treadonly server: ReadonlyArray<string>\n\treadonly identity: ReadonlyArray<string>\n\treadonly days: number\n\treadonly force: boolean\n}\n/** URI-encode names so each identity has a distinct filename, including names with slashes. */\nexport const clientName = (identity: string) =>\n\t`client-${encodeURIComponent(identity)}`\nexport const generate = Effect.fn(\"Certificates.generate\")(function* (\n\toptions: Options,\n) {\n\tconst fs = yield* FileSystem.FileSystem\n\tconst path = yield* Path.Path\n\tconst outputs = [\n\t\t...(options.server.length === 0 ? [] : [\"server\"]),\n\t\t...Array.map(Array.dedupe(options.identity), clientName),\n\t]\n\tif (!options.force) {\n\t\tconst files = Array.flatMap(outputs, (name) =>\n\t\t\tArray.map([\".crt\", \".key\"], (extension) =>\n\t\t\t\tpath.join(options.out, name + extension),\n\t\t\t),\n\t\t)\n\t\tconst taken = yield* Effect.filter(files, fs.exists)\n\t\tif (Array.isReadonlyArrayNonEmpty(taken))\n\t\t\treturn yield* CertificateExists.make({ file: taken[0] })\n\t}\n\tyield* fs\n\t\t.makeDirectory(options.out, { recursive: true })\n\t\t.pipe(Effect.uninterruptible)\n\tconst ca = path.join(options.out, \"ca\")\n\tconst existing =\n\t\t(yield* fs.exists(ca + \".crt\")) || (yield* fs.exists(ca + \".key\"))\n\t// An incomplete CA pair fails on read. Even --force never replaces the signing authority.\n\tconst issuer = existing\n\t\t? yield* read(ca)\n\t\t: yield* issue({ name: \"Graft CA\", usage: \"ca\", days: options.days }).pipe(\n\t\t\t\tEffect.tap((pair) => write(ca, pair)),\n\t\t\t)\n\tif (options.server.length > 0) {\n\t\tconst pair = yield* issue({\n\t\t\tname: \"Graft runner\",\n\t\t\tusage: \"server\",\n\t\t\thosts: options.server,\n\t\t\tdays: options.days,\n\t\t\tissuer,\n\t\t})\n\t\tyield* write(path.join(options.out, \"server\"), pair, options.force)\n\t}\n\tyield* Effect.forEach(\n\t\tArray.dedupe(options.identity),\n\t\t(identity) =>\n\t\t\tissue({\n\t\t\t\tname: identity,\n\t\t\t\tusage: \"client\",\n\t\t\t\tidentities: [identity],\n\t\t\t\tdays: options.days,\n\t\t\t\tissuer,\n\t\t\t}).pipe(\n\t\t\t\tEffect.flatMap((pair) =>\n\t\t\t\t\twrite(\n\t\t\t\t\t\tpath.join(options.out, clientName(identity)),\n\t\t\t\t\t\tpair,\n\t\t\t\t\t\toptions.force,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t{ discard: true },\n\t)\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"Certificates.js","names":[],"sources":["../../src/internal/Certificates.ts"],"sourcesContent":["import {\n\tArray,\n\tDateTime,\n\tEffect,\n\tFileSystem,\n\tPath,\n\tRedacted,\n\tResult,\n\tSchema,\n\tString,\n} from \"effect\"\nimport { SecureRandom, WebCrypto } from \"effect/crypto\"\nimport { Base64 } from \"effect/encoding\"\nimport { NetAddress } from \"effect/net\"\nimport * as asn1js from \"asn1js\"\nimport * as pki from \"pkijs\"\n\nexport class CertificateError extends Schema.TaggedError<\n\tCertificateError,\n\t{ readonly brand: unique symbol }\n>()(\"CertificateError\", {\n\tdetail: Schema.String,\n\tcause: Schema.optional(Schema.Defect()),\n}) {\n\toverride get message() {\n\t\treturn this.detail\n\t}\n}\n\n/** A requested output already exists and replacing it was not asked for. */\nexport class CertificateExists extends Schema.TaggedError<\n\tCertificateExists,\n\t{ readonly brand: unique symbol }\n>()(\"CertificateExists\", { file: Schema.String }) {\n\toverride get message() {\n\t\treturn `${this.file} already exists; use --force to replace the requested certificates`\n\t}\n}\n\n/** Only PEM leaves this boundary; PKI.js objects stay local to each operation. */\nexport interface Pem {\n\treadonly certificate: string\n\treadonly privateKey: Redacted.Redacted<string>\n}\nexport interface IssueOptions {\n\treadonly name: string\n\treadonly days: number\n\treadonly usage: \"ca\" | \"server\" | \"client\"\n\treadonly hosts?: ReadonlyArray<string>\n\treadonly identities?: ReadonlyArray<string>\n\treadonly issuer?: Pem\n}\nconst pem = (label: string, bytes: ArrayBuffer) =>\n\t`-----BEGIN ${label}-----\\n${String.replace(/.{64}(?=.)/g, \"$&\\n\")(Base64.encode(new Uint8Array(bytes)))}\\n-----END ${label}-----\\n`\n// WebCrypto and PKI.js take ArrayBuffer-backed bytes, so the decoded view is copied into one.\nconst der = (value: string) =>\n\tEffect.fromResult(\n\t\tBase64.decode(String.replace(/-----[^-]+-----|\\s/g, \"\")(value)),\n\t).pipe(Effect.map((bytes) => new Uint8Array(bytes)))\nconst subject = (name: string) =>\n\tnew pki.RelativeDistinguishedNames({\n\t\ttypesAndValues: [\n\t\t\tnew pki.AttributeTypeAndValue({\n\t\t\t\ttype: \"2.5.4.3\",\n\t\t\t\tvalue: new asn1js.Utf8String({ value: name }),\n\t\t\t}),\n\t\t],\n\t})\nconst hostName = (host: string) =>\n\tResult.match(NetAddress.ipFromString(host), {\n\t\tonFailure: () => new pki.GeneralName({ type: 2, value: host }),\n\t\tonSuccess: (ip) =>\n\t\t\tnew pki.GeneralName({\n\t\t\t\ttype: 7,\n\t\t\t\tvalue: new asn1js.OctetString({\n\t\t\t\t\tvalueHex: new Uint8Array(\n\t\t\t\t\t\tip._tag === \"Ipv4Address\"\n\t\t\t\t\t\t\t? NetAddress.ipv4ToOctets(ip)\n\t\t\t\t\t\t\t: NetAddress.ipv6ToOctets(ip),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t}),\n\t})\n\nexport const issue = Effect.fn(\"Certificates.issue\")(function* (\n\toptions: IssueOptions,\n) {\n\tconst random = yield* SecureRandom.SecureRandom\n\tconst serial = yield* random.randomBytes(19)\n\tconst now = yield* DateTime.now\n\tconst webcrypto = yield* WebCrypto.WebCrypto\n\tconst engine = new pki.CryptoEngine({\n\t\tname: \"Node WebCrypto\",\n\t\tcrypto: webcrypto,\n\t})\n\tconst failure = (cause: unknown) =>\n\t\tCertificateError.make({\n\t\t\tdetail: `Could not issue the certificate for ${options.name}`,\n\t\t\tcause,\n\t\t})\n\tconst keys = yield* Effect.tryPromise({\n\t\ttry: () =>\n\t\t\twebcrypto.subtle.generateKey(\n\t\t\t\t{ name: \"ECDSA\", namedCurve: \"P-256\" },\n\t\t\t\ttrue,\n\t\t\t\t[\"sign\", \"verify\"],\n\t\t\t),\n\t\tcatch: failure,\n\t})\n\t// Reused CA keys have the same P-256 / PKCS#8 format as the ones this command creates.\n\tconst authority =\n\t\toptions.issuer === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tcertificate: yield* Effect.mapError(\n\t\t\t\t\t\tder(options.issuer.certificate),\n\t\t\t\t\t\tfailure,\n\t\t\t\t\t),\n\t\t\t\t\tprivateKey: yield* Effect.mapError(\n\t\t\t\t\t\tder(Redacted.value(options.issuer.privateKey)),\n\t\t\t\t\t\tfailure,\n\t\t\t\t\t),\n\t\t\t\t}\n\tconst signingKey =\n\t\tauthority === undefined\n\t\t\t? keys.privateKey\n\t\t\t: yield* Effect.tryPromise({\n\t\t\t\t\ttry: () =>\n\t\t\t\t\t\twebcrypto.subtle.importKey(\n\t\t\t\t\t\t\t\"pkcs8\",\n\t\t\t\t\t\t\tauthority.privateKey,\n\t\t\t\t\t\t\t{ name: \"ECDSA\", namedCurve: \"P-256\" },\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\t[\"sign\"],\n\t\t\t\t\t\t),\n\t\t\t\t\tcatch: failure,\n\t\t\t\t})\n\tconst certificate = yield* Effect.try({\n\t\ttry: () => {\n\t\t\tconst issuer =\n\t\t\t\tauthority === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: pki.Certificate.fromBER(authority.certificate)\n\t\t\tconst names = [\n\t\t\t\t...Array.map(options.hosts ?? [], hostName),\n\t\t\t\t...Array.map(\n\t\t\t\t\toptions.identities ?? [],\n\t\t\t\t\t(identity) =>\n\t\t\t\t\t\tnew pki.GeneralName({ type: 6, value: `graft://${identity}` }),\n\t\t\t\t),\n\t\t\t]\n\t\t\treturn new pki.Certificate({\n\t\t\t\tversion: 2,\n\t\t\t\t// A leading nonzero byte keeps the serial positive without losing random bits.\n\t\t\t\tserialNumber: new asn1js.Integer({\n\t\t\t\t\tvalueHex: new Uint8Array([1, ...serial]),\n\t\t\t\t}),\n\t\t\t\tsubject: subject(options.name),\n\t\t\t\tissuer: issuer?.subject ?? subject(options.name),\n\t\t\t\tnotBefore: new pki.Time({ value: DateTime.toDateUtc(now) }),\n\t\t\t\tnotAfter: new pki.Time({\n\t\t\t\t\tvalue: DateTime.toDateUtc(DateTime.add(now, { days: options.days })),\n\t\t\t\t}),\n\t\t\t\textensions: [\n\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\textnID: \"2.5.29.19\",\n\t\t\t\t\t\tcritical: true,\n\t\t\t\t\t\textnValue: new pki.BasicConstraints({ cA: options.usage === \"ca\" })\n\t\t\t\t\t\t\t.toSchema()\n\t\t\t\t\t\t\t.toBER(),\n\t\t\t\t\t}),\n\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\textnID: \"2.5.29.15\",\n\t\t\t\t\t\tcritical: true,\n\t\t\t\t\t\textnValue: new asn1js.BitString({\n\t\t\t\t\t\t\tvalueHex: new Uint8Array([options.usage === \"ca\" ? 0x06 : 0x80]),\n\t\t\t\t\t\t}).toBER(),\n\t\t\t\t\t}),\n\t\t\t\t\t...(options.usage === \"ca\"\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\t\t\t\textnID: \"2.5.29.37\",\n\t\t\t\t\t\t\t\t\textnValue: new pki.ExtKeyUsage({\n\t\t\t\t\t\t\t\t\t\tkeyPurposes: [\n\t\t\t\t\t\t\t\t\t\t\toptions.usage === \"server\"\n\t\t\t\t\t\t\t\t\t\t\t\t? \"1.3.6.1.5.5.7.3.1\"\n\t\t\t\t\t\t\t\t\t\t\t\t: \"1.3.6.1.5.5.7.3.2\",\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t.toSchema()\n\t\t\t\t\t\t\t\t\t\t.toBER(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t...(names.length === 0\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: [\n\t\t\t\t\t\t\t\tnew pki.Extension({\n\t\t\t\t\t\t\t\t\textnID: \"2.5.29.17\",\n\t\t\t\t\t\t\t\t\textnValue: new pki.AltName({ altNames: names })\n\t\t\t\t\t\t\t\t\t\t.toSchema()\n\t\t\t\t\t\t\t\t\t\t.toBER(),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t]),\n\t\t\t\t],\n\t\t\t})\n\t\t},\n\t\tcatch: failure,\n\t})\n\tyield* Effect.tryPromise({\n\t\ttry: () =>\n\t\t\tcertificate.subjectPublicKeyInfo.importKey(keys.publicKey, engine),\n\t\tcatch: failure,\n\t})\n\tyield* Effect.tryPromise({\n\t\ttry: () => certificate.sign(signingKey, \"SHA-256\", engine),\n\t\tcatch: failure,\n\t})\n\tconst privateKey = yield* Effect.tryPromise({\n\t\ttry: () => webcrypto.subtle.exportKey(\"pkcs8\", keys.privateKey),\n\t\tcatch: failure,\n\t})\n\treturn yield* Effect.try({\n\t\ttry: () => ({\n\t\t\tcertificate: pem(\"CERTIFICATE\", certificate.toSchema().toBER()),\n\t\t\tprivateKey: Redacted.make(pem(\"PRIVATE KEY\", privateKey)),\n\t\t}),\n\t\tcatch: failure,\n\t})\n})\n\nexport const read = Effect.fn(\"Certificates.read\")(function* (base: string) {\n\tconst fs = yield* FileSystem.FileSystem\n\tconst certificate = yield* fs.readFileString(base + \".crt\")\n\tconst privateKey = yield* fs.readFileString(base + \".key\")\n\treturn { certificate, privateKey: Redacted.make(privateKey) }\n})\nexport const write = Effect.fn(\"Certificates.write\")(function* (\n\tbase: string,\n\tpair: Pem,\n\tforce: boolean = false,\n) {\n\tconst fs = yield* FileSystem.FileSystem\n\tyield* fs.writeFileString(base + \".key\", Redacted.value(pair.privateKey), {\n\t\tflag: force ? \"w\" : \"wx\",\n\t\tmode: 0o600,\n\t})\n\t// Opening an existing file does not change its permissions when renewing it.\n\tyield* fs.chmod(base + \".key\", 0o600)\n\tyield* fs.writeFileString(base + \".crt\", pair.certificate, {\n\t\tflag: force ? \"w\" : \"wx\",\n\t})\n\t// One region for the pair: an interruption between the files would leave a key without its certificate.\n}, Effect.uninterruptible)\n\nexport interface Options {\n\treadonly out: string\n\treadonly server: ReadonlyArray<string>\n\treadonly identity: ReadonlyArray<string>\n\treadonly days: number\n\treadonly force: boolean\n}\n/** URI-encode names so each identity has a distinct filename, including names with slashes. */\nexport const clientName = (identity: string) =>\n\t`client-${encodeURIComponent(identity)}`\nexport const generate = Effect.fn(\"Certificates.generate\")(function* (\n\toptions: Options,\n) {\n\tconst fs = yield* FileSystem.FileSystem\n\tconst path = yield* Path.Path\n\tconst outputs = [\n\t\t...(options.server.length === 0 ? [] : [\"server\"]),\n\t\t...Array.map(Array.dedupe(options.identity), clientName),\n\t]\n\tif (!options.force) {\n\t\tconst files = Array.flatMap(outputs, (name) =>\n\t\t\tArray.map([\".crt\", \".key\"], (extension) =>\n\t\t\t\tpath.join(options.out, name + extension),\n\t\t\t),\n\t\t)\n\t\tconst taken = yield* Effect.filter(files, fs.exists)\n\t\tif (Array.isReadonlyArrayNonEmpty(taken))\n\t\t\treturn yield* CertificateExists.make({ file: taken[0] })\n\t}\n\tyield* fs\n\t\t.makeDirectory(options.out, { recursive: true })\n\t\t.pipe(Effect.uninterruptible)\n\tconst ca = path.join(options.out, \"ca\")\n\tconst existing =\n\t\t(yield* fs.exists(ca + \".crt\")) || (yield* fs.exists(ca + \".key\"))\n\t// An incomplete CA pair fails on read. Even --force never replaces the signing authority.\n\tconst issuer = existing\n\t\t? yield* read(ca)\n\t\t: yield* issue({ name: \"Graft CA\", usage: \"ca\", days: options.days }).pipe(\n\t\t\t\tEffect.tap((pair) => write(ca, pair)),\n\t\t\t)\n\tif (options.server.length > 0) {\n\t\tconst pair = yield* issue({\n\t\t\tname: \"Graft runner\",\n\t\t\tusage: \"server\",\n\t\t\thosts: options.server,\n\t\t\tdays: options.days,\n\t\t\tissuer,\n\t\t})\n\t\tyield* write(path.join(options.out, \"server\"), pair, options.force)\n\t}\n\tyield* Effect.forEach(\n\t\tArray.dedupe(options.identity),\n\t\t(identity) =>\n\t\t\tissue({\n\t\t\t\tname: identity,\n\t\t\t\tusage: \"client\",\n\t\t\t\tidentities: [identity],\n\t\t\t\tdays: options.days,\n\t\t\t\tissuer,\n\t\t\t}).pipe(\n\t\t\t\tEffect.flatMap((pair) =>\n\t\t\t\t\twrite(\n\t\t\t\t\t\tpath.join(options.out, clientName(identity)),\n\t\t\t\t\t\tpair,\n\t\t\t\t\t\toptions.force,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t{ discard: true },\n\t)\n})\n"],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { ReleaseInterrupted, close } from "./release.js";
2
+ import { cleanupCause } from "./cleanup.js";
2
3
  import { Array, Cause, Data, Deferred, Effect, Exit, Fiber, FiberSet, Ref, Schema, Scope, TxRef } from "effect";
3
4
  // src/internal/FailureGroup.ts
4
5
  const State = Data.taggedEnum();
5
6
  /** One owner for first failure, transaction wakeups, and interruption of sibling work. */
6
- const make = () => Effect.gen(function* () {
7
+ const make = Effect.fnUntraced(function* () {
7
8
  const fibers = yield* FiberSet.make();
8
9
  const state = yield* TxRef.make(State.Open());
9
10
  const failures = yield* Ref.make(Cause.empty);
@@ -37,7 +38,7 @@ const make = () => Effect.gen(function* () {
37
38
  const failure = Effect.tx(check.pipe(Effect.andThen(Effect.txRetry)));
38
39
  const failCause = (cause) => FiberSet.run(fibers, observe(Effect.failCause(cause))).pipe(Effect.asVoid);
39
40
  const close$1 = TxRef.update(state, (s) => s._tag === "Open" ? State.Closed() : s).pipe(Effect.andThen(FiberSet.clear(fibers)), Effect.andThen(Ref.get(cleanup)), Effect.flatMap((cause) => cause.reasons.length > 0 ? Effect.failCause(cause) : Effect.void), Effect.uninterruptible);
40
- yield* Effect.addFinalizer(() => close$1.pipe(Effect.orDie));
41
+ yield* Effect.addFinalizer(() => close$1.pipe(Effect.catchCause((cause) => Effect.failCause(cleanupCause(cause)))));
41
42
  return {
42
43
  await: failure,
43
44
  check,