1import * as Context from "effect/Context";
2import * as Deferred from "effect/Deferred";
3import * as Effect from "effect/Effect";
4import type * as Fiber from "effect/Fiber";
5import type * as Scope from "effect/Scope";
6
7export 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. */
13export 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. */
30export 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);