Skip to content
Source
Sign inSign up

vcsStatusRevalidation.ts

72 lines2.8 KB

1// @effect-diagnostics globalTimers:off - The wake debounce runs in an atom subscription, outside an Effect runtime.
2import type { EnvironmentId } from "@t3tools/contracts";
3import { Atom, type AtomRegistry } from "effect/reactivity";
4​
5import { type AtomCommand, type AtomCommandResult, runAtomCommand } from "./runtime.ts";
6​
7export interface VcsStatusRevalidationTarget {
8 readonly environmentId: EnvironmentId;
9 readonly cwd: string;
11​
12/**
13 * One atom per checkout, so controls showing it share one cadence. Refreshes on
14 * `subscribeWake` (debounced) and whenever `connected`, if given, is true on
15 * mount or turns true. Listening ends with the last subscriber.
16 */
17export function createVcsStatusRevalidationAtomFamily<R>(input: {
18 readonly refreshStatus: AtomCommand<
19 { readonly environmentId: EnvironmentId; readonly input: { readonly cwd: string } },
20 R,
21 unknown
22 >;
23 readonly connected?: (environmentId: EnvironmentId) => Atom.Atom<boolean>;
24 readonly subscribeWake?: (wake: () => void) => () => void;
25 readonly wakeDebounceMs?: number;
26 readonly onRefreshed?: (result: AtomCommandResult<R, unknown>) => void;
27}) {
28 const family = Atom.family((target: VcsStatusRevalidationTarget) => {
29 const { environmentId, cwd } = target;
30 const key = `${environmentId}:${cwd}`;
31​
32 const refresh = async (registry: AtomRegistry.AtomRegistry) => {
33 const result = await runAtomCommand(
34 registry,
35 input.refreshStatus,
36 { environmentId, input: { cwd } },
37 { reportFailure: false },
38 );
39 input.onRefreshed?.(result);
40 };
41​
42 const wakeAtom = Atom.make((get) => {
43 const subscribeWake = input.subscribeWake;
44 if (subscribeWake === undefined) return;
45 const registry = get.registry;
46 let timer: ReturnType<typeof setTimeout> | undefined;
47 const unsubscribe = subscribeWake(() => {
48 if (timer !== undefined) clearTimeout(timer);
49 timer = setTimeout(() => {
50 timer = undefined;
51 void refresh(registry);
52 }, input.wakeDebounceMs ?? 0);
53 });
54 get.addFinalizer(() => {
55 if (timer !== undefined) clearTimeout(timer);
56 unsubscribe();
57 });
58 }).pipe(Atom.withLabel(`vcs-status-revalidation:wake:${key}`));
59​
60 return Atom.make((get) => {
61 get(wakeAtom);
62 const connected = input.connected;
63 // Rebuilds only when the connection flag flips, so each reconnect refreshes once.
64 if (connected !== undefined && get(connected(environmentId))) {
65 void refresh(get.registry);
66 }
67 }).pipe(Atom.withLabel(`vcs-status-revalidation:${key}`));
68 });
69 const idle = Atom.make<void>(undefined).pipe(Atom.withLabel("vcs-status-revalidation:idle"));
70 return (target: VcsStatusRevalidationTarget | null): Atom.Atom<void> =>
71 target === null ? idle : family({ environmentId: target.environmentId, cwd: target.cwd });