1import * as Deferred from "effect/Deferred";
2import * as Effect from "effect/Effect";
3import * as SynchronizedRef from "effect/SynchronizedRef";
4
5export interface ReplayRecorderDeferredRegistry {
6 readonly getOrCreate: (key: string) => Effect.Effect<Deferred.Deferred<void>>;
7 readonly succeed: (key: string) => Effect.Effect<void>;
8}
9
10export const makeReplayRecorderDeferredRegistry = Effect.fn("makeReplayRecorderDeferredRegistry")(
11 function* () {
12 const state = yield* SynchronizedRef.make(new Map<string, Deferred.Deferred<void>>());
13
14 const getOrCreate = Effect.fn("ReplayRecorderDeferredRegistry.getOrCreate")(function* (
15 key: string,
16 ) {
17 return yield* SynchronizedRef.modifyEffect(state, (deferreds) => {
18 const existing = deferreds.get(key);
19 if (existing !== undefined) {
20 return Effect.succeed([existing, deferreds] as const);
21 }
22
23 return Deferred.make<void>().pipe(
24 Effect.map((deferred) => {
25 const next = new Map(deferreds);
26 next.set(key, deferred);
27 return [deferred, next] as const;
28 }),
29 );
30 });
31 });
32
33 const succeed = Effect.fn("ReplayRecorderDeferredRegistry.succeed")(function* (key: string) {
34 const deferred = yield* getOrCreate(key);
35 yield* Deferred.succeed(deferred, undefined);
36 });
37
38 return {
39 getOrCreate,
40 succeed,
41 } satisfies ReplayRecorderDeferredRegistry;
42 },
43);