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
8const DESKTOP_LOCAL_CONNECTION_ID_PREFIX = "local:";
9
10export function desktopLocalConnectionId(backendId: string): string {
11 return `${DESKTOP_LOCAL_CONNECTION_ID_PREFIX}${backendId}`;
12}
13
14export function isDesktopLocalConnectionTarget(
15 target: ConnectionTarget,
16): target is Extract<ConnectionTarget, { readonly _tag: "BearerConnectionTarget" }> {
17 return (
18 target._tag === "BearerConnectionTarget" &&
19 target.connectionId.startsWith(DESKTOP_LOCAL_CONNECTION_ID_PREFIX)
20 );
21}
22
23export function desktopLocalBackendId(target: ConnectionTarget): string | null {
24 return isDesktopLocalConnectionTarget(target)
25 ? target.connectionId.slice(DESKTOP_LOCAL_CONNECTION_ID_PREFIX.length)
26 : null;
27}
28
29export type DesktopSecondaryBootstrapsRead =
30 | {
31 readonly _tag: "Success";
32 readonly bootstraps: ReadonlyArray<DesktopEnvironmentBootstrap>;
33 }
34 | {
35 readonly _tag: "Failure";
36 readonly cause: unknown;
37 };
38
39export interface DesktopSecondaryBootstrapsReader {
40 readonly readResult: () => DesktopSecondaryBootstrapsRead;
41 readonly readSnapshot: () => ReadonlyArray<DesktopEnvironmentBootstrap>;
42}
43
44/** Empty reads clear the snapshot; failed reads retain platform registrations. */
45export function createDesktopSecondaryBootstrapsReader(
46 resolveBridge: () => Pick<DesktopBridge, "getLocalEnvironmentBootstraps"> | undefined,
47): DesktopSecondaryBootstrapsReader {
48 let snapshot: ReadonlyArray<DesktopEnvironmentBootstrap> = [];
49
50 const readResult = (): DesktopSecondaryBootstrapsRead => {
51 const bridge = resolveBridge();
52 if (bridge === undefined) {
53 if (snapshot.length > 0) snapshot = [];
54 return { _tag: "Success", bootstraps: snapshot };
55 }
56 try {
57 const next = bridge
58 .getLocalEnvironmentBootstraps()
59 .filter((entry) => entry.id !== PRIMARY_LOCAL_ENVIRONMENT_ID);
60 if (
61 next.length !== snapshot.length ||
62 next.some((entry, index) => {
63 const previous = snapshot[index];
64 return (
65 previous === undefined ||
66 entry.id !== previous.id ||
67 entry.label !== previous.label ||
68 entry.runningDistro !== previous.runningDistro ||
69 entry.httpBaseUrl !== previous.httpBaseUrl ||
70 entry.wsBaseUrl !== previous.wsBaseUrl ||
71 entry.bootstrapToken !== previous.bootstrapToken
72 );
73 })
74 ) {
75 snapshot = next;
76 }
77 return { _tag: "Success", bootstraps: snapshot };
78 } catch (cause) {
79 return { _tag: "Failure", cause };
80 }
81 };
82
83 return {
84 readResult,
85 readSnapshot: () => {
86 const result = readResult();
87 return result._tag === "Success" ? result.bootstraps : snapshot;
88 },
89 };
90}
91
92const desktopSecondaryBootstrapsReader = createDesktopSecondaryBootstrapsReader(
93 () => window.desktopBridge,
94);
95
96export function readDesktopSecondaryBootstrapsResult(): DesktopSecondaryBootstrapsRead {
97 return desktopSecondaryBootstrapsReader.readResult();
98}
99
100export function readDesktopSecondaryBootstraps(): ReadonlyArray<DesktopEnvironmentBootstrap> {
101 return desktopSecondaryBootstrapsReader.readSnapshot();
102}