| 1 | import * as Context from "effect/Context"; |
| 2 | import * as Deferred from "effect/Deferred"; |
| 3 | import * as Effect from "effect/Effect"; |
| 4 | import type * as Fiber from "effect/Fiber"; |
| 5 | import type * as Scope from "effect/Scope"; |
| 6 | |
| 7 | export class ServerActivation extends Context.Reference<Effect.Effect<void> | undefined>( |
| 8 | "t3/serverActivation", |
| 9 | { defaultValue: () => undefined }, |
| 10 | ) {} |
| 11 | |
| 12 | /** Forks a long-running root before commit, returning it after it reaches the activation boundary. */ |
| 13 | export const forkParkedFiber = <A, E, R>( |
| 14 | effect: Effect.Effect<A, E, R>, |
| 15 | ): Effect.Effect<Fiber.Fiber<A, E>, never, Scope.Scope | R> => |
| 16 | Effect.gen(function* () { |
| 17 | const activation = yield* ServerActivation; |
| 18 | if (activation === undefined) { |
| 19 | return yield* Effect.forkScoped(effect); |
| 20 | } |
| 21 | const parked = yield* Deferred.make<void>(); |
| 22 | const fiber = yield* Effect.forkScoped( |
| 23 | Deferred.succeed(parked, undefined).pipe(Effect.andThen(activation), Effect.andThen(effect)), |
| 24 | ); |
| 25 | yield* Deferred.await(parked); |
| 26 | return fiber; |
| 27 | }); |
| 28 | |
| 29 | /** Forks a long-running root before commit and proves it is parked at the activation boundary. */ |
| 30 | export const forkParked = <A, E, R>( |
| 31 | effect: Effect.Effect<A, E, R>, |
| 32 | ): Effect.Effect<void, never, Scope.Scope | R> => forkParkedFiber(effect).pipe(Effect.asVoid); |