1import { AuthPreviewOperateScope, type BrowserProfile } from "@t3tools/contracts";
2import { useEffect } from "react";
3
4import { useClientSettings, useClientSettingsHydrated } from "~/hooks/useSettings";
5import { useServerConfigs } from "~/state/entities";
6import { useEnvironments } from "~/state/environments";
7import { previewEnvironment } from "~/state/preview";
8import { useEnvironmentsWithScope } from "~/state/session";
9import { useAtomCommand } from "~/state/use-atom-command";
10
11const selectProfiles = (settings: { readonly browserProfiles: ReadonlyArray<BrowserProfile> }) =>
12 settings.browserProfiles;
13const selectDefaultProfileId = (settings: { readonly browserDefaultProfileId: string }) =>
14 settings.browserDefaultProfileId;
15
16/**
17 * Tells each environment that hosts browser tabs which profiles this client
18 * has, so agents can open tabs under them. Profiles live in client settings;
19 * the server keeps only the latest report in memory. A reconnect brings a new
20 * server config, which sends the report again.
21 */
22export function BrowserProfileReporter() {
23 const hydrated = useClientSettingsHydrated();
24 const profiles = useClientSettings(selectProfiles);
25 const defaultProfileId = useClientSettings(selectDefaultProfileId);
26 const { environments } = useEnvironments();
27 const serverConfigs = useServerConfigs();
28 const operable = useEnvironmentsWithScope(environments, AuthPreviewOperateScope);
29 const report = useAtomCommand(previewEnvironment.reportProfiles, { reportFailure: false });
30
31 useEffect(() => {
32 if (!hydrated) return;
33 for (const [environmentId, config] of serverConfigs) {
34 if (!config.environment.capabilities.serverBrowser || !operable.has(environmentId)) continue;
35 void report({ environmentId, input: { profiles, defaultProfileId } });
36 }
37 }, [defaultProfileId, hydrated, operable, profiles, report, serverConfigs]);
38
39 return null;
40}