Repository navigation
Expand file tree
/
Copy pathpreviewWebviewConfigState.ts
More file actions
94 lines (81 loc) · 3.32 KB
/
Copy pathpreviewWebviewConfigState.ts
File metadata and controls
94 lines (81 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { useAtomValue } from "@effect/atom-react";
import type {
DesktopPreviewBridge,
DesktopPreviewWebviewConfig,
EnvironmentId,
} from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as Schema from "effect/Schema";
import { AsyncResult, Atom } from "effect/reactivity";
import { previewBridge } from "~/components/preview/previewBridge";
const PREVIEW_CONFIG_STALE_TIME_MS = 5 * 60_000;
const PREVIEW_CONFIG_IDLE_TTL_MS = 10 * 60_000;
export class PreviewWebviewBridgeUnavailableError extends Schema.TaggedError<PreviewWebviewBridgeUnavailableError>()(
"PreviewWebviewBridgeUnavailableError",
{ environmentId: Schema.String },
) {
override get message(): string {
return `Desktop preview configuration is unavailable for environment "${this.environmentId}".`;
}
}
export class PreviewWebviewConfigLoadError extends Schema.TaggedError<PreviewWebviewConfigLoadError>()(
"PreviewWebviewConfigLoadError",
{
environmentId: Schema.String,
cause: Schema.Defect(),
},
) {
override get message(): string {
return `Failed to load desktop preview configuration for environment "${this.environmentId}".`;
}
}
export const PreviewWebviewConfigError = Schema.Union([
PreviewWebviewBridgeUnavailableError,
PreviewWebviewConfigLoadError,
]);
export type PreviewWebviewConfigError = typeof PreviewWebviewConfigError.Type;
type PreviewConfigBridge = Pick<DesktopPreviewBridge, "getPreviewConfig">;
const loadPreviewWebviewConfig = (
environmentId: EnvironmentId,
profileId?: string,
bridge: PreviewConfigBridge | null = previewBridge,
): Effect.Effect<DesktopPreviewWebviewConfig, PreviewWebviewConfigError> => {
if (bridge === null) {
return Effect.fail(new PreviewWebviewBridgeUnavailableError({ environmentId }));
}
return Effect.tryPromise({
try: () => bridge.getPreviewConfig(environmentId, profileId),
catch: (cause) => new PreviewWebviewConfigLoadError({ environmentId, cause }),
});
};
// Atom.family needs a primitive key; keep profile last so delimiter-containing ids round-trip.
const CONFIG_KEY_DELIMITER = "\u0000";
const configKey = (environmentId: EnvironmentId, profileId: string | undefined): string =>
`${environmentId}${CONFIG_KEY_DELIMITER}${profileId ?? ""}`;
const parseConfigKey = (key: string): { environmentId: EnvironmentId; profileId?: string } => {
const delimiter = key.indexOf(CONFIG_KEY_DELIMITER);
const environmentId = (delimiter === -1 ? key : key.slice(0, delimiter)) as EnvironmentId;
const profileId = delimiter === -1 ? "" : key.slice(delimiter + CONFIG_KEY_DELIMITER.length);
return {
environmentId,
...(profileId === "" ? {} : { profileId }),
};
};
const previewWebviewConfigAtom = Atom.family((key: string) => {
const { environmentId, profileId } = parseConfigKey(key);
return Atom.make(loadPreviewWebviewConfig(environmentId, profileId)).pipe(
Atom.swr({
staleTime: PREVIEW_CONFIG_STALE_TIME_MS,
revalidateOnMount: true,
}),
Atom.setIdleTTL(PREVIEW_CONFIG_IDLE_TTL_MS),
Atom.withLabel(`preview:webview-config:${key}`),
);
});
export function usePreviewWebviewConfig(
environmentId: EnvironmentId,
profileId?: string,
): DesktopPreviewWebviewConfig | null {
const result = useAtomValue(previewWebviewConfigAtom(configKey(environmentId, profileId)));
return AsyncResult.getOrElse(result, () => null);
}