@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
@@ -10,94 +10,86 @@ import * as Multiplex from "./Multiplex"
10
10
  import * as Wire from "./Wire"
11
11
  import { SessionAccessDenied, SessionConflict, type Handle } from "./model"
12
12
 
13
- export const accept = (
13
+ export const accept = Effect.fnUntraced(function* (
14
14
  supervisor: typeof Supervisor.Service,
15
15
  execution: typeof Channels.Service,
16
16
  channel: Channel,
17
- ) =>
18
- Effect.gen(function* () {
19
- const identity = yield* Peer
20
- const scope = yield* Effect.scope
21
- const mux = yield* Multiplex.make(channel)
22
- const peer = yield* Port.make(Wire.channel(mux, 0), {
23
- session: "session-v1",
24
- serve: { session: Wire.Session },
25
- call: {},
26
- })
27
- const attached = yield* Ref.make(Option.none<string>())
28
- const loading = yield* Semaphore.make(1)
29
- const authorize = (handle: Handle) =>
30
- handle.key.identity === identity
31
- ? Effect.void
32
- : Effect.fail(
33
- SessionAccessDenied.make({
34
- detail: "The session belongs to another authenticated identity",
35
- }),
36
- )
37
- const handlers = yield* Wire.Session.toHandlers({
38
- HighWater: ({ instance }) => supervisor.highWater({ identity, instance }),
39
- Open: ({
40
- instance,
17
+ ) {
18
+ const identity = yield* Peer
19
+ const scope = yield* Effect.scope
20
+ const mux = yield* Multiplex.make(channel)
21
+ const peer = yield* Port.make(Wire.channel(mux, 0), {
22
+ session: "session-v1",
23
+ serve: { session: Wire.Session },
24
+ call: {},
25
+ })
26
+ const attached = yield* Ref.make(Option.none<string>())
27
+ const loading = yield* Semaphore.make(1)
28
+ const authorize = (handle: Handle) =>
29
+ handle.key.identity === identity
30
+ ? Effect.void
31
+ : Effect.fail(
32
+ SessionAccessDenied.make({
33
+ detail: "The session belongs to another authenticated identity",
34
+ }),
35
+ )
36
+ const handlers = yield* Wire.Session.toHandlers({
37
+ HighWater: ({ instance }) => supervisor.highWater({ identity, instance }),
38
+ Open: ({ instance, requestId, expectedGeneration, leaseMillis, limits }) =>
39
+ supervisor.open({
40
+ key: { identity, instance },
41
41
  requestId,
42
42
  expectedGeneration,
43
- leaseMillis,
43
+ ...(leaseMillis === undefined ? {} : { lease: leaseMillis }),
44
44
  limits,
45
- }) =>
46
- supervisor.open({
47
- key: { identity, instance },
48
- requestId,
49
- expectedGeneration,
50
- ...(leaseMillis === undefined ? {} : { lease: leaseMillis }),
51
- limits,
52
- }),
53
- Load: ({ handle, ...request }) =>
54
- Effect.gen(function* () {
55
- yield* authorize(handle)
56
- const attachment = yield* Ref.get(attached)
57
- if (Option.isSome(attachment) && attachment.value !== handle.token)
58
- return yield* SessionConflict.make({
59
- detail: "A connection can attach only one execution",
60
- })
61
- const code = yield* supervisor.load(handle, request)
62
- if (Option.isNone(attachment)) {
63
- const child = yield* execution
64
- .peer(handle.token)
65
- .pipe(Scope.provide(scope))
66
- yield* Ref.set(attached, Option.some(handle.token))
67
- // A child EOF must not destroy the session channel before Dispose can acknowledge exit.
68
- yield* Effect.all(
69
- [
70
- Effect.forever(
71
- Effect.flatMap(mux.take(1), (bytes) => child.send(1, bytes)),
72
- ),
73
- Effect.forever(
74
- Effect.flatMap(child.take(1), (bytes) => mux.send(1, bytes)),
75
- ),
76
- ],
77
- { concurrency: "unbounded" },
78
- ).pipe(
79
- Effect.catchCause((cause) =>
80
- Cause.hasInterruptsOnly(cause)
81
- ? Effect.void
82
- : child.fail(TransportError.make({ cause })),
83
- ),
84
- Effect.forkIn(scope),
85
- )
86
- }
87
- return code
88
- }).pipe(loading.withPermit),
89
- Renew: (handle) =>
90
- authorize(handle).pipe(Effect.andThen(supervisor.renew(handle))),
91
- Dispose: (handle) =>
92
- authorize(handle).pipe(Effect.andThen(supervisor.dispose(handle))),
93
- Status: (handle) =>
94
- authorize(handle).pipe(Effect.andThen(supervisor.status(handle))),
95
- })
96
- return yield* RpcServer.make(Wire.Session, {
97
- disableFatalDefects: true,
98
- }).pipe(
99
- Effect.provideContext(handlers),
100
- Effect.provideService(RpcServer.Protocol, peer.serverProtocol("session")),
101
- Effect.raceFirst(mux.await),
102
- )
45
+ }),
46
+ Load: Effect.fnUntraced(function* ({ handle, ...request }) {
47
+ yield* authorize(handle)
48
+ const attachment = yield* Ref.get(attached)
49
+ if (Option.isSome(attachment) && attachment.value !== handle.token)
50
+ return yield* SessionConflict.make({
51
+ detail: "A connection can attach only one execution",
52
+ })
53
+ const code = yield* supervisor.load(handle, request)
54
+ if (Option.isNone(attachment)) {
55
+ const child = yield* execution
56
+ .peer(handle.token)
57
+ .pipe(Scope.provide(scope))
58
+ yield* Ref.set(attached, Option.some(handle.token))
59
+ // A child EOF must not destroy the session channel before Dispose can acknowledge exit.
60
+ yield* Effect.all(
61
+ [
62
+ Effect.forever(
63
+ Effect.flatMap(mux.take(1), (bytes) => child.send(1, bytes)),
64
+ ),
65
+ Effect.forever(
66
+ Effect.flatMap(child.take(1), (bytes) => mux.send(1, bytes)),
67
+ ),
68
+ ],
69
+ { concurrency: "unbounded" },
70
+ ).pipe(
71
+ Effect.catchCause((cause) =>
72
+ Cause.hasInterruptsOnly(cause)
73
+ ? Effect.void
74
+ : child.fail(TransportError.make({ cause })),
75
+ ),
76
+ Effect.forkIn(scope),
77
+ )
78
+ }
79
+ return code
80
+ }, loading.withPermit),
81
+ Renew: (handle) =>
82
+ authorize(handle).pipe(Effect.andThen(supervisor.renew(handle))),
83
+ Dispose: (handle) =>
84
+ authorize(handle).pipe(Effect.andThen(supervisor.dispose(handle))),
85
+ Status: (handle) =>
86
+ authorize(handle).pipe(Effect.andThen(supervisor.status(handle))),
103
87
  })
88
+ return yield* RpcServer.make(Wire.Session, {
89
+ disableFatalDefects: true,
90
+ }).pipe(
91
+ Effect.provideContext(handlers),
92
+ Effect.provideService(RpcServer.Protocol, peer.serverProtocol("session")),
93
+ Effect.raceFirst(mux.await),
94
+ )
95
+ })
@@ -337,28 +337,27 @@ export class RemoteTerminationUnconfirmed extends Schema.TaggedError<
337
337
  { readonly brand: unique symbol }
338
338
  >()("RemoteTerminationUnconfirmed", { handle: Handle }) {}
339
339
  /** Losing contact never becomes a successful stop merely because a lease duration passed. */
340
- export const awaitTermination = <E, R>(
340
+ export const awaitTermination = Effect.fnUntraced(function* <E, R>(
341
341
  handle: Handle,
342
342
  confirmation: Effect.Effect<Termination, E, R>,
343
343
  leaseMillis: number,
344
344
  marginMillis: number,
345
- ) =>
346
- Effect.gen(function* () {
347
- const [elapsed, result] = yield* Effect.exit(
348
- Effect.timeoutOption(confirmation, leaseMillis + marginMillis),
349
- ).pipe(Effect.timed)
350
- if (result._tag === "Success") {
351
- if (Option.isSome(result.value)) return result.value.value
352
- return yield* RemoteTerminationUnconfirmed.make({ handle })
353
- }
354
- // Confirmation and the disconnected wait share one deadline.
355
- yield* Effect.sleep(
356
- Math.max(0, leaseMillis + marginMillis - Duration.toMillis(elapsed)),
357
- )
358
- return yield* Effect.failCause(
359
- Cause.combine(
360
- result.cause,
361
- Cause.fail(RemoteTerminationUnconfirmed.make({ handle })),
362
- ),
363
- )
364
- })
345
+ ) {
346
+ const [elapsed, result] = yield* Effect.exit(
347
+ Effect.timeoutOption(confirmation, leaseMillis + marginMillis),
348
+ ).pipe(Effect.timed)
349
+ if (result._tag === "Success") {
350
+ if (Option.isSome(result.value)) return result.value.value
351
+ return yield* RemoteTerminationUnconfirmed.make({ handle })
352
+ }
353
+ // Confirmation and the disconnected wait share one deadline.
354
+ yield* Effect.sleep(
355
+ Math.max(0, leaseMillis + marginMillis - Duration.toMillis(elapsed)),
356
+ )
357
+ return yield* Effect.failCause(
358
+ Cause.combine(
359
+ result.cause,
360
+ Cause.fail(RemoteTerminationUnconfirmed.make({ handle })),
361
+ ),
362
+ )
363
+ })
@@ -69,19 +69,21 @@ const ready = Plugin.make({
69
69
  })
70
70
 
71
71
  /** Loader logs child cleanup errors; the supervisor's release signal also reaches the command exit. */
72
- const close = (entries: Fork.Fork, lifecycle: typeof ServeLifecycle.Service) =>
73
- Effect.gen(function* () {
74
- const disposed = yield* Effect.exit(entries.dispose)
75
- const released = yield* Effect.exit(Deferred.await(lifecycle.released))
76
- const cause = Array.reduce(
77
- [disposed, released],
78
- Cause.empty,
79
- (cause: Cause.Cause<unknown>, exit: Exit.Exit<void, unknown>) =>
80
- Exit.isFailure(exit) ? Cause.combine(cause, exit.cause) : cause,
81
- )
82
- if (cause.reasons.length > 0)
83
- return yield* Effect.failCause(cleanupCause(cause))
84
- })
72
+ const close = Effect.fnUntraced(function* (
73
+ entries: Fork.Fork,
74
+ lifecycle: typeof ServeLifecycle.Service,
75
+ ) {
76
+ const disposed = yield* Effect.exit(entries.dispose)
77
+ const released = yield* Effect.exit(Deferred.await(lifecycle.released))
78
+ const cause = Array.reduce(
79
+ [disposed, released],
80
+ Cause.empty,
81
+ (cause: Cause.Cause<unknown>, exit: Exit.Exit<void, unknown>) =>
82
+ Exit.isFailure(exit) ? Cause.combine(cause, exit.cause) : cause,
83
+ )
84
+ if (cause.reasons.length > 0)
85
+ return yield* Effect.failCause(cleanupCause(cause))
86
+ })
85
87
 
86
88
  const load = Effect.fnUntraced(function* (config: string, directory: string) {
87
89
  const lifecycle = yield* make
@@ -1,27 +1,9 @@
1
1
  import { Array, Context, Effect, Record } from "effect"
2
2
  import { Graft } from "@graftland/graft"
3
3
  import { RpcClient, RpcServer } from "effect/rpc"
4
- import type { Scope } from "effect"
5
4
  import type { Rpc, RpcClientError, RpcGroup } from "effect/rpc"
6
- import type * as Port from "./port"
5
+ import type { Service } from "../Contract"
7
6
 
8
- type Peer = Port.Port
9
-
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: (
15
- port: Pick<Peer, "serverProtocol">,
16
- ) => Effect.Effect<never, never, R>
17
- readonly publish: (
18
- port: Pick<Peer, "clientProtocol">,
19
- ) => Effect.Effect<
20
- void,
21
- Graft.ServiceConflict,
22
- Graft.Graft | Scope.Scope | ClientR
23
- >
24
- }
25
7
  export const service = <
26
8
  I,
27
9
  S,
@@ -1,6 +1,6 @@
1
1
  /** Executable worker: fd 4 and the lease timer remain independent of the plugin thread. */
2
2
  import { NodeRuntime, NodeStream } from "@effect/platform-node"
3
- import { Effect, FiberHandle, Ref, Schema, Stream } from "effect"
3
+ import { Clock, Effect, FiberHandle, Ref, Schema, Stream } from "effect"
4
4
  import { Socket } from "node:net"
5
5
  import { parentPort } from "node:worker_threads"
6
6
  import process from "node:process"
@@ -17,14 +17,19 @@ const notify = (notice: typeof Notice.Type) =>
17
17
  Effect.sync(() => parentPort?.postMessage(message)),
18
18
  ),
19
19
  )
20
- const now = Effect.sync(() => performance.now())
21
- const expire = (deadline: number): Effect.Effect<never> =>
22
- Effect.gen(function* () {
23
- const remaining = deadline - (yield* now)
24
- if (remaining <= 0) return yield* die
25
- yield* Effect.sleep(Math.min(remaining, 2147483647))
26
- return yield* expire(deadline)
27
- })
20
+ // Milliseconds on the monotonic clock, which the lease sleep also uses.
21
+ const now = Clock.monotonicTimeNanos.pipe(
22
+ Effect.map((nanos) => Number(nanos) / 1_000_000),
23
+ )
24
+ const expire = Effect.fnUntraced(function* (
25
+ deadline: number,
26
+ ): Effect.fn.Return<never> {
27
+ const remaining = deadline - (yield* now)
28
+ if (remaining <= 0) return yield* die
29
+ // The clock splits sleeps longer than the platform timer limit.
30
+ yield* Effect.sleep(remaining)
31
+ return yield* expire(deadline)
32
+ })
28
33
  const main = Effect.scoped(
29
34
  Effect.gen(function* () {
30
35
  const lease = yield* Ref.make({
@@ -45,8 +50,8 @@ const main = Effect.scoped(
45
50
  Stream.decodeText(),
46
51
  Stream.splitLines,
47
52
  Stream.mapEffect((line) => Schema.decodeEffect(CommandJson)(line)),
48
- Stream.runForEach((command) =>
49
- Effect.gen(function* () {
53
+ Stream.runForEach(
54
+ Effect.fnUntraced(function* (command: typeof CommandJson.Type) {
50
55
  if (command.kind === "start") return yield* notify("start")
51
56
  if (command.kind === "stop") {
52
57
  yield* Ref.update(lease, (state) => ({ ...state, stopped: true }))
@@ -12,12 +12,27 @@ import {
12
12
  import { HttpServerRequest, HttpServerResponse } from "effect/http"
13
13
  import type { Socket } from "effect/socket"
14
14
  import { TLSSocket } from "node:tls"
15
- import { AuthenticationFailed, TransportError } from "../Errors"
15
+ import {
16
+ type AuthenticationFailed,
17
+ type AuthenticatorUnavailable,
18
+ TransportError,
19
+ } from "../Errors"
16
20
  import type { Accept, Handshake, Serving } from "../Transport"
17
21
  import * as Channel from "./socketChannel"
18
22
  import { path, protocol, payloadLimit } from "./websocket"
19
23
 
20
- const rejection = (error: AuthenticationFailed) =>
24
+ const rejection = (error: AuthenticationFailed | AuthenticatorUnavailable) =>
25
+ error._tag === "AuthenticatorUnavailable"
26
+ ? unavailable(error)
27
+ : unauthorized(error)
28
+
29
+ // The credential was not judged, so the client is told to retry rather than to replace it.
30
+ const unavailable = (error: AuthenticatorUnavailable) =>
31
+ Effect.logError("Remote host authenticator is unavailable", error.cause).pipe(
32
+ Effect.as(HttpServerResponse.empty({ status: 503 })),
33
+ )
34
+
35
+ const unauthorized = (error: AuthenticationFailed) =>
21
36
  Effect.logWarning(
22
37
  "Remote host authentication failed",
23
38
  {
@@ -83,7 +98,7 @@ const open = Effect.fnUntraced(function* (
83
98
  run: <A, E, R>(
84
99
  accept: Effect.Effect<
85
100
  (socket: Socket.Socket) => Effect.Effect<A, E, R>,
86
- AuthenticationFailed,
101
+ AuthenticationFailed | AuthenticatorUnavailable,
87
102
  HttpServerRequest.HttpServerRequest
88
103
  >,
89
104
  ) =>
@@ -14,7 +14,7 @@ import { Signature } from "effect/crypto"
14
14
  import { HttpClient } from "effect/http"
15
15
  import { Authenticator } from "../../Auth"
16
16
  import { ConfigDirectory } from "@graftland/loader"
17
- import { AuthenticationFailed } from "../../Errors"
17
+ import { AuthenticationFailed, AuthenticatorUnavailable } from "../../Errors"
18
18
  import * as Token from "../../internal/auth/token"
19
19
 
20
20
  export const ClockTolerance = Schema.DurationFromString.check(
@@ -97,12 +97,16 @@ export default Plugin.make({
97
97
  verified.claims[config.identityClaim],
98
98
  ),
99
99
  ),
100
+ // An unreachable key set says nothing about the token; the client must not discard it.
100
101
  Effect.mapError((error) =>
101
- AuthenticationFailed.make({
102
- reason: "invalid",
103
- challenge: 'Bearer error="invalid_token"',
104
- cause: Cause.fail(error),
105
- }),
102
+ error._tag === "JoseError" &&
103
+ error.reason._tag === "KeySetUnavailable"
104
+ ? AuthenticatorUnavailable.make({ cause: Cause.fail(error) })
105
+ : AuthenticationFailed.make({
106
+ reason: "invalid",
107
+ challenge: 'Bearer error="invalid_token"',
108
+ cause: Cause.fail(error),
109
+ }),
106
110
  ),
107
111
  Effect.provideService(Signature.Signature, signature),
108
112
  Effect.provideContext(services),
@@ -1,13 +0,0 @@
1
- import { f as CleanupError } from "./Graft-BsYq3F-J.js";
2
- import { n as close } from "./release-BY4Mlluy.js";
3
- import { Array, Cause, Effect, Schema, Scope } from "effect";
4
- // packages/remote/src/internal/cleanup.ts
5
- /** Finalizers have no typed failure channel. Keep reasons and their annotations flat. */
6
- const cleanupCause = (cause) => Cause.fromReasons(Array.flatMap(cause.reasons, (reason) => {
7
- const error = reason._tag === "Fail" ? reason.error : reason._tag === "Die" ? reason.defect : void 0;
8
- if (Schema.is(CleanupError)(error)) return Array.map(cleanupCause(error.cause).reasons, (inner) => inner.annotate(Cause.reasonAnnotations(reason)));
9
- return [reason._tag === "Fail" ? Cause.makeDieReason(reason.error).annotate(Cause.reasonAnnotations(reason)) : reason];
10
- }));
11
- /** Assembly children close before the entry reports their cleanup as its own result. */
12
- const children = Effect.acquireRelease(Scope.make(), (scope, exit) => close(scope, exit).pipe(Effect.catchCause((cause) => Effect.failCause(cleanupCause(cause)))));
13
- export { cleanupCause as n, children as t };
@@ -1,9 +0,0 @@
1
- import { c as TransportError } from "./Errors-oPsTLY7l.js";
2
- import { t as EndOfStream } from "./Framing-zaYdOJnT.js";
3
- import { t as Peer } from "./Peer-IJgFK6mD.js";
4
- import { Array, Cause, Effect, Schema } from "effect";
5
- import { Socket } from "effect/socket";
6
- // packages/remote/src/internal/runner/connectionEnded.ts
7
- const closedNormally = (cause) => cause.reasons.length > 0 && Array.every(cause.reasons, (reason) => reason._tag === "Fail" && (Schema.is(TransportError)(reason.error) ? closedNormally(reason.error.cause) : Schema.is(EndOfStream)(reason.error) || Socket.isSocketError(reason.error) && reason.error.reason._tag === "SocketCloseError" && reason.error.reason.code === 1e3));
8
- const connectionEnded = (cause) => Cause.hasInterruptsOnly(cause) || closedNormally(cause) ? Effect.void : Effect.flatMap(Peer, (identity) => Effect.logWarning("Remote host connection failed", cause).pipe(Effect.annotateLogs({ "remote.peer": identity })));
9
- export { connectionEnded as n, closedNormally as t };
@@ -1,33 +0,0 @@
1
- import { Schema } from "effect";
2
- declare const AlreadyLoaded_base: Schema.Class<AlreadyLoaded, Schema.TaggedStruct<"AlreadyLoaded", {}>, import("effect/Cause").YieldableError & {
3
- readonly brand: unique symbol;
4
- }>;
5
- export declare class AlreadyLoaded extends AlreadyLoaded_base {}
6
- declare const ContractNotFound_base: Schema.Class<ContractNotFound, Schema.TaggedStruct<"ContractNotFound", {
7
- readonly module: Schema.String;
8
- }>, import("effect/Cause").YieldableError & {
9
- readonly brand: unique symbol;
10
- }>;
11
- export declare class ContractNotFound extends ContractNotFound_base {
12
- get message(): string;
13
- }
14
- declare const ModuleImportFailed_base: Schema.Class<ModuleImportFailed, Schema.TaggedStruct<"ModuleImportFailed", {
15
- readonly module: Schema.String;
16
- readonly cause: Schema.Defect;
17
- }>, import("effect/Cause").YieldableError & {
18
- readonly brand: unique symbol;
19
- }>;
20
- export declare class ModuleImportFailed extends ModuleImportFailed_base {}
21
- declare const ActivationFailed_base: Schema.Class<ActivationFailed, Schema.TaggedStruct<"ActivationFailed", {
22
- readonly detail: Schema.String;
23
- readonly cause: Schema.optionalKey<Schema.Cause<Schema.Defect, Schema.Defect>>;
24
- }>, import("effect/Cause").YieldableError & {
25
- readonly brand: unique symbol;
26
- }>;
27
- export declare class ActivationFailed extends ActivationFailed_base {
28
- get message(): string;
29
- }
30
- export declare const ChildFailure: Schema.Union<readonly [typeof AlreadyLoaded, typeof ContractNotFound, typeof ModuleImportFailed, typeof ActivationFailed]>;
31
- export type ChildFailure = typeof ChildFailure.Type;
32
- export {};
33
- //# sourceMappingURL=childErrors.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"childErrors.d.ts","names":[],"sources":["../../src/internal/childErrors.ts"],"mappings":";;WAImB;;qBAFN,sBAAsB;;;;WAMhB;;qBAFN,yBAAyB;MAIxB;;;;;;WAMK;;qBAFN,2BAA2B;;;;;WASrB;;qBAFN,yBAAyB;MAYxB;;qBAID,cAAY,OAAA,uBAAA,sBAAA,yBAAA,2BAAA;YAMb,sBAAsB,aAAa"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"port.d.ts","names":[],"sources":["../../src/internal/port.ts"],"mappings":";;;;;iBAgDiB;WACP,iBAAiB,qBAAqB,UAAU;WAChD,iBAAiB,qBAAqB,UAAU;WAChD,OAAO,OAAO,cAAc;WAC5B,OAAO,OAAO,mBAAmB,OAAO;WACxC,KAAK,OAAO,aAAa"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Framing.d.ts","names":[],"sources":["../../../src/internal/runner/Framing.ts"],"mappings":";;;;WAImB;;qBAFN,mBAAmB;MAIlB"}