@graftland/plugin-remote 0.3.0 → 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 (209) 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-MCwivGN1.js → Bootstrap-H9gDsgsC.js} +2 -2
  5. package/dist/{Contract-CcpSIJm4.js → Contract-DsJtisvL.js} +8 -46
  6. package/dist/Contract.d.ts +50 -53
  7. package/dist/Contract.d.ts.map +1 -1
  8. package/dist/Contract.js +1 -1
  9. package/dist/Contract.js.map +1 -1
  10. package/dist/{Errors-oPsTLY7l.js → Errors-DYhsGZcZ.js} +14 -1
  11. package/dist/Errors.d.ts +19 -0
  12. package/dist/Errors.d.ts.map +1 -1
  13. package/dist/Errors.js +14 -1
  14. package/dist/Errors.js.map +1 -1
  15. package/dist/{FailureGroup-BcH0XOBi.js → FailureGroup-BgT73AaR.js} +14 -4
  16. package/dist/{Framing-zaYdOJnT.js → Framing-G9eSaeLb.js} +1 -1
  17. package/dist/{Graft-BsYq3F-J.js → Graft-B71CPA2Y.js} +46 -35
  18. package/dist/{Packages-B1TPk8pa.js → Packages-AgoCGotL.js} +23 -26
  19. package/dist/{Peer-IJgFK6mD.js → Peer-DXeVrGBh.js} +5 -5
  20. package/dist/{ProcessObservation-DEGrEMfP.js → ProcessObservation-gLgGirYv.js} +1 -1
  21. package/dist/{ServeLifecycle-CJM0gG5B.js → ServeLifecycle-Bd1FPJ6e.js} +1 -1
  22. package/dist/Testing.d.ts +4 -4
  23. package/dist/Testing.d.ts.map +1 -1
  24. package/dist/Testing.js +10 -4
  25. package/dist/Testing.js.map +1 -1
  26. package/dist/Transport.d.ts +2 -2
  27. package/dist/Transport.d.ts.map +1 -1
  28. package/dist/Transport.js.map +1 -1
  29. package/dist/bin.js +48 -47
  30. package/dist/bin.js.map +1 -1
  31. package/dist/{childRuntime-DSqtFN9o.js → childRuntime-Bm3iSg_N.js} +30 -26
  32. package/dist/connectionEnded-BwcxQ7W8.js +54 -0
  33. package/dist/{entry-SYsx9VNb.js → entry-psOpX3Bj.js} +76 -48
  34. package/dist/host/auth/bearer.d.ts +1 -2
  35. package/dist/host/auth/bearer.d.ts.map +1 -1
  36. package/dist/host/auth/bearer.js +1 -1
  37. package/dist/host/auth/bearer.js.map +1 -1
  38. package/dist/host/auth/jwt.d.ts +1 -2
  39. package/dist/host/auth/jwt.d.ts.map +1 -1
  40. package/dist/host/auth/jwt.js +1 -1
  41. package/dist/host/auth/jwt.js.map +1 -1
  42. package/dist/host/auth/mtls.js +2 -2
  43. package/dist/host/auth/none.js +1 -1
  44. package/dist/host/command.d.ts +1 -1
  45. package/dist/host/command.d.ts.map +1 -1
  46. package/dist/host/command.js +4 -4
  47. package/dist/host/command.js.map +1 -1
  48. package/dist/host/local.d.ts +1 -2
  49. package/dist/host/local.d.ts.map +1 -1
  50. package/dist/host/local.js +3 -3
  51. package/dist/host/local.js.map +1 -1
  52. package/dist/host/unix.d.ts +1 -1
  53. package/dist/host/unix.d.ts.map +1 -1
  54. package/dist/host/unix.js +3 -3
  55. package/dist/host/unix.js.map +1 -1
  56. package/dist/host/websocket.d.ts +1 -1
  57. package/dist/host/websocket.d.ts.map +1 -1
  58. package/dist/host/websocket.js +3 -3
  59. package/dist/host/websocket.js.map +1 -1
  60. package/dist/host/worker.d.ts +1 -2
  61. package/dist/host/worker.d.ts.map +1 -1
  62. package/dist/host/worker.js +4 -5
  63. package/dist/host/worker.js.map +1 -1
  64. package/dist/{importer-D7zSgqxq.js → importer-Cvf88eAY.js} +5 -8
  65. package/dist/index.d.ts +2 -3
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +10 -10
  68. package/dist/index.js.map +1 -1
  69. package/dist/internal/Certificates.js +4 -4
  70. package/dist/internal/Certificates.js.map +1 -1
  71. package/dist/internal/FailureGroup.js +3 -2
  72. package/dist/internal/FailureGroup.js.map +1 -1
  73. package/dist/internal/assembly.js +9 -2
  74. package/dist/internal/assembly.js.map +1 -1
  75. package/dist/internal/auth/mtls.js +1 -1
  76. package/dist/internal/auth/mtls.js.map +1 -1
  77. package/dist/internal/auth/tokenCredentials.d.ts +0 -1
  78. package/dist/internal/auth/tokenCredentials.d.ts.map +1 -1
  79. package/dist/internal/auth/tokenCredentials.js.map +1 -1
  80. package/dist/internal/child.js +20 -17
  81. package/dist/internal/child.js.map +1 -1
  82. package/dist/internal/childRuntime.js +6 -4
  83. package/dist/internal/childRuntime.js.map +1 -1
  84. package/dist/internal/contract.js +26 -0
  85. package/dist/internal/contract.js.map +1 -0
  86. package/dist/internal/credentials.d.ts +6 -6
  87. package/dist/internal/credentials.d.ts.map +1 -1
  88. package/dist/internal/credentials.js.map +1 -1
  89. package/dist/internal/directTransport.d.ts +1 -1
  90. package/dist/internal/entry.d.ts +1 -2
  91. package/dist/internal/entry.d.ts.map +1 -1
  92. package/dist/internal/entry.js +4 -14
  93. package/dist/internal/entry.js.map +1 -1
  94. package/dist/internal/execution.js +44 -7
  95. package/dist/internal/execution.js.map +1 -1
  96. package/dist/internal/host/runner.js +7 -6
  97. package/dist/internal/host/runner.js.map +1 -1
  98. package/dist/internal/host.js +5 -5
  99. package/dist/internal/host.js.map +1 -1
  100. package/dist/internal/port.d.ts +2 -10
  101. package/dist/internal/port.js +5 -5
  102. package/dist/internal/port.js.map +1 -1
  103. package/dist/internal/release.js +1 -1
  104. package/dist/internal/release.js.map +1 -1
  105. package/dist/internal/runner/Connection.d.ts +1 -1
  106. package/dist/internal/runner/Connection.js +4 -4
  107. package/dist/internal/runner/Connection.js.map +1 -1
  108. package/dist/internal/runner/Execution.js +3 -3
  109. package/dist/internal/runner/Execution.js.map +1 -1
  110. package/dist/internal/runner/Framing.d.ts +1 -11
  111. package/dist/internal/runner/Framing.js +1 -1
  112. package/dist/internal/runner/Framing.js.map +1 -1
  113. package/dist/internal/runner/Local.js +1 -1
  114. package/dist/internal/runner/Local.js.map +1 -1
  115. package/dist/internal/runner/Lock.js +1 -1
  116. package/dist/internal/runner/Lock.js.map +1 -1
  117. package/dist/internal/runner/Packages.d.ts +1 -1
  118. package/dist/internal/runner/Packages.js +22 -25
  119. package/dist/internal/runner/Packages.js.map +1 -1
  120. package/dist/internal/runner/Processes.js +7 -9
  121. package/dist/internal/runner/Processes.js.map +1 -1
  122. package/dist/internal/runner/Store.js +3 -3
  123. package/dist/internal/runner/Store.js.map +1 -1
  124. package/dist/internal/runner/Supervisor.js +46 -47
  125. package/dist/internal/runner/Supervisor.js.map +1 -1
  126. package/dist/internal/runner/accept.js +3 -3
  127. package/dist/internal/runner/accept.js.map +1 -1
  128. package/dist/internal/runner/model.js +1 -1
  129. package/dist/internal/runner/model.js.map +1 -1
  130. package/dist/internal/serve.js +1 -1
  131. package/dist/internal/serve.js.map +1 -1
  132. package/dist/internal/services.d.ts +2 -12
  133. package/dist/internal/services.d.ts.map +1 -1
  134. package/dist/internal/services.js.map +1 -1
  135. package/dist/internal/supervisorPlugin.js +1 -1
  136. package/dist/internal/watchdogMain.js +5 -5
  137. package/dist/internal/watchdogMain.js.map +1 -1
  138. package/dist/internal/websocketServer.js +3 -1
  139. package/dist/internal/websocketServer.js.map +1 -1
  140. package/dist/internal/workerMain.js +3 -3
  141. package/dist/{port-Blbh8tms.js → port--3x2zJ4D.js} +8 -8
  142. package/dist/{release-BY4Mlluy.js → release-DfZPuIcK.js} +1 -1
  143. package/dist/runner/auth/bearer.js +2 -2
  144. package/dist/runner/auth/jwt.js +4 -4
  145. package/dist/runner/auth/jwt.js.map +1 -1
  146. package/dist/runner/auth/mtls.js +3 -3
  147. package/dist/runner/auth/none.js +1 -1
  148. package/dist/runner/index.js +5 -5
  149. package/dist/runner/stdio.js +3 -3
  150. package/dist/runner/unix.js +3 -3
  151. package/dist/runner/websocket.js +4 -4
  152. package/dist/{socketChannel-KmtzF-9G.js → socketChannel-CJvL2DiB.js} +2 -2
  153. package/dist/{supervisorPlugin-Inb1S5IV.js → supervisorPlugin-t6Z6PrhD.js} +72 -76
  154. package/dist/{token-v5ne2I0-.js → token-CYBNNlhS.js} +1 -1
  155. package/dist/{tokenCredentials-WUJm2AKm.js → tokenCredentials-CbCuk-Rt.js} +3 -3
  156. package/dist/{websocketServer-MXcCJx0v.js → websocketServer-NQhODlEt.js} +5 -3
  157. package/dist/{workerChannel-P82YdNjh.js → workerChannel-C8hhBJzA.js} +1 -1
  158. package/package.json +3 -3
  159. package/src/Auth.ts +9 -2
  160. package/src/Contract.ts +67 -51
  161. package/src/Errors.ts +23 -0
  162. package/src/Testing.ts +16 -2
  163. package/src/Transport.ts +6 -2
  164. package/src/bin.ts +28 -30
  165. package/src/host/auth/bearer.ts +1 -6
  166. package/src/host/auth/jwt.ts +1 -6
  167. package/src/host/command.ts +2 -0
  168. package/src/host/local.ts +5 -9
  169. package/src/host/unix.ts +2 -0
  170. package/src/host/websocket.ts +2 -0
  171. package/src/host/worker.ts +4 -6
  172. package/src/index.ts +8 -4
  173. package/src/internal/Certificates.ts +10 -13
  174. package/src/internal/FailureGroup.ts +128 -121
  175. package/src/internal/assembly.ts +19 -10
  176. package/src/internal/auth/mtls.ts +19 -20
  177. package/src/internal/auth/tokenCredentials.ts +1 -7
  178. package/src/internal/child.ts +249 -240
  179. package/src/internal/childRuntime.ts +84 -81
  180. package/src/internal/contract.ts +47 -0
  181. package/src/internal/credentials.ts +12 -9
  182. package/src/internal/entry.ts +11 -25
  183. package/src/internal/execution.ts +73 -14
  184. package/src/internal/host/runner.ts +153 -153
  185. package/src/internal/host.ts +123 -130
  186. package/src/internal/port.ts +100 -103
  187. package/src/internal/release.ts +3 -2
  188. package/src/internal/runner/Connection.ts +52 -60
  189. package/src/internal/runner/Execution.ts +163 -164
  190. package/src/internal/runner/Framing.ts +9 -10
  191. package/src/internal/runner/Local.ts +26 -27
  192. package/src/internal/runner/Lock.ts +23 -25
  193. package/src/internal/runner/Packages.ts +67 -70
  194. package/src/internal/runner/Processes.ts +89 -92
  195. package/src/internal/runner/Store.ts +110 -114
  196. package/src/internal/runner/Supervisor.ts +392 -405
  197. package/src/internal/runner/accept.ts +76 -84
  198. package/src/internal/runner/model.ts +20 -21
  199. package/src/internal/serve.ts +15 -13
  200. package/src/internal/services.ts +1 -19
  201. package/src/internal/watchdogMain.ts +16 -11
  202. package/src/internal/websocketServer.ts +18 -3
  203. package/src/runner/auth/jwt.ts +10 -6
  204. package/dist/cleanup-BPWr-5U9.js +0 -13
  205. package/dist/connectionEnded-DUgcobEd.js +0 -9
  206. package/dist/internal/childErrors.d.ts +0 -33
  207. package/dist/internal/childErrors.d.ts.map +0 -1
  208. package/dist/internal/port.d.ts.map +0 -1
  209. package/dist/internal/runner/Framing.d.ts.map +0 -1
@@ -1,11 +1,13 @@
1
- import { c as TransportError } from "./Errors-oPsTLY7l.js";
2
- import { a as payloadLimit, s as protocol, t as fromSocket } from "./socketChannel-KmtzF-9G.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 { c as TransportError } from "./Errors-oPsTLY7l.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.0",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "description": "Local and authenticated network execution for Graft plugins",
6
6
  "license": "Apache-2.0",
@@ -49,9 +49,9 @@
49
49
  "effect": "4.1.*"
50
50
  },
51
51
  "dependencies": {
52
- "@graftland/graft": "0.3.0",
52
+ "@graftland/graft": "0.3.2",
53
53
  "@effect/platform-node": "4.1.2",
54
- "@graftland/loader": "0.3.0",
54
+ "@graftland/loader": "0.3.2",
55
55
  "pkijs": "4.0.1",
56
56
  "asn1js": "4.0.0",
57
57
  "ws": "8.22.1"
package/src/Auth.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  /** Credentials and authenticated identities shared by transport plugins. */
2
2
  import { Context } from "effect"
3
3
  import type { Effect, Redacted, Option, Scope } from "effect"
4
- import type { 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/Contract.ts CHANGED
@@ -1,38 +1,79 @@
1
- import { ChildFailure } from "./internal/childErrors"
2
- export { ChildFailure }
3
- import { Array, Cause, Predicate, Schema } from "effect"
4
-
5
- import type { Service } from "./internal/services"
1
+ import { Array, Predicate, Schema } from "effect"
2
+ import type { Context, Effect, Scope } from "effect"
3
+ import type { Graft } from "@graftland/graft"
4
+ import type { Rpc, RpcClient, RpcGroup, RpcServer } from "effect/rpc"
6
5
  import * as Control from "./internal/control"
7
6
  export { service } from "./internal/services"
8
7
 
9
8
  const TypeId = "~@graftland/plugin-remote/Contract"
10
9
 
11
- /** An undeclared failure still crosses the boundary, with its diagnostic value. */
12
- export class UndeclaredFailure extends Schema.TaggedError<
13
- UndeclaredFailure,
14
- { readonly brand: unique symbol }
15
- >()("UndeclaredFailure", { original: Schema.Defect({ includeStack: true }) }) {}
10
+ /** RPC types stay inside the descriptor; Graft supplies its dynamic activation context. */
11
+ export interface Service<R = never, ClientR = never> {
12
+ readonly key: Context.Key<unknown, unknown>
13
+ readonly group: Pick<RpcGroup.RpcGroup<Rpc.Any>, "requests">
14
+ readonly serve: (port: {
15
+ readonly serverProtocol: (endpoint: string) => RpcServer.Protocol["Service"]
16
+ }) => Effect.Effect<never, never, R>
17
+ readonly publish: (port: {
18
+ readonly clientProtocol: (endpoint: string) => RpcClient.Protocol["Service"]
19
+ }) => Effect.Effect<
20
+ void,
21
+ Graft.ServiceConflict,
22
+ Graft.Graft | Scope.Scope | ClientR
23
+ >
24
+ }
16
25
 
17
- /** Pure metadata shared by the host and the executable runner bootstrap. */
18
- export const make = <
19
- S extends Schema.Top & {
20
- readonly Encoded: Schema.Json
21
- readonly DecodingServices: never
22
- readonly EncodingServices: never
23
- },
24
- E extends Schema.Top & {
25
- readonly DecodingServices: never
26
- readonly EncodingServices: never
27
- },
28
- >(options: {
26
+ /** A self-contained configuration schema that encodes as JSON. */
27
+ export type ConfigSchema = Schema.Top & {
28
+ readonly Encoded: Schema.Json
29
+ readonly DecodingServices: never
30
+ readonly EncodingServices: never
31
+ }
32
+ /** A self-contained schema for declared failures. */
33
+ export type ErrorSchema = Schema.Top & {
34
+ readonly DecodingServices: never
35
+ readonly EncodingServices: never
36
+ }
37
+
38
+ /** The shared configuration and service declarations for one remote plugin. */
39
+ export interface Contract<
40
+ S extends ConfigSchema,
41
+ E extends ErrorSchema = typeof Schema.Never,
42
+ > {
29
43
  readonly name: string
30
44
  readonly config: S
31
45
  readonly error: E
32
46
  readonly module: string
47
+ readonly inject: ReadonlyArray<Service>
48
+ readonly provides: ReadonlyArray<Service>
49
+ readonly [TypeId]: typeof TypeId
50
+ }
51
+ /** Configuration accepted by make; omitted errors default to Never. */
52
+ export interface Options<S extends ConfigSchema, E extends ErrorSchema> {
53
+ readonly name: string
54
+ readonly config: S
55
+ readonly error?: E
56
+ readonly module: string
33
57
  readonly inject?: ReadonlyArray<Service>
34
58
  readonly provides?: ReadonlyArray<Service>
35
- }) => {
59
+ }
60
+
61
+ /** An undeclared failure still crosses the boundary, with its diagnostic value. */
62
+ export class UndeclaredFailure extends Schema.TaggedError<
63
+ UndeclaredFailure,
64
+ { readonly brand: unique symbol }
65
+ >()("UndeclaredFailure", { original: Schema.Defect({ includeStack: true }) }) {}
66
+
67
+ /** Pure metadata shared by the host and the executable runner bootstrap. */
68
+ export function make<S extends ConfigSchema, E extends ErrorSchema>(
69
+ options: Options<S, E> & { readonly error: E },
70
+ ): Contract<S, E>
71
+ export function make<S extends ConfigSchema>(
72
+ options: Options<S, typeof Schema.Never>,
73
+ ): Contract<S>
74
+ export function make<S extends ConfigSchema, E extends ErrorSchema>(
75
+ options: Options<S, E>,
76
+ ): Contract<S, E | typeof Schema.Never> {
36
77
  // Keys are runtime strings; tuple types cannot distinguish independently created keys.
37
78
  const keys = Array.map(
38
79
  [...(options.inject ?? []), ...(options.provides ?? [])],
@@ -45,42 +86,17 @@ export const make = <
45
86
  throw new Error(
46
87
  "Service keys must be unique within a remote contract and must not use the control endpoint",
47
88
  )
48
- const failure = Schema.Union([options.error, UndeclaredFailure, ChildFailure])
49
- const codec = Schema.toCodecJson(
50
- Schema.Cause(failure, Schema.Defect({ includeStack: true })),
51
- )
52
- const declared = Schema.is(failure)
53
- const normalizeCause = (cause: Cause.Cause<unknown>) =>
54
- Cause.map(cause, (error) =>
55
- declared(error) ? error : UndeclaredFailure.make({ original: error }),
56
- )
89
+
57
90
  return {
58
91
  ...options,
59
- control: Control.make(codec),
60
- normalizeCause,
92
+ error: options.error ?? Schema.Never,
61
93
  inject: options.inject ?? [],
62
94
  provides: options.provides ?? [],
63
95
  [TypeId]: TypeId,
64
- encodeCause: (cause: Cause.Cause<unknown>) =>
65
- normalizeCause(cause).pipe(Schema.encodeEffect(codec)),
66
- decodeCause: Schema.decodeUnknownEffect(codec),
67
96
  }
68
97
  }
69
98
 
70
- /** The shared config, error codecs, and service declarations for one remote plugin. */
71
- export type Contract<
72
- S extends Schema.Top & {
73
- readonly Encoded: Schema.Json
74
- readonly DecodingServices: never
75
- readonly EncodingServices: never
76
- },
77
- E extends Schema.Top & {
78
- readonly DecodingServices: never
79
- readonly EncodingServices: never
80
- },
81
- > = ReturnType<typeof make<S, E>>
82
-
83
- /** Dynamic imports retain the control server and cause normalization; hosts retain the declared error type. */
99
+ /** A contract whose schemas are discovered through a dynamic import. */
84
100
  export type RunnerContract = Contract<
85
101
  Schema.Codec<unknown, Schema.Json>,
86
102
  Schema.Codec<unknown>
package/src/Errors.ts CHANGED
@@ -80,3 +80,26 @@ export class AuthenticationFailed extends Schema.TaggedError<
80
80
  challenge: Schema.optionalKey(Schema.String),
81
81
  cause: Schema.optionalKey(Schema.Cause(Schema.Unknown, Schema.Unknown)),
82
82
  }) {}
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
+
92
+ /** A remote entry could not be resolved or configured at the indicated field. */
93
+ export class RemoteEntryError extends Schema.TaggedError<
94
+ RemoteEntryError,
95
+ { readonly brand: unique symbol }
96
+ >()("RemoteEntryError", {
97
+ entry: Schema.Option(Schema.String),
98
+ directory: Schema.Option(Schema.String),
99
+ field: Schema.String,
100
+ cause: Schema.Cause(Schema.Unknown, Schema.Unknown),
101
+ }) {
102
+ override get message() {
103
+ return `Remote entry ${Option.getOrElse(this.entry, () => "<programmatic>")} failed at ${this.field}`
104
+ }
105
+ }
package/src/Testing.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Plugin } from "@graftland/graft"
2
2
  import {
3
3
  Array,
4
+ Cause,
4
5
  Equivalence,
5
6
  Deferred,
6
7
  Effect,
@@ -9,13 +10,17 @@ import {
9
10
  String,
10
11
  Schema,
11
12
  } from "effect"
13
+ import type { TransportError } from "./Errors"
12
14
  import type { Channel } from "./Transport"
13
15
  import * as Framing from "./internal/runner/Framing"
14
16
 
15
17
  export class ConformanceError extends Schema.TaggedError<
16
18
  ConformanceError,
17
19
  { readonly brand: unique symbol }
18
- >()("ConformanceError", { message: Schema.String }) {}
20
+ >()("ConformanceError", {
21
+ message: Schema.String,
22
+ cause: Schema.optionalKey(Schema.Cause(Schema.Unknown, Schema.Unknown)),
23
+ }) {}
19
24
  const check = (condition: boolean, message: string) =>
20
25
  condition ? Effect.void : Effect.fail(ConformanceError.make({ message }))
21
26
  export interface Capabilities {
@@ -88,7 +93,16 @@ export const transport = <E, R>(
88
93
  ),
89
94
  "The channel changed byte order across split or coalesced chunks",
90
95
  )
91
- }),
96
+ }).pipe(
97
+ Effect.mapError((error): E | ConformanceError | TransportError =>
98
+ Schema.is(Framing.FrameError)(error)
99
+ ? ConformanceError.make({
100
+ message: error.message,
101
+ cause: Cause.fail(error),
102
+ })
103
+ : error,
104
+ ),
105
+ ),
92
106
  eof: Effect.gen(function* () {
93
107
  const channel = yield* connect
94
108
  yield* Stream.empty.pipe(Stream.run(channel.output))
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(
@@ -1,10 +1,5 @@
1
- import type { Graft, Plugin } from "@graftland/graft"
2
1
  import { Config, plugin } from "../../internal/auth/tokenCredentials"
3
2
  export { Config }
4
3
 
5
- const capability: Plugin.Plugin<
6
- typeof Config.Type,
7
- typeof Config.Encoded,
8
- Graft.ServiceConflict
9
- > = plugin("remote-bearer-credentials")
4
+ const capability = plugin("remote-bearer-credentials")
10
5
  export default capability
@@ -1,10 +1,5 @@
1
- import type { Graft, Plugin } from "@graftland/graft"
2
1
  import { Config, plugin } from "../../internal/auth/tokenCredentials"
3
2
  export { Config }
4
3
 
5
- const capability: Plugin.Plugin<
6
- typeof Config.Type,
7
- typeof Config.Encoded,
8
- Graft.ServiceConflict
9
- > = plugin("remote-jwt-credentials")
4
+ const capability = plugin("remote-jwt-credentials")
10
5
  export default capability
@@ -1,3 +1,5 @@
1
+ /** Options for the command connector. */
2
+ export type { CommandOptions as Options } from "../internal/transportOptions"
1
3
  import type { CommandOptions } from "../internal/transportOptions"
2
4
  import { Plugin, Graft } from "@graftland/graft"
3
5
  import {
package/src/host/local.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Plugin, type Graft } from "@graftland/graft"
1
+ import { Plugin } from "@graftland/graft"
2
2
  import { Array, Effect, Scope } from "effect"
3
3
  import { ChildProcess, ChildProcessSpawner } from "effect/process"
4
4
  import { LocalTransport } from "../internal/directTransport"
@@ -29,13 +29,9 @@ const make = Effect.map(ChildProcessSpawner.ChildProcessSpawner, (spawner) =>
29
29
  }),
30
30
  }),
31
31
  )
32
- const plugin: Plugin.Plugin<void, void, Graft.ServiceConflict> = Plugin.service(
33
- LocalTransport,
34
- make,
35
- {
36
- name: "remote-local-transport",
37
- inject: [ChildProcessSpawner.ChildProcessSpawner],
38
- },
39
- )
32
+ const plugin = Plugin.service(LocalTransport, make, {
33
+ name: "remote-local-transport",
34
+ inject: [ChildProcessSpawner.ChildProcessSpawner],
35
+ })
40
36
 
41
37
  export default plugin
package/src/host/unix.ts CHANGED
@@ -1,3 +1,5 @@
1
+ /** Options for the unix connector. */
2
+ export type { UnixOptions as Options } from "../internal/transportOptions"
1
3
  import type { UnixOptions } from "../internal/transportOptions"
2
4
  import { Plugin, Graft } from "@graftland/graft"
3
5
  import { ConfigDirectory } from "@graftland/loader"
@@ -1,3 +1,5 @@
1
+ /** Options for the websocket connector. */
2
+ export type { WebsocketOptions as Options } from "../internal/transportOptions"
1
3
  import type { WebsocketOptions } from "../internal/transportOptions"
2
4
  import { Plugin, Graft } from "@graftland/graft"
3
5
  import { Cause, Effect, FileSystem, Option, Path, Schema } from "effect"
@@ -1,4 +1,4 @@
1
- import { Plugin, type Graft } from "@graftland/graft"
1
+ import { Plugin } from "@graftland/graft"
2
2
  import { Cause, Deferred, Effect, FiberSet, Option, Schema } from "effect"
3
3
  import { Worker } from "node:worker_threads"
4
4
  import { WorkerTransport } from "../internal/directTransport"
@@ -82,9 +82,7 @@ const start: typeof WorkerTransport.Service.start = Effect.fnUntraced(
82
82
  }
83
83
  },
84
84
  )
85
- const plugin: Plugin.Plugin<void, void, Graft.ServiceConflict> = Plugin.service(
86
- WorkerTransport,
87
- Effect.succeed({ start }),
88
- { name: "remote-thread-transport" },
89
- )
85
+ const plugin = Plugin.service(WorkerTransport, Effect.succeed({ start }), {
86
+ name: "remote-thread-transport",
87
+ })
90
88
  export default plugin
package/src/index.ts CHANGED
@@ -16,9 +16,11 @@ export { Contract }
16
16
  export { Instance } from "./Instance"
17
17
  export { RemoteTerminationUnconfirmed } from "./internal/runner/model"
18
18
  export { RemoteError, RemoteWithdrawn, MissingInstance } from "./Errors"
19
- export { UndeclaredFailure, ChildFailure } from "./Contract"
19
+ export { UndeclaredFailure } from "./Contract"
20
20
  export type {
21
21
  Connect,
22
+ Authentication,
23
+ Token as CredentialToken,
22
24
  Source as CredentialSource,
23
25
  } from "./internal/credentials"
24
26
 
@@ -90,8 +92,8 @@ export const plugin = <
90
92
  ChildProcessSpawner.ChildProcessSpawner,
91
93
  ],
92
94
  retry: options.retry,
93
- apply: () =>
94
- Effect.gen(function* () {
95
+ apply: Effect.fnUntraced(
96
+ function* () {
95
97
  const input = yield* Schema.decodeUnknownEffect(Configuration.Host)({
96
98
  contract: options.contractModule,
97
99
  connect: options.connect,
@@ -110,6 +112,8 @@ export const plugin = <
110
112
  yield* follow(child, (cause) =>
111
113
  Effect.failCause(publicCause(contract.error, cause)),
112
114
  )
113
- }).pipe(Effect.mapError((error) => publicError(contract.error, error))),
115
+ },
116
+ Effect.mapError((error) => publicError(contract.error, error)),
117
+ ),
114
118
  })
115
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