Skip to content
Source
Sign inSign up

useSubscriptionUsage.ts

66 lines2.7 KB

1import { runAtomCommand } from "@t3tools/client-runtime/state/runtime";
2import type { EnvironmentId } from "@t3tools/contracts";
3import * as Option from "effect/Option";
4import { Atom } from "effect/reactivity";
5​
6import { environmentCatalog } from "../connection/catalog";
7import { isAppActive, subscribeAppState } from "../lib/appState";
8import { appAtomRegistry } from "../state/atom-registry";
9import { environmentPresentations } from "../state/presentation";
10import { serverEnvironment } from "../state/server";
11import { environmentShell } from "../state/shell";
12import { createWidgetRefresher, WIDGET_REFRESH_INTERVAL } from "./subscriptionUsageSnapshot";
13​
14// A shell that failed never goes live, and its environment still needs fresh quotas.
15const shellSettledAtom = Atom.family((environmentId: EnvironmentId) =>
16 Atom.make((get) => {
17 const shell = get(environmentShell.stateValueAtom(environmentId));
18 return shell.status === "live" || Option.isSome(shell.error);
19 }),
20);
21​
22/**
23 * Connected environments whose thread list has loaded. A refresh re-probes every provider on
24 * the host, so on a cold start it waits until it cannot compete with the thread list.
25 */
26const refreshableEnvironmentsAtom = Atom.make((get) =>
27 [...get(environmentPresentations.presentationsAtom)]
28 .filter(
29 ([environmentId, presentation]) =>
30 presentation.connection.phase === "connected" && get(shellSettledAtom(environmentId)),
31 )
32 .map(([environmentId]) => environmentId),
33);
34​
35/**
36 * App-lifetime worker that keeps provider quotas fresh for the usage widget:
37 * on resume, on every connection change, and on a fixed interval while active.
38 * Each environment is refreshed at most once per interval.
39 */
40export function installSubscriptionUsageRefresh(): () => void {
41 const refresh = createWidgetRefresher((environmentId: EnvironmentId) =>
42 runAtomCommand(
43 appAtomRegistry,
44 serverEnvironment.refreshProviders,
45 { environmentId, input: {} },
46 { label: serverEnvironment.refreshProviders.label, reportFailure: false },
47 ),
48 );
49 const update = () => {
50 if (!isAppActive() || !appAtomRegistry.get(environmentCatalog.catalogValueAtom).isReady) return;
51 void refresh(appAtomRegistry.get(refreshableEnvironmentsAtom), Date.now());
52 };
53​
54 const unsubscribeCatalog = appAtomRegistry.subscribe(environmentCatalog.catalogValueAtom, update);
55 const unsubscribeEnvironments = appAtomRegistry.subscribe(refreshableEnvironmentsAtom, update, {
56 immediate: true,
57 });
58 const unsubscribeAppState = subscribeAppState(update);
59 const timer = setInterval(update, WIDGET_REFRESH_INTERVAL);
60 return () => {
61 unsubscribeCatalog();
62 unsubscribeEnvironments();
63 unsubscribeAppState();
64 clearInterval(timer);
65 };