1import type {
2 EnvironmentId,
3 PreviewOpenInput,
4 PreviewRuntime,
5 PreviewSessionSnapshot,
6 PreviewViewportSetting,
7 ScopedThreadRef,
8} from "@t3tools/contracts";
9import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime";
10import * as Cause from "effect/Cause";
11import { AsyncResult } from "effect/reactivity";
12
13import {
14 browserDefaultOpenProfileId,
15 browserDefaultOpenViewport,
16 resolveBrowserDefaults,
17} from "~/browser/browserDefaults";
18import { BrowserSettingsReadError } from "~/browser/openFileInPreview";
19import { previewRuntimeFor } from "~/browser/previewRuntime";
20import { applyPreviewServerSnapshot, rememberPreviewUrl } from "~/previewStateStore";
21
22interface OpenPreviewSessionInput<E> {
23 openPreview: (input: {
24 readonly environmentId: EnvironmentId;
25 readonly input: PreviewOpenInput;
26 }) => Promise<AtomCommandResult<PreviewSessionSnapshot, E>>;
27 threadRef: ScopedThreadRef;
28 url?: string;
29 /** Overrides the configured default; automation passes an explicit size. */
30 viewport?: PreviewViewportSetting;
31 /** Overrides the configured default profile. */
32 profileId?: string;
33 /** Overrides where the tab runs, such as when moving a tab between browsers. */
34 runtime?: PreviewRuntime;
35}
36
37export async function openPreviewSession<E>(
38 input: OpenPreviewSessionInput<E>,
39): Promise<AtomCommandResult<PreviewSessionSnapshot, E | BrowserSettingsReadError>> {
40 // Resolved once: a tab opened before client settings hydrate would otherwise
41 // be born at the schema defaults and never corrected.
42 const defaults = await resolveBrowserDefaults().catch(
43 (cause: unknown) => new BrowserSettingsReadError({ cause }),
44 );
45 if (defaults instanceof BrowserSettingsReadError) {
46 return AsyncResult.failure(Cause.fail(defaults));
47 }
48 const runtime = input.runtime ?? previewRuntimeFor(input.threadRef.environmentId);
49 const result = await input.openPreview({
50 environmentId: input.threadRef.environmentId,
51 input: {
52 threadId: input.threadRef.threadId,
53 ...(input.url === undefined ? {} : { url: input.url }),
54 viewport: input.viewport ?? browserDefaultOpenViewport(defaults),
55 profileId: input.profileId ?? browserDefaultOpenProfileId(defaults),
56 ...(runtime === undefined || runtime === "desktop" ? {} : { runtime }),
57 },
58 });
59 if (result._tag === "Failure") {
60 return result;
61 }
62 const snapshot = result.value;
63 applyPreviewServerSnapshot(input.threadRef, snapshot);
64 if (input.url !== undefined) {
65 rememberPreviewUrl(
66 input.threadRef,
67 snapshot.navStatus._tag === "Idle" ? input.url : snapshot.navStatus.url,
68 );
69 }
70 return result;
71}