1import * as Effect from "effect/Effect";
2import * as PubSub from "effect/PubSub";
3import * as Semaphore from "effect/Semaphore";
4import * as Stream from "effect/Stream";
5
6export interface SnapshotSubscription<A> {
7 readonly latest: A;
8 readonly changes: Stream.Stream<A>;
9}
10
11export const subscribeBeforeSnapshot = Effect.fn("subscribeBeforeSnapshot")(function* <A, E, R>(
12 changes: PubSub.PubSub<A>,
13 snapshot: Effect.Effect<A, E, R>,
14 mutex: Semaphore.Semaphore,
15) {
16 return yield* mutex.withPermits(1)(
17 Effect.gen(function* () {
18 const latest = yield* snapshot;
19 const subscription = yield* PubSub.subscribe(changes);
20 return {
21 latest,
22 changes: Stream.fromSubscription(subscription),
23 } satisfies SnapshotSubscription<A>;
24 }),
25 );
26});
27
28export const subscribeBeforeSnapshotWithoutMutex = Effect.fn("subscribeBeforeSnapshotWithoutMutex")(
29 function* <A, E, R>(changes: PubSub.PubSub<A>, snapshot: Effect.Effect<A, E, R>) {
30 const subscription = yield* PubSub.subscribe(changes);
31 const latest = yield* snapshot;
32 return {
33 latest,
34 changes: Stream.fromSubscription(subscription),
35 } satisfies SnapshotSubscription<A>;
36 },
37);