1import type { ConnectionTarget } from "@t3tools/client-runtime/connection";
2import {
3 PRIMARY_LOCAL_ENVIRONMENT_ID,
4 type DesktopBridge,
5 type DesktopEnvironmentBootstrap,
6} from "@t3tools/contracts";
7
8/**
9 * Desktop-local secondary backends (e.g. a parallel WSL backend) are registered
10 * by the connection platform source as bearer connections whose id carries this
11 * prefix. It is the renderer's single signal that an environment is a
12 * host-managed local backend rather than a user-saved remote, SSH, or relay
13 * environment.
14 *
15 * Keep this the one source of truth: the producer (`connection/platform.ts`)
16 * mints ids via {@link desktopLocalConnectionId} and every consumer classifies
17 * via {@link isDesktopLocalConnectionTarget}, so the convention can never drift
18 * between the two.
19 */
20const DESKTOP_LOCAL_CONNECTION_ID_PREFIX = "local:";
21
22export function desktopLocalConnectionId(backendId: string): string {
23 return `${DESKTOP_LOCAL_CONNECTION_ID_PREFIX}${backendId}`;
24}
25
26export function isDesktopLocalConnectionTarget(
27 target: ConnectionTarget,
28): target is Extract<ConnectionTarget, { readonly _tag: "BearerConnectionTarget" }> {
29 return (
30 target._tag === "BearerConnectionTarget" &&
31 target.connectionId.startsWith(DESKTOP_LOCAL_CONNECTION_ID_PREFIX)
32 );
33}
34
35export function desktopLocalBackendId(target: ConnectionTarget): string | null {
36 return isDesktopLocalConnectionTarget(target)
37 ? target.connectionId.slice(DESKTOP_LOCAL_CONNECTION_ID_PREFIX.length)
38 : null;
39}
40
41export function isWslConnectionTarget(target: ConnectionTarget): boolean {
42 return desktopLocalBackendId(target)?.startsWith("wsl:") === true;
43}
44
45export type DesktopSecondaryBootstrapsRead =
46 | {
47 readonly _tag: "Success";
48 readonly bootstraps: ReadonlyArray<DesktopEnvironmentBootstrap>;
49 }
50 | {
51 readonly _tag: "Failure";
52 readonly cause: unknown;
53 };
54
55export interface DesktopSecondaryBootstrapsReader {
56 readonly readResult: () => DesktopSecondaryBootstrapsRead;
57 readonly readSnapshot: () => ReadonlyArray<DesktopEnvironmentBootstrap>;
58}
59
60/**
61 * Build a topology reader whose snapshot advances only after successful bridge
62 * reads. A successful empty read is authoritative; a thrown read preserves the
63 * previous snapshot so UI consumers cannot temporarily disagree with the
64 * platform's retained registrations.
65 */
66export function createDesktopSecondaryBootstrapsReader(
67 resolveBridge: () => Pick<DesktopBridge, "getLocalEnvironmentBootstraps"> | undefined,
68): DesktopSecondaryBootstrapsReader {
69 let snapshot: ReadonlyArray<DesktopEnvironmentBootstrap> = [];
70
71 const readResult = (): DesktopSecondaryBootstrapsRead => {
72 const bridge = resolveBridge();
73 if (bridge === undefined) {
74 if (snapshot.length > 0) snapshot = [];
75 return { _tag: "Success", bootstraps: snapshot };
76 }
77 try {
78 const next = bridge
79 .getLocalEnvironmentBootstraps()
80 .filter((entry) => entry.id !== PRIMARY_LOCAL_ENVIRONMENT_ID);
81 if (
82 next.length !== snapshot.length ||
83 next.some((entry, index) => {
84 const previous = snapshot[index];
85 return (
86 previous === undefined ||
87 entry.id !== previous.id ||
88 entry.label !== previous.label ||
89 entry.runningDistro !== previous.runningDistro ||
90 entry.httpBaseUrl !== previous.httpBaseUrl ||
91 entry.wsBaseUrl !== previous.wsBaseUrl ||
92 entry.bootstrapToken !== previous.bootstrapToken
93 );
94 })
95 ) {
96 snapshot = next;
97 }
98 return { _tag: "Success", bootstraps: snapshot };
99 } catch (cause) {
100 return { _tag: "Failure", cause };
101 }
102 };
103
104 return {
105 readResult,
106 readSnapshot: () => {
107 const result = readResult();
108 return result._tag === "Success" ? result.bootstraps : snapshot;
109 },
110 };
111}
112
113const desktopSecondaryBootstrapsReader = createDesktopSecondaryBootstrapsReader(
114 () => window.desktopBridge,
115);
116
117/** Read the topology while preserving failures for platform cache policy. */
118export function readDesktopSecondaryBootstrapsResult(): DesktopSecondaryBootstrapsRead {
119 return desktopSecondaryBootstrapsReader.readResult();
120}
121
122/** Read the latest successful topology snapshot for renderer consumers. */
123export function readDesktopSecondaryBootstraps(): ReadonlyArray<DesktopEnvironmentBootstrap> {
124 return desktopSecondaryBootstrapsReader.readSnapshot();
125}