@tutti-os/browser-node 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-BZRJYTPK.js → chunk-Q3TQYLDL.js} +31 -7
- package/dist/chunk-Q3TQYLDL.js.map +1 -0
- package/dist/{chunk-LVVPDNEF.js → chunk-ZRH4UQZB.js} +5 -1
- package/dist/chunk-ZRH4UQZB.js.map +1 -0
- package/dist/electron-main/index.js +2 -2
- package/dist/electron-main/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/react/index.js +2 -2
- package/dist/workbench/index.js +2 -2
- package/package.json +5 -5
- package/dist/chunk-BZRJYTPK.js.map +0 -1
- package/dist/chunk-LVVPDNEF.js.map +0 -1
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
normalizeBrowserComparableUrl,
|
|
6
6
|
normalizeHostBrowserComparableUrl
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZRH4UQZB.js";
|
|
8
8
|
|
|
9
9
|
// src/react/BrowserNode.tsx
|
|
10
10
|
import {
|
|
@@ -774,7 +774,7 @@ function BrowserNode({
|
|
|
774
774
|
const errorMessage = runtime.error ? formatBrowserNodeErrorMessage(feature, runtime.error) : null;
|
|
775
775
|
const errorStatus = runtime.error ? formatBrowserNodeErrorStatus(feature, runtime.error) : null;
|
|
776
776
|
const isShowingLoadError = errorMessage !== null;
|
|
777
|
-
const openExternalUrl = feature
|
|
777
|
+
const openExternalUrl = resolveBrowserNodeOpenExternalUrl(feature, state);
|
|
778
778
|
const {
|
|
779
779
|
devToolsContextMenu,
|
|
780
780
|
dismissDevToolsContextMenu,
|
|
@@ -824,7 +824,7 @@ function BrowserNode({
|
|
|
824
824
|
void controller.submitDraftUrl().catch(() => void 0);
|
|
825
825
|
},
|
|
826
826
|
onOpenExternal: openExternalUrl ? () => {
|
|
827
|
-
void feature
|
|
827
|
+
void openBrowserNodeExternal(feature, openExternalUrl);
|
|
828
828
|
} : void 0,
|
|
829
829
|
onGoBack: () => {
|
|
830
830
|
void controller.goBack().catch(() => void 0);
|
|
@@ -871,7 +871,7 @@ function BrowserNode({
|
|
|
871
871
|
type: "button",
|
|
872
872
|
variant: "outline",
|
|
873
873
|
onClick: () => {
|
|
874
|
-
void feature
|
|
874
|
+
void openBrowserNodeExternal(feature, openExternalUrl);
|
|
875
875
|
},
|
|
876
876
|
children: [
|
|
877
877
|
/* @__PURE__ */ jsx(LaunchIcon, { className: "size-3.5" }),
|
|
@@ -932,7 +932,7 @@ function BrowserNodeWorkbenchHeader({
|
|
|
932
932
|
nodeId
|
|
933
933
|
});
|
|
934
934
|
const runtime = state.runtime;
|
|
935
|
-
const openExternalUrl = feature
|
|
935
|
+
const openExternalUrl = resolveBrowserNodeOpenExternalUrl(feature, state);
|
|
936
936
|
return /* @__PURE__ */ jsx(
|
|
937
937
|
BrowserNodeHeader,
|
|
938
938
|
{
|
|
@@ -952,7 +952,7 @@ function BrowserNodeWorkbenchHeader({
|
|
|
952
952
|
void controller.submitDraftUrl().catch(() => void 0);
|
|
953
953
|
},
|
|
954
954
|
onOpenExternal: openExternalUrl ? () => {
|
|
955
|
-
void feature
|
|
955
|
+
void openBrowserNodeExternal(feature, openExternalUrl);
|
|
956
956
|
} : void 0,
|
|
957
957
|
onGoBack: () => {
|
|
958
958
|
void controller.goBack().catch(() => void 0);
|
|
@@ -1117,6 +1117,30 @@ function BrowserNodeHeader({
|
|
|
1117
1117
|
}
|
|
1118
1118
|
);
|
|
1119
1119
|
}
|
|
1120
|
+
function resolveBrowserNodeOpenExternalUrl(feature, state) {
|
|
1121
|
+
if (!feature.hostApi.openExternal) {
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1124
|
+
const sourceUrl = state.runtime.url?.trim() || state.displayUrl.trim();
|
|
1125
|
+
if (sourceUrl.length === 0 || sourceUrl === "about:blank") {
|
|
1126
|
+
return null;
|
|
1127
|
+
}
|
|
1128
|
+
return feature.resolveOpenExternalUrl(sourceUrl).url;
|
|
1129
|
+
}
|
|
1130
|
+
async function openBrowserNodeExternal(feature, url) {
|
|
1131
|
+
try {
|
|
1132
|
+
await feature.hostApi.openExternal?.({ url });
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
feature.reportDiagnostic?.({
|
|
1135
|
+
details: {
|
|
1136
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1137
|
+
url
|
|
1138
|
+
},
|
|
1139
|
+
event: "open-external-failed",
|
|
1140
|
+
level: "warn"
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1120
1144
|
function formatBrowserNodeErrorMessage(feature, error) {
|
|
1121
1145
|
switch (error.code) {
|
|
1122
1146
|
case "invalid-url":
|
|
@@ -1176,4 +1200,4 @@ export {
|
|
|
1176
1200
|
BrowserNodeWorkbenchHeader,
|
|
1177
1201
|
BrowserNodeHeader
|
|
1178
1202
|
};
|
|
1179
|
-
//# sourceMappingURL=chunk-
|
|
1203
|
+
//# sourceMappingURL=chunk-Q3TQYLDL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/BrowserNode.tsx","../src/react/useBrowserNodeController.ts","../src/core/nodeController.ts","../src/react/useBrowserNodeWebview.ts","../src/core/webviewController.ts"],"sourcesContent":["import {\n ArrowLeftIcon,\n ArrowRightIcon,\n Badge,\n Button,\n Input,\n LaunchIcon,\n LoadingIcon,\n RefreshIcon,\n WarningLinedIcon,\n ViewportMenuSurface,\n cn,\n menuItemClassName\n} from \"@tutti-os/ui-system\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { HTMLAttributes, JSX, ReactNode } from \"react\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type { BrowserNodeControllerState } from \"../core/nodeController.ts\";\nimport type {\n BrowserNodeNavigationPolicy,\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport { useBrowserNodeController } from \"./useBrowserNodeController.ts\";\nimport { useBrowserNodeWebview } from \"./useBrowserNodeWebview.ts\";\n\n// Electron needs the serialized string attribute for dynamically created webviews.\nconst browserNodeAllowPopupsAttribute = \"true\" as unknown as boolean;\n\nexport interface BrowserNodeProps {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onFocusRequest?: () => void;\n onNavigated?: (url: string) => void;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n showHeader?: boolean;\n syncDefaultUrl?: boolean;\n}\n\nexport function BrowserNode({\n defaultUrl,\n feature,\n navigationPolicy = null,\n nodeId,\n onFocusRequest,\n onNavigated,\n profileId = null,\n sessionMode = \"shared\",\n sessionPartition = null,\n showHeader = true,\n syncDefaultUrl = false\n}: BrowserNodeProps): JSX.Element {\n const { controller, state } = useBrowserNodeController({\n defaultUrl,\n feature,\n navigationPolicy,\n nodeId,\n profileId,\n sessionMode,\n sessionPartition,\n syncDefaultUrl\n });\n const runtime = state.runtime;\n const lastNavigatedUrlRef = useRef<string | null>(\n state.runtime.url?.trim() || null\n );\n const errorMessage = runtime.error\n ? formatBrowserNodeErrorMessage(feature, runtime.error)\n : null;\n const errorStatus = runtime.error\n ? formatBrowserNodeErrorStatus(feature, runtime.error)\n : null;\n const isShowingLoadError = errorMessage !== null;\n const openExternalUrl = resolveBrowserNodeOpenExternalUrl(feature, state);\n const {\n devToolsContextMenu,\n dismissDevToolsContextMenu,\n openDevToolsFromContextMenu,\n shouldRenderWebview,\n setWebviewRef,\n webviewKey,\n webviewPartition,\n webviewSrc\n } = useBrowserNodeWebview({\n feature,\n initialUrl: state.displayUrl,\n lifecycle: runtime.lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction: onFocusRequest,\n profileId,\n sessionMode,\n sessionPartition\n });\n\n useEffect(() => {\n const navigatedUrl = state.runtime.url?.trim() ?? \"\";\n if (\n !onNavigated ||\n state.runtime.isLoading ||\n state.runtime.error ||\n navigatedUrl.length === 0 ||\n navigatedUrl === \"about:blank\" ||\n lastNavigatedUrlRef.current === navigatedUrl\n ) {\n return;\n }\n\n lastNavigatedUrlRef.current = navigatedUrl;\n onNavigated(navigatedUrl);\n }, [\n onNavigated,\n state.runtime.error,\n state.runtime.isLoading,\n state.runtime.url\n ]);\n\n return (\n <div className=\"flex h-full min-h-0 flex-col overflow-hidden bg-[var(--background-panel)]\">\n {showHeader ? (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n draftUrl={state.draftUrl}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n onDraftUrlChange={(nextUrl) => controller.setDraftUrl(nextUrl)}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={() => {\n void controller.submitDraftUrl().catch(() => undefined);\n }}\n onOpenExternal={\n openExternalUrl\n ? () => {\n void openBrowserNodeExternal(feature, openExternalUrl);\n }\n : undefined\n }\n onGoBack={() => {\n void controller.goBack().catch(() => undefined);\n }}\n onGoForward={() => {\n void controller.goForward().catch(() => undefined);\n }}\n onReload={() => {\n void controller.reload().catch(() => undefined);\n }}\n />\n ) : null}\n <div className=\"relative min-h-0 flex-1 overflow-hidden bg-[var(--background-panel)]\">\n {shouldRenderWebview ? (\n <webview\n allowpopups={browserNodeAllowPopupsAttribute}\n key={webviewKey}\n ref={setWebviewRef}\n className={cn(\n \"absolute inset-0 h-full w-full border-0 bg-[var(--background-panel)]\",\n isShowingLoadError ? \"hidden pointer-events-none\" : \"visible\"\n )}\n data-browser-node-webview=\"true\"\n partition={webviewPartition}\n src={webviewSrc}\n />\n ) : null}\n {errorMessage ? (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-[var(--background-panel)] px-8 py-10 text-center\">\n <div\n className=\"flex w-full max-w-[440px] flex-col items-center\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div className=\"flex size-11 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--state-danger)_22%,transparent)] bg-[color-mix(in_srgb,var(--state-danger)_8%,transparent)] text-[var(--state-danger)]\">\n <WarningLinedIcon className=\"size-5\" />\n </div>\n <div className=\"mt-4 text-lg font-semibold text-[var(--text-primary)]\">\n {feature.i18n.t(\"loadFailed\")}\n </div>\n <div className=\"mt-1 max-w-[360px] text-[13px] leading-5 text-[var(--text-secondary)]\">\n {errorMessage}\n </div>\n {errorStatus ? (\n <div className=\"mt-4 rounded-full border border-border bg-[var(--transparency-block)] px-2.5 py-1 text-[11px] font-medium text-[var(--text-secondary)]\">\n {errorStatus}\n </div>\n ) : null}\n {openExternalUrl ? (\n <div className=\"mt-5 flex flex-wrap items-center justify-center gap-2\">\n <Button\n size=\"sm\"\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n void openBrowserNodeExternal(feature, openExternalUrl);\n }}\n >\n <LaunchIcon className=\"size-3.5\" />\n {feature.i18n.t(\"actions.openExternal\")}\n </Button>\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n {devToolsContextMenu ? (\n <ViewportMenuSurface\n open\n className=\"w-44\"\n dismissOnEscape\n dismissOnPointerDownOutside\n onDismiss={dismissDevToolsContextMenu}\n placement={{\n type: \"point\",\n point: devToolsContextMenu,\n alignX: \"start\",\n alignY: \"start\",\n estimatedSize: {\n width: 176,\n height: 40\n }\n }}\n >\n <button\n className={cn(menuItemClassName, \"w-full\")}\n type=\"button\"\n onClick={() => {\n void openDevToolsFromContextMenu().catch(() => undefined);\n }}\n >\n {feature.i18n.t(\"actions.openDevTools\")}\n </button>\n </ViewportMenuSurface>\n ) : null}\n </div>\n </div>\n );\n}\n\nexport interface BrowserNodeWorkbenchHeaderProps {\n className?: string;\n defaultActions?: ReactNode;\n defaultUrl: string;\n dragHandleProps?: HTMLAttributes<HTMLElement>;\n feature: BrowserNodeFeature;\n nodeId: string;\n onCloseRequest?: () => void;\n onFocusRequest?: () => void;\n}\n\nexport function BrowserNodeWorkbenchHeader({\n className,\n defaultActions,\n defaultUrl,\n dragHandleProps,\n feature,\n nodeId,\n onCloseRequest,\n onFocusRequest\n}: BrowserNodeWorkbenchHeaderProps): JSX.Element {\n const { controller, state } = useBrowserNodeController({\n defaultUrl,\n feature,\n nodeId\n });\n const runtime = state.runtime;\n const openExternalUrl = resolveBrowserNodeOpenExternalUrl(feature, state);\n\n return (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n className={className}\n defaultActions={defaultActions}\n draftUrl={state.draftUrl}\n dragHandleProps={dragHandleProps}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n onCloseRequest={onCloseRequest}\n onDraftUrlChange={(nextUrl) => controller.setDraftUrl(nextUrl)}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={() => {\n void controller.submitDraftUrl().catch(() => undefined);\n }}\n onOpenExternal={\n openExternalUrl\n ? () => {\n void openBrowserNodeExternal(feature, openExternalUrl);\n }\n : undefined\n }\n onGoBack={() => {\n void controller.goBack().catch(() => undefined);\n }}\n onGoForward={() => {\n void controller.goForward().catch(() => undefined);\n }}\n onReload={() => {\n void controller.reload().catch(() => undefined);\n }}\n withBorder={false}\n />\n );\n}\n\nexport function BrowserNodeHeader({\n canGoBack,\n canGoForward,\n className,\n defaultActions,\n draftUrl,\n dragHandleProps,\n feature,\n isCold = false,\n isLoading,\n onCloseRequest,\n onDraftUrlChange,\n onFocusRequest,\n onGoBack,\n onGoForward,\n onOpenExternal,\n onReload,\n onSubmitUrl,\n withBorder = true\n}: {\n canGoBack: boolean;\n canGoForward: boolean;\n className?: string;\n defaultActions?: ReactNode;\n draftUrl: string;\n dragHandleProps?: HTMLAttributes<HTMLElement>;\n feature: BrowserNodeFeature;\n isCold?: boolean;\n isLoading: boolean;\n onCloseRequest?: () => void;\n onDraftUrlChange: (nextUrl: string) => void;\n onFocusRequest?: () => void;\n onGoBack: () => void;\n onGoForward: () => void;\n onOpenExternal?: () => void;\n onReload: () => void;\n onSubmitUrl: () => void;\n withBorder?: boolean;\n}): JSX.Element {\n const [reloadAnimationKey, setReloadAnimationKey] = useState(0);\n\n const handleReload = (): void => {\n setReloadAnimationKey((currentKey) => currentKey + 1);\n onReload();\n };\n\n return (\n <div\n className={cn(\n \"flex h-[var(--workbench-header-height,38px)] min-h-[var(--workbench-header-height,38px)] items-center gap-2 bg-[var(--background-panel)] px-2 pl-3\",\n withBorder ? \"border-b border-border\" : null,\n className\n )}\n data-browser-node-header=\"true\"\n onDoubleClick={(event) => {\n if (\n event.target instanceof Element &&\n event.target.closest(\".nodrag\")\n ) {\n return;\n }\n event.stopPropagation();\n dragHandleProps?.onDoubleClick?.(event);\n }}\n >\n <div className=\"inline-flex items-center gap-1\">\n <BrowserNodeHeaderButton\n disabled={!canGoBack}\n label={feature.i18n.t(\"actions.back\")}\n onClick={onGoBack}\n >\n <ArrowLeftIcon className=\"size-[15px]\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n disabled={!canGoForward}\n label={feature.i18n.t(\"actions.forward\")}\n onClick={onGoForward}\n >\n <ArrowRightIcon className=\"size-[15px]\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n label={feature.i18n.t(\"actions.reload\")}\n onClick={handleReload}\n >\n <RefreshIcon\n key={reloadAnimationKey}\n className={cn(\n \"size-[15px]\",\n reloadAnimationKey > 0 &&\n \"motion-safe:animate-[spin_520ms_cubic-bezier(0.4,0,0.2,1)_1_reverse]\"\n )}\n />\n </BrowserNodeHeaderButton>\n </div>\n <div\n {...dragHandleProps}\n className=\"h-full w-8 shrink-0 cursor-grab active:cursor-grabbing\"\n data-browser-node-drag-gutter=\"true\"\n data-node-drag-handle=\"true\"\n aria-hidden=\"true\"\n />\n <form\n className=\"nodrag relative min-w-0 flex-1\"\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onSubmitUrl();\n }}\n >\n <Input\n aria-label={feature.i18n.t(\"addressLabel\")}\n className=\"pr-8 focus-visible:border-input focus-visible:ring-0 focus-visible:ring-offset-0\"\n placeholder={feature.i18n.t(\"addressPlaceholder\")}\n size=\"sm\"\n value={draftUrl}\n onChange={(event) => onDraftUrlChange(event.target.value)}\n onFocus={onFocusRequest}\n />\n {isLoading ? (\n <LoadingIcon className=\"pointer-events-none absolute right-2 top-1/2 z-[1] size-4 -translate-y-1/2 animate-spin text-[var(--text-tertiary)]\" />\n ) : null}\n </form>\n {onOpenExternal ? (\n <BrowserNodeHeaderButton\n label={feature.i18n.t(\"actions.openExternal\")}\n onClick={onOpenExternal}\n >\n <LaunchIcon className=\"size-[15px]\" />\n </BrowserNodeHeaderButton>\n ) : null}\n {defaultActions ? (\n <div className=\"nodrag flex shrink-0 items-center gap-1.5\">\n {isCold ? (\n <Badge\n className=\"h-[26px] min-w-7 rounded-md text-[10px] font-semibold lowercase tracking-[0.08em]\"\n aria-label={feature.i18n.t(\"coldStatus\")}\n >\n {feature.i18n.t(\"coldStatus\")}\n </Badge>\n ) : null}\n <span\n className=\"contents\"\n onClickCapture={(event) => {\n if (\n !onCloseRequest ||\n !(event.target instanceof Element) ||\n !event.target.closest('[data-workbench-action=\"close\"]')\n ) {\n return;\n }\n onCloseRequest();\n }}\n >\n {defaultActions}\n </span>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction resolveBrowserNodeOpenExternalUrl(\n feature: BrowserNodeFeature,\n state: BrowserNodeControllerState\n): string | null {\n if (!feature.hostApi.openExternal) {\n return null;\n }\n\n const sourceUrl = state.runtime.url?.trim() || state.displayUrl.trim();\n if (sourceUrl.length === 0 || sourceUrl === \"about:blank\") {\n return null;\n }\n\n return feature.resolveOpenExternalUrl(sourceUrl).url;\n}\n\nasync function openBrowserNodeExternal(\n feature: BrowserNodeFeature,\n url: string\n): Promise<void> {\n try {\n await feature.hostApi.openExternal?.({ url });\n } catch (error) {\n feature.reportDiagnostic?.({\n details: {\n error: error instanceof Error ? error.message : String(error),\n url\n },\n event: \"open-external-failed\",\n level: \"warn\"\n });\n }\n}\n\nfunction formatBrowserNodeErrorMessage(\n feature: BrowserNodeFeature,\n error: BrowserNodeRuntimeError\n): string {\n switch (error.code) {\n case \"invalid-url\":\n return feature.i18n.t(\"errors.invalidUrl\", error.params);\n case \"navigation-failed\":\n if (error.params && error.params.statusCode !== undefined) {\n return feature.i18n.t(\n \"errors.navigationFailedWithStatus\",\n error.params\n );\n }\n return feature.i18n.t(\"errors.navigationFailed\", error.params);\n case \"unsupported-protocol\":\n return feature.i18n.t(\"errors.unsupportedProtocol\", error.params);\n case \"unsupported-url\":\n return feature.i18n.t(\"errors.unsupportedUrl\", error.params);\n }\n}\n\nfunction formatBrowserNodeErrorStatus(\n feature: BrowserNodeFeature,\n error: BrowserNodeRuntimeError\n): string | null {\n if (error.code !== \"navigation-failed\" || !error.params) {\n return null;\n }\n\n const statusCode = error.params.statusCode;\n if (typeof statusCode === \"number\") {\n return feature.i18n.t(\"errors.statusCode\", { statusCode });\n }\n\n const errorCode = error.params.errorCode;\n if (typeof errorCode === \"number\") {\n return feature.i18n.t(\"errors.errorCode\", { errorCode });\n }\n\n return null;\n}\n\nfunction BrowserNodeHeaderButton({\n children,\n disabled,\n label,\n onClick\n}: {\n children: ReactNode;\n disabled?: boolean;\n label: string;\n onClick: () => void;\n}) {\n return (\n <Button\n aria-label={label}\n className=\"rounded-md\"\n disabled={disabled}\n size=\"icon-sm\"\n title={label}\n type=\"button\"\n variant=\"chrome\"\n onClick={onClick}\n >\n {children}\n </Button>\n );\n}\n","import { useEffect, useMemo } from \"react\";\nimport { useExternalStoreSnapshot } from \"@tutti-os/ui-react-hooks\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport {\n acquireBrowserNodeController,\n type BrowserNodeControllerState\n} from \"../core/nodeController.ts\";\nimport type {\n BrowserNodeNavigationPolicy,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\n\nexport function useBrowserNodeController(input: {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n syncDefaultUrl?: boolean;\n}) {\n const controller = useMemo(\n () =>\n acquireBrowserNodeController({\n defaultUrl: input.defaultUrl,\n feature: input.feature,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n profileId: input.profileId ?? null,\n sessionMode: input.sessionMode ?? \"shared\",\n sessionPartition: input.sessionPartition,\n syncDefaultUrl: input.syncDefaultUrl ?? false\n }),\n [\n input.defaultUrl,\n input.feature,\n input.navigationPolicy,\n input.nodeId,\n input.profileId,\n input.sessionMode,\n input.sessionPartition,\n input.syncDefaultUrl\n ]\n );\n\n useEffect(() => {\n controller.retain();\n return () => {\n controller.release();\n };\n }, [controller]);\n\n useEffect(() => {\n controller.sync();\n }, [\n controller,\n input.defaultUrl,\n input.feature,\n input.navigationPolicy,\n input.nodeId,\n input.profileId,\n input.sessionMode,\n input.sessionPartition,\n input.syncDefaultUrl\n ]);\n const state = useExternalStoreSnapshot<BrowserNodeControllerState>({\n getSnapshot() {\n return controller.getState();\n },\n subscribe(listener) {\n return controller.subscribe(listener);\n }\n });\n\n return {\n controller,\n state\n };\n}\n","import type { BrowserNodeFeature } from \"./feature.ts\";\nimport {\n normalizeBrowserComparableUrl,\n normalizeHostBrowserComparableUrl\n} from \"./url.ts\";\nimport type {\n BrowserNodeNavigationPolicy,\n BrowserNodeRuntimeState,\n BrowserNodeSessionMode\n} from \"./types.ts\";\n\nexport interface BrowserNodeControllerState {\n displayUrl: string;\n draftUrl: string;\n runtime: BrowserNodeRuntimeState;\n}\n\nexport interface BrowserNodeController {\n getState(): BrowserNodeControllerState;\n goBack(): Promise<void>;\n goForward(): Promise<void>;\n reload(): Promise<void>;\n release(): void;\n retain(): void;\n setDraftUrl(nextUrl: string): void;\n sync(): void;\n subscribe(listener: () => void): () => void;\n submitDraftUrl(): Promise<void>;\n}\n\ninterface BrowserNodeControllerContext {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n syncDefaultUrl: boolean;\n}\n\ninterface BrowserNodeControllerEntry {\n connectedRelease: (() => void) | null;\n controller: BrowserNodeController;\n context: BrowserNodeControllerContext;\n lastColdActivationUrl: string | null;\n listeners: Set<() => void>;\n pendingColdActivationUrl: string | null;\n refCount: number;\n runtimeUnsubscribe: (() => void) | null;\n state: BrowserNodeControllerState;\n}\n\nconst controllerRegistry = new Map<string, BrowserNodeControllerEntry>();\n\nexport function acquireBrowserNodeController(input: {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n syncDefaultUrl?: boolean;\n}): BrowserNodeController {\n const existing = controllerRegistry.get(input.nodeId);\n const entry =\n existing ??\n createBrowserNodeControllerEntry({\n defaultUrl: input.defaultUrl,\n feature: input.feature,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n profileId: input.profileId ?? null,\n sessionMode: input.sessionMode ?? \"shared\",\n sessionPartition: input.sessionPartition,\n syncDefaultUrl: input.syncDefaultUrl ?? false\n });\n\n entry.context = {\n defaultUrl: input.defaultUrl,\n feature: input.feature,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n profileId: input.profileId ?? null,\n sessionMode: input.sessionMode ?? \"shared\",\n sessionPartition: input.sessionPartition,\n syncDefaultUrl: input.syncDefaultUrl ?? false\n };\n\n if (!existing) {\n controllerRegistry.set(input.nodeId, entry);\n }\n\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: false,\n notifyListeners: false\n });\n\n return entry.controller;\n}\n\nfunction createBrowserNodeControllerEntry(\n context: BrowserNodeControllerContext\n): BrowserNodeControllerEntry {\n const runtime = context.feature.runtimeStore.getNodeState(context.nodeId);\n const displayUrl = resolveBrowserNodeDisplayUrl(runtime, context.defaultUrl);\n const entry = {\n connectedRelease: null,\n controller: null as unknown as BrowserNodeController,\n context,\n lastColdActivationUrl: resolveInitialLastColdActivationUrl(\n runtime,\n context.defaultUrl\n ),\n listeners: new Set(),\n pendingColdActivationUrl: null,\n refCount: 0,\n runtimeUnsubscribe: null,\n state: {\n displayUrl,\n draftUrl: displayUrl,\n runtime\n }\n } as BrowserNodeControllerEntry;\n\n entry.controller = {\n getState() {\n return entry.state;\n },\n goBack() {\n return entry.context.feature.hostApi.goBack({\n nodeId: entry.context.nodeId\n });\n },\n goForward() {\n return entry.context.feature.hostApi.goForward({\n nodeId: entry.context.nodeId\n });\n },\n reload() {\n return entry.context.feature.hostApi.reload({\n nodeId: entry.context.nodeId\n });\n },\n release() {\n entry.refCount = Math.max(0, entry.refCount - 1);\n if (entry.refCount > 0) {\n return;\n }\n\n entry.connectedRelease?.();\n entry.connectedRelease = null;\n entry.runtimeUnsubscribe?.();\n entry.runtimeUnsubscribe = null;\n controllerRegistry.delete(entry.context.nodeId);\n },\n retain() {\n entry.refCount += 1;\n if (entry.refCount > 1) {\n return;\n }\n\n if (!controllerRegistry.has(entry.context.nodeId)) {\n controllerRegistry.set(entry.context.nodeId, entry);\n }\n entry.connectedRelease = entry.context.feature.connect();\n entry.runtimeUnsubscribe = entry.context.feature.runtimeStore.subscribe(\n () => {\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: true,\n notifyListeners: true\n });\n }\n );\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: true,\n notifyListeners: true\n });\n },\n setDraftUrl(nextUrl) {\n if (entry.state.draftUrl === nextUrl) {\n return;\n }\n\n entry.state = {\n ...entry.state,\n draftUrl: nextUrl\n };\n notifyBrowserNodeControllerListeners(entry);\n },\n sync() {\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: true,\n notifyListeners: true\n });\n },\n subscribe(listener) {\n entry.listeners.add(listener);\n return () => {\n entry.listeners.delete(listener);\n };\n },\n async submitDraftUrl() {\n const resolved = entry.context.feature.resolveAddressInput(\n entry.state.draftUrl\n );\n if (!resolved.url) {\n return;\n }\n\n if (entry.state.draftUrl !== resolved.url) {\n entry.state = {\n ...entry.state,\n draftUrl: resolved.url\n };\n notifyBrowserNodeControllerListeners(entry);\n }\n\n await entry.context.feature.hostApi.navigate({\n navigationPolicy: entry.context.navigationPolicy,\n nodeId: entry.context.nodeId,\n url: resolved.url\n });\n }\n };\n\n return entry;\n}\n\nfunction resolveInitialLastColdActivationUrl(\n runtime: BrowserNodeRuntimeState,\n defaultUrl: string\n): string | null {\n const trimmedUrl = defaultUrl.trim();\n if (\n runtime.lifecycle === \"cold\" ||\n runtime.error !== null ||\n trimmedUrl.length === 0 ||\n trimmedUrl === \"about:blank\"\n ) {\n return null;\n }\n\n const comparableDefaultUrl = normalizeBrowserComparableUrl(trimmedUrl);\n const comparableRuntimeUrl = runtime.url\n ? normalizeBrowserComparableUrl(runtime.url)\n : null;\n return comparableDefaultUrl !== null &&\n comparableDefaultUrl === comparableRuntimeUrl\n ? trimmedUrl\n : null;\n}\n\nfunction notifyBrowserNodeControllerListeners(\n entry: BrowserNodeControllerEntry\n): void {\n for (const listener of entry.listeners) {\n listener();\n }\n}\n\nfunction resolveBrowserNodeDisplayUrl(\n runtime: BrowserNodeRuntimeState,\n defaultUrl: string\n): string {\n const resolvedRuntimeUrl = runtime.url?.trim() ?? \"\";\n return resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;\n}\n\nfunction reconcileBrowserNodeControllerState(\n entry: BrowserNodeControllerEntry,\n options: {\n allowAutoActivate: boolean;\n notifyListeners: boolean;\n }\n): void {\n const runtime = entry.context.feature.runtimeStore.getNodeState(\n entry.context.nodeId\n );\n const displayUrl = resolveBrowserNodeDisplayUrl(\n runtime,\n entry.context.defaultUrl\n );\n const nextDraftUrl =\n displayUrl !== entry.state.displayUrl ? displayUrl : entry.state.draftUrl;\n\n const changed =\n entry.state.runtime !== runtime ||\n entry.state.displayUrl !== displayUrl ||\n entry.state.draftUrl !== nextDraftUrl;\n\n if (changed) {\n entry.state = {\n displayUrl,\n draftUrl: nextDraftUrl,\n runtime\n };\n if (options.notifyListeners) {\n notifyBrowserNodeControllerListeners(entry);\n }\n }\n\n if (options.allowAutoActivate) {\n void maybeActivateBrowserNodeDefaultUrl(entry).catch(() => undefined);\n }\n}\n\nasync function maybeActivateBrowserNodeDefaultUrl(\n entry: BrowserNodeControllerEntry\n): Promise<void> {\n const {\n defaultUrl,\n feature,\n navigationPolicy,\n nodeId,\n profileId,\n sessionMode,\n sessionPartition,\n syncDefaultUrl\n } = entry.context;\n const trimmedUrl = defaultUrl.trim();\n const comparableDefaultUrl = normalizeHostBrowserComparableUrl(trimmedUrl);\n const comparableRuntimeUrl = entry.state.runtime.url\n ? normalizeHostBrowserComparableUrl(entry.state.runtime.url)\n : null;\n const shouldActivateColdNode = entry.state.runtime.lifecycle === \"cold\";\n const shouldSyncDefaultUrl =\n syncDefaultUrl &&\n entry.state.runtime.lifecycle !== \"cold\" &&\n comparableDefaultUrl !== null &&\n (comparableRuntimeUrl !== comparableDefaultUrl ||\n entry.state.runtime.error !== null) &&\n entry.lastColdActivationUrl !== trimmedUrl;\n if (\n trimmedUrl.length === 0 ||\n trimmedUrl === \"about:blank\" ||\n entry.state.runtime.isLoading ||\n entry.pendingColdActivationUrl === trimmedUrl ||\n (!shouldActivateColdNode && !shouldSyncDefaultUrl) ||\n (shouldActivateColdNode &&\n entry.state.runtime.error !== null &&\n entry.lastColdActivationUrl === trimmedUrl)\n ) {\n return;\n }\n\n entry.pendingColdActivationUrl = trimmedUrl;\n try {\n await feature.hostApi.activate({\n navigationPolicy,\n nodeId,\n profileId,\n sessionMode,\n sessionPartition,\n url: trimmedUrl\n });\n entry.lastColdActivationUrl = trimmedUrl;\n } finally {\n if (entry.pendingColdActivationUrl === trimmedUrl) {\n entry.pendingColdActivationUrl = null;\n }\n }\n}\n","import { useCallback, useEffect, useMemo } from \"react\";\nimport { useExternalStoreSnapshot } from \"@tutti-os/ui-react-hooks\";\nimport {\n acquireBrowserNodeWebviewController,\n type BrowserNodeWebviewContextMenuPoint,\n type BrowserNodeWebviewControllerState\n} from \"../core/webviewController.ts\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeLifecycle,\n BrowserNodeNavigationPolicy,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport type { BrowserNodeWebviewTag } from \"./webviewTag.ts\";\n\nexport function useBrowserNodeWebview({\n feature,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n}: {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n}): {\n devToolsContextMenu: BrowserNodeWebviewContextMenuPoint | null;\n dismissDevToolsContextMenu: () => void;\n openDevToolsFromContextMenu: () => Promise<void>;\n shouldRenderWebview: boolean;\n setWebviewRef: (element: BrowserNodeWebviewTag | null) => void;\n webviewKey: string;\n webviewPartition: string;\n webviewSrc: string;\n} {\n const controller = useMemo(\n () =>\n acquireBrowserNodeWebviewController({\n feature,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n }),\n [\n feature,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n ]\n );\n\n useEffect(() => {\n controller.retain();\n return () => {\n controller.release();\n };\n }, [controller]);\n\n useEffect(() => {\n controller.sync();\n }, [\n controller,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n ]);\n const state = useExternalStoreSnapshot<BrowserNodeWebviewControllerState>({\n getSnapshot() {\n return controller.getState();\n },\n subscribe(listener) {\n return controller.subscribe(listener);\n }\n });\n\n const setWebviewRef = useCallback(\n (element: BrowserNodeWebviewTag | null) => {\n controller.setWebview(element);\n },\n [controller]\n );\n const dismissDevToolsContextMenu = useCallback(() => {\n controller.dismissDevToolsContextMenu();\n }, [controller]);\n const openDevToolsFromContextMenu = useCallback(() => {\n return controller.openDevToolsFromContextMenu();\n }, [controller]);\n\n return {\n devToolsContextMenu: state.devToolsContextMenu,\n dismissDevToolsContextMenu,\n openDevToolsFromContextMenu,\n shouldRenderWebview: state.shouldRenderWebview,\n setWebviewRef,\n webviewKey: state.webviewKey,\n webviewPartition: state.webviewPartition,\n webviewSrc: state.webviewSrc\n };\n}\n","import type { BrowserNodeFeature } from \"./feature.ts\";\nimport { resolveBrowserSessionPartition } from \"./session.ts\";\nimport type {\n BrowserNodeLifecycle,\n BrowserNodeNavigationPolicy,\n BrowserNodeSessionMode\n} from \"./types.ts\";\nimport type { BrowserNodeWebviewTag } from \"../react/webviewTag.ts\";\n\nconst browserGuestUnregisterGraceMs = 250;\nconst browserNodeInitialWebviewSrc = \"about:blank\";\n\nexport interface BrowserNodeWebviewControllerState {\n devToolsContextMenu: BrowserNodeWebviewContextMenuPoint | null;\n shouldRenderWebview: boolean;\n webviewKey: string;\n webviewPartition: string;\n webviewSrc: string;\n}\n\nexport interface BrowserNodeWebviewContextMenuPoint {\n x: number;\n y: number;\n}\n\nexport interface BrowserNodeWebviewController {\n dismissDevToolsContextMenu(): void;\n getState(): BrowserNodeWebviewControllerState;\n openDevToolsFromContextMenu(): Promise<void>;\n release(): void;\n retain(): void;\n setWebview(element: BrowserNodeWebviewTag | null): void;\n sync(): void;\n subscribe(listener: () => void): () => void;\n}\n\ninterface BrowserNodeWebviewControllerContext {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n}\n\ninterface BrowserNodeWebviewControllerEntry {\n attachedListeners: Array<{\n event: string;\n listener: EventListener;\n }>;\n context: BrowserNodeWebviewControllerContext;\n controller: BrowserNodeWebviewController;\n listeners: Set<() => void>;\n refCount: number;\n registeredGuestId: number | null;\n registeringGuestId: number | null;\n state: BrowserNodeWebviewControllerState;\n webview: BrowserNodeWebviewTag | null;\n}\n\nconst webviewControllerRegistry = new Map<\n string,\n BrowserNodeWebviewControllerEntry\n>();\nconst pendingGuestIdsByNodeId = new Map<string, number>();\nconst pendingUnregisterTimersByNodeId = new Map<\n string,\n ReturnType<typeof globalThis.setTimeout>\n>();\n\nexport function acquireBrowserNodeWebviewController(input: {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n}): BrowserNodeWebviewController {\n const existing = webviewControllerRegistry.get(input.nodeId);\n const entry =\n existing ??\n createBrowserNodeWebviewControllerEntry({\n feature: input.feature,\n initialUrl: input.initialUrl,\n lifecycle: input.lifecycle,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n onGuestInteraction: input.onGuestInteraction,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n });\n\n entry.context = {\n feature: input.feature,\n initialUrl: input.initialUrl,\n lifecycle: input.lifecycle,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n onGuestInteraction: input.onGuestInteraction,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n };\n if (!existing) {\n webviewControllerRegistry.set(input.nodeId, entry);\n }\n return entry.controller;\n}\n\nfunction createBrowserNodeWebviewControllerEntry(\n context: BrowserNodeWebviewControllerContext\n): BrowserNodeWebviewControllerEntry {\n const state = resolveBrowserNodeWebviewControllerState(context);\n const entry = {\n attachedListeners: [],\n context,\n controller: null as unknown as BrowserNodeWebviewController,\n listeners: new Set(),\n refCount: 0,\n registeredGuestId: null,\n registeringGuestId: null,\n state,\n webview: null\n } as BrowserNodeWebviewControllerEntry;\n\n entry.controller = {\n dismissDevToolsContextMenu() {\n setBrowserNodeDevToolsContextMenu(entry, null);\n },\n getState() {\n return entry.state;\n },\n async openDevToolsFromContextMenu() {\n setBrowserNodeDevToolsContextMenu(entry, null);\n try {\n await entry.context.feature.hostApi.openDevTools?.({\n nodeId: entry.context.nodeId\n });\n } catch (error) {\n reportBrowserNodeWebviewDiagnostic(\n entry,\n \"devtools.open.failed\",\n {\n error: error instanceof Error ? error.message : String(error),\n webContentsId: readBrowserNodeWebContentsId(entry.webview),\n webviewPartition: entry.state.webviewPartition\n },\n \"warn\"\n );\n throw error;\n }\n },\n release() {\n entry.refCount = Math.max(0, entry.refCount - 1);\n if (entry.refCount > 0) {\n return;\n }\n scheduleBrowserNodeGuestUnregister(entry);\n detachBrowserNodeWebview(entry);\n webviewControllerRegistry.delete(entry.context.nodeId);\n },\n retain() {\n entry.refCount += 1;\n if (entry.refCount > 1) {\n return;\n }\n reconcileBrowserNodeWebviewControllerState(entry, {\n allowHostEffects: true,\n notifyListeners: true,\n rebindWebview: true\n });\n },\n setWebview(element) {\n if (entry.webview === element) {\n return;\n }\n detachBrowserNodeWebview(entry);\n entry.webview = element;\n attachBrowserNodeWebview(entry);\n },\n sync() {\n reconcileBrowserNodeWebviewControllerState(entry, {\n allowHostEffects: true,\n notifyListeners: true,\n rebindWebview: true\n });\n },\n subscribe(listener) {\n entry.listeners.add(listener);\n return () => {\n entry.listeners.delete(listener);\n };\n }\n };\n\n return entry;\n}\n\nfunction resolveBrowserNodeWebviewControllerState(\n context: BrowserNodeWebviewControllerContext\n): BrowserNodeWebviewControllerState {\n const webviewPartition = resolveBrowserSessionPartition({\n profileId: context.profileId,\n sessionMode: context.sessionMode,\n sessionPartition: context.sessionPartition\n });\n return {\n devToolsContextMenu: null,\n shouldRenderWebview: context.lifecycle !== \"cold\",\n webviewKey: `${context.nodeId}:${webviewPartition}`,\n webviewPartition,\n webviewSrc: browserNodeInitialWebviewSrc\n };\n}\n\nfunction reconcileBrowserNodeWebviewControllerState(\n entry: BrowserNodeWebviewControllerEntry,\n options: {\n allowHostEffects: boolean;\n notifyListeners: boolean;\n rebindWebview: boolean;\n }\n): void {\n const nextState = resolveBrowserNodeWebviewControllerState(entry.context);\n const changed =\n entry.state.devToolsContextMenu !== nextState.devToolsContextMenu ||\n entry.state.shouldRenderWebview !== nextState.shouldRenderWebview ||\n entry.state.webviewKey !== nextState.webviewKey ||\n entry.state.webviewPartition !== nextState.webviewPartition ||\n entry.state.webviewSrc !== nextState.webviewSrc;\n\n if (options.allowHostEffects) {\n if (entry.context.lifecycle === \"cold\") {\n scheduleBrowserNodeGuestUnregister(entry);\n } else {\n clearPendingBrowserNodeGuestUnregister(entry.context.nodeId);\n void entry.context.feature.hostApi\n .prepareSession({\n navigationPolicy: entry.context.navigationPolicy,\n nodeId: entry.context.nodeId,\n profileId: entry.context.profileId,\n sessionMode: entry.context.sessionMode,\n sessionPartition: entry.context.sessionPartition\n })\n .catch(() => undefined);\n }\n }\n\n if (!changed) {\n if (\n options.rebindWebview &&\n entry.webview &&\n entry.attachedListeners.length === 0\n ) {\n attachBrowserNodeWebview(entry);\n }\n return;\n }\n\n entry.state = nextState;\n detachBrowserNodeWebview(entry);\n attachBrowserNodeWebview(entry);\n if (options.notifyListeners) {\n notifyBrowserNodeWebviewControllerListeners(entry);\n }\n}\n\nfunction setBrowserNodeDevToolsContextMenu(\n entry: BrowserNodeWebviewControllerEntry,\n devToolsContextMenu: BrowserNodeWebviewContextMenuPoint | null\n): void {\n if (\n entry.state.devToolsContextMenu?.x === devToolsContextMenu?.x &&\n entry.state.devToolsContextMenu?.y === devToolsContextMenu?.y\n ) {\n return;\n }\n entry.state = {\n ...entry.state,\n devToolsContextMenu\n };\n notifyBrowserNodeWebviewControllerListeners(entry);\n}\n\nfunction notifyBrowserNodeWebviewControllerListeners(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n for (const listener of entry.listeners) {\n listener();\n }\n}\n\nfunction clearPendingBrowserNodeGuestUnregister(nodeId: string): void {\n const timerId = pendingUnregisterTimersByNodeId.get(nodeId);\n if (timerId !== undefined) {\n globalThis.clearTimeout(timerId);\n pendingUnregisterTimersByNodeId.delete(nodeId);\n }\n pendingGuestIdsByNodeId.delete(nodeId);\n}\n\nfunction scheduleBrowserNodeGuestUnregister(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n const guestId = entry.registeredGuestId;\n const nodeId = entry.context.nodeId;\n entry.registeringGuestId = null;\n if (guestId === null) {\n clearPendingBrowserNodeGuestUnregister(nodeId);\n return;\n }\n\n entry.registeredGuestId = null;\n clearPendingBrowserNodeGuestUnregister(nodeId);\n pendingGuestIdsByNodeId.set(nodeId, guestId);\n const timerId = globalThis.setTimeout(() => {\n pendingUnregisterTimersByNodeId.delete(nodeId);\n const pendingGuestId = pendingGuestIdsByNodeId.get(nodeId);\n pendingGuestIdsByNodeId.delete(nodeId);\n if (\n typeof pendingGuestId !== \"number\" ||\n !Number.isFinite(pendingGuestId)\n ) {\n return;\n }\n\n void entry.context.feature.hostApi\n .unregisterGuest({\n nodeId: entry.context.nodeId,\n webContentsId: pendingGuestId\n })\n .catch(() => undefined);\n }, browserGuestUnregisterGraceMs);\n pendingUnregisterTimersByNodeId.set(nodeId, timerId);\n}\n\nfunction detachBrowserNodeWebview(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n if (!entry.webview) {\n entry.attachedListeners = [];\n return;\n }\n for (const record of entry.attachedListeners) {\n entry.webview.removeEventListener(record.event, record.listener);\n }\n entry.attachedListeners = [];\n}\n\nfunction attachBrowserNodeWebview(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n const webview = entry.webview;\n if (!webview || !entry.state.shouldRenderWebview) {\n return;\n }\n\n const registerGuest = async (): Promise<void> => {\n const guestId = webview.getWebContentsId?.();\n if (\n typeof guestId !== \"number\" ||\n !Number.isFinite(guestId) ||\n guestId <= 0 ||\n entry.registeredGuestId === guestId ||\n entry.registeringGuestId === guestId\n ) {\n return;\n }\n\n clearPendingBrowserNodeGuestUnregister(entry.context.nodeId);\n entry.registeringGuestId = guestId;\n try {\n await entry.context.feature.hostApi.registerGuest({\n navigationPolicy: entry.context.navigationPolicy,\n nodeId: entry.context.nodeId,\n profileId: entry.context.profileId,\n sessionMode: entry.context.sessionMode,\n sessionPartition: entry.context.sessionPartition,\n webContentsId: guestId\n });\n entry.registeredGuestId = guestId;\n } finally {\n if (entry.registeringGuestId === guestId) {\n entry.registeringGuestId = null;\n }\n }\n };\n\n const handleDidAttach: EventListener = () => {\n void registerGuest().catch(() => undefined);\n };\n const handleDomReady: EventListener = () => {\n void registerGuest().catch(() => undefined);\n };\n const handleGuestInteraction: EventListener = () => {\n entry.context.onGuestInteraction?.();\n };\n const handleDevToolsContextMenu: EventListener = (event) => {\n const hasNativeContextMenu =\n entry.context.feature.hostApi.showDevToolsContextMenu !== undefined;\n const hasInlineContextMenu =\n entry.context.feature.hostApi.openDevTools !== undefined;\n if (!hasNativeContextMenu && !hasInlineContextMenu) {\n return;\n }\n event.preventDefault();\n const point = resolveBrowserNodeContextMenuPoint(event, webview);\n if (hasNativeContextMenu) {\n void entry.context.feature.hostApi\n .showDevToolsContextMenu?.({\n label: entry.context.feature.i18n.t(\"actions.openDevTools\"),\n nodeId: entry.context.nodeId,\n point\n })\n .catch((error: unknown) => {\n reportBrowserNodeWebviewDiagnostic(\n entry,\n \"devtools.native-context-menu.failed\",\n {\n error: error instanceof Error ? error.message : String(error),\n webContentsId: readBrowserNodeWebContentsId(webview),\n webviewPartition: entry.state.webviewPartition\n },\n \"warn\"\n );\n });\n return;\n }\n setBrowserNodeDevToolsContextMenu(entry, point);\n };\n\n const records = [\n { event: \"did-attach\", listener: handleDidAttach },\n { event: \"dom-ready\", listener: handleDomReady },\n { event: \"context-menu\", listener: handleDevToolsContextMenu },\n { event: \"contextmenu\", listener: handleDevToolsContextMenu },\n { event: \"focus\", listener: handleGuestInteraction },\n { event: \"ipc-message\", listener: handleGuestInteraction }\n ];\n for (const record of records) {\n webview.addEventListener(record.event, record.listener);\n }\n entry.attachedListeners = records;\n}\n\nfunction resolveBrowserNodeContextMenuPoint(\n event: Event,\n webview: BrowserNodeWebviewTag\n): BrowserNodeWebviewContextMenuPoint {\n const eventWithPoint = event as Event & {\n clientX?: unknown;\n clientY?: unknown;\n params?: { x?: unknown; y?: unknown };\n };\n const clientX = readFiniteNumber(eventWithPoint.clientX);\n const clientY = readFiniteNumber(eventWithPoint.clientY);\n if (clientX !== null && clientY !== null) {\n return { x: clientX, y: clientY };\n }\n\n const paramX = readFiniteNumber(eventWithPoint.params?.x);\n const paramY = readFiniteNumber(eventWithPoint.params?.y);\n if (paramX !== null && paramY !== null) {\n return { x: paramX, y: paramY };\n }\n\n const rect = webview.getBoundingClientRect();\n return {\n x: rect.left,\n y: rect.top\n };\n}\n\nfunction readFiniteNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction readBrowserNodeWebContentsId(\n webview: BrowserNodeWebviewTag | null\n): number | null {\n const webContentsId = webview?.getWebContentsId?.();\n return typeof webContentsId === \"number\" && Number.isFinite(webContentsId)\n ? webContentsId\n : null;\n}\n\nfunction reportBrowserNodeWebviewDiagnostic(\n entry: BrowserNodeWebviewControllerEntry,\n event: string,\n details: Record<string, unknown>,\n level: \"debug\" | \"info\" | \"warn\" | \"error\" = \"info\"\n): void {\n entry.context.feature.reportDiagnostic?.({\n details: {\n ...details,\n nodeId: entry.context.nodeId\n },\n event,\n level\n });\n}\n"],"mappings":"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","names":["useEffect","useEffect","useMemo","useExternalStoreSnapshot","useMemo","useEffect","useExternalStoreSnapshot","useEffect"]}
|
|
@@ -57,6 +57,9 @@ function normalizeBrowserComparableUrl(rawUrl) {
|
|
|
57
57
|
const resolved = resolveBrowserNavigationUrl(rawUrl);
|
|
58
58
|
return resolved.errorCode === null ? resolved.url : null;
|
|
59
59
|
}
|
|
60
|
+
function resolveBrowserOpenExternalUrl(rawUrl) {
|
|
61
|
+
return resolveHostBrowserNavigationUrl(rawUrl);
|
|
62
|
+
}
|
|
60
63
|
function resolveHostBrowserNavigationUrl(rawUrl) {
|
|
61
64
|
const trimmed = rawUrl.trim();
|
|
62
65
|
if (trimmed.length === 0) {
|
|
@@ -87,7 +90,8 @@ export {
|
|
|
87
90
|
resolveBrowserNavigationUrl,
|
|
88
91
|
resolveBrowserAddressInput,
|
|
89
92
|
normalizeBrowserComparableUrl,
|
|
93
|
+
resolveBrowserOpenExternalUrl,
|
|
90
94
|
resolveHostBrowserNavigationUrl,
|
|
91
95
|
normalizeHostBrowserComparableUrl
|
|
92
96
|
};
|
|
93
|
-
//# sourceMappingURL=chunk-
|
|
97
|
+
//# sourceMappingURL=chunk-ZRH4UQZB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/url.ts"],"sourcesContent":["const allowedBrowserProtocols = new Set([\"http:\", \"https:\"]);\nconst likelyHostPattern =\n /^(localhost|(\\d{1,3}\\.){3}\\d{1,3}|(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,})(?::\\d{1,5})?(?:[/?#][^\\s]*)?$/i;\nconst explicitProtocolPattern = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//;\nconst loopbackHostPattern =\n /^(localhost|127(?:\\.\\d{1,3}){3})(?::\\d{1,5})?(?:[/?#][^\\s]*)?$/i;\n\nfunction defaultSchemeForHostInput(value: string): \"http\" | \"https\" {\n return loopbackHostPattern.test(value) ? \"http\" : \"https\";\n}\n\nexport type BrowserNavigationUrlErrorCode =\n | \"invalid-url\"\n | \"unsupported-protocol\";\n\nexport interface BrowserNavigationUrlResolution {\n errorCode: BrowserNavigationUrlErrorCode | null;\n errorParams?: Record<string, string>;\n url: string | null;\n}\n\nexport type BrowserSearchUrlResolver = (query: string) => string | null;\n\nexport function resolveBrowserNavigationUrl(\n rawUrl: string\n): BrowserNavigationUrlResolution {\n const trimmed = rawUrl.trim();\n if (trimmed.length === 0) {\n return { errorCode: null, url: null };\n }\n\n if (explicitProtocolPattern.test(trimmed)) {\n try {\n const parsed = new URL(trimmed);\n if (!allowedBrowserProtocols.has(parsed.protocol)) {\n return {\n errorCode: \"unsupported-protocol\",\n errorParams: { protocol: parsed.protocol },\n url: null\n };\n }\n\n return { errorCode: null, url: parsed.toString() };\n } catch {\n return { errorCode: \"invalid-url\", url: null };\n }\n }\n\n if (!likelyHostPattern.test(trimmed)) {\n return { errorCode: \"invalid-url\", url: null };\n }\n\n try {\n const parsed = new URL(\n `${defaultSchemeForHostInput(trimmed)}://${trimmed}`\n );\n return { errorCode: null, url: parsed.toString() };\n } catch {\n return { errorCode: \"invalid-url\", url: null };\n }\n}\n\nexport type BrowserAddressInputResolution = BrowserNavigationUrlResolution;\n\nexport function resolveBrowserAddressInput(\n rawInput: string,\n options: {\n resolveSearchUrl?: BrowserSearchUrlResolver;\n } = {}\n): BrowserAddressInputResolution {\n const trimmed = rawInput.trim();\n if (trimmed.length === 0) {\n return { errorCode: null, url: null };\n }\n\n const navigation = resolveBrowserNavigationUrl(trimmed);\n if (navigation.url) {\n return navigation;\n }\n\n const searchUrl = options.resolveSearchUrl?.(trimmed);\n if (!searchUrl) {\n return navigation;\n }\n\n return resolveBrowserNavigationUrl(searchUrl);\n}\n\nexport function normalizeBrowserComparableUrl(rawUrl: string): string | null {\n const resolved = resolveBrowserNavigationUrl(rawUrl);\n return resolved.errorCode === null ? resolved.url : null;\n}\n\nexport function resolveBrowserOpenExternalUrl(\n rawUrl: string\n): BrowserNavigationUrlResolution {\n return resolveHostBrowserNavigationUrl(rawUrl);\n}\n\nexport function resolveHostBrowserNavigationUrl(\n rawUrl: string\n): BrowserNavigationUrlResolution {\n const trimmed = rawUrl.trim();\n if (trimmed.length === 0) {\n return { errorCode: null, url: null };\n }\n\n if (trimmed.startsWith(\"file://\")) {\n try {\n return { errorCode: null, url: new URL(trimmed).toString() };\n } catch {\n return { errorCode: \"invalid-url\", url: null };\n }\n }\n\n return resolveBrowserNavigationUrl(trimmed);\n}\n\nexport function normalizeHostBrowserComparableUrl(\n rawUrl: string\n): string | null {\n const trimmed = rawUrl.trim();\n if (trimmed.startsWith(\"file://\")) {\n try {\n return new URL(trimmed).toString();\n } catch {\n return null;\n }\n }\n\n return normalizeBrowserComparableUrl(trimmed);\n}\n"],"mappings":";AAAA,IAAM,0BAA0B,oBAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;AAC3D,IAAM,oBACJ;AACF,IAAM,0BAA0B;AAChC,IAAM,sBACJ;AAEF,SAAS,0BAA0B,OAAiC;AAClE,SAAO,oBAAoB,KAAK,KAAK,IAAI,SAAS;AACpD;AAcO,SAAS,4BACd,QACgC;AAChC,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,WAAW,MAAM,KAAK,KAAK;AAAA,EACtC;AAEA,MAAI,wBAAwB,KAAK,OAAO,GAAG;AACzC,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,OAAO;AAC9B,UAAI,CAAC,wBAAwB,IAAI,OAAO,QAAQ,GAAG;AACjD,eAAO;AAAA,UACL,WAAW;AAAA,UACX,aAAa,EAAE,UAAU,OAAO,SAAS;AAAA,UACzC,KAAK;AAAA,QACP;AAAA,MACF;AAEA,aAAO,EAAE,WAAW,MAAM,KAAK,OAAO,SAAS,EAAE;AAAA,IACnD,QAAQ;AACN,aAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,CAAC,kBAAkB,KAAK,OAAO,GAAG;AACpC,WAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,EAC/C;AAEA,MAAI;AACF,UAAM,SAAS,IAAI;AAAA,MACjB,GAAG,0BAA0B,OAAO,CAAC,MAAM,OAAO;AAAA,IACpD;AACA,WAAO,EAAE,WAAW,MAAM,KAAK,OAAO,SAAS,EAAE;AAAA,EACnD,QAAQ;AACN,WAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,EAC/C;AACF;AAIO,SAAS,2BACd,UACA,UAEI,CAAC,GAC0B;AAC/B,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,WAAW,MAAM,KAAK,KAAK;AAAA,EACtC;AAEA,QAAM,aAAa,4BAA4B,OAAO;AACtD,MAAI,WAAW,KAAK;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,QAAQ,mBAAmB,OAAO;AACpD,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SAAO,4BAA4B,SAAS;AAC9C;AAEO,SAAS,8BAA8B,QAA+B;AAC3E,QAAM,WAAW,4BAA4B,MAAM;AACnD,SAAO,SAAS,cAAc,OAAO,SAAS,MAAM;AACtD;AAEO,SAAS,8BACd,QACgC;AAChC,SAAO,gCAAgC,MAAM;AAC/C;AAEO,SAAS,gCACd,QACgC;AAChC,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,WAAW,MAAM,KAAK,KAAK;AAAA,EACtC;AAEA,MAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,QAAI;AACF,aAAO,EAAE,WAAW,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,SAAS,EAAE;AAAA,IAC7D,QAAQ;AACN,aAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO,4BAA4B,OAAO;AAC5C;AAEO,SAAS,kCACd,QACe;AACf,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,QAAI;AACF,aAAO,IAAI,IAAI,OAAO,EAAE,SAAS;AAAA,IACnC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,8BAA8B,OAAO;AAC9C;","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
normalizeHostBrowserComparableUrl,
|
|
7
7
|
resolveBrowserNavigationUrl,
|
|
8
8
|
resolveHostBrowserNavigationUrl
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-ZRH4UQZB.js";
|
|
10
10
|
|
|
11
11
|
// src/electron-main/loopbackPreviewProxy.ts
|
|
12
12
|
import {
|
|
@@ -953,7 +953,7 @@ function createBrowserGuestManager({
|
|
|
953
953
|
await loadDesiredUrl(session);
|
|
954
954
|
},
|
|
955
955
|
async openExternal(input) {
|
|
956
|
-
const resolved =
|
|
956
|
+
const resolved = resolveHostBrowserNavigationUrl(input.url);
|
|
957
957
|
if (!resolved.url) {
|
|
958
958
|
throw new Error("Browser Node rejected external URL");
|
|
959
959
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/electron-main/loopbackPreviewProxy.ts","../../src/electron-main/guestManager.ts","../../src/electron-main/registerElectronMain.ts","../../src/electron-main/userAgent.ts","../../src/electron-main/webviewSecurity.ts"],"sourcesContent":["import {\n createServer,\n request as httpRequest,\n type IncomingHttpHeaders,\n type IncomingMessage,\n type Server,\n type ServerResponse\n} from \"node:http\";\nimport { request as httpsRequest } from \"node:https\";\nimport type { Socket } from \"node:net\";\nimport { pipeline } from \"node:stream\";\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport type { RawData } from \"ws\";\nimport type { BrowserNodeSessionMode } from \"../core/types.ts\";\nimport type {\n BrowserNodeLoopbackPreviewRoutingOptions,\n BrowserNodeLoopbackPreviewTarget\n} from \"./loopbackPreview.ts\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nconst defaultLoopbackPreviewCacheTtlMs = 30_000;\nconst loopbackHostPattern = /^(localhost|127(?:\\.\\d{1,3}){0,3})$/i;\n// Order matters: bypass all, subtract loopback so local previews can proxy,\n// then keep HTTPS/WSS direct because this proxy does not implement CONNECT.\nconst loopbackPreviewProxyBypassRules = \"*;<-loopback>;https://*;wss://*\";\nconst hopByHopHeaders = new Set([\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\"\n]);\n\ninterface CachedLoopbackPreviewTarget {\n expiresAt: number;\n target: BrowserNodeLoopbackPreviewTarget | null;\n}\n\nexport interface BrowserNodePreviewSession {\n setProxy(input: {\n mode: \"fixed_servers\";\n proxyBypassRules: string;\n proxyRules: string;\n }): Promise<void>;\n}\n\nexport interface BrowserNodeLoopbackPreviewProxy {\n configureSession(input: {\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n }): Promise<void>;\n dispose(): Promise<void>;\n addressForTesting(): string;\n serverForTesting(): Server;\n}\n\nexport interface BrowserNodeLoopbackPreviewProxyInput {\n logger?: BrowserNodeElectronLogger;\n resolveSession: (input: {\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n }) => BrowserNodePreviewSession | Promise<BrowserNodePreviewSession>;\n routing: BrowserNodeLoopbackPreviewRoutingOptions;\n}\n\nexport function createBrowserNodeLoopbackPreviewProxy({\n logger,\n resolveSession,\n routing\n}: BrowserNodeLoopbackPreviewProxyInput): BrowserNodeLoopbackPreviewProxy {\n const configuredSessions = new WeakSet<BrowserNodePreviewSession>();\n const targetCache = new Map<string, CachedLoopbackPreviewTarget>();\n const downstreamWebSocketServer = new WebSocketServer({ noServer: true });\n let server: Server | null = null;\n let serverStartPromise: Promise<string> | null = null;\n\n const cacheTtlMs = routing.cacheTtlMs ?? defaultLoopbackPreviewCacheTtlMs;\n const fallback = routing.fallback ?? \"direct\";\n\n const pruneExpiredTargets = (now: number): void => {\n for (const [cacheKey, cachedTarget] of targetCache.entries()) {\n if (cachedTarget.expiresAt <= now) {\n targetCache.delete(cacheKey);\n }\n }\n };\n\n const start = async (): Promise<string> => {\n if (server?.listening) {\n return addressForTesting();\n }\n if (serverStartPromise) {\n return serverStartPromise;\n }\n\n serverStartPromise = new Promise<string>((resolve, reject) => {\n const nextServer = createServer((request, response) => {\n void handleRequest(request, response);\n });\n nextServer.on(\"upgrade\", (request, socket, head) => {\n void handleUpgrade(request, socket as Socket, head);\n });\n\n const cleanup = (): void => {\n nextServer.removeListener(\"error\", onError);\n nextServer.removeListener(\"listening\", onListening);\n };\n const onError = (error: Error): void => {\n cleanup();\n reject(error);\n };\n const onListening = (): void => {\n cleanup();\n server = nextServer;\n resolve(addressForTesting());\n };\n\n nextServer.once(\"error\", onError);\n nextServer.once(\"listening\", onListening);\n nextServer.listen(0, \"127.0.0.1\");\n }).finally(() => {\n serverStartPromise = null;\n });\n\n return serverStartPromise;\n };\n\n const resolveLoopbackTarget = async (\n originalUrl: URL\n ): Promise<BrowserNodeLoopbackPreviewTarget | null> => {\n const port = Number(originalUrl.port);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n return null;\n }\n\n const now = Date.now();\n pruneExpiredTargets(now);\n\n const cacheKey = originalUrl.toString();\n const cached = targetCache.get(cacheKey);\n if (cached && cached.expiresAt > now) {\n return cached.target;\n }\n\n const nextTarget = await Promise.resolve(\n routing.resolver.resolveTarget({\n port,\n url: originalUrl.toString()\n })\n );\n\n const target = normalizeLoopbackPreviewTarget(nextTarget);\n targetCache.set(cacheKey, {\n expiresAt: now + Math.max(0, cacheTtlMs),\n target\n });\n return target;\n };\n\n const configureSession = async (input: {\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n }): Promise<void> => {\n const nextSession = await resolveSession(input);\n if (configuredSessions.has(nextSession)) {\n return;\n }\n const address = await start();\n await nextSession.setProxy({\n mode: \"fixed_servers\",\n proxyBypassRules: loopbackPreviewProxyBypassRules,\n proxyRules: `http=${address}`\n });\n configuredSessions.add(nextSession);\n };\n\n const dispose = async (): Promise<void> => {\n targetCache.clear();\n downstreamWebSocketServer.close();\n const activeServer = server;\n server = null;\n if (!activeServer || !activeServer.listening) {\n return;\n }\n await new Promise<void>((resolve) => {\n activeServer.close(() => resolve());\n });\n };\n\n const handleRequest = async (\n request: IncomingMessage,\n response: ServerResponse\n ): Promise<void> => {\n const originalUrl = resolveProxyRequestUrl(request);\n if (!originalUrl) {\n response.writeHead(400);\n response.end(\"invalid proxy request\");\n return;\n }\n if (originalUrl.protocol !== \"http:\") {\n response.writeHead(400);\n response.end(\"unsupported proxy request\");\n return;\n }\n\n const targetContext = await resolveTargetRequestContext(originalUrl);\n if (!targetContext.targetUrl) {\n response.writeHead(502);\n response.end(\"unable to resolve loopback preview target\");\n return;\n }\n\n const headers = filterProxyHeaders(request.headers);\n headers.set(\"host\", targetContext.targetUrl.host);\n\n const forward =\n targetContext.targetUrl.protocol === \"https:\"\n ? httpsRequest\n : httpRequest;\n const upstream = forward(\n targetContext.targetUrl,\n {\n headers: Object.fromEntries(headers.entries()),\n method: request.method\n },\n (upstreamResponse) => {\n const responseHeaders = filterProxyHeaders(upstreamResponse.headers);\n const location = responseHeaders.get(\"location\");\n if (location && targetContext.loopbackTarget) {\n const rewritten = rewriteLoopbackLocation({\n location,\n originalUrl,\n targetUrl: targetContext.loopbackTarget.targetUrl\n });\n if (rewritten) {\n responseHeaders.set(\"location\", rewritten);\n }\n }\n\n response.writeHead(\n upstreamResponse.statusCode ?? 502,\n upstreamResponse.statusMessage,\n Object.fromEntries(responseHeaders.entries())\n );\n pipeline(upstreamResponse, response, () => undefined);\n }\n );\n\n upstream.on(\"error\", (error) => {\n logger?.warn?.(\"Browser Node loopback preview request failed\", {\n error: normalizeProxyError(error),\n originalUrl: originalUrl.toString(),\n targetUrl: targetContext.targetUrl?.toString() ?? null,\n workspaceId: targetContext.loopbackTarget?.workspaceId ?? null\n });\n if (!response.headersSent) {\n response.writeHead(502);\n }\n response.end(\n `loopback preview upstream request failed: ${normalizeProxyError(error)}`\n );\n });\n\n pipeline(request, upstream, () => undefined);\n };\n\n const handleUpgrade = async (\n request: IncomingMessage,\n socket: Socket,\n head: Buffer\n ): Promise<void> => {\n const originalUrl = resolveProxyRequestUrl(request, \"ws:\");\n if (!originalUrl) {\n socket.destroy();\n return;\n }\n if (originalUrl.protocol !== \"ws:\") {\n socket.destroy();\n return;\n }\n\n const targetContext = await resolveTargetRequestContext(originalUrl);\n const targetUrl = targetContext.targetUrl;\n if (!targetUrl) {\n socket.destroy();\n return;\n }\n\n downstreamWebSocketServer.handleUpgrade(\n request,\n socket,\n head,\n (downstream) => {\n const headers = Object.fromEntries(\n filterProxyHeaders(request.headers).entries()\n );\n headers.host = targetUrl.host;\n\n const upstream = new WebSocket(targetUrl, { headers });\n const pendingMessages: Array<{ data: RawData; isBinary: boolean }> = [];\n\n downstream.on(\"message\", (data, isBinary) => {\n if (upstream.readyState === WebSocket.OPEN) {\n upstream.send(data, { binary: isBinary });\n return;\n }\n pendingMessages.push({ data, isBinary });\n });\n\n upstream.once(\"open\", () => {\n for (const nextMessage of pendingMessages.splice(0)) {\n upstream.send(nextMessage.data, { binary: nextMessage.isBinary });\n }\n });\n\n upstream.on(\"message\", (data, isBinary) => {\n if (downstream.readyState === WebSocket.OPEN) {\n downstream.send(data, { binary: isBinary });\n }\n });\n\n upstream.once(\"close\", (code, reason) => {\n if (\n downstream.readyState === WebSocket.OPEN ||\n downstream.readyState === WebSocket.CONNECTING\n ) {\n downstream.close(normalizeWebSocketCloseCode(code), reason);\n }\n });\n\n downstream.once(\"close\", (code, reason) => {\n if (\n upstream.readyState === WebSocket.OPEN ||\n upstream.readyState === WebSocket.CONNECTING\n ) {\n upstream.close(normalizeWebSocketCloseCode(code), reason);\n }\n });\n\n upstream.once(\"error\", (error) => {\n logger?.warn?.(\"Browser Node loopback preview websocket failed\", {\n error: normalizeProxyError(error),\n originalUrl: originalUrl.toString(),\n targetUrl: targetContext.targetUrl?.toString() ?? null,\n workspaceId: targetContext.loopbackTarget?.workspaceId ?? null\n });\n downstream.close(1011, \"loopback preview websocket upstream failed\");\n });\n }\n );\n };\n\n const resolveTargetRequestContext = async (\n originalUrl: URL\n ): Promise<{\n loopbackTarget: BrowserNodeLoopbackPreviewTarget | null;\n targetUrl: URL | null;\n }> => {\n if (!isLoopbackUrl(originalUrl)) {\n return {\n loopbackTarget: null,\n targetUrl: null\n };\n }\n\n const loopbackTarget = await resolveLoopbackTarget(originalUrl);\n if (loopbackTarget) {\n return {\n loopbackTarget,\n targetUrl: buildTargetRequestUrl(loopbackTarget.targetUrl, originalUrl)\n };\n }\n\n if (fallback === \"direct\") {\n return {\n loopbackTarget: null,\n targetUrl: cloneUrl(originalUrl)\n };\n }\n\n return {\n loopbackTarget: null,\n targetUrl: null\n };\n };\n\n const addressForTesting = (): string => {\n const address = server?.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Browser Node loopback preview proxy is not listening\");\n }\n return `127.0.0.1:${address.port}`;\n };\n\n const serverForTesting = (): Server => {\n if (!server) {\n throw new Error(\"Browser Node loopback preview proxy is not started\");\n }\n return server;\n };\n\n return {\n addressForTesting,\n configureSession,\n dispose,\n serverForTesting\n };\n}\n\nfunction normalizeLoopbackPreviewTarget(\n input: BrowserNodeLoopbackPreviewTarget | null | undefined\n): BrowserNodeLoopbackPreviewTarget | null {\n if (!input) {\n return null;\n }\n const normalizedTargetUrl = input.targetUrl.trim();\n if (normalizedTargetUrl.length === 0) {\n return null;\n }\n try {\n const parsed = new URL(normalizedTargetUrl);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return null;\n }\n return {\n targetUrl: parsed.toString(),\n workspaceId: input.workspaceId\n };\n } catch {\n return null;\n }\n}\n\nfunction resolveProxyRequestUrl(\n request: IncomingMessage,\n defaultProtocol = \"http:\"\n): URL | null {\n const rawUrl = request.url ?? \"\";\n try {\n if (/^[a-z][a-z\\d+\\-.]*:\\/\\//i.test(rawUrl)) {\n return new URL(rawUrl);\n }\n const host = request.headers.host;\n if (typeof host !== \"string\" || host.trim().length === 0) {\n return null;\n }\n const path = rawUrl.startsWith(\"/\") ? rawUrl : `/${rawUrl}`;\n return new URL(`${defaultProtocol}//${host}${path}`);\n } catch {\n return null;\n }\n}\n\nfunction filterProxyHeaders(input: Headers | IncomingHttpHeaders): Headers {\n const output = new Headers();\n const appendValue = (key: string, value: string): void => {\n if (hopByHopHeaders.has(key.toLowerCase())) {\n return;\n }\n output.append(key, value);\n };\n\n if (input instanceof Headers) {\n input.forEach((value, key) => {\n appendValue(key, value);\n });\n return output;\n }\n\n for (const [key, value] of Object.entries(input)) {\n if (Array.isArray(value)) {\n for (const nextValue of value) {\n appendValue(key, nextValue);\n }\n continue;\n }\n if (typeof value === \"string\") {\n appendValue(key, value);\n }\n }\n return output;\n}\n\nfunction isLoopbackUrl(url: URL): boolean {\n return (\n (url.protocol === \"http:\" || url.protocol === \"ws:\") &&\n loopbackHostPattern.test(url.hostname) &&\n url.port.length > 0\n );\n}\n\nfunction buildTargetRequestUrl(\n targetUrl: string,\n originalUrl: URL\n): URL | null {\n try {\n const base = new URL(targetUrl);\n const normalizedBasePath = normalizeBasePath(base.pathname);\n const nextUrl = new URL(base.toString());\n nextUrl.pathname = joinBasePath(normalizedBasePath, originalUrl.pathname);\n nextUrl.search = originalUrl.search;\n nextUrl.hash = \"\";\n if (originalUrl.protocol === \"ws:\") {\n nextUrl.protocol = nextUrl.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n }\n return nextUrl;\n } catch {\n return null;\n }\n}\n\nfunction rewriteLoopbackLocation({\n location,\n originalUrl,\n targetUrl\n}: {\n location: string;\n originalUrl: URL;\n targetUrl: string;\n}): string | null {\n try {\n const targetBase = new URL(targetUrl);\n const resolvedLocation = new URL(location, targetBase);\n if (resolvedLocation.origin !== targetBase.origin) {\n return location;\n }\n\n const basePath = normalizeBasePath(targetBase.pathname);\n const strippedPath =\n stripBasePath(basePath, resolvedLocation.pathname) ??\n resolvedLocation.pathname;\n\n const loopbackUrl = new URL(originalUrl.origin);\n resolvedLocation.protocol = loopbackUrl.protocol;\n resolvedLocation.host = loopbackUrl.host;\n resolvedLocation.pathname = strippedPath;\n resolvedLocation.username = \"\";\n resolvedLocation.password = \"\";\n return resolvedLocation.toString();\n } catch {\n return location;\n }\n}\n\nfunction normalizeBasePath(pathname: string): string {\n const normalized = pathname.startsWith(\"/\") ? pathname : `/${pathname}`;\n return normalized.endsWith(\"/\") ? normalized : `${normalized}/`;\n}\n\nfunction joinBasePath(basePath: string, requestPath: string): string {\n const normalizedRequestPath =\n requestPath === \"/\" ? \"\" : requestPath.replace(/^\\/+/, \"\");\n return normalizedRequestPath.length > 0\n ? `${basePath}${normalizedRequestPath}`.replace(/\\/{2,}/g, \"/\")\n : basePath;\n}\n\nfunction stripBasePath(basePath: string, pathname: string): string | null {\n const normalizedPath = pathname.startsWith(\"/\") ? pathname : `/${pathname}`;\n if (normalizedPath === basePath.slice(0, -1)) {\n return \"/\";\n }\n if (!normalizedPath.startsWith(basePath)) {\n return null;\n }\n const suffix = normalizedPath.slice(basePath.length);\n return suffix.length > 0 ? `/${suffix}` : \"/\";\n}\n\nfunction cloneUrl(url: URL): URL | null {\n try {\n return new URL(url.toString());\n } catch {\n return null;\n }\n}\n\nfunction normalizeProxyError(error: unknown): string {\n if (error instanceof Error) {\n const code =\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ? ` ${(error as NodeJS.ErrnoException).code}`\n : \"\";\n return `${error.message}${code}`;\n }\n return String(error);\n}\n\nfunction normalizeWebSocketCloseCode(code: number): number {\n if (code === 1000 || (code >= 3000 && code <= 4999)) {\n return code;\n }\n return 1000;\n}\n","import type {\n BrowserNodeLifecycle,\n BrowserNodeNavigationPolicy,\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport {\n normalizeHostBrowserComparableUrl,\n resolveBrowserNavigationUrl,\n resolveHostBrowserNavigationUrl,\n type BrowserNavigationUrlResolution\n} from \"../core/url.ts\";\nimport type {\n BrowserGuestManager,\n BrowserGuestManagerInput,\n BrowserGuestNativeImage,\n BrowserPreferredColorScheme,\n BrowserGuestWebContents\n} from \"./types.ts\";\n\nconst browserPreviewMaxWidth = 260;\nconst browserPreviewMaxHeight = 170;\nconst abortedNavigationErrorCode = -3;\n\ninterface BrowserGuestSession {\n appliedColorScheme: BrowserPreferredColorScheme | null;\n contents: BrowserGuestWebContents | null;\n desiredUrl: string;\n lifecycle: BrowserNodeLifecycle;\n listeners: Array<{\n event: string;\n listener: (...args: unknown[]) => void;\n }>;\n navigationFailureSequence: number;\n navigationPolicy: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition: string | null;\n webContentsId: number | null;\n}\n\nfunction canGuestGoBack(contents: BrowserGuestWebContents): boolean {\n return contents.navigationHistory?.canGoBack() ?? contents.canGoBack();\n}\n\nfunction canGuestGoForward(contents: BrowserGuestWebContents): boolean {\n return contents.navigationHistory?.canGoForward() ?? contents.canGoForward();\n}\n\nfunction goGuestBack(contents: BrowserGuestWebContents): void {\n if (contents.navigationHistory) {\n contents.navigationHistory.goBack();\n return;\n }\n contents.goBack();\n}\n\nfunction goGuestForward(contents: BrowserGuestWebContents): void {\n if (contents.navigationHistory) {\n contents.navigationHistory.goForward();\n return;\n }\n contents.goForward();\n}\n\nfunction resolveBrowserNodeUrlError(\n resolved: BrowserNavigationUrlResolution\n): BrowserNodeRuntimeError {\n if (resolved.errorCode === \"invalid-url\") {\n return { code: \"invalid-url\" };\n }\n\n if (resolved.errorCode === \"unsupported-protocol\") {\n return {\n code: \"unsupported-protocol\",\n params: resolved.errorParams\n };\n }\n\n return { code: \"unsupported-url\" };\n}\n\nfunction resizeBrowserPreviewImage(\n image: BrowserGuestNativeImage\n): BrowserGuestNativeImage {\n if (image.isEmpty?.() === true || !image.resize || !image.getSize) {\n return image;\n }\n\n const size = image.getSize();\n if (size.width <= 0 || size.height <= 0) {\n return image;\n }\n\n const scale = Math.min(\n 1,\n browserPreviewMaxWidth / size.width,\n browserPreviewMaxHeight / size.height\n );\n if (scale >= 1) {\n return image;\n }\n\n return image.resize({\n height: Math.max(1, Math.round(size.height * scale)),\n quality: \"good\",\n width: Math.max(1, Math.round(size.width * scale))\n });\n}\n\nfunction isAbortedNavigationError(input: {\n errorCode?: number;\n errorDescription?: string;\n}): boolean {\n return (\n input.errorCode === abortedNavigationErrorCode ||\n input.errorDescription === \"ERR_ABORTED\"\n );\n}\n\nfunction isHttpErrorStatusCode(statusCode: number | undefined): boolean {\n return statusCode !== undefined && statusCode >= 400;\n}\n\nfunction emitBrowserNavigationFailed(input: {\n emit: BrowserGuestManagerInput[\"emit\"];\n errorCode?: number;\n errorDescription?: string;\n nodeId: string;\n}): void {\n input.emit({\n code: \"navigation-failed\",\n diagnosticMessage: input.errorDescription,\n nodeId: input.nodeId,\n params:\n input.errorCode === undefined\n ? undefined\n : { errorCode: input.errorCode },\n type: \"error\"\n });\n}\n\nfunction isGoogleGisOAuthPopupUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n if (\n parsed.protocol !== \"https:\" ||\n parsed.hostname !== \"accounts.google.com\" ||\n (parsed.pathname !== \"/o/oauth2/v2/auth\" &&\n parsed.pathname !== \"/o/oauth2/auth\")\n ) {\n return false;\n }\n\n const isGisSdkPopup =\n parsed.searchParams.get(\"gsiwebsdk\") === \"gis_attributes\";\n const isPopupResponse =\n parsed.searchParams.get(\"display\") === \"popup\" &&\n (parsed.searchParams.get(\"response_mode\") === \"form_post\" ||\n parsed.searchParams.get(\"redirect_uri\") === \"gis_transform\");\n\n return isGisSdkPopup || isPopupResponse;\n } catch {\n return false;\n }\n}\n\nfunction resolveBrowserNavigationOrigin(url: string): string | null {\n const resolved = resolveBrowserNavigationUrl(url);\n if (!resolved.url) {\n return null;\n }\n\n try {\n return new URL(resolved.url).origin;\n } catch {\n return null;\n }\n}\n\nfunction isBrowserNavigationAllowedByPolicy(input: {\n policy: BrowserNodeNavigationPolicy | null;\n url: string;\n}): boolean {\n if (!input.policy) {\n return true;\n }\n\n if (input.policy.mode === \"same-origin\") {\n const policyOrigin = resolveBrowserNavigationOrigin(input.policy.originUrl);\n const nextOrigin = resolveBrowserNavigationOrigin(input.url);\n return (\n policyOrigin !== null &&\n nextOrigin !== null &&\n policyOrigin === nextOrigin\n );\n }\n\n return true;\n}\n\nasync function applyPreferredColorSchemeToGuest(\n session: BrowserGuestSession,\n logger: BrowserGuestManagerInput[\"logger\"],\n syncPreferredColorScheme: BrowserGuestManagerInput[\"syncPreferredColorScheme\"],\n scheme: BrowserPreferredColorScheme | null\n): Promise<void> {\n const contents = session.contents;\n if (\n !contents ||\n contents.isDestroyed() ||\n !syncPreferredColorScheme ||\n scheme === null ||\n session.appliedColorScheme === scheme\n ) {\n return;\n }\n\n try {\n await syncPreferredColorScheme(contents, scheme);\n session.appliedColorScheme = scheme;\n } catch (error) {\n session.appliedColorScheme = null;\n logger?.warn?.(\"Browser Node failed to sync guest color scheme\", {\n error: error instanceof Error ? error.message : String(error),\n nodeId: session.nodeId,\n scheme,\n webContentsId: session.webContentsId\n });\n }\n}\n\nexport function createBrowserGuestManager({\n emit,\n getPreferredColorScheme,\n logger,\n openExternal,\n prepareSession,\n resolveWebContents,\n syncPreferredColorScheme,\n subscribePreferredColorScheme\n}: BrowserGuestManagerInput): BrowserGuestManager {\n const sessions = new Map<string, BrowserGuestSession>();\n const nodeIdByWebContentsId = new Map<number, string>();\n let preferredColorScheme = getPreferredColorScheme?.() ?? null;\n\n const getSession = (\n nodeId: string,\n input?: {\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n url?: string;\n }\n ): BrowserGuestSession => {\n const existing = sessions.get(nodeId);\n if (existing) {\n if (input?.profileId !== undefined) {\n existing.profileId = input.profileId;\n }\n if (input?.sessionMode !== undefined) {\n existing.sessionMode = input.sessionMode;\n }\n if (input?.sessionPartition !== undefined) {\n existing.sessionPartition = input.sessionPartition;\n }\n if (input?.navigationPolicy !== undefined) {\n existing.navigationPolicy = input.navigationPolicy;\n }\n if (input?.url !== undefined) {\n existing.desiredUrl = input.url;\n }\n return existing;\n }\n\n const session: BrowserGuestSession = {\n appliedColorScheme: null,\n contents: null,\n desiredUrl: input?.url ?? \"about:blank\",\n lifecycle: \"cold\",\n listeners: [],\n navigationFailureSequence: 0,\n navigationPolicy: input?.navigationPolicy ?? null,\n nodeId,\n profileId: input?.profileId ?? null,\n sessionMode: input?.sessionMode ?? \"shared\",\n sessionPartition: input?.sessionPartition ?? null,\n webContentsId: null\n };\n sessions.set(nodeId, session);\n return session;\n };\n\n const publishState = (session: BrowserGuestSession): void => {\n const contents =\n session.contents && !session.contents.isDestroyed()\n ? session.contents\n : null;\n emit({\n canGoBack: contents ? canGuestGoBack(contents) : false,\n canGoForward: contents ? canGuestGoForward(contents) : false,\n isAttachedToWindow: Boolean(contents),\n isLoading: contents ? contents.isLoading() : false,\n isOccluded: session.lifecycle === \"cold\",\n lifecycle: session.lifecycle,\n nodeId: session.nodeId,\n title: contents ? contents.getTitle() || null : null,\n type: \"state\",\n url: contents\n ? contents.getURL() || session.desiredUrl\n : session.desiredUrl\n });\n };\n\n const detachGuest = (session: BrowserGuestSession): void => {\n const contents = session.contents;\n const webContentsId = session.webContentsId;\n if (contents) {\n for (const record of session.listeners) {\n contents.off(record.event, record.listener);\n }\n }\n session.listeners = [];\n session.contents = null;\n session.appliedColorScheme = null;\n session.webContentsId = null;\n if (\n webContentsId !== null &&\n nodeIdByWebContentsId.get(webContentsId) === session.nodeId\n ) {\n nodeIdByWebContentsId.delete(webContentsId);\n }\n publishState(session);\n };\n\n const handlePreferredColorSchemeChange = (\n scheme: BrowserPreferredColorScheme\n ) => {\n preferredColorScheme = scheme;\n for (const session of sessions.values()) {\n session.appliedColorScheme = null;\n void applyPreferredColorSchemeToGuest(\n session,\n logger,\n syncPreferredColorScheme,\n scheme\n ).catch(() => undefined);\n }\n };\n\n const unsubscribePreferredColorScheme =\n subscribePreferredColorScheme?.(handlePreferredColorSchemeChange) ?? null;\n\n const attachGuestListeners = (session: BrowserGuestSession): void => {\n const contents = session.contents;\n if (!contents) {\n return;\n }\n\n const onStateChange = () => publishState(session);\n const onDidNavigate = (...args: unknown[]) => {\n const url = typeof args[1] === \"string\" ? args[1] : undefined;\n const statusCode = typeof args[2] === \"number\" ? args[2] : undefined;\n const statusText = typeof args[3] === \"string\" ? args[3] : undefined;\n publishState(session);\n if (!isHttpErrorStatusCode(statusCode)) {\n return;\n }\n\n logger?.warn?.(\"Browser Node guest navigation returned HTTP error\", {\n currentUrl: contents.getURL(),\n desiredUrl: session.desiredUrl,\n nodeId: session.nodeId,\n statusCode,\n statusText,\n url,\n webContentsId: session.webContentsId\n });\n emit({\n code: \"navigation-failed\",\n diagnosticMessage: statusText,\n nodeId: session.nodeId,\n params: {\n statusCode,\n ...(statusText ? { statusText } : {})\n },\n type: \"error\"\n });\n };\n const onFailLoad = (...args: unknown[]) => {\n const errorCode = typeof args[1] === \"number\" ? args[1] : undefined;\n const errorDescription =\n typeof args[2] === \"string\" ? args[2] : undefined;\n const validatedUrl = typeof args[3] === \"string\" ? args[3] : undefined;\n const isMainFrame = typeof args[4] === \"boolean\" ? args[4] : undefined;\n if (isAbortedNavigationError({ errorCode, errorDescription })) {\n publishState(session);\n return;\n }\n logger?.warn?.(\"Browser Node guest navigation failed\", {\n currentUrl: contents.getURL(),\n desiredUrl: session.desiredUrl,\n errorCode,\n errorDescription,\n isMainFrame,\n nodeId: session.nodeId,\n validatedUrl,\n webContentsId: session.webContentsId\n });\n session.navigationFailureSequence += 1;\n publishState(session);\n emitBrowserNavigationFailed({\n emit,\n errorCode,\n errorDescription,\n nodeId: session.nodeId\n });\n };\n const onDestroyed = () => detachGuest(session);\n const onWillNavigate = (...args: unknown[]) => {\n const event =\n args[0] && typeof args[0] === \"object\" && \"preventDefault\" in args[0]\n ? (args[0] as { preventDefault?: () => void })\n : null;\n const url = typeof args[1] === \"string\" ? args[1] : \"\";\n if (\n url.length === 0 ||\n isBrowserNavigationAllowedByPolicy({\n policy: session.navigationPolicy,\n url\n })\n ) {\n return;\n }\n\n event?.preventDefault?.();\n emitOpenUrlFromGuest(session, url);\n publishState(session);\n };\n\n const records: BrowserGuestSession[\"listeners\"] = [\n { event: \"did-start-loading\", listener: onStateChange },\n { event: \"did-stop-loading\", listener: onStateChange },\n { event: \"did-navigate\", listener: onDidNavigate },\n { event: \"did-navigate-in-page\", listener: onStateChange },\n { event: \"page-title-updated\", listener: onStateChange },\n { event: \"will-navigate\", listener: onWillNavigate },\n { event: \"did-fail-load\", listener: onFailLoad },\n { event: \"destroyed\", listener: onDestroyed }\n ];\n\n for (const record of records) {\n contents.on(record.event, record.listener);\n }\n session.listeners = records;\n };\n\n const loadDesiredUrl = async (\n session: BrowserGuestSession\n ): Promise<void> => {\n const contents = session.contents;\n if (!contents || contents.isDestroyed()) {\n publishState(session);\n return;\n }\n\n const resolved = resolveHostBrowserNavigationUrl(session.desiredUrl);\n if (!resolved.url) {\n emit({\n ...resolveBrowserNodeUrlError(resolved),\n nodeId: session.nodeId,\n type: \"error\"\n });\n publishState(session);\n return;\n }\n if (\n !isBrowserNavigationAllowedByPolicy({\n policy: session.navigationPolicy,\n url: resolved.url\n })\n ) {\n emitOpenUrlFromGuest(session, resolved.url);\n publishState(session);\n return;\n }\n\n const currentComparable = normalizeHostBrowserComparableUrl(\n contents.getURL()\n );\n const nextComparable = normalizeHostBrowserComparableUrl(resolved.url);\n if (currentComparable && currentComparable === nextComparable) {\n publishState(session);\n return;\n }\n\n const failureSequenceBeforeLoad = session.navigationFailureSequence;\n try {\n await contents.loadURL(resolved.url);\n publishState(session);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger?.warn?.(\"Browser Node guest loadURL failed\", {\n currentUrl: contents.getURL(),\n desiredUrl: session.desiredUrl,\n error: message,\n nodeId: session.nodeId,\n resolvedUrl: resolved.url,\n webContentsId: session.webContentsId\n });\n if (session.navigationFailureSequence !== failureSequenceBeforeLoad) {\n return;\n }\n publishState(session);\n emitBrowserNavigationFailed({\n emit,\n errorDescription: message,\n nodeId: session.nodeId\n });\n }\n };\n\n const emitOpenUrlFromGuest = (\n session: BrowserGuestSession,\n url: string\n ): { action: \"deny\" } => {\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n logger?.info?.(\"Browser Node guest emitted open-url\", {\n nodeId: session.nodeId,\n url: resolved.url,\n webContentsId: session.webContentsId\n });\n emit({\n reuseIfOpen: true,\n sourceNodeId: session.nodeId,\n type: \"open-url\",\n url: resolved.url\n });\n return { action: \"deny\" };\n }\n void Promise.resolve(openExternal(url)).catch((error: unknown) => {\n logger?.warn?.(\"Browser Node openExternal failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n });\n return { action: \"deny\" };\n };\n\n return {\n async activate(input) {\n const resolved = resolveHostBrowserNavigationUrl(input.url);\n if (!resolved.url) {\n throw new Error(\"Browser Node rejected navigation URL\");\n }\n const session = getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition,\n url: resolved.url\n });\n session.lifecycle = \"active\";\n await loadDesiredUrl(session);\n },\n async capturePreview(input) {\n const session = sessions.get(input.nodeId);\n const contents =\n session?.contents && !session.contents.isDestroyed()\n ? session.contents\n : null;\n if (!contents?.capturePage) {\n return null;\n }\n\n const image = await contents.capturePage();\n if (image.isEmpty?.() === true) {\n return null;\n }\n\n return resizeBrowserPreviewImage(image).toDataURL();\n },\n close(input) {\n const session = sessions.get(input.nodeId);\n if (session) {\n detachGuest(session);\n sessions.delete(input.nodeId);\n }\n emit({ nodeId: input.nodeId, type: \"closed\" });\n return Promise.resolve();\n },\n debugDump(input) {\n const session = sessions.get(input.nodeId);\n if (!session) {\n return null;\n }\n const contents =\n session.contents && !session.contents.isDestroyed()\n ? session.contents\n : null;\n return {\n canGoBack: contents ? canGuestGoBack(contents) : false,\n canGoForward: contents ? canGuestGoForward(contents) : false,\n currentUrl: contents ? contents.getURL() : null,\n desiredUrl: session.desiredUrl,\n isAttachedToWindow: Boolean(contents),\n isLoading: contents ? contents.isLoading() : false,\n lifecycle: session.lifecycle,\n nodeId: session.nodeId,\n profileId: session.profileId,\n sessionMode: session.sessionMode,\n sessionPartition: session.sessionPartition,\n title: contents ? contents.getTitle() : null,\n userAgent: contents?.getUserAgent?.() ?? null,\n webContentsDestroyed: session.contents\n ? session.contents.isDestroyed()\n : null,\n webContentsId: session.webContentsId\n };\n },\n goBack(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed() && canGuestGoBack(contents)) {\n goGuestBack(contents);\n }\n return Promise.resolve();\n },\n goForward(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed() && canGuestGoForward(contents)) {\n goGuestForward(contents);\n }\n return Promise.resolve();\n },\n handleGuestOpenUrl(webContentsId, input) {\n const nodeId = nodeIdByWebContentsId.get(webContentsId);\n const session = nodeId ? sessions.get(nodeId) : null;\n if (!session) {\n logger?.warn?.(\"Browser Node ignored guest open-url request\", {\n url: input.url,\n webContentsId\n });\n return;\n }\n logger?.info?.(\"Browser Node handling guest open-url request\", {\n nodeId: session.nodeId,\n url: input.url,\n webContentsId\n });\n emitOpenUrlFromGuest(session, input.url);\n },\n async navigate(input) {\n const resolved = resolveBrowserNavigationUrl(input.url);\n if (!resolved.url) {\n throw new Error(\"Browser Node rejected navigation URL\");\n }\n const session = getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n url: resolved.url\n });\n session.lifecycle = \"active\";\n await loadDesiredUrl(session);\n },\n async openExternal(input) {\n const resolved = resolveBrowserNavigationUrl(input.url);\n if (!resolved.url) {\n throw new Error(\"Browser Node rejected external URL\");\n }\n await Promise.resolve(openExternal(resolved.url));\n },\n openDevTools(input) {\n const session = sessions.get(input.nodeId);\n const contents = session?.contents ?? null;\n if (contents && !contents.isDestroyed()) {\n try {\n contents.openDevTools?.({ activate: true, mode: \"detach\" });\n } catch (error) {\n logger?.warn?.(\"Browser Node open devtools failed\", {\n error: error instanceof Error ? error.message : String(error),\n nodeId: input.nodeId,\n webContentsId: session?.webContentsId ?? null\n });\n throw error;\n }\n }\n return Promise.resolve();\n },\n async prepareSession(input) {\n await prepareSession?.(input);\n getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n });\n },\n async registerGuest(input) {\n await prepareSession?.({\n nodeId: input.nodeId,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition,\n navigationPolicy: input.navigationPolicy\n });\n const contents = resolveWebContents(input.webContentsId);\n if (!contents || contents.isDestroyed()) {\n throw new Error(\n `Browser Node guest ${input.webContentsId} is not available`\n );\n }\n\n const ownerNodeId = nodeIdByWebContentsId.get(input.webContentsId);\n if (ownerNodeId && ownerNodeId !== input.nodeId) {\n throw new Error(\n `Browser Node guest ${input.webContentsId} is already registered`\n );\n }\n\n const session = getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n });\n if (\n session.webContentsId === input.webContentsId &&\n session.contents === contents\n ) {\n publishState(session);\n return;\n }\n if (session.contents && session.contents !== contents) {\n detachGuest(session);\n }\n session.contents = contents;\n session.webContentsId = input.webContentsId;\n nodeIdByWebContentsId.set(input.webContentsId, input.nodeId);\n session.lifecycle = \"active\";\n logger?.info?.(\"Browser Node registered guest owner\", {\n nodeId: input.nodeId,\n sessionPartition: session.sessionPartition,\n webContentsId: input.webContentsId\n });\n contents.setWindowOpenHandler?.(({ url }) => {\n if (isGoogleGisOAuthPopupUrl(url)) {\n logger?.info?.(\"Browser Node allowing Google GIS OAuth popup\", {\n nodeId: session.nodeId,\n webContentsId: session.webContentsId\n });\n return { action: \"allow\" };\n }\n\n return emitOpenUrlFromGuest(session, url);\n });\n attachGuestListeners(session);\n await applyPreferredColorSchemeToGuest(\n session,\n logger,\n syncPreferredColorScheme,\n preferredColorScheme\n );\n await loadDesiredUrl(session);\n },\n reload(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed()) {\n contents.reload();\n }\n return Promise.resolve();\n },\n unregisterGuest(input) {\n const session = sessions.get(input.nodeId);\n if (!session || session.webContentsId !== input.webContentsId) {\n return Promise.resolve();\n }\n session.lifecycle = \"cold\";\n detachGuest(session);\n return Promise.resolve();\n },\n dispose() {\n unsubscribePreferredColorScheme?.();\n }\n };\n}\n","import type { BrowserWindow } from \"electron\";\nimport { resolveBrowserSessionPartition } from \"../core/session.ts\";\nimport type { BrowserNodeLoopbackPreviewRoutingOptions } from \"./loopbackPreview.ts\";\nimport { createBrowserNodeLoopbackPreviewProxy } from \"./loopbackPreviewProxy.ts\";\nimport type {\n BrowserNodeActivationInput,\n BrowserNodeGuestOpenUrlInput,\n BrowserNodeNavigateInput,\n BrowserNodeNodeIdInput,\n BrowserNodeOpenExternalInput,\n BrowserNodePrepareSessionInput,\n BrowserNodeRegisterGuestInput,\n BrowserNodeShowDevToolsContextMenuInput,\n BrowserNodeUnregisterGuestInput\n} from \"../core/types.ts\";\nimport { createBrowserGuestManager } from \"./guestManager.ts\";\nimport type {\n BrowserGuestManager,\n BrowserPreferredColorScheme,\n BrowserGuestWebContents,\n BrowserNodeElectronLogger\n} from \"./types.ts\";\n\nexport interface BrowserNodeElectronMainChannels {\n readonly activate: string;\n readonly capturePreview?: string;\n readonly close: string;\n readonly debugDump?: string;\n readonly event: string;\n readonly goBack: string;\n readonly goForward: string;\n readonly guestOpenUrl?: string;\n readonly navigate: string;\n readonly openDevTools?: string;\n readonly openExternal?: string;\n readonly prepareSession: string;\n readonly registerGuest: string;\n readonly reload: string;\n readonly showDevToolsContextMenu?: string;\n readonly unregisterGuest: string;\n}\n\nexport interface BrowserNodeElectronDevToolsContextMenuInput {\n readonly label: string;\n readonly openDevTools: () => Promise<void> | void;\n readonly ownerWindow: BrowserWindow;\n readonly point: { x: number; y: number };\n}\n\nexport interface RegisterBrowserNodeElectronMainInput {\n readonly channels: BrowserNodeElectronMainChannels;\n readonly getOwnerWindow: (event: unknown) => BrowserWindow | null;\n readonly getPreferredColorScheme?: () => BrowserPreferredColorScheme;\n readonly logger?: BrowserNodeElectronLogger;\n readonly loopbackPreviewRouting?: BrowserNodeLoopbackPreviewRoutingOptions;\n readonly openExternal: (url: string) => Promise<void> | void;\n readonly registerHandler: <TPayload, TResult>(\n channel: string,\n handler: (event: unknown, payload: TPayload) => Promise<TResult> | TResult\n ) => void;\n readonly registerListener?: <TPayload>(\n channel: string,\n handler: (event: unknown, payload: TPayload) => void\n ) => void;\n readonly resolveWebContents: (input: {\n event: unknown;\n ownerWindow: BrowserWindow;\n webContentsId: number;\n }) => BrowserGuestWebContents | null;\n readonly showDevToolsContextMenu?: (\n input: BrowserNodeElectronDevToolsContextMenuInput\n ) => Promise<void> | void;\n readonly syncPreferredColorScheme?: (\n contents: BrowserGuestWebContents,\n scheme: BrowserPreferredColorScheme\n ) => Promise<void> | void;\n readonly subscribePreferredColorScheme?: (\n listener: (scheme: BrowserPreferredColorScheme) => void\n ) => () => void;\n}\n\nexport function registerBrowserNodeElectronMain(\n input: RegisterBrowserNodeElectronMainInput\n): void {\n const managersByWindow = new WeakMap<BrowserWindow, BrowserGuestManager>();\n const loopbackPreviewProxy =\n input.loopbackPreviewRouting !== undefined\n ? createBrowserNodeLoopbackPreviewProxy({\n logger: input.logger,\n resolveSession: async ({\n profileId,\n sessionMode,\n sessionPartition\n }) => {\n const { session } = await import(\"electron\");\n return session.fromPartition(\n resolveBrowserSessionPartition({\n profileId,\n sessionMode,\n sessionPartition\n })\n );\n },\n routing: input.loopbackPreviewRouting\n })\n : null;\n\n const resolveManagerForWindow = (\n event: unknown,\n ownerWindow: BrowserWindow\n ): BrowserGuestManager => {\n const existing = managersByWindow.get(ownerWindow);\n if (existing) {\n return existing;\n }\n\n const manager = createBrowserGuestManager({\n emit(browserEvent) {\n if (!ownerWindow.isDestroyed()) {\n ownerWindow.webContents.send(input.channels.event, browserEvent);\n }\n },\n getPreferredColorScheme: input.getPreferredColorScheme,\n logger: input.logger,\n openExternal: input.openExternal,\n prepareSession:\n loopbackPreviewProxy !== null\n ? (payload) => loopbackPreviewProxy.configureSession(payload)\n : undefined,\n resolveWebContents: (webContentsId) =>\n input.resolveWebContents({\n event,\n ownerWindow,\n webContentsId\n }),\n syncPreferredColorScheme: input.syncPreferredColorScheme,\n subscribePreferredColorScheme: input.subscribePreferredColorScheme\n });\n ownerWindow.once(\"closed\", () => {\n manager.dispose();\n managersByWindow.delete(ownerWindow);\n });\n managersByWindow.set(ownerWindow, manager);\n return manager;\n };\n\n const resolveOwnedManager = (event: unknown) => {\n const ownerWindow = input.getOwnerWindow(event);\n if (!ownerWindow) {\n throw new Error(\"Browser Node IPC requires an owner window\");\n }\n return {\n manager: resolveManagerForWindow(event, ownerWindow),\n ownerWindow\n };\n };\n\n const showDevToolsContextMenu =\n input.showDevToolsContextMenu ?? showElectronDevToolsContextMenu;\n\n input.registerHandler(input.channels.prepareSession, (event, payload) =>\n resolveOwnedManager(event).manager.prepareSession(\n payload as BrowserNodePrepareSessionInput\n )\n );\n input.registerHandler(input.channels.activate, (event, payload) =>\n resolveOwnedManager(event).manager.activate(\n payload as BrowserNodeActivationInput\n )\n );\n if (input.channels.capturePreview) {\n input.registerHandler(input.channels.capturePreview, (event, payload) =>\n resolveOwnedManager(event).manager.capturePreview(\n payload as BrowserNodeNodeIdInput\n )\n );\n }\n input.registerHandler(input.channels.registerGuest, (event, payload) =>\n resolveOwnedManager(event).manager.registerGuest(\n payload as BrowserNodeRegisterGuestInput\n )\n );\n input.registerHandler(input.channels.unregisterGuest, (event, payload) =>\n resolveOwnedManager(event).manager.unregisterGuest(\n payload as BrowserNodeUnregisterGuestInput\n )\n );\n input.registerHandler(input.channels.navigate, (event, payload) =>\n resolveOwnedManager(event).manager.navigate(\n payload as BrowserNodeNavigateInput\n )\n );\n if (input.channels.openExternal) {\n input.registerHandler(input.channels.openExternal, (event, payload) =>\n resolveOwnedManager(event).manager.openExternal(\n payload as BrowserNodeOpenExternalInput\n )\n );\n }\n if (input.channels.openDevTools) {\n input.registerHandler(input.channels.openDevTools, (event, payload) => {\n const nodePayload = payload as BrowserNodeNodeIdInput;\n return resolveOwnedManager(event).manager.openDevTools(nodePayload);\n });\n }\n if (input.channels.showDevToolsContextMenu) {\n input.registerHandler(\n input.channels.showDevToolsContextMenu,\n (event, payload) => {\n const contextMenuPayload =\n payload as BrowserNodeShowDevToolsContextMenuInput;\n const { manager, ownerWindow } = resolveOwnedManager(event);\n return showDevToolsContextMenu({\n label: contextMenuPayload.label,\n openDevTools: () => {\n return manager.openDevTools({ nodeId: contextMenuPayload.nodeId });\n },\n ownerWindow,\n point: contextMenuPayload.point\n });\n }\n );\n }\n input.registerHandler(input.channels.goBack, (event, payload) =>\n resolveOwnedManager(event).manager.goBack(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.goForward, (event, payload) =>\n resolveOwnedManager(event).manager.goForward(\n payload as BrowserNodeNodeIdInput\n )\n );\n input.registerHandler(input.channels.reload, (event, payload) =>\n resolveOwnedManager(event).manager.reload(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.close, (event, payload) =>\n resolveOwnedManager(event).manager.close(payload as BrowserNodeNodeIdInput)\n );\n if (input.channels.debugDump) {\n input.registerHandler(input.channels.debugDump, (event, payload) =>\n resolveOwnedManager(event).manager.debugDump(\n payload as BrowserNodeNodeIdInput\n )\n );\n }\n if (input.channels.guestOpenUrl && input.registerListener) {\n input.registerListener(input.channels.guestOpenUrl, (event, payload) => {\n const senderId = readBrowserNodeIpcSenderId(event);\n const openUrlPayload = payload as BrowserNodeGuestOpenUrlInput | null;\n if (\n typeof senderId !== \"number\" ||\n !Number.isFinite(senderId) ||\n !openUrlPayload ||\n typeof openUrlPayload.url !== \"string\"\n ) {\n return;\n }\n resolveOwnedManager(event).manager.handleGuestOpenUrl(\n senderId,\n openUrlPayload\n );\n });\n }\n}\n\nasync function showElectronDevToolsContextMenu(\n input: BrowserNodeElectronDevToolsContextMenuInput\n): Promise<void> {\n const { Menu } = await import(\"electron\");\n const menu = Menu.buildFromTemplate([\n {\n click: () => {\n void Promise.resolve(input.openDevTools()).catch(() => undefined);\n },\n label: input.label\n }\n ]);\n menu.popup({\n window: input.ownerWindow,\n x: Math.round(input.point.x),\n y: Math.round(input.point.y)\n });\n}\n\nfunction readBrowserNodeIpcSenderId(event: unknown): number | null {\n const sender = (event as { sender?: { id?: unknown } } | null)?.sender;\n return typeof sender?.id === \"number\" ? sender.id : null;\n}\n","import type { WebContents } from \"electron\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nconst electronUserAgentTokenPattern = /\\sElectron\\/[^\\s]+/g;\n\nexport function sanitizeBrowserGuestUserAgent(userAgent: string): string {\n return userAgent\n .trim()\n .replace(electronUserAgentTokenPattern, \"\")\n .replace(/\\s{2,}/g, \" \");\n}\n\nexport function applyBrowserGuestUserAgent(\n contents: WebContents,\n logger?: BrowserNodeElectronLogger\n): void {\n const guestContents = contents as WebContents & {\n getUserAgent?: () => string;\n setUserAgent?: (userAgent: string) => void;\n };\n if (\n typeof guestContents.getUserAgent !== \"function\" ||\n typeof guestContents.setUserAgent !== \"function\"\n ) {\n return;\n }\n\n const currentUserAgent = guestContents.getUserAgent().trim();\n const nextUserAgent = sanitizeBrowserGuestUserAgent(currentUserAgent);\n if (!nextUserAgent || nextUserAgent === currentUserAgent) {\n return;\n }\n\n guestContents.setUserAgent(nextUserAgent);\n logger?.debug?.(\"Browser Node sanitized guest user agent\", {\n webContentsId: contents.id ?? null\n });\n}\n","import type { Event, WebContents, WebPreferences } from \"electron\";\nimport {\n isBrowserSessionPartitionAllowed,\n type BrowserSessionPartitionAllowedOptions\n} from \"../core/session.ts\";\nimport { resolveBrowserNavigationUrl } from \"../core/url.ts\";\nimport { applyBrowserGuestUserAgent } from \"./userAgent.ts\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nexport interface BrowserWebviewSecurityInput {\n allowedSessionPartitions?: BrowserSessionPartitionAllowedOptions;\n params: Record<string, string>;\n resolvePreload?: BrowserWebviewPreloadResolver;\n webPreferences: WebPreferences;\n}\n\nexport interface BrowserWebviewSecurityResult {\n allowed: boolean;\n reason: string | null;\n}\n\nexport type BrowserNodeWebviewMatcher = (\n params: Record<string, string>\n) => boolean;\n\ninterface PendingBrowserWebviewAttach {\n allowNativePopups: boolean;\n}\n\nexport interface BrowserWebviewPreloadResolverInput {\n params: Readonly<Record<string, string>>;\n}\n\nexport type BrowserWebviewPreloadResolver = (\n input: BrowserWebviewPreloadResolverInput\n) => string | null | undefined;\n\nfunction isBrowserNodeInitialWebviewUrl(url: string | undefined): boolean {\n return (url ?? \"\").trim() === \"about:blank\";\n}\n\nexport function isBrowserNodeWebviewAttach(\n params: Record<string, string>,\n allowedSessionPartitions?: BrowserSessionPartitionAllowedOptions\n): boolean {\n return (\n params[\"data-browser-node-webview\"] === \"true\" ||\n isBrowserSessionPartitionAllowed(params.partition, allowedSessionPartitions)\n );\n}\n\nfunction shouldAllowBrowserNodeNativePopups(\n params: Record<string, string>\n): boolean {\n return (\n params[\"data-browser-node-webview\"] === \"true\" ||\n isBrowserSessionPartitionAllowed(params.partition)\n );\n}\n\nfunction getPopupLogMetadata(url: string): Record<string, unknown> {\n try {\n const parsed = new URL(url);\n return {\n popupOrigin: parsed.origin,\n popupPath: parsed.pathname,\n popupProtocol: parsed.protocol\n };\n } catch {\n return {\n popupOrigin: null,\n popupPath: null,\n popupProtocol: null\n };\n }\n}\n\nfunction externalizeBrowserNodePopupWindow({\n guestWebContentsId,\n logger,\n openExternal,\n url\n}: {\n guestWebContentsId: number | null;\n logger?: BrowserNodeElectronLogger;\n openExternal: (url: string) => Promise<void> | void;\n url: string;\n}) {\n logger?.info?.(\"Browser Node webview popup externalized\", {\n guestWebContentsId,\n ...getPopupLogMetadata(url)\n });\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n void Promise.resolve(openExternal(resolved.url)).catch(() => undefined);\n }\n return { action: \"deny\" as const };\n}\n\nexport function enforceBrowserWebviewSecurity({\n allowedSessionPartitions,\n params,\n resolvePreload,\n webPreferences\n}: BrowserWebviewSecurityInput): BrowserWebviewSecurityResult {\n webPreferences.allowRunningInsecureContent = false;\n webPreferences.contextIsolation = true;\n webPreferences.javascript = true;\n webPreferences.nodeIntegration = false;\n webPreferences.plugins = false;\n webPreferences.sandbox = true;\n webPreferences.webSecurity = true;\n delete webPreferences.preload;\n\n const partition = params.partition;\n if (\n !partition ||\n !isBrowserSessionPartitionAllowed(partition, allowedSessionPartitions)\n ) {\n return {\n allowed: false,\n reason: \"Unsupported Browser Node session partition\"\n };\n }\n\n if (isBrowserNodeInitialWebviewUrl(params.src)) {\n params.src = \"about:blank\";\n } else {\n const resolved = resolveBrowserNavigationUrl(params.src ?? \"about:blank\");\n if (!resolved.url) {\n return {\n allowed: false,\n reason: \"Unsupported browser URL\"\n };\n }\n params.src = resolved.url;\n }\n\n const preload = resolvePreload?.({ params: { ...params } });\n const resolvedPreload = typeof preload === \"string\" ? preload.trim() : \"\";\n if (resolvedPreload.length > 0) {\n webPreferences.preload = resolvedPreload;\n }\n\n return { allowed: true, reason: null };\n}\n\nexport interface InstallBrowserWebviewSecurityInput {\n allowedSessionPartitions?: BrowserSessionPartitionAllowedOptions;\n contents: WebContents;\n logger?: BrowserNodeElectronLogger;\n onGuestAttached?: (guestContents: WebContents) => void;\n openExternal: (url: string) => Promise<void> | void;\n resolvePreload?: BrowserWebviewPreloadResolver;\n shouldHandleWebview?: BrowserNodeWebviewMatcher;\n}\n\nexport function installBrowserWebviewSecurity({\n allowedSessionPartitions,\n contents,\n logger,\n onGuestAttached,\n openExternal,\n resolvePreload,\n shouldHandleWebview\n}: InstallBrowserWebviewSecurityInput): () => void {\n const pendingBrowserAttaches: PendingBrowserWebviewAttach[] = [];\n\n const handleWillAttachWebview = (\n event: Event,\n webPreferences: WebPreferences,\n params: Record<string, string>\n ) => {\n const shouldHandle =\n shouldHandleWebview?.(params) ??\n isBrowserNodeWebviewAttach(params, allowedSessionPartitions);\n logger?.debug?.(\"Browser Node webview will attach\", {\n partition: params.partition ?? null,\n shouldHandle,\n src: params.src ?? null\n });\n if (!shouldHandle) {\n return;\n }\n\n const allowNativePopups = shouldAllowBrowserNodeNativePopups(params);\n if (allowNativePopups) {\n params.allowpopups = \"true\";\n }\n logger?.info?.(\"Browser Node webview popup policy applied\", {\n allowNativePopups,\n allowpopups: params.allowpopups ?? null,\n partition: params.partition ?? null,\n src: params.src ?? null\n });\n\n const result = enforceBrowserWebviewSecurity({\n allowedSessionPartitions,\n params,\n resolvePreload,\n webPreferences\n });\n if (!result.allowed) {\n logger?.warn?.(\"Browser Node webview blocked\", { reason: result.reason });\n event.preventDefault();\n return;\n }\n pendingBrowserAttaches.push({\n allowNativePopups\n });\n logger?.debug?.(\"Browser Node webview attach allowed\", {\n partition: params.partition ?? null,\n src: params.src ?? null\n });\n };\n\n const handleDidAttachWebview = (\n _event: Event,\n guestContents: WebContents\n ) => {\n const pendingAttach = pendingBrowserAttaches.shift();\n if (!pendingAttach) {\n logger?.debug?.(\"Browser Node webview did attach ignored\", {\n guestWebContentsId: guestContents.id ?? null,\n pendingBrowserAttachCount: pendingBrowserAttaches.length\n });\n return;\n }\n\n applyBrowserGuestUserAgent(guestContents, logger);\n if (pendingAttach.allowNativePopups) {\n guestContents.setWindowOpenHandler(({ url }) => {\n return externalizeBrowserNodePopupWindow({\n guestWebContentsId: guestContents.id ?? null,\n logger,\n openExternal,\n url\n });\n });\n } else {\n guestContents.setWindowOpenHandler(({ url }) => {\n return externalizeBrowserNodePopupWindow({\n guestWebContentsId: guestContents.id ?? null,\n logger,\n openExternal,\n url\n });\n });\n }\n onGuestAttached?.(guestContents);\n logger?.debug?.(\"Browser Node webview guest attached\", {\n guestWebContentsId: guestContents.id ?? null,\n pendingBrowserAttachCount: pendingBrowserAttaches.length\n });\n };\n\n contents.on(\"will-attach-webview\", handleWillAttachWebview);\n contents.on(\"did-attach-webview\", handleDidAttachWebview);\n\n return () => {\n contents.off(\"will-attach-webview\", handleWillAttachWebview);\n contents.off(\"did-attach-webview\", handleDidAttachWebview);\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/electron-main/loopbackPreviewProxy.ts","../../src/electron-main/guestManager.ts","../../src/electron-main/registerElectronMain.ts","../../src/electron-main/userAgent.ts","../../src/electron-main/webviewSecurity.ts"],"sourcesContent":["import {\n createServer,\n request as httpRequest,\n type IncomingHttpHeaders,\n type IncomingMessage,\n type Server,\n type ServerResponse\n} from \"node:http\";\nimport { request as httpsRequest } from \"node:https\";\nimport type { Socket } from \"node:net\";\nimport { pipeline } from \"node:stream\";\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport type { RawData } from \"ws\";\nimport type { BrowserNodeSessionMode } from \"../core/types.ts\";\nimport type {\n BrowserNodeLoopbackPreviewRoutingOptions,\n BrowserNodeLoopbackPreviewTarget\n} from \"./loopbackPreview.ts\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nconst defaultLoopbackPreviewCacheTtlMs = 30_000;\nconst loopbackHostPattern = /^(localhost|127(?:\\.\\d{1,3}){0,3})$/i;\n// Order matters: bypass all, subtract loopback so local previews can proxy,\n// then keep HTTPS/WSS direct because this proxy does not implement CONNECT.\nconst loopbackPreviewProxyBypassRules = \"*;<-loopback>;https://*;wss://*\";\nconst hopByHopHeaders = new Set([\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\"\n]);\n\ninterface CachedLoopbackPreviewTarget {\n expiresAt: number;\n target: BrowserNodeLoopbackPreviewTarget | null;\n}\n\nexport interface BrowserNodePreviewSession {\n setProxy(input: {\n mode: \"fixed_servers\";\n proxyBypassRules: string;\n proxyRules: string;\n }): Promise<void>;\n}\n\nexport interface BrowserNodeLoopbackPreviewProxy {\n configureSession(input: {\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n }): Promise<void>;\n dispose(): Promise<void>;\n addressForTesting(): string;\n serverForTesting(): Server;\n}\n\nexport interface BrowserNodeLoopbackPreviewProxyInput {\n logger?: BrowserNodeElectronLogger;\n resolveSession: (input: {\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n }) => BrowserNodePreviewSession | Promise<BrowserNodePreviewSession>;\n routing: BrowserNodeLoopbackPreviewRoutingOptions;\n}\n\nexport function createBrowserNodeLoopbackPreviewProxy({\n logger,\n resolveSession,\n routing\n}: BrowserNodeLoopbackPreviewProxyInput): BrowserNodeLoopbackPreviewProxy {\n const configuredSessions = new WeakSet<BrowserNodePreviewSession>();\n const targetCache = new Map<string, CachedLoopbackPreviewTarget>();\n const downstreamWebSocketServer = new WebSocketServer({ noServer: true });\n let server: Server | null = null;\n let serverStartPromise: Promise<string> | null = null;\n\n const cacheTtlMs = routing.cacheTtlMs ?? defaultLoopbackPreviewCacheTtlMs;\n const fallback = routing.fallback ?? \"direct\";\n\n const pruneExpiredTargets = (now: number): void => {\n for (const [cacheKey, cachedTarget] of targetCache.entries()) {\n if (cachedTarget.expiresAt <= now) {\n targetCache.delete(cacheKey);\n }\n }\n };\n\n const start = async (): Promise<string> => {\n if (server?.listening) {\n return addressForTesting();\n }\n if (serverStartPromise) {\n return serverStartPromise;\n }\n\n serverStartPromise = new Promise<string>((resolve, reject) => {\n const nextServer = createServer((request, response) => {\n void handleRequest(request, response);\n });\n nextServer.on(\"upgrade\", (request, socket, head) => {\n void handleUpgrade(request, socket as Socket, head);\n });\n\n const cleanup = (): void => {\n nextServer.removeListener(\"error\", onError);\n nextServer.removeListener(\"listening\", onListening);\n };\n const onError = (error: Error): void => {\n cleanup();\n reject(error);\n };\n const onListening = (): void => {\n cleanup();\n server = nextServer;\n resolve(addressForTesting());\n };\n\n nextServer.once(\"error\", onError);\n nextServer.once(\"listening\", onListening);\n nextServer.listen(0, \"127.0.0.1\");\n }).finally(() => {\n serverStartPromise = null;\n });\n\n return serverStartPromise;\n };\n\n const resolveLoopbackTarget = async (\n originalUrl: URL\n ): Promise<BrowserNodeLoopbackPreviewTarget | null> => {\n const port = Number(originalUrl.port);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n return null;\n }\n\n const now = Date.now();\n pruneExpiredTargets(now);\n\n const cacheKey = originalUrl.toString();\n const cached = targetCache.get(cacheKey);\n if (cached && cached.expiresAt > now) {\n return cached.target;\n }\n\n const nextTarget = await Promise.resolve(\n routing.resolver.resolveTarget({\n port,\n url: originalUrl.toString()\n })\n );\n\n const target = normalizeLoopbackPreviewTarget(nextTarget);\n targetCache.set(cacheKey, {\n expiresAt: now + Math.max(0, cacheTtlMs),\n target\n });\n return target;\n };\n\n const configureSession = async (input: {\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n }): Promise<void> => {\n const nextSession = await resolveSession(input);\n if (configuredSessions.has(nextSession)) {\n return;\n }\n const address = await start();\n await nextSession.setProxy({\n mode: \"fixed_servers\",\n proxyBypassRules: loopbackPreviewProxyBypassRules,\n proxyRules: `http=${address}`\n });\n configuredSessions.add(nextSession);\n };\n\n const dispose = async (): Promise<void> => {\n targetCache.clear();\n downstreamWebSocketServer.close();\n const activeServer = server;\n server = null;\n if (!activeServer || !activeServer.listening) {\n return;\n }\n await new Promise<void>((resolve) => {\n activeServer.close(() => resolve());\n });\n };\n\n const handleRequest = async (\n request: IncomingMessage,\n response: ServerResponse\n ): Promise<void> => {\n const originalUrl = resolveProxyRequestUrl(request);\n if (!originalUrl) {\n response.writeHead(400);\n response.end(\"invalid proxy request\");\n return;\n }\n if (originalUrl.protocol !== \"http:\") {\n response.writeHead(400);\n response.end(\"unsupported proxy request\");\n return;\n }\n\n const targetContext = await resolveTargetRequestContext(originalUrl);\n if (!targetContext.targetUrl) {\n response.writeHead(502);\n response.end(\"unable to resolve loopback preview target\");\n return;\n }\n\n const headers = filterProxyHeaders(request.headers);\n headers.set(\"host\", targetContext.targetUrl.host);\n\n const forward =\n targetContext.targetUrl.protocol === \"https:\"\n ? httpsRequest\n : httpRequest;\n const upstream = forward(\n targetContext.targetUrl,\n {\n headers: Object.fromEntries(headers.entries()),\n method: request.method\n },\n (upstreamResponse) => {\n const responseHeaders = filterProxyHeaders(upstreamResponse.headers);\n const location = responseHeaders.get(\"location\");\n if (location && targetContext.loopbackTarget) {\n const rewritten = rewriteLoopbackLocation({\n location,\n originalUrl,\n targetUrl: targetContext.loopbackTarget.targetUrl\n });\n if (rewritten) {\n responseHeaders.set(\"location\", rewritten);\n }\n }\n\n response.writeHead(\n upstreamResponse.statusCode ?? 502,\n upstreamResponse.statusMessage,\n Object.fromEntries(responseHeaders.entries())\n );\n pipeline(upstreamResponse, response, () => undefined);\n }\n );\n\n upstream.on(\"error\", (error) => {\n logger?.warn?.(\"Browser Node loopback preview request failed\", {\n error: normalizeProxyError(error),\n originalUrl: originalUrl.toString(),\n targetUrl: targetContext.targetUrl?.toString() ?? null,\n workspaceId: targetContext.loopbackTarget?.workspaceId ?? null\n });\n if (!response.headersSent) {\n response.writeHead(502);\n }\n response.end(\n `loopback preview upstream request failed: ${normalizeProxyError(error)}`\n );\n });\n\n pipeline(request, upstream, () => undefined);\n };\n\n const handleUpgrade = async (\n request: IncomingMessage,\n socket: Socket,\n head: Buffer\n ): Promise<void> => {\n const originalUrl = resolveProxyRequestUrl(request, \"ws:\");\n if (!originalUrl) {\n socket.destroy();\n return;\n }\n if (originalUrl.protocol !== \"ws:\") {\n socket.destroy();\n return;\n }\n\n const targetContext = await resolveTargetRequestContext(originalUrl);\n const targetUrl = targetContext.targetUrl;\n if (!targetUrl) {\n socket.destroy();\n return;\n }\n\n downstreamWebSocketServer.handleUpgrade(\n request,\n socket,\n head,\n (downstream) => {\n const headers = Object.fromEntries(\n filterProxyHeaders(request.headers).entries()\n );\n headers.host = targetUrl.host;\n\n const upstream = new WebSocket(targetUrl, { headers });\n const pendingMessages: Array<{ data: RawData; isBinary: boolean }> = [];\n\n downstream.on(\"message\", (data, isBinary) => {\n if (upstream.readyState === WebSocket.OPEN) {\n upstream.send(data, { binary: isBinary });\n return;\n }\n pendingMessages.push({ data, isBinary });\n });\n\n upstream.once(\"open\", () => {\n for (const nextMessage of pendingMessages.splice(0)) {\n upstream.send(nextMessage.data, { binary: nextMessage.isBinary });\n }\n });\n\n upstream.on(\"message\", (data, isBinary) => {\n if (downstream.readyState === WebSocket.OPEN) {\n downstream.send(data, { binary: isBinary });\n }\n });\n\n upstream.once(\"close\", (code, reason) => {\n if (\n downstream.readyState === WebSocket.OPEN ||\n downstream.readyState === WebSocket.CONNECTING\n ) {\n downstream.close(normalizeWebSocketCloseCode(code), reason);\n }\n });\n\n downstream.once(\"close\", (code, reason) => {\n if (\n upstream.readyState === WebSocket.OPEN ||\n upstream.readyState === WebSocket.CONNECTING\n ) {\n upstream.close(normalizeWebSocketCloseCode(code), reason);\n }\n });\n\n upstream.once(\"error\", (error) => {\n logger?.warn?.(\"Browser Node loopback preview websocket failed\", {\n error: normalizeProxyError(error),\n originalUrl: originalUrl.toString(),\n targetUrl: targetContext.targetUrl?.toString() ?? null,\n workspaceId: targetContext.loopbackTarget?.workspaceId ?? null\n });\n downstream.close(1011, \"loopback preview websocket upstream failed\");\n });\n }\n );\n };\n\n const resolveTargetRequestContext = async (\n originalUrl: URL\n ): Promise<{\n loopbackTarget: BrowserNodeLoopbackPreviewTarget | null;\n targetUrl: URL | null;\n }> => {\n if (!isLoopbackUrl(originalUrl)) {\n return {\n loopbackTarget: null,\n targetUrl: null\n };\n }\n\n const loopbackTarget = await resolveLoopbackTarget(originalUrl);\n if (loopbackTarget) {\n return {\n loopbackTarget,\n targetUrl: buildTargetRequestUrl(loopbackTarget.targetUrl, originalUrl)\n };\n }\n\n if (fallback === \"direct\") {\n return {\n loopbackTarget: null,\n targetUrl: cloneUrl(originalUrl)\n };\n }\n\n return {\n loopbackTarget: null,\n targetUrl: null\n };\n };\n\n const addressForTesting = (): string => {\n const address = server?.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Browser Node loopback preview proxy is not listening\");\n }\n return `127.0.0.1:${address.port}`;\n };\n\n const serverForTesting = (): Server => {\n if (!server) {\n throw new Error(\"Browser Node loopback preview proxy is not started\");\n }\n return server;\n };\n\n return {\n addressForTesting,\n configureSession,\n dispose,\n serverForTesting\n };\n}\n\nfunction normalizeLoopbackPreviewTarget(\n input: BrowserNodeLoopbackPreviewTarget | null | undefined\n): BrowserNodeLoopbackPreviewTarget | null {\n if (!input) {\n return null;\n }\n const normalizedTargetUrl = input.targetUrl.trim();\n if (normalizedTargetUrl.length === 0) {\n return null;\n }\n try {\n const parsed = new URL(normalizedTargetUrl);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return null;\n }\n return {\n targetUrl: parsed.toString(),\n workspaceId: input.workspaceId\n };\n } catch {\n return null;\n }\n}\n\nfunction resolveProxyRequestUrl(\n request: IncomingMessage,\n defaultProtocol = \"http:\"\n): URL | null {\n const rawUrl = request.url ?? \"\";\n try {\n if (/^[a-z][a-z\\d+\\-.]*:\\/\\//i.test(rawUrl)) {\n return new URL(rawUrl);\n }\n const host = request.headers.host;\n if (typeof host !== \"string\" || host.trim().length === 0) {\n return null;\n }\n const path = rawUrl.startsWith(\"/\") ? rawUrl : `/${rawUrl}`;\n return new URL(`${defaultProtocol}//${host}${path}`);\n } catch {\n return null;\n }\n}\n\nfunction filterProxyHeaders(input: Headers | IncomingHttpHeaders): Headers {\n const output = new Headers();\n const appendValue = (key: string, value: string): void => {\n if (hopByHopHeaders.has(key.toLowerCase())) {\n return;\n }\n output.append(key, value);\n };\n\n if (input instanceof Headers) {\n input.forEach((value, key) => {\n appendValue(key, value);\n });\n return output;\n }\n\n for (const [key, value] of Object.entries(input)) {\n if (Array.isArray(value)) {\n for (const nextValue of value) {\n appendValue(key, nextValue);\n }\n continue;\n }\n if (typeof value === \"string\") {\n appendValue(key, value);\n }\n }\n return output;\n}\n\nfunction isLoopbackUrl(url: URL): boolean {\n return (\n (url.protocol === \"http:\" || url.protocol === \"ws:\") &&\n loopbackHostPattern.test(url.hostname) &&\n url.port.length > 0\n );\n}\n\nfunction buildTargetRequestUrl(\n targetUrl: string,\n originalUrl: URL\n): URL | null {\n try {\n const base = new URL(targetUrl);\n const normalizedBasePath = normalizeBasePath(base.pathname);\n const nextUrl = new URL(base.toString());\n nextUrl.pathname = joinBasePath(normalizedBasePath, originalUrl.pathname);\n nextUrl.search = originalUrl.search;\n nextUrl.hash = \"\";\n if (originalUrl.protocol === \"ws:\") {\n nextUrl.protocol = nextUrl.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n }\n return nextUrl;\n } catch {\n return null;\n }\n}\n\nfunction rewriteLoopbackLocation({\n location,\n originalUrl,\n targetUrl\n}: {\n location: string;\n originalUrl: URL;\n targetUrl: string;\n}): string | null {\n try {\n const targetBase = new URL(targetUrl);\n const resolvedLocation = new URL(location, targetBase);\n if (resolvedLocation.origin !== targetBase.origin) {\n return location;\n }\n\n const basePath = normalizeBasePath(targetBase.pathname);\n const strippedPath =\n stripBasePath(basePath, resolvedLocation.pathname) ??\n resolvedLocation.pathname;\n\n const loopbackUrl = new URL(originalUrl.origin);\n resolvedLocation.protocol = loopbackUrl.protocol;\n resolvedLocation.host = loopbackUrl.host;\n resolvedLocation.pathname = strippedPath;\n resolvedLocation.username = \"\";\n resolvedLocation.password = \"\";\n return resolvedLocation.toString();\n } catch {\n return location;\n }\n}\n\nfunction normalizeBasePath(pathname: string): string {\n const normalized = pathname.startsWith(\"/\") ? pathname : `/${pathname}`;\n return normalized.endsWith(\"/\") ? normalized : `${normalized}/`;\n}\n\nfunction joinBasePath(basePath: string, requestPath: string): string {\n const normalizedRequestPath =\n requestPath === \"/\" ? \"\" : requestPath.replace(/^\\/+/, \"\");\n return normalizedRequestPath.length > 0\n ? `${basePath}${normalizedRequestPath}`.replace(/\\/{2,}/g, \"/\")\n : basePath;\n}\n\nfunction stripBasePath(basePath: string, pathname: string): string | null {\n const normalizedPath = pathname.startsWith(\"/\") ? pathname : `/${pathname}`;\n if (normalizedPath === basePath.slice(0, -1)) {\n return \"/\";\n }\n if (!normalizedPath.startsWith(basePath)) {\n return null;\n }\n const suffix = normalizedPath.slice(basePath.length);\n return suffix.length > 0 ? `/${suffix}` : \"/\";\n}\n\nfunction cloneUrl(url: URL): URL | null {\n try {\n return new URL(url.toString());\n } catch {\n return null;\n }\n}\n\nfunction normalizeProxyError(error: unknown): string {\n if (error instanceof Error) {\n const code =\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ? ` ${(error as NodeJS.ErrnoException).code}`\n : \"\";\n return `${error.message}${code}`;\n }\n return String(error);\n}\n\nfunction normalizeWebSocketCloseCode(code: number): number {\n if (code === 1000 || (code >= 3000 && code <= 4999)) {\n return code;\n }\n return 1000;\n}\n","import type {\n BrowserNodeLifecycle,\n BrowserNodeNavigationPolicy,\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport {\n normalizeHostBrowserComparableUrl,\n resolveBrowserNavigationUrl,\n resolveHostBrowserNavigationUrl,\n type BrowserNavigationUrlResolution\n} from \"../core/url.ts\";\nimport type {\n BrowserGuestManager,\n BrowserGuestManagerInput,\n BrowserGuestNativeImage,\n BrowserPreferredColorScheme,\n BrowserGuestWebContents\n} from \"./types.ts\";\n\nconst browserPreviewMaxWidth = 260;\nconst browserPreviewMaxHeight = 170;\nconst abortedNavigationErrorCode = -3;\n\ninterface BrowserGuestSession {\n appliedColorScheme: BrowserPreferredColorScheme | null;\n contents: BrowserGuestWebContents | null;\n desiredUrl: string;\n lifecycle: BrowserNodeLifecycle;\n listeners: Array<{\n event: string;\n listener: (...args: unknown[]) => void;\n }>;\n navigationFailureSequence: number;\n navigationPolicy: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition: string | null;\n webContentsId: number | null;\n}\n\nfunction canGuestGoBack(contents: BrowserGuestWebContents): boolean {\n return contents.navigationHistory?.canGoBack() ?? contents.canGoBack();\n}\n\nfunction canGuestGoForward(contents: BrowserGuestWebContents): boolean {\n return contents.navigationHistory?.canGoForward() ?? contents.canGoForward();\n}\n\nfunction goGuestBack(contents: BrowserGuestWebContents): void {\n if (contents.navigationHistory) {\n contents.navigationHistory.goBack();\n return;\n }\n contents.goBack();\n}\n\nfunction goGuestForward(contents: BrowserGuestWebContents): void {\n if (contents.navigationHistory) {\n contents.navigationHistory.goForward();\n return;\n }\n contents.goForward();\n}\n\nfunction resolveBrowserNodeUrlError(\n resolved: BrowserNavigationUrlResolution\n): BrowserNodeRuntimeError {\n if (resolved.errorCode === \"invalid-url\") {\n return { code: \"invalid-url\" };\n }\n\n if (resolved.errorCode === \"unsupported-protocol\") {\n return {\n code: \"unsupported-protocol\",\n params: resolved.errorParams\n };\n }\n\n return { code: \"unsupported-url\" };\n}\n\nfunction resizeBrowserPreviewImage(\n image: BrowserGuestNativeImage\n): BrowserGuestNativeImage {\n if (image.isEmpty?.() === true || !image.resize || !image.getSize) {\n return image;\n }\n\n const size = image.getSize();\n if (size.width <= 0 || size.height <= 0) {\n return image;\n }\n\n const scale = Math.min(\n 1,\n browserPreviewMaxWidth / size.width,\n browserPreviewMaxHeight / size.height\n );\n if (scale >= 1) {\n return image;\n }\n\n return image.resize({\n height: Math.max(1, Math.round(size.height * scale)),\n quality: \"good\",\n width: Math.max(1, Math.round(size.width * scale))\n });\n}\n\nfunction isAbortedNavigationError(input: {\n errorCode?: number;\n errorDescription?: string;\n}): boolean {\n return (\n input.errorCode === abortedNavigationErrorCode ||\n input.errorDescription === \"ERR_ABORTED\"\n );\n}\n\nfunction isHttpErrorStatusCode(statusCode: number | undefined): boolean {\n return statusCode !== undefined && statusCode >= 400;\n}\n\nfunction emitBrowserNavigationFailed(input: {\n emit: BrowserGuestManagerInput[\"emit\"];\n errorCode?: number;\n errorDescription?: string;\n nodeId: string;\n}): void {\n input.emit({\n code: \"navigation-failed\",\n diagnosticMessage: input.errorDescription,\n nodeId: input.nodeId,\n params:\n input.errorCode === undefined\n ? undefined\n : { errorCode: input.errorCode },\n type: \"error\"\n });\n}\n\nfunction isGoogleGisOAuthPopupUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n if (\n parsed.protocol !== \"https:\" ||\n parsed.hostname !== \"accounts.google.com\" ||\n (parsed.pathname !== \"/o/oauth2/v2/auth\" &&\n parsed.pathname !== \"/o/oauth2/auth\")\n ) {\n return false;\n }\n\n const isGisSdkPopup =\n parsed.searchParams.get(\"gsiwebsdk\") === \"gis_attributes\";\n const isPopupResponse =\n parsed.searchParams.get(\"display\") === \"popup\" &&\n (parsed.searchParams.get(\"response_mode\") === \"form_post\" ||\n parsed.searchParams.get(\"redirect_uri\") === \"gis_transform\");\n\n return isGisSdkPopup || isPopupResponse;\n } catch {\n return false;\n }\n}\n\nfunction resolveBrowserNavigationOrigin(url: string): string | null {\n const resolved = resolveBrowserNavigationUrl(url);\n if (!resolved.url) {\n return null;\n }\n\n try {\n return new URL(resolved.url).origin;\n } catch {\n return null;\n }\n}\n\nfunction isBrowserNavigationAllowedByPolicy(input: {\n policy: BrowserNodeNavigationPolicy | null;\n url: string;\n}): boolean {\n if (!input.policy) {\n return true;\n }\n\n if (input.policy.mode === \"same-origin\") {\n const policyOrigin = resolveBrowserNavigationOrigin(input.policy.originUrl);\n const nextOrigin = resolveBrowserNavigationOrigin(input.url);\n return (\n policyOrigin !== null &&\n nextOrigin !== null &&\n policyOrigin === nextOrigin\n );\n }\n\n return true;\n}\n\nasync function applyPreferredColorSchemeToGuest(\n session: BrowserGuestSession,\n logger: BrowserGuestManagerInput[\"logger\"],\n syncPreferredColorScheme: BrowserGuestManagerInput[\"syncPreferredColorScheme\"],\n scheme: BrowserPreferredColorScheme | null\n): Promise<void> {\n const contents = session.contents;\n if (\n !contents ||\n contents.isDestroyed() ||\n !syncPreferredColorScheme ||\n scheme === null ||\n session.appliedColorScheme === scheme\n ) {\n return;\n }\n\n try {\n await syncPreferredColorScheme(contents, scheme);\n session.appliedColorScheme = scheme;\n } catch (error) {\n session.appliedColorScheme = null;\n logger?.warn?.(\"Browser Node failed to sync guest color scheme\", {\n error: error instanceof Error ? error.message : String(error),\n nodeId: session.nodeId,\n scheme,\n webContentsId: session.webContentsId\n });\n }\n}\n\nexport function createBrowserGuestManager({\n emit,\n getPreferredColorScheme,\n logger,\n openExternal,\n prepareSession,\n resolveWebContents,\n syncPreferredColorScheme,\n subscribePreferredColorScheme\n}: BrowserGuestManagerInput): BrowserGuestManager {\n const sessions = new Map<string, BrowserGuestSession>();\n const nodeIdByWebContentsId = new Map<number, string>();\n let preferredColorScheme = getPreferredColorScheme?.() ?? null;\n\n const getSession = (\n nodeId: string,\n input?: {\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n url?: string;\n }\n ): BrowserGuestSession => {\n const existing = sessions.get(nodeId);\n if (existing) {\n if (input?.profileId !== undefined) {\n existing.profileId = input.profileId;\n }\n if (input?.sessionMode !== undefined) {\n existing.sessionMode = input.sessionMode;\n }\n if (input?.sessionPartition !== undefined) {\n existing.sessionPartition = input.sessionPartition;\n }\n if (input?.navigationPolicy !== undefined) {\n existing.navigationPolicy = input.navigationPolicy;\n }\n if (input?.url !== undefined) {\n existing.desiredUrl = input.url;\n }\n return existing;\n }\n\n const session: BrowserGuestSession = {\n appliedColorScheme: null,\n contents: null,\n desiredUrl: input?.url ?? \"about:blank\",\n lifecycle: \"cold\",\n listeners: [],\n navigationFailureSequence: 0,\n navigationPolicy: input?.navigationPolicy ?? null,\n nodeId,\n profileId: input?.profileId ?? null,\n sessionMode: input?.sessionMode ?? \"shared\",\n sessionPartition: input?.sessionPartition ?? null,\n webContentsId: null\n };\n sessions.set(nodeId, session);\n return session;\n };\n\n const publishState = (session: BrowserGuestSession): void => {\n const contents =\n session.contents && !session.contents.isDestroyed()\n ? session.contents\n : null;\n emit({\n canGoBack: contents ? canGuestGoBack(contents) : false,\n canGoForward: contents ? canGuestGoForward(contents) : false,\n isAttachedToWindow: Boolean(contents),\n isLoading: contents ? contents.isLoading() : false,\n isOccluded: session.lifecycle === \"cold\",\n lifecycle: session.lifecycle,\n nodeId: session.nodeId,\n title: contents ? contents.getTitle() || null : null,\n type: \"state\",\n url: contents\n ? contents.getURL() || session.desiredUrl\n : session.desiredUrl\n });\n };\n\n const detachGuest = (session: BrowserGuestSession): void => {\n const contents = session.contents;\n const webContentsId = session.webContentsId;\n if (contents) {\n for (const record of session.listeners) {\n contents.off(record.event, record.listener);\n }\n }\n session.listeners = [];\n session.contents = null;\n session.appliedColorScheme = null;\n session.webContentsId = null;\n if (\n webContentsId !== null &&\n nodeIdByWebContentsId.get(webContentsId) === session.nodeId\n ) {\n nodeIdByWebContentsId.delete(webContentsId);\n }\n publishState(session);\n };\n\n const handlePreferredColorSchemeChange = (\n scheme: BrowserPreferredColorScheme\n ) => {\n preferredColorScheme = scheme;\n for (const session of sessions.values()) {\n session.appliedColorScheme = null;\n void applyPreferredColorSchemeToGuest(\n session,\n logger,\n syncPreferredColorScheme,\n scheme\n ).catch(() => undefined);\n }\n };\n\n const unsubscribePreferredColorScheme =\n subscribePreferredColorScheme?.(handlePreferredColorSchemeChange) ?? null;\n\n const attachGuestListeners = (session: BrowserGuestSession): void => {\n const contents = session.contents;\n if (!contents) {\n return;\n }\n\n const onStateChange = () => publishState(session);\n const onDidNavigate = (...args: unknown[]) => {\n const url = typeof args[1] === \"string\" ? args[1] : undefined;\n const statusCode = typeof args[2] === \"number\" ? args[2] : undefined;\n const statusText = typeof args[3] === \"string\" ? args[3] : undefined;\n publishState(session);\n if (!isHttpErrorStatusCode(statusCode)) {\n return;\n }\n\n logger?.warn?.(\"Browser Node guest navigation returned HTTP error\", {\n currentUrl: contents.getURL(),\n desiredUrl: session.desiredUrl,\n nodeId: session.nodeId,\n statusCode,\n statusText,\n url,\n webContentsId: session.webContentsId\n });\n emit({\n code: \"navigation-failed\",\n diagnosticMessage: statusText,\n nodeId: session.nodeId,\n params: {\n statusCode,\n ...(statusText ? { statusText } : {})\n },\n type: \"error\"\n });\n };\n const onFailLoad = (...args: unknown[]) => {\n const errorCode = typeof args[1] === \"number\" ? args[1] : undefined;\n const errorDescription =\n typeof args[2] === \"string\" ? args[2] : undefined;\n const validatedUrl = typeof args[3] === \"string\" ? args[3] : undefined;\n const isMainFrame = typeof args[4] === \"boolean\" ? args[4] : undefined;\n if (isAbortedNavigationError({ errorCode, errorDescription })) {\n publishState(session);\n return;\n }\n logger?.warn?.(\"Browser Node guest navigation failed\", {\n currentUrl: contents.getURL(),\n desiredUrl: session.desiredUrl,\n errorCode,\n errorDescription,\n isMainFrame,\n nodeId: session.nodeId,\n validatedUrl,\n webContentsId: session.webContentsId\n });\n session.navigationFailureSequence += 1;\n publishState(session);\n emitBrowserNavigationFailed({\n emit,\n errorCode,\n errorDescription,\n nodeId: session.nodeId\n });\n };\n const onDestroyed = () => detachGuest(session);\n const onWillNavigate = (...args: unknown[]) => {\n const event =\n args[0] && typeof args[0] === \"object\" && \"preventDefault\" in args[0]\n ? (args[0] as { preventDefault?: () => void })\n : null;\n const url = typeof args[1] === \"string\" ? args[1] : \"\";\n if (\n url.length === 0 ||\n isBrowserNavigationAllowedByPolicy({\n policy: session.navigationPolicy,\n url\n })\n ) {\n return;\n }\n\n event?.preventDefault?.();\n emitOpenUrlFromGuest(session, url);\n publishState(session);\n };\n\n const records: BrowserGuestSession[\"listeners\"] = [\n { event: \"did-start-loading\", listener: onStateChange },\n { event: \"did-stop-loading\", listener: onStateChange },\n { event: \"did-navigate\", listener: onDidNavigate },\n { event: \"did-navigate-in-page\", listener: onStateChange },\n { event: \"page-title-updated\", listener: onStateChange },\n { event: \"will-navigate\", listener: onWillNavigate },\n { event: \"did-fail-load\", listener: onFailLoad },\n { event: \"destroyed\", listener: onDestroyed }\n ];\n\n for (const record of records) {\n contents.on(record.event, record.listener);\n }\n session.listeners = records;\n };\n\n const loadDesiredUrl = async (\n session: BrowserGuestSession\n ): Promise<void> => {\n const contents = session.contents;\n if (!contents || contents.isDestroyed()) {\n publishState(session);\n return;\n }\n\n const resolved = resolveHostBrowserNavigationUrl(session.desiredUrl);\n if (!resolved.url) {\n emit({\n ...resolveBrowserNodeUrlError(resolved),\n nodeId: session.nodeId,\n type: \"error\"\n });\n publishState(session);\n return;\n }\n if (\n !isBrowserNavigationAllowedByPolicy({\n policy: session.navigationPolicy,\n url: resolved.url\n })\n ) {\n emitOpenUrlFromGuest(session, resolved.url);\n publishState(session);\n return;\n }\n\n const currentComparable = normalizeHostBrowserComparableUrl(\n contents.getURL()\n );\n const nextComparable = normalizeHostBrowserComparableUrl(resolved.url);\n if (currentComparable && currentComparable === nextComparable) {\n publishState(session);\n return;\n }\n\n const failureSequenceBeforeLoad = session.navigationFailureSequence;\n try {\n await contents.loadURL(resolved.url);\n publishState(session);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger?.warn?.(\"Browser Node guest loadURL failed\", {\n currentUrl: contents.getURL(),\n desiredUrl: session.desiredUrl,\n error: message,\n nodeId: session.nodeId,\n resolvedUrl: resolved.url,\n webContentsId: session.webContentsId\n });\n if (session.navigationFailureSequence !== failureSequenceBeforeLoad) {\n return;\n }\n publishState(session);\n emitBrowserNavigationFailed({\n emit,\n errorDescription: message,\n nodeId: session.nodeId\n });\n }\n };\n\n const emitOpenUrlFromGuest = (\n session: BrowserGuestSession,\n url: string\n ): { action: \"deny\" } => {\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n logger?.info?.(\"Browser Node guest emitted open-url\", {\n nodeId: session.nodeId,\n url: resolved.url,\n webContentsId: session.webContentsId\n });\n emit({\n reuseIfOpen: true,\n sourceNodeId: session.nodeId,\n type: \"open-url\",\n url: resolved.url\n });\n return { action: \"deny\" };\n }\n void Promise.resolve(openExternal(url)).catch((error: unknown) => {\n logger?.warn?.(\"Browser Node openExternal failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n });\n return { action: \"deny\" };\n };\n\n return {\n async activate(input) {\n const resolved = resolveHostBrowserNavigationUrl(input.url);\n if (!resolved.url) {\n throw new Error(\"Browser Node rejected navigation URL\");\n }\n const session = getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition,\n url: resolved.url\n });\n session.lifecycle = \"active\";\n await loadDesiredUrl(session);\n },\n async capturePreview(input) {\n const session = sessions.get(input.nodeId);\n const contents =\n session?.contents && !session.contents.isDestroyed()\n ? session.contents\n : null;\n if (!contents?.capturePage) {\n return null;\n }\n\n const image = await contents.capturePage();\n if (image.isEmpty?.() === true) {\n return null;\n }\n\n return resizeBrowserPreviewImage(image).toDataURL();\n },\n close(input) {\n const session = sessions.get(input.nodeId);\n if (session) {\n detachGuest(session);\n sessions.delete(input.nodeId);\n }\n emit({ nodeId: input.nodeId, type: \"closed\" });\n return Promise.resolve();\n },\n debugDump(input) {\n const session = sessions.get(input.nodeId);\n if (!session) {\n return null;\n }\n const contents =\n session.contents && !session.contents.isDestroyed()\n ? session.contents\n : null;\n return {\n canGoBack: contents ? canGuestGoBack(contents) : false,\n canGoForward: contents ? canGuestGoForward(contents) : false,\n currentUrl: contents ? contents.getURL() : null,\n desiredUrl: session.desiredUrl,\n isAttachedToWindow: Boolean(contents),\n isLoading: contents ? contents.isLoading() : false,\n lifecycle: session.lifecycle,\n nodeId: session.nodeId,\n profileId: session.profileId,\n sessionMode: session.sessionMode,\n sessionPartition: session.sessionPartition,\n title: contents ? contents.getTitle() : null,\n userAgent: contents?.getUserAgent?.() ?? null,\n webContentsDestroyed: session.contents\n ? session.contents.isDestroyed()\n : null,\n webContentsId: session.webContentsId\n };\n },\n goBack(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed() && canGuestGoBack(contents)) {\n goGuestBack(contents);\n }\n return Promise.resolve();\n },\n goForward(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed() && canGuestGoForward(contents)) {\n goGuestForward(contents);\n }\n return Promise.resolve();\n },\n handleGuestOpenUrl(webContentsId, input) {\n const nodeId = nodeIdByWebContentsId.get(webContentsId);\n const session = nodeId ? sessions.get(nodeId) : null;\n if (!session) {\n logger?.warn?.(\"Browser Node ignored guest open-url request\", {\n url: input.url,\n webContentsId\n });\n return;\n }\n logger?.info?.(\"Browser Node handling guest open-url request\", {\n nodeId: session.nodeId,\n url: input.url,\n webContentsId\n });\n emitOpenUrlFromGuest(session, input.url);\n },\n async navigate(input) {\n const resolved = resolveBrowserNavigationUrl(input.url);\n if (!resolved.url) {\n throw new Error(\"Browser Node rejected navigation URL\");\n }\n const session = getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n url: resolved.url\n });\n session.lifecycle = \"active\";\n await loadDesiredUrl(session);\n },\n async openExternal(input) {\n const resolved = resolveHostBrowserNavigationUrl(input.url);\n if (!resolved.url) {\n throw new Error(\"Browser Node rejected external URL\");\n }\n await Promise.resolve(openExternal(resolved.url));\n },\n openDevTools(input) {\n const session = sessions.get(input.nodeId);\n const contents = session?.contents ?? null;\n if (contents && !contents.isDestroyed()) {\n try {\n contents.openDevTools?.({ activate: true, mode: \"detach\" });\n } catch (error) {\n logger?.warn?.(\"Browser Node open devtools failed\", {\n error: error instanceof Error ? error.message : String(error),\n nodeId: input.nodeId,\n webContentsId: session?.webContentsId ?? null\n });\n throw error;\n }\n }\n return Promise.resolve();\n },\n async prepareSession(input) {\n await prepareSession?.(input);\n getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n });\n },\n async registerGuest(input) {\n await prepareSession?.({\n nodeId: input.nodeId,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition,\n navigationPolicy: input.navigationPolicy\n });\n const contents = resolveWebContents(input.webContentsId);\n if (!contents || contents.isDestroyed()) {\n throw new Error(\n `Browser Node guest ${input.webContentsId} is not available`\n );\n }\n\n const ownerNodeId = nodeIdByWebContentsId.get(input.webContentsId);\n if (ownerNodeId && ownerNodeId !== input.nodeId) {\n throw new Error(\n `Browser Node guest ${input.webContentsId} is already registered`\n );\n }\n\n const session = getSession(input.nodeId, {\n navigationPolicy: input.navigationPolicy,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n });\n if (\n session.webContentsId === input.webContentsId &&\n session.contents === contents\n ) {\n publishState(session);\n return;\n }\n if (session.contents && session.contents !== contents) {\n detachGuest(session);\n }\n session.contents = contents;\n session.webContentsId = input.webContentsId;\n nodeIdByWebContentsId.set(input.webContentsId, input.nodeId);\n session.lifecycle = \"active\";\n logger?.info?.(\"Browser Node registered guest owner\", {\n nodeId: input.nodeId,\n sessionPartition: session.sessionPartition,\n webContentsId: input.webContentsId\n });\n contents.setWindowOpenHandler?.(({ url }) => {\n if (isGoogleGisOAuthPopupUrl(url)) {\n logger?.info?.(\"Browser Node allowing Google GIS OAuth popup\", {\n nodeId: session.nodeId,\n webContentsId: session.webContentsId\n });\n return { action: \"allow\" };\n }\n\n return emitOpenUrlFromGuest(session, url);\n });\n attachGuestListeners(session);\n await applyPreferredColorSchemeToGuest(\n session,\n logger,\n syncPreferredColorScheme,\n preferredColorScheme\n );\n await loadDesiredUrl(session);\n },\n reload(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed()) {\n contents.reload();\n }\n return Promise.resolve();\n },\n unregisterGuest(input) {\n const session = sessions.get(input.nodeId);\n if (!session || session.webContentsId !== input.webContentsId) {\n return Promise.resolve();\n }\n session.lifecycle = \"cold\";\n detachGuest(session);\n return Promise.resolve();\n },\n dispose() {\n unsubscribePreferredColorScheme?.();\n }\n };\n}\n","import type { BrowserWindow } from \"electron\";\nimport { resolveBrowserSessionPartition } from \"../core/session.ts\";\nimport type { BrowserNodeLoopbackPreviewRoutingOptions } from \"./loopbackPreview.ts\";\nimport { createBrowserNodeLoopbackPreviewProxy } from \"./loopbackPreviewProxy.ts\";\nimport type {\n BrowserNodeActivationInput,\n BrowserNodeGuestOpenUrlInput,\n BrowserNodeNavigateInput,\n BrowserNodeNodeIdInput,\n BrowserNodeOpenExternalInput,\n BrowserNodePrepareSessionInput,\n BrowserNodeRegisterGuestInput,\n BrowserNodeShowDevToolsContextMenuInput,\n BrowserNodeUnregisterGuestInput\n} from \"../core/types.ts\";\nimport { createBrowserGuestManager } from \"./guestManager.ts\";\nimport type {\n BrowserGuestManager,\n BrowserPreferredColorScheme,\n BrowserGuestWebContents,\n BrowserNodeElectronLogger\n} from \"./types.ts\";\n\nexport interface BrowserNodeElectronMainChannels {\n readonly activate: string;\n readonly capturePreview?: string;\n readonly close: string;\n readonly debugDump?: string;\n readonly event: string;\n readonly goBack: string;\n readonly goForward: string;\n readonly guestOpenUrl?: string;\n readonly navigate: string;\n readonly openDevTools?: string;\n readonly openExternal?: string;\n readonly prepareSession: string;\n readonly registerGuest: string;\n readonly reload: string;\n readonly showDevToolsContextMenu?: string;\n readonly unregisterGuest: string;\n}\n\nexport interface BrowserNodeElectronDevToolsContextMenuInput {\n readonly label: string;\n readonly openDevTools: () => Promise<void> | void;\n readonly ownerWindow: BrowserWindow;\n readonly point: { x: number; y: number };\n}\n\nexport interface RegisterBrowserNodeElectronMainInput {\n readonly channels: BrowserNodeElectronMainChannels;\n readonly getOwnerWindow: (event: unknown) => BrowserWindow | null;\n readonly getPreferredColorScheme?: () => BrowserPreferredColorScheme;\n readonly logger?: BrowserNodeElectronLogger;\n readonly loopbackPreviewRouting?: BrowserNodeLoopbackPreviewRoutingOptions;\n readonly openExternal: (url: string) => Promise<void> | void;\n readonly registerHandler: <TPayload, TResult>(\n channel: string,\n handler: (event: unknown, payload: TPayload) => Promise<TResult> | TResult\n ) => void;\n readonly registerListener?: <TPayload>(\n channel: string,\n handler: (event: unknown, payload: TPayload) => void\n ) => void;\n readonly resolveWebContents: (input: {\n event: unknown;\n ownerWindow: BrowserWindow;\n webContentsId: number;\n }) => BrowserGuestWebContents | null;\n readonly showDevToolsContextMenu?: (\n input: BrowserNodeElectronDevToolsContextMenuInput\n ) => Promise<void> | void;\n readonly syncPreferredColorScheme?: (\n contents: BrowserGuestWebContents,\n scheme: BrowserPreferredColorScheme\n ) => Promise<void> | void;\n readonly subscribePreferredColorScheme?: (\n listener: (scheme: BrowserPreferredColorScheme) => void\n ) => () => void;\n}\n\nexport function registerBrowserNodeElectronMain(\n input: RegisterBrowserNodeElectronMainInput\n): void {\n const managersByWindow = new WeakMap<BrowserWindow, BrowserGuestManager>();\n const loopbackPreviewProxy =\n input.loopbackPreviewRouting !== undefined\n ? createBrowserNodeLoopbackPreviewProxy({\n logger: input.logger,\n resolveSession: async ({\n profileId,\n sessionMode,\n sessionPartition\n }) => {\n const { session } = await import(\"electron\");\n return session.fromPartition(\n resolveBrowserSessionPartition({\n profileId,\n sessionMode,\n sessionPartition\n })\n );\n },\n routing: input.loopbackPreviewRouting\n })\n : null;\n\n const resolveManagerForWindow = (\n event: unknown,\n ownerWindow: BrowserWindow\n ): BrowserGuestManager => {\n const existing = managersByWindow.get(ownerWindow);\n if (existing) {\n return existing;\n }\n\n const manager = createBrowserGuestManager({\n emit(browserEvent) {\n if (!ownerWindow.isDestroyed()) {\n ownerWindow.webContents.send(input.channels.event, browserEvent);\n }\n },\n getPreferredColorScheme: input.getPreferredColorScheme,\n logger: input.logger,\n openExternal: input.openExternal,\n prepareSession:\n loopbackPreviewProxy !== null\n ? (payload) => loopbackPreviewProxy.configureSession(payload)\n : undefined,\n resolveWebContents: (webContentsId) =>\n input.resolveWebContents({\n event,\n ownerWindow,\n webContentsId\n }),\n syncPreferredColorScheme: input.syncPreferredColorScheme,\n subscribePreferredColorScheme: input.subscribePreferredColorScheme\n });\n ownerWindow.once(\"closed\", () => {\n manager.dispose();\n managersByWindow.delete(ownerWindow);\n });\n managersByWindow.set(ownerWindow, manager);\n return manager;\n };\n\n const resolveOwnedManager = (event: unknown) => {\n const ownerWindow = input.getOwnerWindow(event);\n if (!ownerWindow) {\n throw new Error(\"Browser Node IPC requires an owner window\");\n }\n return {\n manager: resolveManagerForWindow(event, ownerWindow),\n ownerWindow\n };\n };\n\n const showDevToolsContextMenu =\n input.showDevToolsContextMenu ?? showElectronDevToolsContextMenu;\n\n input.registerHandler(input.channels.prepareSession, (event, payload) =>\n resolveOwnedManager(event).manager.prepareSession(\n payload as BrowserNodePrepareSessionInput\n )\n );\n input.registerHandler(input.channels.activate, (event, payload) =>\n resolveOwnedManager(event).manager.activate(\n payload as BrowserNodeActivationInput\n )\n );\n if (input.channels.capturePreview) {\n input.registerHandler(input.channels.capturePreview, (event, payload) =>\n resolveOwnedManager(event).manager.capturePreview(\n payload as BrowserNodeNodeIdInput\n )\n );\n }\n input.registerHandler(input.channels.registerGuest, (event, payload) =>\n resolveOwnedManager(event).manager.registerGuest(\n payload as BrowserNodeRegisterGuestInput\n )\n );\n input.registerHandler(input.channels.unregisterGuest, (event, payload) =>\n resolveOwnedManager(event).manager.unregisterGuest(\n payload as BrowserNodeUnregisterGuestInput\n )\n );\n input.registerHandler(input.channels.navigate, (event, payload) =>\n resolveOwnedManager(event).manager.navigate(\n payload as BrowserNodeNavigateInput\n )\n );\n if (input.channels.openExternal) {\n input.registerHandler(input.channels.openExternal, (event, payload) =>\n resolveOwnedManager(event).manager.openExternal(\n payload as BrowserNodeOpenExternalInput\n )\n );\n }\n if (input.channels.openDevTools) {\n input.registerHandler(input.channels.openDevTools, (event, payload) => {\n const nodePayload = payload as BrowserNodeNodeIdInput;\n return resolveOwnedManager(event).manager.openDevTools(nodePayload);\n });\n }\n if (input.channels.showDevToolsContextMenu) {\n input.registerHandler(\n input.channels.showDevToolsContextMenu,\n (event, payload) => {\n const contextMenuPayload =\n payload as BrowserNodeShowDevToolsContextMenuInput;\n const { manager, ownerWindow } = resolveOwnedManager(event);\n return showDevToolsContextMenu({\n label: contextMenuPayload.label,\n openDevTools: () => {\n return manager.openDevTools({ nodeId: contextMenuPayload.nodeId });\n },\n ownerWindow,\n point: contextMenuPayload.point\n });\n }\n );\n }\n input.registerHandler(input.channels.goBack, (event, payload) =>\n resolveOwnedManager(event).manager.goBack(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.goForward, (event, payload) =>\n resolveOwnedManager(event).manager.goForward(\n payload as BrowserNodeNodeIdInput\n )\n );\n input.registerHandler(input.channels.reload, (event, payload) =>\n resolveOwnedManager(event).manager.reload(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.close, (event, payload) =>\n resolveOwnedManager(event).manager.close(payload as BrowserNodeNodeIdInput)\n );\n if (input.channels.debugDump) {\n input.registerHandler(input.channels.debugDump, (event, payload) =>\n resolveOwnedManager(event).manager.debugDump(\n payload as BrowserNodeNodeIdInput\n )\n );\n }\n if (input.channels.guestOpenUrl && input.registerListener) {\n input.registerListener(input.channels.guestOpenUrl, (event, payload) => {\n const senderId = readBrowserNodeIpcSenderId(event);\n const openUrlPayload = payload as BrowserNodeGuestOpenUrlInput | null;\n if (\n typeof senderId !== \"number\" ||\n !Number.isFinite(senderId) ||\n !openUrlPayload ||\n typeof openUrlPayload.url !== \"string\"\n ) {\n return;\n }\n resolveOwnedManager(event).manager.handleGuestOpenUrl(\n senderId,\n openUrlPayload\n );\n });\n }\n}\n\nasync function showElectronDevToolsContextMenu(\n input: BrowserNodeElectronDevToolsContextMenuInput\n): Promise<void> {\n const { Menu } = await import(\"electron\");\n const menu = Menu.buildFromTemplate([\n {\n click: () => {\n void Promise.resolve(input.openDevTools()).catch(() => undefined);\n },\n label: input.label\n }\n ]);\n menu.popup({\n window: input.ownerWindow,\n x: Math.round(input.point.x),\n y: Math.round(input.point.y)\n });\n}\n\nfunction readBrowserNodeIpcSenderId(event: unknown): number | null {\n const sender = (event as { sender?: { id?: unknown } } | null)?.sender;\n return typeof sender?.id === \"number\" ? sender.id : null;\n}\n","import type { WebContents } from \"electron\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nconst electronUserAgentTokenPattern = /\\sElectron\\/[^\\s]+/g;\n\nexport function sanitizeBrowserGuestUserAgent(userAgent: string): string {\n return userAgent\n .trim()\n .replace(electronUserAgentTokenPattern, \"\")\n .replace(/\\s{2,}/g, \" \");\n}\n\nexport function applyBrowserGuestUserAgent(\n contents: WebContents,\n logger?: BrowserNodeElectronLogger\n): void {\n const guestContents = contents as WebContents & {\n getUserAgent?: () => string;\n setUserAgent?: (userAgent: string) => void;\n };\n if (\n typeof guestContents.getUserAgent !== \"function\" ||\n typeof guestContents.setUserAgent !== \"function\"\n ) {\n return;\n }\n\n const currentUserAgent = guestContents.getUserAgent().trim();\n const nextUserAgent = sanitizeBrowserGuestUserAgent(currentUserAgent);\n if (!nextUserAgent || nextUserAgent === currentUserAgent) {\n return;\n }\n\n guestContents.setUserAgent(nextUserAgent);\n logger?.debug?.(\"Browser Node sanitized guest user agent\", {\n webContentsId: contents.id ?? null\n });\n}\n","import type { Event, WebContents, WebPreferences } from \"electron\";\nimport {\n isBrowserSessionPartitionAllowed,\n type BrowserSessionPartitionAllowedOptions\n} from \"../core/session.ts\";\nimport { resolveBrowserNavigationUrl } from \"../core/url.ts\";\nimport { applyBrowserGuestUserAgent } from \"./userAgent.ts\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nexport interface BrowserWebviewSecurityInput {\n allowedSessionPartitions?: BrowserSessionPartitionAllowedOptions;\n params: Record<string, string>;\n resolvePreload?: BrowserWebviewPreloadResolver;\n webPreferences: WebPreferences;\n}\n\nexport interface BrowserWebviewSecurityResult {\n allowed: boolean;\n reason: string | null;\n}\n\nexport type BrowserNodeWebviewMatcher = (\n params: Record<string, string>\n) => boolean;\n\ninterface PendingBrowserWebviewAttach {\n allowNativePopups: boolean;\n}\n\nexport interface BrowserWebviewPreloadResolverInput {\n params: Readonly<Record<string, string>>;\n}\n\nexport type BrowserWebviewPreloadResolver = (\n input: BrowserWebviewPreloadResolverInput\n) => string | null | undefined;\n\nfunction isBrowserNodeInitialWebviewUrl(url: string | undefined): boolean {\n return (url ?? \"\").trim() === \"about:blank\";\n}\n\nexport function isBrowserNodeWebviewAttach(\n params: Record<string, string>,\n allowedSessionPartitions?: BrowserSessionPartitionAllowedOptions\n): boolean {\n return (\n params[\"data-browser-node-webview\"] === \"true\" ||\n isBrowserSessionPartitionAllowed(params.partition, allowedSessionPartitions)\n );\n}\n\nfunction shouldAllowBrowserNodeNativePopups(\n params: Record<string, string>\n): boolean {\n return (\n params[\"data-browser-node-webview\"] === \"true\" ||\n isBrowserSessionPartitionAllowed(params.partition)\n );\n}\n\nfunction getPopupLogMetadata(url: string): Record<string, unknown> {\n try {\n const parsed = new URL(url);\n return {\n popupOrigin: parsed.origin,\n popupPath: parsed.pathname,\n popupProtocol: parsed.protocol\n };\n } catch {\n return {\n popupOrigin: null,\n popupPath: null,\n popupProtocol: null\n };\n }\n}\n\nfunction externalizeBrowserNodePopupWindow({\n guestWebContentsId,\n logger,\n openExternal,\n url\n}: {\n guestWebContentsId: number | null;\n logger?: BrowserNodeElectronLogger;\n openExternal: (url: string) => Promise<void> | void;\n url: string;\n}) {\n logger?.info?.(\"Browser Node webview popup externalized\", {\n guestWebContentsId,\n ...getPopupLogMetadata(url)\n });\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n void Promise.resolve(openExternal(resolved.url)).catch(() => undefined);\n }\n return { action: \"deny\" as const };\n}\n\nexport function enforceBrowserWebviewSecurity({\n allowedSessionPartitions,\n params,\n resolvePreload,\n webPreferences\n}: BrowserWebviewSecurityInput): BrowserWebviewSecurityResult {\n webPreferences.allowRunningInsecureContent = false;\n webPreferences.contextIsolation = true;\n webPreferences.javascript = true;\n webPreferences.nodeIntegration = false;\n webPreferences.plugins = false;\n webPreferences.sandbox = true;\n webPreferences.webSecurity = true;\n delete webPreferences.preload;\n\n const partition = params.partition;\n if (\n !partition ||\n !isBrowserSessionPartitionAllowed(partition, allowedSessionPartitions)\n ) {\n return {\n allowed: false,\n reason: \"Unsupported Browser Node session partition\"\n };\n }\n\n if (isBrowserNodeInitialWebviewUrl(params.src)) {\n params.src = \"about:blank\";\n } else {\n const resolved = resolveBrowserNavigationUrl(params.src ?? \"about:blank\");\n if (!resolved.url) {\n return {\n allowed: false,\n reason: \"Unsupported browser URL\"\n };\n }\n params.src = resolved.url;\n }\n\n const preload = resolvePreload?.({ params: { ...params } });\n const resolvedPreload = typeof preload === \"string\" ? preload.trim() : \"\";\n if (resolvedPreload.length > 0) {\n webPreferences.preload = resolvedPreload;\n }\n\n return { allowed: true, reason: null };\n}\n\nexport interface InstallBrowserWebviewSecurityInput {\n allowedSessionPartitions?: BrowserSessionPartitionAllowedOptions;\n contents: WebContents;\n logger?: BrowserNodeElectronLogger;\n onGuestAttached?: (guestContents: WebContents) => void;\n openExternal: (url: string) => Promise<void> | void;\n resolvePreload?: BrowserWebviewPreloadResolver;\n shouldHandleWebview?: BrowserNodeWebviewMatcher;\n}\n\nexport function installBrowserWebviewSecurity({\n allowedSessionPartitions,\n contents,\n logger,\n onGuestAttached,\n openExternal,\n resolvePreload,\n shouldHandleWebview\n}: InstallBrowserWebviewSecurityInput): () => void {\n const pendingBrowserAttaches: PendingBrowserWebviewAttach[] = [];\n\n const handleWillAttachWebview = (\n event: Event,\n webPreferences: WebPreferences,\n params: Record<string, string>\n ) => {\n const shouldHandle =\n shouldHandleWebview?.(params) ??\n isBrowserNodeWebviewAttach(params, allowedSessionPartitions);\n logger?.debug?.(\"Browser Node webview will attach\", {\n partition: params.partition ?? null,\n shouldHandle,\n src: params.src ?? null\n });\n if (!shouldHandle) {\n return;\n }\n\n const allowNativePopups = shouldAllowBrowserNodeNativePopups(params);\n if (allowNativePopups) {\n params.allowpopups = \"true\";\n }\n logger?.info?.(\"Browser Node webview popup policy applied\", {\n allowNativePopups,\n allowpopups: params.allowpopups ?? null,\n partition: params.partition ?? null,\n src: params.src ?? null\n });\n\n const result = enforceBrowserWebviewSecurity({\n allowedSessionPartitions,\n params,\n resolvePreload,\n webPreferences\n });\n if (!result.allowed) {\n logger?.warn?.(\"Browser Node webview blocked\", { reason: result.reason });\n event.preventDefault();\n return;\n }\n pendingBrowserAttaches.push({\n allowNativePopups\n });\n logger?.debug?.(\"Browser Node webview attach allowed\", {\n partition: params.partition ?? null,\n src: params.src ?? null\n });\n };\n\n const handleDidAttachWebview = (\n _event: Event,\n guestContents: WebContents\n ) => {\n const pendingAttach = pendingBrowserAttaches.shift();\n if (!pendingAttach) {\n logger?.debug?.(\"Browser Node webview did attach ignored\", {\n guestWebContentsId: guestContents.id ?? null,\n pendingBrowserAttachCount: pendingBrowserAttaches.length\n });\n return;\n }\n\n applyBrowserGuestUserAgent(guestContents, logger);\n if (pendingAttach.allowNativePopups) {\n guestContents.setWindowOpenHandler(({ url }) => {\n return externalizeBrowserNodePopupWindow({\n guestWebContentsId: guestContents.id ?? null,\n logger,\n openExternal,\n url\n });\n });\n } else {\n guestContents.setWindowOpenHandler(({ url }) => {\n return externalizeBrowserNodePopupWindow({\n guestWebContentsId: guestContents.id ?? null,\n logger,\n openExternal,\n url\n });\n });\n }\n onGuestAttached?.(guestContents);\n logger?.debug?.(\"Browser Node webview guest attached\", {\n guestWebContentsId: guestContents.id ?? null,\n pendingBrowserAttachCount: pendingBrowserAttaches.length\n });\n };\n\n contents.on(\"will-attach-webview\", handleWillAttachWebview);\n contents.on(\"did-attach-webview\", handleDidAttachWebview);\n\n return () => {\n contents.off(\"will-attach-webview\", handleWillAttachWebview);\n contents.off(\"did-attach-webview\", handleDidAttachWebview);\n };\n}\n"],"mappings":";;;;;;;;;;;AAAA;AAAA,EACE;AAAA,EACA,WAAW;AAAA,OAKN;AACP,SAAS,WAAW,oBAAoB;AAExC,SAAS,gBAAgB;AACzB,OAAO,aAAa,uBAAuB;AAS3C,IAAM,mCAAmC;AACzC,IAAM,sBAAsB;AAG5B,IAAM,kCAAkC;AACxC,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAoCM,SAAS,sCAAsC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AACF,GAA0E;AACxE,QAAM,qBAAqB,oBAAI,QAAmC;AAClE,QAAM,cAAc,oBAAI,IAAyC;AACjE,QAAM,4BAA4B,IAAI,gBAAgB,EAAE,UAAU,KAAK,CAAC;AACxE,MAAI,SAAwB;AAC5B,MAAI,qBAA6C;AAEjD,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,WAAW,QAAQ,YAAY;AAErC,QAAM,sBAAsB,CAAC,QAAsB;AACjD,eAAW,CAAC,UAAU,YAAY,KAAK,YAAY,QAAQ,GAAG;AAC5D,UAAI,aAAa,aAAa,KAAK;AACjC,oBAAY,OAAO,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,YAA6B;AACzC,QAAI,QAAQ,WAAW;AACrB,aAAO,kBAAkB;AAAA,IAC3B;AACA,QAAI,oBAAoB;AACtB,aAAO;AAAA,IACT;AAEA,yBAAqB,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC5D,YAAM,aAAa,aAAa,CAAC,SAAS,aAAa;AACrD,aAAK,cAAc,SAAS,QAAQ;AAAA,MACtC,CAAC;AACD,iBAAW,GAAG,WAAW,CAAC,SAAS,QAAQ,SAAS;AAClD,aAAK,cAAc,SAAS,QAAkB,IAAI;AAAA,MACpD,CAAC;AAED,YAAM,UAAU,MAAY;AAC1B,mBAAW,eAAe,SAAS,OAAO;AAC1C,mBAAW,eAAe,aAAa,WAAW;AAAA,MACpD;AACA,YAAM,UAAU,CAAC,UAAuB;AACtC,gBAAQ;AACR,eAAO,KAAK;AAAA,MACd;AACA,YAAM,cAAc,MAAY;AAC9B,gBAAQ;AACR,iBAAS;AACT,gBAAQ,kBAAkB,CAAC;AAAA,MAC7B;AAEA,iBAAW,KAAK,SAAS,OAAO;AAChC,iBAAW,KAAK,aAAa,WAAW;AACxC,iBAAW,OAAO,GAAG,WAAW;AAAA,IAClC,CAAC,EAAE,QAAQ,MAAM;AACf,2BAAqB;AAAA,IACvB,CAAC;AAED,WAAO;AAAA,EACT;AAEA,QAAM,wBAAwB,OAC5B,gBACqD;AACrD,UAAM,OAAO,OAAO,YAAY,IAAI;AACpC,QAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OAAO;AACvD,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,IAAI;AACrB,wBAAoB,GAAG;AAEvB,UAAM,WAAW,YAAY,SAAS;AACtC,UAAM,SAAS,YAAY,IAAI,QAAQ;AACvC,QAAI,UAAU,OAAO,YAAY,KAAK;AACpC,aAAO,OAAO;AAAA,IAChB;AAEA,UAAM,aAAa,MAAM,QAAQ;AAAA,MAC/B,QAAQ,SAAS,cAAc;AAAA,QAC7B;AAAA,QACA,KAAK,YAAY,SAAS;AAAA,MAC5B,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,+BAA+B,UAAU;AACxD,gBAAY,IAAI,UAAU;AAAA,MACxB,WAAW,MAAM,KAAK,IAAI,GAAG,UAAU;AAAA,MACvC;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,OAAO,UAIX;AACnB,UAAM,cAAc,MAAM,eAAe,KAAK;AAC9C,QAAI,mBAAmB,IAAI,WAAW,GAAG;AACvC;AAAA,IACF;AACA,UAAM,UAAU,MAAM,MAAM;AAC5B,UAAM,YAAY,SAAS;AAAA,MACzB,MAAM;AAAA,MACN,kBAAkB;AAAA,MAClB,YAAY,QAAQ,OAAO;AAAA,IAC7B,CAAC;AACD,uBAAmB,IAAI,WAAW;AAAA,EACpC;AAEA,QAAM,UAAU,YAA2B;AACzC,gBAAY,MAAM;AAClB,8BAA0B,MAAM;AAChC,UAAM,eAAe;AACrB,aAAS;AACT,QAAI,CAAC,gBAAgB,CAAC,aAAa,WAAW;AAC5C;AAAA,IACF;AACA,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,mBAAa,MAAM,MAAM,QAAQ,CAAC;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,OACpB,SACA,aACkB;AAClB,UAAM,cAAc,uBAAuB,OAAO;AAClD,QAAI,CAAC,aAAa;AAChB,eAAS,UAAU,GAAG;AACtB,eAAS,IAAI,uBAAuB;AACpC;AAAA,IACF;AACA,QAAI,YAAY,aAAa,SAAS;AACpC,eAAS,UAAU,GAAG;AACtB,eAAS,IAAI,2BAA2B;AACxC;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM,4BAA4B,WAAW;AACnE,QAAI,CAAC,cAAc,WAAW;AAC5B,eAAS,UAAU,GAAG;AACtB,eAAS,IAAI,2CAA2C;AACxD;AAAA,IACF;AAEA,UAAM,UAAU,mBAAmB,QAAQ,OAAO;AAClD,YAAQ,IAAI,QAAQ,cAAc,UAAU,IAAI;AAEhD,UAAM,UACJ,cAAc,UAAU,aAAa,WACjC,eACA;AACN,UAAM,WAAW;AAAA,MACf,cAAc;AAAA,MACd;AAAA,QACE,SAAS,OAAO,YAAY,QAAQ,QAAQ,CAAC;AAAA,QAC7C,QAAQ,QAAQ;AAAA,MAClB;AAAA,MACA,CAAC,qBAAqB;AACpB,cAAM,kBAAkB,mBAAmB,iBAAiB,OAAO;AACnE,cAAM,WAAW,gBAAgB,IAAI,UAAU;AAC/C,YAAI,YAAY,cAAc,gBAAgB;AAC5C,gBAAM,YAAY,wBAAwB;AAAA,YACxC;AAAA,YACA;AAAA,YACA,WAAW,cAAc,eAAe;AAAA,UAC1C,CAAC;AACD,cAAI,WAAW;AACb,4BAAgB,IAAI,YAAY,SAAS;AAAA,UAC3C;AAAA,QACF;AAEA,iBAAS;AAAA,UACP,iBAAiB,cAAc;AAAA,UAC/B,iBAAiB;AAAA,UACjB,OAAO,YAAY,gBAAgB,QAAQ,CAAC;AAAA,QAC9C;AACA,iBAAS,kBAAkB,UAAU,MAAM,MAAS;AAAA,MACtD;AAAA,IACF;AAEA,aAAS,GAAG,SAAS,CAAC,UAAU;AAC9B,cAAQ,OAAO,gDAAgD;AAAA,QAC7D,OAAO,oBAAoB,KAAK;AAAA,QAChC,aAAa,YAAY,SAAS;AAAA,QAClC,WAAW,cAAc,WAAW,SAAS,KAAK;AAAA,QAClD,aAAa,cAAc,gBAAgB,eAAe;AAAA,MAC5D,CAAC;AACD,UAAI,CAAC,SAAS,aAAa;AACzB,iBAAS,UAAU,GAAG;AAAA,MACxB;AACA,eAAS;AAAA,QACP,6CAA6C,oBAAoB,KAAK,CAAC;AAAA,MACzE;AAAA,IACF,CAAC;AAED,aAAS,SAAS,UAAU,MAAM,MAAS;AAAA,EAC7C;AAEA,QAAM,gBAAgB,OACpB,SACA,QACA,SACkB;AAClB,UAAM,cAAc,uBAAuB,SAAS,KAAK;AACzD,QAAI,CAAC,aAAa;AAChB,aAAO,QAAQ;AACf;AAAA,IACF;AACA,QAAI,YAAY,aAAa,OAAO;AAClC,aAAO,QAAQ;AACf;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM,4BAA4B,WAAW;AACnE,UAAM,YAAY,cAAc;AAChC,QAAI,CAAC,WAAW;AACd,aAAO,QAAQ;AACf;AAAA,IACF;AAEA,8BAA0B;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,eAAe;AACd,cAAM,UAAU,OAAO;AAAA,UACrB,mBAAmB,QAAQ,OAAO,EAAE,QAAQ;AAAA,QAC9C;AACA,gBAAQ,OAAO,UAAU;AAEzB,cAAM,WAAW,IAAI,UAAU,WAAW,EAAE,QAAQ,CAAC;AACrD,cAAM,kBAA+D,CAAC;AAEtE,mBAAW,GAAG,WAAW,CAAC,MAAM,aAAa;AAC3C,cAAI,SAAS,eAAe,UAAU,MAAM;AAC1C,qBAAS,KAAK,MAAM,EAAE,QAAQ,SAAS,CAAC;AACxC;AAAA,UACF;AACA,0BAAgB,KAAK,EAAE,MAAM,SAAS,CAAC;AAAA,QACzC,CAAC;AAED,iBAAS,KAAK,QAAQ,MAAM;AAC1B,qBAAW,eAAe,gBAAgB,OAAO,CAAC,GAAG;AACnD,qBAAS,KAAK,YAAY,MAAM,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UAClE;AAAA,QACF,CAAC;AAED,iBAAS,GAAG,WAAW,CAAC,MAAM,aAAa;AACzC,cAAI,WAAW,eAAe,UAAU,MAAM;AAC5C,uBAAW,KAAK,MAAM,EAAE,QAAQ,SAAS,CAAC;AAAA,UAC5C;AAAA,QACF,CAAC;AAED,iBAAS,KAAK,SAAS,CAAC,MAAM,WAAW;AACvC,cACE,WAAW,eAAe,UAAU,QACpC,WAAW,eAAe,UAAU,YACpC;AACA,uBAAW,MAAM,4BAA4B,IAAI,GAAG,MAAM;AAAA,UAC5D;AAAA,QACF,CAAC;AAED,mBAAW,KAAK,SAAS,CAAC,MAAM,WAAW;AACzC,cACE,SAAS,eAAe,UAAU,QAClC,SAAS,eAAe,UAAU,YAClC;AACA,qBAAS,MAAM,4BAA4B,IAAI,GAAG,MAAM;AAAA,UAC1D;AAAA,QACF,CAAC;AAED,iBAAS,KAAK,SAAS,CAAC,UAAU;AAChC,kBAAQ,OAAO,kDAAkD;AAAA,YAC/D,OAAO,oBAAoB,KAAK;AAAA,YAChC,aAAa,YAAY,SAAS;AAAA,YAClC,WAAW,cAAc,WAAW,SAAS,KAAK;AAAA,YAClD,aAAa,cAAc,gBAAgB,eAAe;AAAA,UAC5D,CAAC;AACD,qBAAW,MAAM,MAAM,4CAA4C;AAAA,QACrE,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,QAAM,8BAA8B,OAClC,gBAII;AACJ,QAAI,CAAC,cAAc,WAAW,GAAG;AAC/B,aAAO;AAAA,QACL,gBAAgB;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,sBAAsB,WAAW;AAC9D,QAAI,gBAAgB;AAClB,aAAO;AAAA,QACL;AAAA,QACA,WAAW,sBAAsB,eAAe,WAAW,WAAW;AAAA,MACxE;AAAA,IACF;AAEA,QAAI,aAAa,UAAU;AACzB,aAAO;AAAA,QACL,gBAAgB;AAAA,QAChB,WAAW,SAAS,WAAW;AAAA,MACjC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,WAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAc;AACtC,UAAM,UAAU,QAAQ,QAAQ;AAChC,QAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,YAAM,IAAI,MAAM,sDAAsD;AAAA,IACxE;AACA,WAAO,aAAa,QAAQ,IAAI;AAAA,EAClC;AAEA,QAAM,mBAAmB,MAAc;AACrC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,+BACP,OACyC;AACzC,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,sBAAsB,MAAM,UAAU,KAAK;AACjD,MAAI,oBAAoB,WAAW,GAAG;AACpC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,mBAAmB;AAC1C,QAAI,OAAO,aAAa,WAAW,OAAO,aAAa,UAAU;AAC/D,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,WAAW,OAAO,SAAS;AAAA,MAC3B,aAAa,MAAM;AAAA,IACrB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBACP,SACA,kBAAkB,SACN;AACZ,QAAM,SAAS,QAAQ,OAAO;AAC9B,MAAI;AACF,QAAI,2BAA2B,KAAK,MAAM,GAAG;AAC3C,aAAO,IAAI,IAAI,MAAM;AAAA,IACvB;AACA,UAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAI,OAAO,SAAS,YAAY,KAAK,KAAK,EAAE,WAAW,GAAG;AACxD,aAAO;AAAA,IACT;AACA,UAAM,OAAO,OAAO,WAAW,GAAG,IAAI,SAAS,IAAI,MAAM;AACzD,WAAO,IAAI,IAAI,GAAG,eAAe,KAAK,IAAI,GAAG,IAAI,EAAE;AAAA,EACrD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,OAA+C;AACzE,QAAM,SAAS,IAAI,QAAQ;AAC3B,QAAM,cAAc,CAAC,KAAa,UAAwB;AACxD,QAAI,gBAAgB,IAAI,IAAI,YAAY,CAAC,GAAG;AAC1C;AAAA,IACF;AACA,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B;AAEA,MAAI,iBAAiB,SAAS;AAC5B,UAAM,QAAQ,CAAC,OAAO,QAAQ;AAC5B,kBAAY,KAAK,KAAK;AAAA,IACxB,CAAC;AACD,WAAO;AAAA,EACT;AAEA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,aAAa,OAAO;AAC7B,oBAAY,KAAK,SAAS;AAAA,MAC5B;AACA;AAAA,IACF;AACA,QAAI,OAAO,UAAU,UAAU;AAC7B,kBAAY,KAAK,KAAK;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,KAAmB;AACxC,UACG,IAAI,aAAa,WAAW,IAAI,aAAa,UAC9C,oBAAoB,KAAK,IAAI,QAAQ,KACrC,IAAI,KAAK,SAAS;AAEtB;AAEA,SAAS,sBACP,WACA,aACY;AACZ,MAAI;AACF,UAAM,OAAO,IAAI,IAAI,SAAS;AAC9B,UAAM,qBAAqB,kBAAkB,KAAK,QAAQ;AAC1D,UAAM,UAAU,IAAI,IAAI,KAAK,SAAS,CAAC;AACvC,YAAQ,WAAW,aAAa,oBAAoB,YAAY,QAAQ;AACxE,YAAQ,SAAS,YAAY;AAC7B,YAAQ,OAAO;AACf,QAAI,YAAY,aAAa,OAAO;AAClC,cAAQ,WAAW,QAAQ,aAAa,WAAW,SAAS;AAAA,IAC9D;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,GAIkB;AAChB,MAAI;AACF,UAAM,aAAa,IAAI,IAAI,SAAS;AACpC,UAAM,mBAAmB,IAAI,IAAI,UAAU,UAAU;AACrD,QAAI,iBAAiB,WAAW,WAAW,QAAQ;AACjD,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,kBAAkB,WAAW,QAAQ;AACtD,UAAM,eACJ,cAAc,UAAU,iBAAiB,QAAQ,KACjD,iBAAiB;AAEnB,UAAM,cAAc,IAAI,IAAI,YAAY,MAAM;AAC9C,qBAAiB,WAAW,YAAY;AACxC,qBAAiB,OAAO,YAAY;AACpC,qBAAiB,WAAW;AAC5B,qBAAiB,WAAW;AAC5B,qBAAiB,WAAW;AAC5B,WAAO,iBAAiB,SAAS;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,UAA0B;AACnD,QAAM,aAAa,SAAS,WAAW,GAAG,IAAI,WAAW,IAAI,QAAQ;AACrE,SAAO,WAAW,SAAS,GAAG,IAAI,aAAa,GAAG,UAAU;AAC9D;AAEA,SAAS,aAAa,UAAkB,aAA6B;AACnE,QAAM,wBACJ,gBAAgB,MAAM,KAAK,YAAY,QAAQ,QAAQ,EAAE;AAC3D,SAAO,sBAAsB,SAAS,IAClC,GAAG,QAAQ,GAAG,qBAAqB,GAAG,QAAQ,WAAW,GAAG,IAC5D;AACN;AAEA,SAAS,cAAc,UAAkB,UAAiC;AACxE,QAAM,iBAAiB,SAAS,WAAW,GAAG,IAAI,WAAW,IAAI,QAAQ;AACzE,MAAI,mBAAmB,SAAS,MAAM,GAAG,EAAE,GAAG;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,CAAC,eAAe,WAAW,QAAQ,GAAG;AACxC,WAAO;AAAA,EACT;AACA,QAAM,SAAS,eAAe,MAAM,SAAS,MAAM;AACnD,SAAO,OAAO,SAAS,IAAI,IAAI,MAAM,KAAK;AAC5C;AAEA,SAAS,SAAS,KAAsB;AACtC,MAAI;AACF,WAAO,IAAI,IAAI,IAAI,SAAS,CAAC;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,OAAwB;AACnD,MAAI,iBAAiB,OAAO;AAC1B,UAAM,OACJ,OAAQ,MAAgC,SAAS,WAC7C,IAAK,MAAgC,IAAI,KACzC;AACN,WAAO,GAAG,MAAM,OAAO,GAAG,IAAI;AAAA,EAChC;AACA,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,4BAA4B,MAAsB;AACzD,MAAI,SAAS,OAAS,QAAQ,OAAQ,QAAQ,MAAO;AACnD,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACpkBA,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,6BAA6B;AAoBnC,SAAS,eAAe,UAA4C;AAClE,SAAO,SAAS,mBAAmB,UAAU,KAAK,SAAS,UAAU;AACvE;AAEA,SAAS,kBAAkB,UAA4C;AACrE,SAAO,SAAS,mBAAmB,aAAa,KAAK,SAAS,aAAa;AAC7E;AAEA,SAAS,YAAY,UAAyC;AAC5D,MAAI,SAAS,mBAAmB;AAC9B,aAAS,kBAAkB,OAAO;AAClC;AAAA,EACF;AACA,WAAS,OAAO;AAClB;AAEA,SAAS,eAAe,UAAyC;AAC/D,MAAI,SAAS,mBAAmB;AAC9B,aAAS,kBAAkB,UAAU;AACrC;AAAA,EACF;AACA,WAAS,UAAU;AACrB;AAEA,SAAS,2BACP,UACyB;AACzB,MAAI,SAAS,cAAc,eAAe;AACxC,WAAO,EAAE,MAAM,cAAc;AAAA,EAC/B;AAEA,MAAI,SAAS,cAAc,wBAAwB;AACjD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,kBAAkB;AACnC;AAEA,SAAS,0BACP,OACyB;AACzB,MAAI,MAAM,UAAU,MAAM,QAAQ,CAAC,MAAM,UAAU,CAAC,MAAM,SAAS;AACjE,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM,QAAQ;AAC3B,MAAI,KAAK,SAAS,KAAK,KAAK,UAAU,GAAG;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,KAAK;AAAA,IACjB;AAAA,IACA,yBAAyB,KAAK;AAAA,IAC9B,0BAA0B,KAAK;AAAA,EACjC;AACA,MAAI,SAAS,GAAG;AACd,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,OAAO;AAAA,IAClB,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,IACnD,SAAS;AAAA,IACT,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,QAAQ,KAAK,CAAC;AAAA,EACnD,CAAC;AACH;AAEA,SAAS,yBAAyB,OAGtB;AACV,SACE,MAAM,cAAc,8BACpB,MAAM,qBAAqB;AAE/B;AAEA,SAAS,sBAAsB,YAAyC;AACtE,SAAO,eAAe,UAAa,cAAc;AACnD;AAEA,SAAS,4BAA4B,OAK5B;AACP,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,mBAAmB,MAAM;AAAA,IACzB,QAAQ,MAAM;AAAA,IACd,QACE,MAAM,cAAc,SAChB,SACA,EAAE,WAAW,MAAM,UAAU;AAAA,IACnC,MAAM;AAAA,EACR,CAAC;AACH;AAEA,SAAS,yBAAyB,KAAsB;AACtD,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QACE,OAAO,aAAa,YACpB,OAAO,aAAa,yBACnB,OAAO,aAAa,uBACnB,OAAO,aAAa,kBACtB;AACA,aAAO;AAAA,IACT;AAEA,UAAM,gBACJ,OAAO,aAAa,IAAI,WAAW,MAAM;AAC3C,UAAM,kBACJ,OAAO,aAAa,IAAI,SAAS,MAAM,YACtC,OAAO,aAAa,IAAI,eAAe,MAAM,eAC5C,OAAO,aAAa,IAAI,cAAc,MAAM;AAEhD,WAAO,iBAAiB;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,+BAA+B,KAA4B;AAClE,QAAM,WAAW,4BAA4B,GAAG;AAChD,MAAI,CAAC,SAAS,KAAK;AACjB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,IAAI,IAAI,SAAS,GAAG,EAAE;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mCAAmC,OAGhC;AACV,MAAI,CAAC,MAAM,QAAQ;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,OAAO,SAAS,eAAe;AACvC,UAAM,eAAe,+BAA+B,MAAM,OAAO,SAAS;AAC1E,UAAM,aAAa,+BAA+B,MAAM,GAAG;AAC3D,WACE,iBAAiB,QACjB,eAAe,QACf,iBAAiB;AAAA,EAErB;AAEA,SAAO;AACT;AAEA,eAAe,iCACb,SACA,QACA,0BACA,QACe;AACf,QAAM,WAAW,QAAQ;AACzB,MACE,CAAC,YACD,SAAS,YAAY,KACrB,CAAC,4BACD,WAAW,QACX,QAAQ,uBAAuB,QAC/B;AACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,yBAAyB,UAAU,MAAM;AAC/C,YAAQ,qBAAqB;AAAA,EAC/B,SAAS,OAAO;AACd,YAAQ,qBAAqB;AAC7B,YAAQ,OAAO,kDAAkD;AAAA,MAC/D,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC5D,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA,eAAe,QAAQ;AAAA,IACzB,CAAC;AAAA,EACH;AACF;AAEO,SAAS,0BAA0B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkD;AAChD,QAAM,WAAW,oBAAI,IAAiC;AACtD,QAAM,wBAAwB,oBAAI,IAAoB;AACtD,MAAI,uBAAuB,0BAA0B,KAAK;AAE1D,QAAM,aAAa,CACjB,QACA,UAOwB;AACxB,UAAM,WAAW,SAAS,IAAI,MAAM;AACpC,QAAI,UAAU;AACZ,UAAI,OAAO,cAAc,QAAW;AAClC,iBAAS,YAAY,MAAM;AAAA,MAC7B;AACA,UAAI,OAAO,gBAAgB,QAAW;AACpC,iBAAS,cAAc,MAAM;AAAA,MAC/B;AACA,UAAI,OAAO,qBAAqB,QAAW;AACzC,iBAAS,mBAAmB,MAAM;AAAA,MACpC;AACA,UAAI,OAAO,qBAAqB,QAAW;AACzC,iBAAS,mBAAmB,MAAM;AAAA,MACpC;AACA,UAAI,OAAO,QAAQ,QAAW;AAC5B,iBAAS,aAAa,MAAM;AAAA,MAC9B;AACA,aAAO;AAAA,IACT;AAEA,UAAM,UAA+B;AAAA,MACnC,oBAAoB;AAAA,MACpB,UAAU;AAAA,MACV,YAAY,OAAO,OAAO;AAAA,MAC1B,WAAW;AAAA,MACX,WAAW,CAAC;AAAA,MACZ,2BAA2B;AAAA,MAC3B,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C;AAAA,MACA,WAAW,OAAO,aAAa;AAAA,MAC/B,aAAa,OAAO,eAAe;AAAA,MACnC,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,eAAe;AAAA,IACjB;AACA,aAAS,IAAI,QAAQ,OAAO;AAC5B,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,CAAC,YAAuC;AAC3D,UAAM,WACJ,QAAQ,YAAY,CAAC,QAAQ,SAAS,YAAY,IAC9C,QAAQ,WACR;AACN,SAAK;AAAA,MACH,WAAW,WAAW,eAAe,QAAQ,IAAI;AAAA,MACjD,cAAc,WAAW,kBAAkB,QAAQ,IAAI;AAAA,MACvD,oBAAoB,QAAQ,QAAQ;AAAA,MACpC,WAAW,WAAW,SAAS,UAAU,IAAI;AAAA,MAC7C,YAAY,QAAQ,cAAc;AAAA,MAClC,WAAW,QAAQ;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,OAAO,WAAW,SAAS,SAAS,KAAK,OAAO;AAAA,MAChD,MAAM;AAAA,MACN,KAAK,WACD,SAAS,OAAO,KAAK,QAAQ,aAC7B,QAAQ;AAAA,IACd,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,CAAC,YAAuC;AAC1D,UAAM,WAAW,QAAQ;AACzB,UAAM,gBAAgB,QAAQ;AAC9B,QAAI,UAAU;AACZ,iBAAW,UAAU,QAAQ,WAAW;AACtC,iBAAS,IAAI,OAAO,OAAO,OAAO,QAAQ;AAAA,MAC5C;AAAA,IACF;AACA,YAAQ,YAAY,CAAC;AACrB,YAAQ,WAAW;AACnB,YAAQ,qBAAqB;AAC7B,YAAQ,gBAAgB;AACxB,QACE,kBAAkB,QAClB,sBAAsB,IAAI,aAAa,MAAM,QAAQ,QACrD;AACA,4BAAsB,OAAO,aAAa;AAAA,IAC5C;AACA,iBAAa,OAAO;AAAA,EACtB;AAEA,QAAM,mCAAmC,CACvC,WACG;AACH,2BAAuB;AACvB,eAAW,WAAW,SAAS,OAAO,GAAG;AACvC,cAAQ,qBAAqB;AAC7B,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,MAAM,MAAM,MAAS;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,kCACJ,gCAAgC,gCAAgC,KAAK;AAEvE,QAAM,uBAAuB,CAAC,YAAuC;AACnE,UAAM,WAAW,QAAQ;AACzB,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM,aAAa,OAAO;AAChD,UAAM,gBAAgB,IAAI,SAAoB;AAC5C,YAAM,MAAM,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AACpD,YAAM,aAAa,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AAC3D,YAAM,aAAa,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AAC3D,mBAAa,OAAO;AACpB,UAAI,CAAC,sBAAsB,UAAU,GAAG;AACtC;AAAA,MACF;AAEA,cAAQ,OAAO,qDAAqD;AAAA,QAClE,YAAY,SAAS,OAAO;AAAA,QAC5B,YAAY,QAAQ;AAAA,QACpB,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,QAAQ;AAAA,MACzB,CAAC;AACD,WAAK;AAAA,QACH,MAAM;AAAA,QACN,mBAAmB;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,UACN;AAAA,UACA,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,QACrC;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AACA,UAAM,aAAa,IAAI,SAAoB;AACzC,YAAM,YAAY,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AAC1D,YAAM,mBACJ,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AAC1C,YAAM,eAAe,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AAC7D,YAAM,cAAc,OAAO,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,IAAI;AAC7D,UAAI,yBAAyB,EAAE,WAAW,iBAAiB,CAAC,GAAG;AAC7D,qBAAa,OAAO;AACpB;AAAA,MACF;AACA,cAAQ,OAAO,wCAAwC;AAAA,QACrD,YAAY,SAAS,OAAO;AAAA,QAC5B,YAAY,QAAQ;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA,eAAe,QAAQ;AAAA,MACzB,CAAC;AACD,cAAQ,6BAA6B;AACrC,mBAAa,OAAO;AACpB,kCAA4B;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH;AACA,UAAM,cAAc,MAAM,YAAY,OAAO;AAC7C,UAAM,iBAAiB,IAAI,SAAoB;AAC7C,YAAM,QACJ,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,MAAM,YAAY,oBAAoB,KAAK,CAAC,IAC/D,KAAK,CAAC,IACP;AACN,YAAM,MAAM,OAAO,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,IAAI;AACpD,UACE,IAAI,WAAW,KACf,mCAAmC;AAAA,QACjC,QAAQ,QAAQ;AAAA,QAChB;AAAA,MACF,CAAC,GACD;AACA;AAAA,MACF;AAEA,aAAO,iBAAiB;AACxB,2BAAqB,SAAS,GAAG;AACjC,mBAAa,OAAO;AAAA,IACtB;AAEA,UAAM,UAA4C;AAAA,MAChD,EAAE,OAAO,qBAAqB,UAAU,cAAc;AAAA,MACtD,EAAE,OAAO,oBAAoB,UAAU,cAAc;AAAA,MACrD,EAAE,OAAO,gBAAgB,UAAU,cAAc;AAAA,MACjD,EAAE,OAAO,wBAAwB,UAAU,cAAc;AAAA,MACzD,EAAE,OAAO,sBAAsB,UAAU,cAAc;AAAA,MACvD,EAAE,OAAO,iBAAiB,UAAU,eAAe;AAAA,MACnD,EAAE,OAAO,iBAAiB,UAAU,WAAW;AAAA,MAC/C,EAAE,OAAO,aAAa,UAAU,YAAY;AAAA,IAC9C;AAEA,eAAW,UAAU,SAAS;AAC5B,eAAS,GAAG,OAAO,OAAO,OAAO,QAAQ;AAAA,IAC3C;AACA,YAAQ,YAAY;AAAA,EACtB;AAEA,QAAM,iBAAiB,OACrB,YACkB;AAClB,UAAM,WAAW,QAAQ;AACzB,QAAI,CAAC,YAAY,SAAS,YAAY,GAAG;AACvC,mBAAa,OAAO;AACpB;AAAA,IACF;AAEA,UAAM,WAAW,gCAAgC,QAAQ,UAAU;AACnE,QAAI,CAAC,SAAS,KAAK;AACjB,WAAK;AAAA,QACH,GAAG,2BAA2B,QAAQ;AAAA,QACtC,QAAQ,QAAQ;AAAA,QAChB,MAAM;AAAA,MACR,CAAC;AACD,mBAAa,OAAO;AACpB;AAAA,IACF;AACA,QACE,CAAC,mCAAmC;AAAA,MAClC,QAAQ,QAAQ;AAAA,MAChB,KAAK,SAAS;AAAA,IAChB,CAAC,GACD;AACA,2BAAqB,SAAS,SAAS,GAAG;AAC1C,mBAAa,OAAO;AACpB;AAAA,IACF;AAEA,UAAM,oBAAoB;AAAA,MACxB,SAAS,OAAO;AAAA,IAClB;AACA,UAAM,iBAAiB,kCAAkC,SAAS,GAAG;AACrE,QAAI,qBAAqB,sBAAsB,gBAAgB;AAC7D,mBAAa,OAAO;AACpB;AAAA,IACF;AAEA,UAAM,4BAA4B,QAAQ;AAC1C,QAAI;AACF,YAAM,SAAS,QAAQ,SAAS,GAAG;AACnC,mBAAa,OAAO;AAAA,IACtB,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,OAAO,qCAAqC;AAAA,QAClD,YAAY,SAAS,OAAO;AAAA,QAC5B,YAAY,QAAQ;AAAA,QACpB,OAAO;AAAA,QACP,QAAQ,QAAQ;AAAA,QAChB,aAAa,SAAS;AAAA,QACtB,eAAe,QAAQ;AAAA,MACzB,CAAC;AACD,UAAI,QAAQ,8BAA8B,2BAA2B;AACnE;AAAA,MACF;AACA,mBAAa,OAAO;AACpB,kCAA4B;AAAA,QAC1B;AAAA,QACA,kBAAkB;AAAA,QAClB,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,uBAAuB,CAC3B,SACA,QACuB;AACvB,UAAM,WAAW,4BAA4B,GAAG;AAChD,QAAI,SAAS,KAAK;AAChB,cAAQ,OAAO,uCAAuC;AAAA,QACpD,QAAQ,QAAQ;AAAA,QAChB,KAAK,SAAS;AAAA,QACd,eAAe,QAAQ;AAAA,MACzB,CAAC;AACD,WAAK;AAAA,QACH,aAAa;AAAA,QACb,cAAc,QAAQ;AAAA,QACtB,MAAM;AAAA,QACN,KAAK,SAAS;AAAA,MAChB,CAAC;AACD,aAAO,EAAE,QAAQ,OAAO;AAAA,IAC1B;AACA,SAAK,QAAQ,QAAQ,aAAa,GAAG,CAAC,EAAE,MAAM,CAAC,UAAmB;AAChE,cAAQ,OAAO,oCAAoC;AAAA,QACjD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH,CAAC;AACD,WAAO,EAAE,QAAQ,OAAO;AAAA,EAC1B;AAEA,SAAO;AAAA,IACL,MAAM,SAAS,OAAO;AACpB,YAAM,WAAW,gCAAgC,MAAM,GAAG;AAC1D,UAAI,CAAC,SAAS,KAAK;AACjB,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,YAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,QACvC,kBAAkB,MAAM;AAAA,QACxB,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,kBAAkB,MAAM;AAAA,QACxB,KAAK,SAAS;AAAA,MAChB,CAAC;AACD,cAAQ,YAAY;AACpB,YAAM,eAAe,OAAO;AAAA,IAC9B;AAAA,IACA,MAAM,eAAe,OAAO;AAC1B,YAAM,UAAU,SAAS,IAAI,MAAM,MAAM;AACzC,YAAM,WACJ,SAAS,YAAY,CAAC,QAAQ,SAAS,YAAY,IAC/C,QAAQ,WACR;AACN,UAAI,CAAC,UAAU,aAAa;AAC1B,eAAO;AAAA,MACT;AAEA,YAAM,QAAQ,MAAM,SAAS,YAAY;AACzC,UAAI,MAAM,UAAU,MAAM,MAAM;AAC9B,eAAO;AAAA,MACT;AAEA,aAAO,0BAA0B,KAAK,EAAE,UAAU;AAAA,IACpD;AAAA,IACA,MAAM,OAAO;AACX,YAAM,UAAU,SAAS,IAAI,MAAM,MAAM;AACzC,UAAI,SAAS;AACX,oBAAY,OAAO;AACnB,iBAAS,OAAO,MAAM,MAAM;AAAA,MAC9B;AACA,WAAK,EAAE,QAAQ,MAAM,QAAQ,MAAM,SAAS,CAAC;AAC7C,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,UAAU,OAAO;AACf,YAAM,UAAU,SAAS,IAAI,MAAM,MAAM;AACzC,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,MACT;AACA,YAAM,WACJ,QAAQ,YAAY,CAAC,QAAQ,SAAS,YAAY,IAC9C,QAAQ,WACR;AACN,aAAO;AAAA,QACL,WAAW,WAAW,eAAe,QAAQ,IAAI;AAAA,QACjD,cAAc,WAAW,kBAAkB,QAAQ,IAAI;AAAA,QACvD,YAAY,WAAW,SAAS,OAAO,IAAI;AAAA,QAC3C,YAAY,QAAQ;AAAA,QACpB,oBAAoB,QAAQ,QAAQ;AAAA,QACpC,WAAW,WAAW,SAAS,UAAU,IAAI;AAAA,QAC7C,WAAW,QAAQ;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB,WAAW,QAAQ;AAAA,QACnB,aAAa,QAAQ;AAAA,QACrB,kBAAkB,QAAQ;AAAA,QAC1B,OAAO,WAAW,SAAS,SAAS,IAAI;AAAA,QACxC,WAAW,UAAU,eAAe,KAAK;AAAA,QACzC,sBAAsB,QAAQ,WAC1B,QAAQ,SAAS,YAAY,IAC7B;AAAA,QACJ,eAAe,QAAQ;AAAA,MACzB;AAAA,IACF;AAAA,IACA,OAAO,OAAO;AACZ,YAAM,WAAW,SAAS,IAAI,MAAM,MAAM,GAAG;AAC7C,UAAI,YAAY,CAAC,SAAS,YAAY,KAAK,eAAe,QAAQ,GAAG;AACnE,oBAAY,QAAQ;AAAA,MACtB;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,UAAU,OAAO;AACf,YAAM,WAAW,SAAS,IAAI,MAAM,MAAM,GAAG;AAC7C,UAAI,YAAY,CAAC,SAAS,YAAY,KAAK,kBAAkB,QAAQ,GAAG;AACtE,uBAAe,QAAQ;AAAA,MACzB;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,mBAAmB,eAAe,OAAO;AACvC,YAAM,SAAS,sBAAsB,IAAI,aAAa;AACtD,YAAM,UAAU,SAAS,SAAS,IAAI,MAAM,IAAI;AAChD,UAAI,CAAC,SAAS;AACZ,gBAAQ,OAAO,+CAA+C;AAAA,UAC5D,KAAK,MAAM;AAAA,UACX;AAAA,QACF,CAAC;AACD;AAAA,MACF;AACA,cAAQ,OAAO,gDAAgD;AAAA,QAC7D,QAAQ,QAAQ;AAAA,QAChB,KAAK,MAAM;AAAA,QACX;AAAA,MACF,CAAC;AACD,2BAAqB,SAAS,MAAM,GAAG;AAAA,IACzC;AAAA,IACA,MAAM,SAAS,OAAO;AACpB,YAAM,WAAW,4BAA4B,MAAM,GAAG;AACtD,UAAI,CAAC,SAAS,KAAK;AACjB,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,YAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,QACvC,kBAAkB,MAAM;AAAA,QACxB,KAAK,SAAS;AAAA,MAChB,CAAC;AACD,cAAQ,YAAY;AACpB,YAAM,eAAe,OAAO;AAAA,IAC9B;AAAA,IACA,MAAM,aAAa,OAAO;AACxB,YAAM,WAAW,gCAAgC,MAAM,GAAG;AAC1D,UAAI,CAAC,SAAS,KAAK;AACjB,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AACA,YAAM,QAAQ,QAAQ,aAAa,SAAS,GAAG,CAAC;AAAA,IAClD;AAAA,IACA,aAAa,OAAO;AAClB,YAAM,UAAU,SAAS,IAAI,MAAM,MAAM;AACzC,YAAM,WAAW,SAAS,YAAY;AACtC,UAAI,YAAY,CAAC,SAAS,YAAY,GAAG;AACvC,YAAI;AACF,mBAAS,eAAe,EAAE,UAAU,MAAM,MAAM,SAAS,CAAC;AAAA,QAC5D,SAAS,OAAO;AACd,kBAAQ,OAAO,qCAAqC;AAAA,YAClD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC5D,QAAQ,MAAM;AAAA,YACd,eAAe,SAAS,iBAAiB;AAAA,UAC3C,CAAC;AACD,gBAAM;AAAA,QACR;AAAA,MACF;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,MAAM,eAAe,OAAO;AAC1B,YAAM,iBAAiB,KAAK;AAC5B,iBAAW,MAAM,QAAQ;AAAA,QACvB,kBAAkB,MAAM;AAAA,QACxB,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,kBAAkB,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,IACA,MAAM,cAAc,OAAO;AACzB,YAAM,iBAAiB;AAAA,QACrB,QAAQ,MAAM;AAAA,QACd,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,kBAAkB,MAAM;AAAA,QACxB,kBAAkB,MAAM;AAAA,MAC1B,CAAC;AACD,YAAM,WAAW,mBAAmB,MAAM,aAAa;AACvD,UAAI,CAAC,YAAY,SAAS,YAAY,GAAG;AACvC,cAAM,IAAI;AAAA,UACR,sBAAsB,MAAM,aAAa;AAAA,QAC3C;AAAA,MACF;AAEA,YAAM,cAAc,sBAAsB,IAAI,MAAM,aAAa;AACjE,UAAI,eAAe,gBAAgB,MAAM,QAAQ;AAC/C,cAAM,IAAI;AAAA,UACR,sBAAsB,MAAM,aAAa;AAAA,QAC3C;AAAA,MACF;AAEA,YAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,QACvC,kBAAkB,MAAM;AAAA,QACxB,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,kBAAkB,MAAM;AAAA,MAC1B,CAAC;AACD,UACE,QAAQ,kBAAkB,MAAM,iBAChC,QAAQ,aAAa,UACrB;AACA,qBAAa,OAAO;AACpB;AAAA,MACF;AACA,UAAI,QAAQ,YAAY,QAAQ,aAAa,UAAU;AACrD,oBAAY,OAAO;AAAA,MACrB;AACA,cAAQ,WAAW;AACnB,cAAQ,gBAAgB,MAAM;AAC9B,4BAAsB,IAAI,MAAM,eAAe,MAAM,MAAM;AAC3D,cAAQ,YAAY;AACpB,cAAQ,OAAO,uCAAuC;AAAA,QACpD,QAAQ,MAAM;AAAA,QACd,kBAAkB,QAAQ;AAAA,QAC1B,eAAe,MAAM;AAAA,MACvB,CAAC;AACD,eAAS,uBAAuB,CAAC,EAAE,IAAI,MAAM;AAC3C,YAAI,yBAAyB,GAAG,GAAG;AACjC,kBAAQ,OAAO,gDAAgD;AAAA,YAC7D,QAAQ,QAAQ;AAAA,YAChB,eAAe,QAAQ;AAAA,UACzB,CAAC;AACD,iBAAO,EAAE,QAAQ,QAAQ;AAAA,QAC3B;AAEA,eAAO,qBAAqB,SAAS,GAAG;AAAA,MAC1C,CAAC;AACD,2BAAqB,OAAO;AAC5B,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,eAAe,OAAO;AAAA,IAC9B;AAAA,IACA,OAAO,OAAO;AACZ,YAAM,WAAW,SAAS,IAAI,MAAM,MAAM,GAAG;AAC7C,UAAI,YAAY,CAAC,SAAS,YAAY,GAAG;AACvC,iBAAS,OAAO;AAAA,MAClB;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,gBAAgB,OAAO;AACrB,YAAM,UAAU,SAAS,IAAI,MAAM,MAAM;AACzC,UAAI,CAAC,WAAW,QAAQ,kBAAkB,MAAM,eAAe;AAC7D,eAAO,QAAQ,QAAQ;AAAA,MACzB;AACA,cAAQ,YAAY;AACpB,kBAAY,OAAO;AACnB,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,UAAU;AACR,wCAAkC;AAAA,IACpC;AAAA,EACF;AACF;;;AChsBO,SAAS,gCACd,OACM;AACN,QAAM,mBAAmB,oBAAI,QAA4C;AACzE,QAAM,uBACJ,MAAM,2BAA2B,SAC7B,sCAAsC;AAAA,IACpC,QAAQ,MAAM;AAAA,IACd,gBAAgB,OAAO;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,UAAU;AAC3C,aAAO,QAAQ;AAAA,QACb,+BAA+B;AAAA,UAC7B;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,SAAS,MAAM;AAAA,EACjB,CAAC,IACD;AAEN,QAAM,0BAA0B,CAC9B,OACA,gBACwB;AACxB,UAAM,WAAW,iBAAiB,IAAI,WAAW;AACjD,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,0BAA0B;AAAA,MACxC,KAAK,cAAc;AACjB,YAAI,CAAC,YAAY,YAAY,GAAG;AAC9B,sBAAY,YAAY,KAAK,MAAM,SAAS,OAAO,YAAY;AAAA,QACjE;AAAA,MACF;AAAA,MACA,yBAAyB,MAAM;AAAA,MAC/B,QAAQ,MAAM;AAAA,MACd,cAAc,MAAM;AAAA,MACpB,gBACE,yBAAyB,OACrB,CAAC,YAAY,qBAAqB,iBAAiB,OAAO,IAC1D;AAAA,MACN,oBAAoB,CAAC,kBACnB,MAAM,mBAAmB;AAAA,QACvB;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACH,0BAA0B,MAAM;AAAA,MAChC,+BAA+B,MAAM;AAAA,IACvC,CAAC;AACD,gBAAY,KAAK,UAAU,MAAM;AAC/B,cAAQ,QAAQ;AAChB,uBAAiB,OAAO,WAAW;AAAA,IACrC,CAAC;AACD,qBAAiB,IAAI,aAAa,OAAO;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,sBAAsB,CAAC,UAAmB;AAC9C,UAAM,cAAc,MAAM,eAAe,KAAK;AAC9C,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AACA,WAAO;AAAA,MACL,SAAS,wBAAwB,OAAO,WAAW;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,0BACJ,MAAM,2BAA2B;AAEnC,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAgB,CAAC,OAAO,YAC3D,oBAAoB,KAAK,EAAE,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAU,CAAC,OAAO,YACrD,oBAAoB,KAAK,EAAE,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,gBAAgB;AACjC,UAAM;AAAA,MAAgB,MAAM,SAAS;AAAA,MAAgB,CAAC,OAAO,YAC3D,oBAAoB,KAAK,EAAE,QAAQ;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAe,CAAC,OAAO,YAC1D,oBAAoB,KAAK,EAAE,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAiB,CAAC,OAAO,YAC5D,oBAAoB,KAAK,EAAE,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAU,CAAC,OAAO,YACrD,oBAAoB,KAAK,EAAE,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,cAAc;AAC/B,UAAM;AAAA,MAAgB,MAAM,SAAS;AAAA,MAAc,CAAC,OAAO,YACzD,oBAAoB,KAAK,EAAE,QAAQ;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,cAAc;AAC/B,UAAM,gBAAgB,MAAM,SAAS,cAAc,CAAC,OAAO,YAAY;AACrE,YAAM,cAAc;AACpB,aAAO,oBAAoB,KAAK,EAAE,QAAQ,aAAa,WAAW;AAAA,IACpE,CAAC;AAAA,EACH;AACA,MAAI,MAAM,SAAS,yBAAyB;AAC1C,UAAM;AAAA,MACJ,MAAM,SAAS;AAAA,MACf,CAAC,OAAO,YAAY;AAClB,cAAM,qBACJ;AACF,cAAM,EAAE,SAAS,YAAY,IAAI,oBAAoB,KAAK;AAC1D,eAAO,wBAAwB;AAAA,UAC7B,OAAO,mBAAmB;AAAA,UAC1B,cAAc,MAAM;AAClB,mBAAO,QAAQ,aAAa,EAAE,QAAQ,mBAAmB,OAAO,CAAC;AAAA,UACnE;AAAA,UACA;AAAA,UACA,OAAO,mBAAmB;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAQ,CAAC,OAAO,YACnD,oBAAoB,KAAK,EAAE,QAAQ,OAAO,OAAiC;AAAA,EAC7E;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAW,CAAC,OAAO,YACtD,oBAAoB,KAAK,EAAE,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAQ,CAAC,OAAO,YACnD,oBAAoB,KAAK,EAAE,QAAQ,OAAO,OAAiC;AAAA,EAC7E;AACA,QAAM;AAAA,IAAgB,MAAM,SAAS;AAAA,IAAO,CAAC,OAAO,YAClD,oBAAoB,KAAK,EAAE,QAAQ,MAAM,OAAiC;AAAA,EAC5E;AACA,MAAI,MAAM,SAAS,WAAW;AAC5B,UAAM;AAAA,MAAgB,MAAM,SAAS;AAAA,MAAW,CAAC,OAAO,YACtD,oBAAoB,KAAK,EAAE,QAAQ;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,gBAAgB,MAAM,kBAAkB;AACzD,UAAM,iBAAiB,MAAM,SAAS,cAAc,CAAC,OAAO,YAAY;AACtE,YAAM,WAAW,2BAA2B,KAAK;AACjD,YAAM,iBAAiB;AACvB,UACE,OAAO,aAAa,YACpB,CAAC,OAAO,SAAS,QAAQ,KACzB,CAAC,kBACD,OAAO,eAAe,QAAQ,UAC9B;AACA;AAAA,MACF;AACA,0BAAoB,KAAK,EAAE,QAAQ;AAAA,QACjC;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,eAAe,gCACb,OACe;AACf,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,UAAU;AACxC,QAAM,OAAO,KAAK,kBAAkB;AAAA,IAClC;AAAA,MACE,OAAO,MAAM;AACX,aAAK,QAAQ,QAAQ,MAAM,aAAa,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,MAClE;AAAA,MACA,OAAO,MAAM;AAAA,IACf;AAAA,EACF,CAAC;AACD,OAAK,MAAM;AAAA,IACT,QAAQ,MAAM;AAAA,IACd,GAAG,KAAK,MAAM,MAAM,MAAM,CAAC;AAAA,IAC3B,GAAG,KAAK,MAAM,MAAM,MAAM,CAAC;AAAA,EAC7B,CAAC;AACH;AAEA,SAAS,2BAA2B,OAA+B;AACjE,QAAM,SAAU,OAAgD;AAChE,SAAO,OAAO,QAAQ,OAAO,WAAW,OAAO,KAAK;AACtD;;;AC3RA,IAAM,gCAAgC;AAE/B,SAAS,8BAA8B,WAA2B;AACvE,SAAO,UACJ,KAAK,EACL,QAAQ,+BAA+B,EAAE,EACzC,QAAQ,WAAW,GAAG;AAC3B;AAEO,SAAS,2BACd,UACA,QACM;AACN,QAAM,gBAAgB;AAItB,MACE,OAAO,cAAc,iBAAiB,cACtC,OAAO,cAAc,iBAAiB,YACtC;AACA;AAAA,EACF;AAEA,QAAM,mBAAmB,cAAc,aAAa,EAAE,KAAK;AAC3D,QAAM,gBAAgB,8BAA8B,gBAAgB;AACpE,MAAI,CAAC,iBAAiB,kBAAkB,kBAAkB;AACxD;AAAA,EACF;AAEA,gBAAc,aAAa,aAAa;AACxC,UAAQ,QAAQ,2CAA2C;AAAA,IACzD,eAAe,SAAS,MAAM;AAAA,EAChC,CAAC;AACH;;;ACAA,SAAS,+BAA+B,KAAkC;AACxE,UAAQ,OAAO,IAAI,KAAK,MAAM;AAChC;AAEO,SAAS,2BACd,QACA,0BACS;AACT,SACE,OAAO,2BAA2B,MAAM,UACxC,iCAAiC,OAAO,WAAW,wBAAwB;AAE/E;AAEA,SAAS,mCACP,QACS;AACT,SACE,OAAO,2BAA2B,MAAM,UACxC,iCAAiC,OAAO,SAAS;AAErD;AAEA,SAAS,oBAAoB,KAAsC;AACjE,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,WAAO;AAAA,MACL,aAAa,OAAO;AAAA,MACpB,WAAW,OAAO;AAAA,MAClB,eAAe,OAAO;AAAA,IACxB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW;AAAA,MACX,eAAe;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,kCAAkC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,UAAQ,OAAO,2CAA2C;AAAA,IACxD;AAAA,IACA,GAAG,oBAAoB,GAAG;AAAA,EAC5B,CAAC;AACD,QAAM,WAAW,4BAA4B,GAAG;AAChD,MAAI,SAAS,KAAK;AAChB,SAAK,QAAQ,QAAQ,aAAa,SAAS,GAAG,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EACxE;AACA,SAAO,EAAE,QAAQ,OAAgB;AACnC;AAEO,SAAS,8BAA8B;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8D;AAC5D,iBAAe,8BAA8B;AAC7C,iBAAe,mBAAmB;AAClC,iBAAe,aAAa;AAC5B,iBAAe,kBAAkB;AACjC,iBAAe,UAAU;AACzB,iBAAe,UAAU;AACzB,iBAAe,cAAc;AAC7B,SAAO,eAAe;AAEtB,QAAM,YAAY,OAAO;AACzB,MACE,CAAC,aACD,CAAC,iCAAiC,WAAW,wBAAwB,GACrE;AACA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,+BAA+B,OAAO,GAAG,GAAG;AAC9C,WAAO,MAAM;AAAA,EACf,OAAO;AACL,UAAM,WAAW,4BAA4B,OAAO,OAAO,aAAa;AACxE,QAAI,CAAC,SAAS,KAAK;AACjB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAO,MAAM,SAAS;AAAA,EACxB;AAEA,QAAM,UAAU,iBAAiB,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;AAC1D,QAAM,kBAAkB,OAAO,YAAY,WAAW,QAAQ,KAAK,IAAI;AACvE,MAAI,gBAAgB,SAAS,GAAG;AAC9B,mBAAe,UAAU;AAAA,EAC3B;AAEA,SAAO,EAAE,SAAS,MAAM,QAAQ,KAAK;AACvC;AAYO,SAAS,8BAA8B;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmD;AACjD,QAAM,yBAAwD,CAAC;AAE/D,QAAM,0BAA0B,CAC9B,OACA,gBACA,WACG;AACH,UAAM,eACJ,sBAAsB,MAAM,KAC5B,2BAA2B,QAAQ,wBAAwB;AAC7D,YAAQ,QAAQ,oCAAoC;AAAA,MAClD,WAAW,OAAO,aAAa;AAAA,MAC/B;AAAA,MACA,KAAK,OAAO,OAAO;AAAA,IACrB,CAAC;AACD,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AAEA,UAAM,oBAAoB,mCAAmC,MAAM;AACnE,QAAI,mBAAmB;AACrB,aAAO,cAAc;AAAA,IACvB;AACA,YAAQ,OAAO,6CAA6C;AAAA,MAC1D;AAAA,MACA,aAAa,OAAO,eAAe;AAAA,MACnC,WAAW,OAAO,aAAa;AAAA,MAC/B,KAAK,OAAO,OAAO;AAAA,IACrB,CAAC;AAED,UAAM,SAAS,8BAA8B;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,CAAC,OAAO,SAAS;AACnB,cAAQ,OAAO,gCAAgC,EAAE,QAAQ,OAAO,OAAO,CAAC;AACxE,YAAM,eAAe;AACrB;AAAA,IACF;AACA,2BAAuB,KAAK;AAAA,MAC1B;AAAA,IACF,CAAC;AACD,YAAQ,QAAQ,uCAAuC;AAAA,MACrD,WAAW,OAAO,aAAa;AAAA,MAC/B,KAAK,OAAO,OAAO;AAAA,IACrB,CAAC;AAAA,EACH;AAEA,QAAM,yBAAyB,CAC7B,QACA,kBACG;AACH,UAAM,gBAAgB,uBAAuB,MAAM;AACnD,QAAI,CAAC,eAAe;AAClB,cAAQ,QAAQ,2CAA2C;AAAA,QACzD,oBAAoB,cAAc,MAAM;AAAA,QACxC,2BAA2B,uBAAuB;AAAA,MACpD,CAAC;AACD;AAAA,IACF;AAEA,+BAA2B,eAAe,MAAM;AAChD,QAAI,cAAc,mBAAmB;AACnC,oBAAc,qBAAqB,CAAC,EAAE,IAAI,MAAM;AAC9C,eAAO,kCAAkC;AAAA,UACvC,oBAAoB,cAAc,MAAM;AAAA,UACxC;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH,OAAO;AACL,oBAAc,qBAAqB,CAAC,EAAE,IAAI,MAAM;AAC9C,eAAO,kCAAkC;AAAA,UACvC,oBAAoB,cAAc,MAAM;AAAA,UACxC;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AACA,sBAAkB,aAAa;AAC/B,YAAQ,QAAQ,uCAAuC;AAAA,MACrD,oBAAoB,cAAc,MAAM;AAAA,MACxC,2BAA2B,uBAAuB;AAAA,IACpD,CAAC;AAAA,EACH;AAEA,WAAS,GAAG,uBAAuB,uBAAuB;AAC1D,WAAS,GAAG,sBAAsB,sBAAsB;AAExD,SAAO,MAAM;AACX,aAAS,IAAI,uBAAuB,uBAAuB;AAC3D,aAAS,IAAI,sBAAsB,sBAAsB;AAAA,EAC3D;AACF;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -166,6 +166,7 @@ interface BrowserNodeFeature {
|
|
|
166
166
|
i18n: BrowserNodeI18nRuntime;
|
|
167
167
|
reportDiagnostic?: BrowserNodeDiagnosticReporter;
|
|
168
168
|
resolveAddressInput(rawInput: string): BrowserAddressInputResolution;
|
|
169
|
+
resolveOpenExternalUrl(rawInput: string): BrowserNavigationUrlResolution;
|
|
169
170
|
runtimeStore: BrowserNodeRuntimeStore;
|
|
170
171
|
connect(): () => void;
|
|
171
172
|
}
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
} from "./chunk-IS2USG4D.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveBrowserAddressInput,
|
|
6
|
-
resolveBrowserNavigationUrl
|
|
7
|
-
|
|
6
|
+
resolveBrowserNavigationUrl,
|
|
7
|
+
resolveBrowserOpenExternalUrl
|
|
8
|
+
} from "./chunk-ZRH4UQZB.js";
|
|
8
9
|
|
|
9
10
|
// src/core/runtimeStore.ts
|
|
10
11
|
var defaultBrowserNodeRuntimeState = {
|
|
@@ -155,6 +156,9 @@ function createBrowserNodeFeature({
|
|
|
155
156
|
resolveAddressInput(rawInput) {
|
|
156
157
|
return resolveBrowserAddressInput(rawInput, { resolveSearchUrl });
|
|
157
158
|
},
|
|
159
|
+
resolveOpenExternalUrl(rawInput) {
|
|
160
|
+
return resolveBrowserOpenExternalUrl(rawInput);
|
|
161
|
+
},
|
|
158
162
|
runtimeStore
|
|
159
163
|
};
|
|
160
164
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/runtimeStore.ts","../src/core/feature.ts"],"sourcesContent":["import type { BrowserNodeEvent, BrowserNodeRuntimeState } from \"./types.ts\";\n\nexport interface BrowserNodeRuntimeStore {\n applyEvent(event: BrowserNodeEvent): void;\n clearAll(): void;\n clearNode(nodeId: string): void;\n getNodeState(nodeId: string): BrowserNodeRuntimeState;\n getSnapshot(): Record<string, BrowserNodeRuntimeState | undefined>;\n subscribe(listener: () => void): () => void;\n}\n\nconst defaultBrowserNodeRuntimeState: BrowserNodeRuntimeState = {\n canGoBack: false,\n canGoForward: false,\n error: null,\n isAttachedToWindow: false,\n isLoading: false,\n isOccluded: false,\n lifecycle: \"cold\",\n title: null,\n url: null\n};\n\nconst chromiumErrorPageUrlPrefix = \"chrome-error://\";\n\nfunction isChromiumErrorPageUrl(value: string | null | undefined): boolean {\n return value?.trim().startsWith(chromiumErrorPageUrlPrefix) === true;\n}\n\nfunction normalizePublishedBrowserValue(\n value: string | null | undefined\n): string | null {\n const trimmed = value?.trim() ?? \"\";\n if (\n trimmed.length === 0 ||\n trimmed === \"about:blank\" ||\n isChromiumErrorPageUrl(trimmed)\n ) {\n return null;\n }\n return trimmed;\n}\n\nfunction shouldClearLoadError({\n isLoading,\n url\n}: {\n isLoading: boolean;\n url: string | null;\n}): boolean {\n return isLoading && !isChromiumErrorPageUrl(url);\n}\n\nexport function createBrowserNodeRuntimeStore(): BrowserNodeRuntimeStore {\n const listeners = new Set<() => void>();\n let runtimeByNodeId: Record<string, BrowserNodeRuntimeState | undefined> = {};\n\n const notify = () => {\n for (const listener of listeners) {\n listener();\n }\n };\n\n return {\n applyEvent(event) {\n if (event.type === \"open-url\") {\n return;\n }\n\n if (event.type === \"closed\") {\n if (!runtimeByNodeId[event.nodeId]) {\n return;\n }\n const next = { ...runtimeByNodeId };\n delete next[event.nodeId];\n runtimeByNodeId = next;\n notify();\n return;\n }\n\n const previous =\n runtimeByNodeId[event.nodeId] ?? defaultBrowserNodeRuntimeState;\n const next =\n event.type === \"state\"\n ? resolveNextState(previous, event)\n : {\n ...previous,\n error: {\n code: event.code,\n diagnosticMessage: event.diagnosticMessage,\n params: event.params\n }\n };\n\n runtimeByNodeId = {\n ...runtimeByNodeId,\n [event.nodeId]: next\n };\n notify();\n },\n clearAll() {\n if (Object.keys(runtimeByNodeId).length === 0) {\n return;\n }\n runtimeByNodeId = {};\n notify();\n },\n clearNode(nodeId) {\n const normalized = nodeId.trim();\n if (normalized.length === 0 || !runtimeByNodeId[normalized]) {\n return;\n }\n const next = { ...runtimeByNodeId };\n delete next[normalized];\n runtimeByNodeId = next;\n notify();\n },\n getNodeState(nodeId) {\n return runtimeByNodeId[nodeId] ?? defaultBrowserNodeRuntimeState;\n },\n getSnapshot() {\n return runtimeByNodeId;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n };\n}\n\nfunction resolveNextState(\n previous: BrowserNodeRuntimeState,\n event: Extract<BrowserNodeEvent, { type: \"state\" }>\n): BrowserNodeRuntimeState {\n const nextUrl =\n normalizePublishedBrowserValue(event.url) ??\n (event.lifecycle !== \"cold\" ? previous.url : null);\n const nextTitle =\n normalizePublishedBrowserValue(event.title) ??\n (event.lifecycle !== \"cold\" ? previous.title : null);\n\n return {\n ...previous,\n canGoBack: event.canGoBack,\n canGoForward: event.canGoForward,\n error: shouldClearLoadError({\n isLoading: event.isLoading,\n url: event.url\n })\n ? null\n : previous.error,\n isAttachedToWindow: event.isAttachedToWindow ?? previous.isAttachedToWindow,\n isLoading: event.isLoading,\n isOccluded: event.isOccluded,\n lifecycle: event.lifecycle,\n title: nextTitle,\n url: nextUrl\n };\n}\n","import type { I18nRuntime } from \"@tutti-os/ui-i18n-runtime\";\nimport { createBrowserNodeI18nRuntime } from \"../i18n/browserNodeI18n.ts\";\nimport type { BrowserNodeI18nRuntime } from \"../i18n/browserNodeI18n.ts\";\nimport type { BrowserNodeHostApi } from \"./types.ts\";\nimport {\n createBrowserNodeRuntimeStore,\n type BrowserNodeRuntimeStore\n} from \"./runtimeStore.ts\";\nimport {\n resolveBrowserAddressInput,\n type BrowserAddressInputResolution,\n type BrowserSearchUrlResolver\n} from \"./url.ts\";\n\nexport interface BrowserNodeFeature {\n hostApi: BrowserNodeHostApi;\n i18n: BrowserNodeI18nRuntime;\n reportDiagnostic?: BrowserNodeDiagnosticReporter;\n resolveAddressInput(rawInput: string): BrowserAddressInputResolution;\n runtimeStore: BrowserNodeRuntimeStore;\n connect(): () => void;\n}\n\nexport interface BrowserNodeDiagnosticPayload {\n details?: Record<string, unknown>;\n event: string;\n level?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nexport type BrowserNodeDiagnosticReporter = (\n payload: BrowserNodeDiagnosticPayload\n) => void;\n\nexport interface CreateBrowserNodeFeatureInput {\n hostApi: BrowserNodeHostApi;\n i18n?: I18nRuntime<string>;\n reportDiagnostic?: BrowserNodeDiagnosticReporter;\n resolveSearchUrl?: BrowserSearchUrlResolver;\n runtimeStore?: BrowserNodeRuntimeStore;\n}\n\nexport function createBrowserNodeFeature({\n hostApi,\n i18n,\n reportDiagnostic,\n resolveSearchUrl,\n runtimeStore = createBrowserNodeRuntimeStore()\n}: CreateBrowserNodeFeatureInput): BrowserNodeFeature {\n let listenerCount = 0;\n let disconnect: (() => void) | null = null;\n\n const connect = () => {\n listenerCount += 1;\n if (!disconnect) {\n disconnect = hostApi.onEvent((event) => runtimeStore.applyEvent(event));\n }\n\n return () => {\n listenerCount = Math.max(0, listenerCount - 1);\n if (listenerCount === 0) {\n disconnect?.();\n disconnect = null;\n }\n };\n };\n\n return {\n connect,\n hostApi,\n i18n: createBrowserNodeI18nRuntime(i18n),\n reportDiagnostic,\n resolveAddressInput(rawInput) {\n return resolveBrowserAddressInput(rawInput, { resolveSearchUrl });\n },\n runtimeStore\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/core/runtimeStore.ts","../src/core/feature.ts"],"sourcesContent":["import type { BrowserNodeEvent, BrowserNodeRuntimeState } from \"./types.ts\";\n\nexport interface BrowserNodeRuntimeStore {\n applyEvent(event: BrowserNodeEvent): void;\n clearAll(): void;\n clearNode(nodeId: string): void;\n getNodeState(nodeId: string): BrowserNodeRuntimeState;\n getSnapshot(): Record<string, BrowserNodeRuntimeState | undefined>;\n subscribe(listener: () => void): () => void;\n}\n\nconst defaultBrowserNodeRuntimeState: BrowserNodeRuntimeState = {\n canGoBack: false,\n canGoForward: false,\n error: null,\n isAttachedToWindow: false,\n isLoading: false,\n isOccluded: false,\n lifecycle: \"cold\",\n title: null,\n url: null\n};\n\nconst chromiumErrorPageUrlPrefix = \"chrome-error://\";\n\nfunction isChromiumErrorPageUrl(value: string | null | undefined): boolean {\n return value?.trim().startsWith(chromiumErrorPageUrlPrefix) === true;\n}\n\nfunction normalizePublishedBrowserValue(\n value: string | null | undefined\n): string | null {\n const trimmed = value?.trim() ?? \"\";\n if (\n trimmed.length === 0 ||\n trimmed === \"about:blank\" ||\n isChromiumErrorPageUrl(trimmed)\n ) {\n return null;\n }\n return trimmed;\n}\n\nfunction shouldClearLoadError({\n isLoading,\n url\n}: {\n isLoading: boolean;\n url: string | null;\n}): boolean {\n return isLoading && !isChromiumErrorPageUrl(url);\n}\n\nexport function createBrowserNodeRuntimeStore(): BrowserNodeRuntimeStore {\n const listeners = new Set<() => void>();\n let runtimeByNodeId: Record<string, BrowserNodeRuntimeState | undefined> = {};\n\n const notify = () => {\n for (const listener of listeners) {\n listener();\n }\n };\n\n return {\n applyEvent(event) {\n if (event.type === \"open-url\") {\n return;\n }\n\n if (event.type === \"closed\") {\n if (!runtimeByNodeId[event.nodeId]) {\n return;\n }\n const next = { ...runtimeByNodeId };\n delete next[event.nodeId];\n runtimeByNodeId = next;\n notify();\n return;\n }\n\n const previous =\n runtimeByNodeId[event.nodeId] ?? defaultBrowserNodeRuntimeState;\n const next =\n event.type === \"state\"\n ? resolveNextState(previous, event)\n : {\n ...previous,\n error: {\n code: event.code,\n diagnosticMessage: event.diagnosticMessage,\n params: event.params\n }\n };\n\n runtimeByNodeId = {\n ...runtimeByNodeId,\n [event.nodeId]: next\n };\n notify();\n },\n clearAll() {\n if (Object.keys(runtimeByNodeId).length === 0) {\n return;\n }\n runtimeByNodeId = {};\n notify();\n },\n clearNode(nodeId) {\n const normalized = nodeId.trim();\n if (normalized.length === 0 || !runtimeByNodeId[normalized]) {\n return;\n }\n const next = { ...runtimeByNodeId };\n delete next[normalized];\n runtimeByNodeId = next;\n notify();\n },\n getNodeState(nodeId) {\n return runtimeByNodeId[nodeId] ?? defaultBrowserNodeRuntimeState;\n },\n getSnapshot() {\n return runtimeByNodeId;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n }\n };\n}\n\nfunction resolveNextState(\n previous: BrowserNodeRuntimeState,\n event: Extract<BrowserNodeEvent, { type: \"state\" }>\n): BrowserNodeRuntimeState {\n const nextUrl =\n normalizePublishedBrowserValue(event.url) ??\n (event.lifecycle !== \"cold\" ? previous.url : null);\n const nextTitle =\n normalizePublishedBrowserValue(event.title) ??\n (event.lifecycle !== \"cold\" ? previous.title : null);\n\n return {\n ...previous,\n canGoBack: event.canGoBack,\n canGoForward: event.canGoForward,\n error: shouldClearLoadError({\n isLoading: event.isLoading,\n url: event.url\n })\n ? null\n : previous.error,\n isAttachedToWindow: event.isAttachedToWindow ?? previous.isAttachedToWindow,\n isLoading: event.isLoading,\n isOccluded: event.isOccluded,\n lifecycle: event.lifecycle,\n title: nextTitle,\n url: nextUrl\n };\n}\n","import type { I18nRuntime } from \"@tutti-os/ui-i18n-runtime\";\nimport { createBrowserNodeI18nRuntime } from \"../i18n/browserNodeI18n.ts\";\nimport type { BrowserNodeI18nRuntime } from \"../i18n/browserNodeI18n.ts\";\nimport type { BrowserNodeHostApi } from \"./types.ts\";\nimport {\n createBrowserNodeRuntimeStore,\n type BrowserNodeRuntimeStore\n} from \"./runtimeStore.ts\";\nimport {\n resolveBrowserAddressInput,\n resolveBrowserOpenExternalUrl,\n type BrowserAddressInputResolution,\n type BrowserNavigationUrlResolution,\n type BrowserSearchUrlResolver\n} from \"./url.ts\";\n\nexport interface BrowserNodeFeature {\n hostApi: BrowserNodeHostApi;\n i18n: BrowserNodeI18nRuntime;\n reportDiagnostic?: BrowserNodeDiagnosticReporter;\n resolveAddressInput(rawInput: string): BrowserAddressInputResolution;\n resolveOpenExternalUrl(rawInput: string): BrowserNavigationUrlResolution;\n runtimeStore: BrowserNodeRuntimeStore;\n connect(): () => void;\n}\n\nexport interface BrowserNodeDiagnosticPayload {\n details?: Record<string, unknown>;\n event: string;\n level?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nexport type BrowserNodeDiagnosticReporter = (\n payload: BrowserNodeDiagnosticPayload\n) => void;\n\nexport interface CreateBrowserNodeFeatureInput {\n hostApi: BrowserNodeHostApi;\n i18n?: I18nRuntime<string>;\n reportDiagnostic?: BrowserNodeDiagnosticReporter;\n resolveSearchUrl?: BrowserSearchUrlResolver;\n runtimeStore?: BrowserNodeRuntimeStore;\n}\n\nexport function createBrowserNodeFeature({\n hostApi,\n i18n,\n reportDiagnostic,\n resolveSearchUrl,\n runtimeStore = createBrowserNodeRuntimeStore()\n}: CreateBrowserNodeFeatureInput): BrowserNodeFeature {\n let listenerCount = 0;\n let disconnect: (() => void) | null = null;\n\n const connect = () => {\n listenerCount += 1;\n if (!disconnect) {\n disconnect = hostApi.onEvent((event) => runtimeStore.applyEvent(event));\n }\n\n return () => {\n listenerCount = Math.max(0, listenerCount - 1);\n if (listenerCount === 0) {\n disconnect?.();\n disconnect = null;\n }\n };\n };\n\n return {\n connect,\n hostApi,\n i18n: createBrowserNodeI18nRuntime(i18n),\n reportDiagnostic,\n resolveAddressInput(rawInput) {\n return resolveBrowserAddressInput(rawInput, { resolveSearchUrl });\n },\n resolveOpenExternalUrl(rawInput) {\n return resolveBrowserOpenExternalUrl(rawInput);\n },\n runtimeStore\n };\n}\n"],"mappings":"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","names":["next"]}
|
package/dist/react/index.js
CHANGED
package/dist/workbench/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserNode,
|
|
3
3
|
BrowserNodeWorkbenchHeader
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-Q3TQYLDL.js";
|
|
5
5
|
import "../chunk-UTXZLRPE.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-ZRH4UQZB.js";
|
|
7
7
|
|
|
8
8
|
// src/workbench/index.ts
|
|
9
9
|
import { createElement } from "react";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tutti-os/browser-node",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"directory": "packages/browser/workbench-node"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@tutti-os/ui-i18n-runtime": "0.0.
|
|
52
|
-
"@tutti-os/ui-react-hooks": "0.0.
|
|
53
|
-
"@tutti-os/ui-system": "0.0.
|
|
54
|
-
"@tutti-os/workbench-surface": "0.0.
|
|
51
|
+
"@tutti-os/ui-i18n-runtime": "0.0.12",
|
|
52
|
+
"@tutti-os/ui-react-hooks": "0.0.12",
|
|
53
|
+
"@tutti-os/ui-system": "0.0.12",
|
|
54
|
+
"@tutti-os/workbench-surface": "0.0.12",
|
|
55
55
|
"ws": "^8.21.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/BrowserNode.tsx","../src/react/useBrowserNodeController.ts","../src/core/nodeController.ts","../src/react/useBrowserNodeWebview.ts","../src/core/webviewController.ts"],"sourcesContent":["import {\n ArrowLeftIcon,\n ArrowRightIcon,\n Badge,\n Button,\n Input,\n LaunchIcon,\n LoadingIcon,\n RefreshIcon,\n WarningLinedIcon,\n ViewportMenuSurface,\n cn,\n menuItemClassName\n} from \"@tutti-os/ui-system\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { HTMLAttributes, JSX, ReactNode } from \"react\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeNavigationPolicy,\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport { useBrowserNodeController } from \"./useBrowserNodeController.ts\";\nimport { useBrowserNodeWebview } from \"./useBrowserNodeWebview.ts\";\n\n// Electron needs the serialized string attribute for dynamically created webviews.\nconst browserNodeAllowPopupsAttribute = \"true\" as unknown as boolean;\n\nexport interface BrowserNodeProps {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onFocusRequest?: () => void;\n onNavigated?: (url: string) => void;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n showHeader?: boolean;\n syncDefaultUrl?: boolean;\n}\n\nexport function BrowserNode({\n defaultUrl,\n feature,\n navigationPolicy = null,\n nodeId,\n onFocusRequest,\n onNavigated,\n profileId = null,\n sessionMode = \"shared\",\n sessionPartition = null,\n showHeader = true,\n syncDefaultUrl = false\n}: BrowserNodeProps): JSX.Element {\n const { controller, state } = useBrowserNodeController({\n defaultUrl,\n feature,\n navigationPolicy,\n nodeId,\n profileId,\n sessionMode,\n sessionPartition,\n syncDefaultUrl\n });\n const runtime = state.runtime;\n const lastNavigatedUrlRef = useRef<string | null>(\n state.runtime.url?.trim() || null\n );\n const errorMessage = runtime.error\n ? formatBrowserNodeErrorMessage(feature, runtime.error)\n : null;\n const errorStatus = runtime.error\n ? formatBrowserNodeErrorStatus(feature, runtime.error)\n : null;\n const isShowingLoadError = errorMessage !== null;\n const openExternalUrl = feature.hostApi.openExternal\n ? feature.resolveAddressInput(state.displayUrl).url\n : null;\n const {\n devToolsContextMenu,\n dismissDevToolsContextMenu,\n openDevToolsFromContextMenu,\n shouldRenderWebview,\n setWebviewRef,\n webviewKey,\n webviewPartition,\n webviewSrc\n } = useBrowserNodeWebview({\n feature,\n initialUrl: state.displayUrl,\n lifecycle: runtime.lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction: onFocusRequest,\n profileId,\n sessionMode,\n sessionPartition\n });\n\n useEffect(() => {\n const navigatedUrl = state.runtime.url?.trim() ?? \"\";\n if (\n !onNavigated ||\n state.runtime.isLoading ||\n state.runtime.error ||\n navigatedUrl.length === 0 ||\n navigatedUrl === \"about:blank\" ||\n lastNavigatedUrlRef.current === navigatedUrl\n ) {\n return;\n }\n\n lastNavigatedUrlRef.current = navigatedUrl;\n onNavigated(navigatedUrl);\n }, [\n onNavigated,\n state.runtime.error,\n state.runtime.isLoading,\n state.runtime.url\n ]);\n\n return (\n <div className=\"flex h-full min-h-0 flex-col overflow-hidden bg-[var(--background-panel)]\">\n {showHeader ? (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n draftUrl={state.draftUrl}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n onDraftUrlChange={(nextUrl) => controller.setDraftUrl(nextUrl)}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={() => {\n void controller.submitDraftUrl().catch(() => undefined);\n }}\n onOpenExternal={\n openExternalUrl\n ? () => {\n void feature.hostApi\n .openExternal?.({ url: openExternalUrl })\n .catch(() => undefined);\n }\n : undefined\n }\n onGoBack={() => {\n void controller.goBack().catch(() => undefined);\n }}\n onGoForward={() => {\n void controller.goForward().catch(() => undefined);\n }}\n onReload={() => {\n void controller.reload().catch(() => undefined);\n }}\n />\n ) : null}\n <div className=\"relative min-h-0 flex-1 overflow-hidden bg-[var(--background-panel)]\">\n {shouldRenderWebview ? (\n <webview\n allowpopups={browserNodeAllowPopupsAttribute}\n key={webviewKey}\n ref={setWebviewRef}\n className={cn(\n \"absolute inset-0 h-full w-full border-0 bg-[var(--background-panel)]\",\n isShowingLoadError ? \"hidden pointer-events-none\" : \"visible\"\n )}\n data-browser-node-webview=\"true\"\n partition={webviewPartition}\n src={webviewSrc}\n />\n ) : null}\n {errorMessage ? (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-[var(--background-panel)] px-8 py-10 text-center\">\n <div\n className=\"flex w-full max-w-[440px] flex-col items-center\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div className=\"flex size-11 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--state-danger)_22%,transparent)] bg-[color-mix(in_srgb,var(--state-danger)_8%,transparent)] text-[var(--state-danger)]\">\n <WarningLinedIcon className=\"size-5\" />\n </div>\n <div className=\"mt-4 text-lg font-semibold text-[var(--text-primary)]\">\n {feature.i18n.t(\"loadFailed\")}\n </div>\n <div className=\"mt-1 max-w-[360px] text-[13px] leading-5 text-[var(--text-secondary)]\">\n {errorMessage}\n </div>\n {errorStatus ? (\n <div className=\"mt-4 rounded-full border border-border bg-[var(--transparency-block)] px-2.5 py-1 text-[11px] font-medium text-[var(--text-secondary)]\">\n {errorStatus}\n </div>\n ) : null}\n {openExternalUrl ? (\n <div className=\"mt-5 flex flex-wrap items-center justify-center gap-2\">\n <Button\n size=\"sm\"\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n void feature.hostApi\n .openExternal?.({ url: openExternalUrl })\n .catch(() => undefined);\n }}\n >\n <LaunchIcon className=\"size-3.5\" />\n {feature.i18n.t(\"actions.openExternal\")}\n </Button>\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n {devToolsContextMenu ? (\n <ViewportMenuSurface\n open\n className=\"w-44\"\n dismissOnEscape\n dismissOnPointerDownOutside\n onDismiss={dismissDevToolsContextMenu}\n placement={{\n type: \"point\",\n point: devToolsContextMenu,\n alignX: \"start\",\n alignY: \"start\",\n estimatedSize: {\n width: 176,\n height: 40\n }\n }}\n >\n <button\n className={cn(menuItemClassName, \"w-full\")}\n type=\"button\"\n onClick={() => {\n void openDevToolsFromContextMenu().catch(() => undefined);\n }}\n >\n {feature.i18n.t(\"actions.openDevTools\")}\n </button>\n </ViewportMenuSurface>\n ) : null}\n </div>\n </div>\n );\n}\n\nexport interface BrowserNodeWorkbenchHeaderProps {\n className?: string;\n defaultActions?: ReactNode;\n defaultUrl: string;\n dragHandleProps?: HTMLAttributes<HTMLElement>;\n feature: BrowserNodeFeature;\n nodeId: string;\n onCloseRequest?: () => void;\n onFocusRequest?: () => void;\n}\n\nexport function BrowserNodeWorkbenchHeader({\n className,\n defaultActions,\n defaultUrl,\n dragHandleProps,\n feature,\n nodeId,\n onCloseRequest,\n onFocusRequest\n}: BrowserNodeWorkbenchHeaderProps): JSX.Element {\n const { controller, state } = useBrowserNodeController({\n defaultUrl,\n feature,\n nodeId\n });\n const runtime = state.runtime;\n const openExternalUrl = feature.hostApi.openExternal\n ? feature.resolveAddressInput(state.displayUrl).url\n : null;\n\n return (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n className={className}\n defaultActions={defaultActions}\n draftUrl={state.draftUrl}\n dragHandleProps={dragHandleProps}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n onCloseRequest={onCloseRequest}\n onDraftUrlChange={(nextUrl) => controller.setDraftUrl(nextUrl)}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={() => {\n void controller.submitDraftUrl().catch(() => undefined);\n }}\n onOpenExternal={\n openExternalUrl\n ? () => {\n void feature.hostApi\n .openExternal?.({ url: openExternalUrl })\n .catch(() => undefined);\n }\n : undefined\n }\n onGoBack={() => {\n void controller.goBack().catch(() => undefined);\n }}\n onGoForward={() => {\n void controller.goForward().catch(() => undefined);\n }}\n onReload={() => {\n void controller.reload().catch(() => undefined);\n }}\n withBorder={false}\n />\n );\n}\n\nexport function BrowserNodeHeader({\n canGoBack,\n canGoForward,\n className,\n defaultActions,\n draftUrl,\n dragHandleProps,\n feature,\n isCold = false,\n isLoading,\n onCloseRequest,\n onDraftUrlChange,\n onFocusRequest,\n onGoBack,\n onGoForward,\n onOpenExternal,\n onReload,\n onSubmitUrl,\n withBorder = true\n}: {\n canGoBack: boolean;\n canGoForward: boolean;\n className?: string;\n defaultActions?: ReactNode;\n draftUrl: string;\n dragHandleProps?: HTMLAttributes<HTMLElement>;\n feature: BrowserNodeFeature;\n isCold?: boolean;\n isLoading: boolean;\n onCloseRequest?: () => void;\n onDraftUrlChange: (nextUrl: string) => void;\n onFocusRequest?: () => void;\n onGoBack: () => void;\n onGoForward: () => void;\n onOpenExternal?: () => void;\n onReload: () => void;\n onSubmitUrl: () => void;\n withBorder?: boolean;\n}): JSX.Element {\n const [reloadAnimationKey, setReloadAnimationKey] = useState(0);\n\n const handleReload = (): void => {\n setReloadAnimationKey((currentKey) => currentKey + 1);\n onReload();\n };\n\n return (\n <div\n className={cn(\n \"flex h-[var(--workbench-header-height,38px)] min-h-[var(--workbench-header-height,38px)] items-center gap-2 bg-[var(--background-panel)] px-2 pl-3\",\n withBorder ? \"border-b border-border\" : null,\n className\n )}\n data-browser-node-header=\"true\"\n onDoubleClick={(event) => {\n if (\n event.target instanceof Element &&\n event.target.closest(\".nodrag\")\n ) {\n return;\n }\n event.stopPropagation();\n dragHandleProps?.onDoubleClick?.(event);\n }}\n >\n <div className=\"inline-flex items-center gap-1\">\n <BrowserNodeHeaderButton\n disabled={!canGoBack}\n label={feature.i18n.t(\"actions.back\")}\n onClick={onGoBack}\n >\n <ArrowLeftIcon className=\"size-[15px]\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n disabled={!canGoForward}\n label={feature.i18n.t(\"actions.forward\")}\n onClick={onGoForward}\n >\n <ArrowRightIcon className=\"size-[15px]\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n label={feature.i18n.t(\"actions.reload\")}\n onClick={handleReload}\n >\n <RefreshIcon\n key={reloadAnimationKey}\n className={cn(\n \"size-[15px]\",\n reloadAnimationKey > 0 &&\n \"motion-safe:animate-[spin_520ms_cubic-bezier(0.4,0,0.2,1)_1_reverse]\"\n )}\n />\n </BrowserNodeHeaderButton>\n </div>\n <div\n {...dragHandleProps}\n className=\"h-full w-8 shrink-0 cursor-grab active:cursor-grabbing\"\n data-browser-node-drag-gutter=\"true\"\n data-node-drag-handle=\"true\"\n aria-hidden=\"true\"\n />\n <form\n className=\"nodrag relative min-w-0 flex-1\"\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onSubmitUrl();\n }}\n >\n <Input\n aria-label={feature.i18n.t(\"addressLabel\")}\n className=\"pr-8 focus-visible:border-input focus-visible:ring-0 focus-visible:ring-offset-0\"\n placeholder={feature.i18n.t(\"addressPlaceholder\")}\n size=\"sm\"\n value={draftUrl}\n onChange={(event) => onDraftUrlChange(event.target.value)}\n onFocus={onFocusRequest}\n />\n {isLoading ? (\n <LoadingIcon className=\"pointer-events-none absolute right-2 top-1/2 z-[1] size-4 -translate-y-1/2 animate-spin text-[var(--text-tertiary)]\" />\n ) : null}\n </form>\n {onOpenExternal ? (\n <BrowserNodeHeaderButton\n label={feature.i18n.t(\"actions.openExternal\")}\n onClick={onOpenExternal}\n >\n <LaunchIcon className=\"size-[15px]\" />\n </BrowserNodeHeaderButton>\n ) : null}\n {defaultActions ? (\n <div className=\"nodrag flex shrink-0 items-center gap-1.5\">\n {isCold ? (\n <Badge\n className=\"h-[26px] min-w-7 rounded-md text-[10px] font-semibold lowercase tracking-[0.08em]\"\n aria-label={feature.i18n.t(\"coldStatus\")}\n >\n {feature.i18n.t(\"coldStatus\")}\n </Badge>\n ) : null}\n <span\n className=\"contents\"\n onClickCapture={(event) => {\n if (\n !onCloseRequest ||\n !(event.target instanceof Element) ||\n !event.target.closest('[data-workbench-action=\"close\"]')\n ) {\n return;\n }\n onCloseRequest();\n }}\n >\n {defaultActions}\n </span>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction formatBrowserNodeErrorMessage(\n feature: BrowserNodeFeature,\n error: BrowserNodeRuntimeError\n): string {\n switch (error.code) {\n case \"invalid-url\":\n return feature.i18n.t(\"errors.invalidUrl\", error.params);\n case \"navigation-failed\":\n if (error.params && error.params.statusCode !== undefined) {\n return feature.i18n.t(\n \"errors.navigationFailedWithStatus\",\n error.params\n );\n }\n return feature.i18n.t(\"errors.navigationFailed\", error.params);\n case \"unsupported-protocol\":\n return feature.i18n.t(\"errors.unsupportedProtocol\", error.params);\n case \"unsupported-url\":\n return feature.i18n.t(\"errors.unsupportedUrl\", error.params);\n }\n}\n\nfunction formatBrowserNodeErrorStatus(\n feature: BrowserNodeFeature,\n error: BrowserNodeRuntimeError\n): string | null {\n if (error.code !== \"navigation-failed\" || !error.params) {\n return null;\n }\n\n const statusCode = error.params.statusCode;\n if (typeof statusCode === \"number\") {\n return feature.i18n.t(\"errors.statusCode\", { statusCode });\n }\n\n const errorCode = error.params.errorCode;\n if (typeof errorCode === \"number\") {\n return feature.i18n.t(\"errors.errorCode\", { errorCode });\n }\n\n return null;\n}\n\nfunction BrowserNodeHeaderButton({\n children,\n disabled,\n label,\n onClick\n}: {\n children: ReactNode;\n disabled?: boolean;\n label: string;\n onClick: () => void;\n}) {\n return (\n <Button\n aria-label={label}\n className=\"rounded-md\"\n disabled={disabled}\n size=\"icon-sm\"\n title={label}\n type=\"button\"\n variant=\"chrome\"\n onClick={onClick}\n >\n {children}\n </Button>\n );\n}\n","import { useEffect, useMemo } from \"react\";\nimport { useExternalStoreSnapshot } from \"@tutti-os/ui-react-hooks\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport {\n acquireBrowserNodeController,\n type BrowserNodeControllerState\n} from \"../core/nodeController.ts\";\nimport type {\n BrowserNodeNavigationPolicy,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\n\nexport function useBrowserNodeController(input: {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n syncDefaultUrl?: boolean;\n}) {\n const controller = useMemo(\n () =>\n acquireBrowserNodeController({\n defaultUrl: input.defaultUrl,\n feature: input.feature,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n profileId: input.profileId ?? null,\n sessionMode: input.sessionMode ?? \"shared\",\n sessionPartition: input.sessionPartition,\n syncDefaultUrl: input.syncDefaultUrl ?? false\n }),\n [\n input.defaultUrl,\n input.feature,\n input.navigationPolicy,\n input.nodeId,\n input.profileId,\n input.sessionMode,\n input.sessionPartition,\n input.syncDefaultUrl\n ]\n );\n\n useEffect(() => {\n controller.retain();\n return () => {\n controller.release();\n };\n }, [controller]);\n\n useEffect(() => {\n controller.sync();\n }, [\n controller,\n input.defaultUrl,\n input.feature,\n input.navigationPolicy,\n input.nodeId,\n input.profileId,\n input.sessionMode,\n input.sessionPartition,\n input.syncDefaultUrl\n ]);\n const state = useExternalStoreSnapshot<BrowserNodeControllerState>({\n getSnapshot() {\n return controller.getState();\n },\n subscribe(listener) {\n return controller.subscribe(listener);\n }\n });\n\n return {\n controller,\n state\n };\n}\n","import type { BrowserNodeFeature } from \"./feature.ts\";\nimport {\n normalizeBrowserComparableUrl,\n normalizeHostBrowserComparableUrl\n} from \"./url.ts\";\nimport type {\n BrowserNodeNavigationPolicy,\n BrowserNodeRuntimeState,\n BrowserNodeSessionMode\n} from \"./types.ts\";\n\nexport interface BrowserNodeControllerState {\n displayUrl: string;\n draftUrl: string;\n runtime: BrowserNodeRuntimeState;\n}\n\nexport interface BrowserNodeController {\n getState(): BrowserNodeControllerState;\n goBack(): Promise<void>;\n goForward(): Promise<void>;\n reload(): Promise<void>;\n release(): void;\n retain(): void;\n setDraftUrl(nextUrl: string): void;\n sync(): void;\n subscribe(listener: () => void): () => void;\n submitDraftUrl(): Promise<void>;\n}\n\ninterface BrowserNodeControllerContext {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n syncDefaultUrl: boolean;\n}\n\ninterface BrowserNodeControllerEntry {\n connectedRelease: (() => void) | null;\n controller: BrowserNodeController;\n context: BrowserNodeControllerContext;\n lastColdActivationUrl: string | null;\n listeners: Set<() => void>;\n pendingColdActivationUrl: string | null;\n refCount: number;\n runtimeUnsubscribe: (() => void) | null;\n state: BrowserNodeControllerState;\n}\n\nconst controllerRegistry = new Map<string, BrowserNodeControllerEntry>();\n\nexport function acquireBrowserNodeController(input: {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n syncDefaultUrl?: boolean;\n}): BrowserNodeController {\n const existing = controllerRegistry.get(input.nodeId);\n const entry =\n existing ??\n createBrowserNodeControllerEntry({\n defaultUrl: input.defaultUrl,\n feature: input.feature,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n profileId: input.profileId ?? null,\n sessionMode: input.sessionMode ?? \"shared\",\n sessionPartition: input.sessionPartition,\n syncDefaultUrl: input.syncDefaultUrl ?? false\n });\n\n entry.context = {\n defaultUrl: input.defaultUrl,\n feature: input.feature,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n profileId: input.profileId ?? null,\n sessionMode: input.sessionMode ?? \"shared\",\n sessionPartition: input.sessionPartition,\n syncDefaultUrl: input.syncDefaultUrl ?? false\n };\n\n if (!existing) {\n controllerRegistry.set(input.nodeId, entry);\n }\n\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: false,\n notifyListeners: false\n });\n\n return entry.controller;\n}\n\nfunction createBrowserNodeControllerEntry(\n context: BrowserNodeControllerContext\n): BrowserNodeControllerEntry {\n const runtime = context.feature.runtimeStore.getNodeState(context.nodeId);\n const displayUrl = resolveBrowserNodeDisplayUrl(runtime, context.defaultUrl);\n const entry = {\n connectedRelease: null,\n controller: null as unknown as BrowserNodeController,\n context,\n lastColdActivationUrl: resolveInitialLastColdActivationUrl(\n runtime,\n context.defaultUrl\n ),\n listeners: new Set(),\n pendingColdActivationUrl: null,\n refCount: 0,\n runtimeUnsubscribe: null,\n state: {\n displayUrl,\n draftUrl: displayUrl,\n runtime\n }\n } as BrowserNodeControllerEntry;\n\n entry.controller = {\n getState() {\n return entry.state;\n },\n goBack() {\n return entry.context.feature.hostApi.goBack({\n nodeId: entry.context.nodeId\n });\n },\n goForward() {\n return entry.context.feature.hostApi.goForward({\n nodeId: entry.context.nodeId\n });\n },\n reload() {\n return entry.context.feature.hostApi.reload({\n nodeId: entry.context.nodeId\n });\n },\n release() {\n entry.refCount = Math.max(0, entry.refCount - 1);\n if (entry.refCount > 0) {\n return;\n }\n\n entry.connectedRelease?.();\n entry.connectedRelease = null;\n entry.runtimeUnsubscribe?.();\n entry.runtimeUnsubscribe = null;\n controllerRegistry.delete(entry.context.nodeId);\n },\n retain() {\n entry.refCount += 1;\n if (entry.refCount > 1) {\n return;\n }\n\n if (!controllerRegistry.has(entry.context.nodeId)) {\n controllerRegistry.set(entry.context.nodeId, entry);\n }\n entry.connectedRelease = entry.context.feature.connect();\n entry.runtimeUnsubscribe = entry.context.feature.runtimeStore.subscribe(\n () => {\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: true,\n notifyListeners: true\n });\n }\n );\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: true,\n notifyListeners: true\n });\n },\n setDraftUrl(nextUrl) {\n if (entry.state.draftUrl === nextUrl) {\n return;\n }\n\n entry.state = {\n ...entry.state,\n draftUrl: nextUrl\n };\n notifyBrowserNodeControllerListeners(entry);\n },\n sync() {\n reconcileBrowserNodeControllerState(entry, {\n allowAutoActivate: true,\n notifyListeners: true\n });\n },\n subscribe(listener) {\n entry.listeners.add(listener);\n return () => {\n entry.listeners.delete(listener);\n };\n },\n async submitDraftUrl() {\n const resolved = entry.context.feature.resolveAddressInput(\n entry.state.draftUrl\n );\n if (!resolved.url) {\n return;\n }\n\n if (entry.state.draftUrl !== resolved.url) {\n entry.state = {\n ...entry.state,\n draftUrl: resolved.url\n };\n notifyBrowserNodeControllerListeners(entry);\n }\n\n await entry.context.feature.hostApi.navigate({\n navigationPolicy: entry.context.navigationPolicy,\n nodeId: entry.context.nodeId,\n url: resolved.url\n });\n }\n };\n\n return entry;\n}\n\nfunction resolveInitialLastColdActivationUrl(\n runtime: BrowserNodeRuntimeState,\n defaultUrl: string\n): string | null {\n const trimmedUrl = defaultUrl.trim();\n if (\n runtime.lifecycle === \"cold\" ||\n runtime.error !== null ||\n trimmedUrl.length === 0 ||\n trimmedUrl === \"about:blank\"\n ) {\n return null;\n }\n\n const comparableDefaultUrl = normalizeBrowserComparableUrl(trimmedUrl);\n const comparableRuntimeUrl = runtime.url\n ? normalizeBrowserComparableUrl(runtime.url)\n : null;\n return comparableDefaultUrl !== null &&\n comparableDefaultUrl === comparableRuntimeUrl\n ? trimmedUrl\n : null;\n}\n\nfunction notifyBrowserNodeControllerListeners(\n entry: BrowserNodeControllerEntry\n): void {\n for (const listener of entry.listeners) {\n listener();\n }\n}\n\nfunction resolveBrowserNodeDisplayUrl(\n runtime: BrowserNodeRuntimeState,\n defaultUrl: string\n): string {\n const resolvedRuntimeUrl = runtime.url?.trim() ?? \"\";\n return resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;\n}\n\nfunction reconcileBrowserNodeControllerState(\n entry: BrowserNodeControllerEntry,\n options: {\n allowAutoActivate: boolean;\n notifyListeners: boolean;\n }\n): void {\n const runtime = entry.context.feature.runtimeStore.getNodeState(\n entry.context.nodeId\n );\n const displayUrl = resolveBrowserNodeDisplayUrl(\n runtime,\n entry.context.defaultUrl\n );\n const nextDraftUrl =\n displayUrl !== entry.state.displayUrl ? displayUrl : entry.state.draftUrl;\n\n const changed =\n entry.state.runtime !== runtime ||\n entry.state.displayUrl !== displayUrl ||\n entry.state.draftUrl !== nextDraftUrl;\n\n if (changed) {\n entry.state = {\n displayUrl,\n draftUrl: nextDraftUrl,\n runtime\n };\n if (options.notifyListeners) {\n notifyBrowserNodeControllerListeners(entry);\n }\n }\n\n if (options.allowAutoActivate) {\n void maybeActivateBrowserNodeDefaultUrl(entry).catch(() => undefined);\n }\n}\n\nasync function maybeActivateBrowserNodeDefaultUrl(\n entry: BrowserNodeControllerEntry\n): Promise<void> {\n const {\n defaultUrl,\n feature,\n navigationPolicy,\n nodeId,\n profileId,\n sessionMode,\n sessionPartition,\n syncDefaultUrl\n } = entry.context;\n const trimmedUrl = defaultUrl.trim();\n const comparableDefaultUrl = normalizeHostBrowserComparableUrl(trimmedUrl);\n const comparableRuntimeUrl = entry.state.runtime.url\n ? normalizeHostBrowserComparableUrl(entry.state.runtime.url)\n : null;\n const shouldActivateColdNode = entry.state.runtime.lifecycle === \"cold\";\n const shouldSyncDefaultUrl =\n syncDefaultUrl &&\n entry.state.runtime.lifecycle !== \"cold\" &&\n comparableDefaultUrl !== null &&\n (comparableRuntimeUrl !== comparableDefaultUrl ||\n entry.state.runtime.error !== null) &&\n entry.lastColdActivationUrl !== trimmedUrl;\n if (\n trimmedUrl.length === 0 ||\n trimmedUrl === \"about:blank\" ||\n entry.state.runtime.isLoading ||\n entry.pendingColdActivationUrl === trimmedUrl ||\n (!shouldActivateColdNode && !shouldSyncDefaultUrl) ||\n (shouldActivateColdNode &&\n entry.state.runtime.error !== null &&\n entry.lastColdActivationUrl === trimmedUrl)\n ) {\n return;\n }\n\n entry.pendingColdActivationUrl = trimmedUrl;\n try {\n await feature.hostApi.activate({\n navigationPolicy,\n nodeId,\n profileId,\n sessionMode,\n sessionPartition,\n url: trimmedUrl\n });\n entry.lastColdActivationUrl = trimmedUrl;\n } finally {\n if (entry.pendingColdActivationUrl === trimmedUrl) {\n entry.pendingColdActivationUrl = null;\n }\n }\n}\n","import { useCallback, useEffect, useMemo } from \"react\";\nimport { useExternalStoreSnapshot } from \"@tutti-os/ui-react-hooks\";\nimport {\n acquireBrowserNodeWebviewController,\n type BrowserNodeWebviewContextMenuPoint,\n type BrowserNodeWebviewControllerState\n} from \"../core/webviewController.ts\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeLifecycle,\n BrowserNodeNavigationPolicy,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport type { BrowserNodeWebviewTag } from \"./webviewTag.ts\";\n\nexport function useBrowserNodeWebview({\n feature,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n}: {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n}): {\n devToolsContextMenu: BrowserNodeWebviewContextMenuPoint | null;\n dismissDevToolsContextMenu: () => void;\n openDevToolsFromContextMenu: () => Promise<void>;\n shouldRenderWebview: boolean;\n setWebviewRef: (element: BrowserNodeWebviewTag | null) => void;\n webviewKey: string;\n webviewPartition: string;\n webviewSrc: string;\n} {\n const controller = useMemo(\n () =>\n acquireBrowserNodeWebviewController({\n feature,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n }),\n [\n feature,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n ]\n );\n\n useEffect(() => {\n controller.retain();\n return () => {\n controller.release();\n };\n }, [controller]);\n\n useEffect(() => {\n controller.sync();\n }, [\n controller,\n initialUrl,\n lifecycle,\n navigationPolicy,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode,\n sessionPartition\n ]);\n const state = useExternalStoreSnapshot<BrowserNodeWebviewControllerState>({\n getSnapshot() {\n return controller.getState();\n },\n subscribe(listener) {\n return controller.subscribe(listener);\n }\n });\n\n const setWebviewRef = useCallback(\n (element: BrowserNodeWebviewTag | null) => {\n controller.setWebview(element);\n },\n [controller]\n );\n const dismissDevToolsContextMenu = useCallback(() => {\n controller.dismissDevToolsContextMenu();\n }, [controller]);\n const openDevToolsFromContextMenu = useCallback(() => {\n return controller.openDevToolsFromContextMenu();\n }, [controller]);\n\n return {\n devToolsContextMenu: state.devToolsContextMenu,\n dismissDevToolsContextMenu,\n openDevToolsFromContextMenu,\n shouldRenderWebview: state.shouldRenderWebview,\n setWebviewRef,\n webviewKey: state.webviewKey,\n webviewPartition: state.webviewPartition,\n webviewSrc: state.webviewSrc\n };\n}\n","import type { BrowserNodeFeature } from \"./feature.ts\";\nimport { resolveBrowserSessionPartition } from \"./session.ts\";\nimport type {\n BrowserNodeLifecycle,\n BrowserNodeNavigationPolicy,\n BrowserNodeSessionMode\n} from \"./types.ts\";\nimport type { BrowserNodeWebviewTag } from \"../react/webviewTag.ts\";\n\nconst browserGuestUnregisterGraceMs = 250;\nconst browserNodeInitialWebviewSrc = \"about:blank\";\n\nexport interface BrowserNodeWebviewControllerState {\n devToolsContextMenu: BrowserNodeWebviewContextMenuPoint | null;\n shouldRenderWebview: boolean;\n webviewKey: string;\n webviewPartition: string;\n webviewSrc: string;\n}\n\nexport interface BrowserNodeWebviewContextMenuPoint {\n x: number;\n y: number;\n}\n\nexport interface BrowserNodeWebviewController {\n dismissDevToolsContextMenu(): void;\n getState(): BrowserNodeWebviewControllerState;\n openDevToolsFromContextMenu(): Promise<void>;\n release(): void;\n retain(): void;\n setWebview(element: BrowserNodeWebviewTag | null): void;\n sync(): void;\n subscribe(listener: () => void): () => void;\n}\n\ninterface BrowserNodeWebviewControllerContext {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n}\n\ninterface BrowserNodeWebviewControllerEntry {\n attachedListeners: Array<{\n event: string;\n listener: EventListener;\n }>;\n context: BrowserNodeWebviewControllerContext;\n controller: BrowserNodeWebviewController;\n listeners: Set<() => void>;\n refCount: number;\n registeredGuestId: number | null;\n registeringGuestId: number | null;\n state: BrowserNodeWebviewControllerState;\n webview: BrowserNodeWebviewTag | null;\n}\n\nconst webviewControllerRegistry = new Map<\n string,\n BrowserNodeWebviewControllerEntry\n>();\nconst pendingGuestIdsByNodeId = new Map<string, number>();\nconst pendingUnregisterTimersByNodeId = new Map<\n string,\n ReturnType<typeof globalThis.setTimeout>\n>();\n\nexport function acquireBrowserNodeWebviewController(input: {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n navigationPolicy?: BrowserNodeNavigationPolicy | null;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n sessionPartition?: string | null;\n}): BrowserNodeWebviewController {\n const existing = webviewControllerRegistry.get(input.nodeId);\n const entry =\n existing ??\n createBrowserNodeWebviewControllerEntry({\n feature: input.feature,\n initialUrl: input.initialUrl,\n lifecycle: input.lifecycle,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n onGuestInteraction: input.onGuestInteraction,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n });\n\n entry.context = {\n feature: input.feature,\n initialUrl: input.initialUrl,\n lifecycle: input.lifecycle,\n navigationPolicy: input.navigationPolicy,\n nodeId: input.nodeId,\n onGuestInteraction: input.onGuestInteraction,\n profileId: input.profileId,\n sessionMode: input.sessionMode,\n sessionPartition: input.sessionPartition\n };\n if (!existing) {\n webviewControllerRegistry.set(input.nodeId, entry);\n }\n return entry.controller;\n}\n\nfunction createBrowserNodeWebviewControllerEntry(\n context: BrowserNodeWebviewControllerContext\n): BrowserNodeWebviewControllerEntry {\n const state = resolveBrowserNodeWebviewControllerState(context);\n const entry = {\n attachedListeners: [],\n context,\n controller: null as unknown as BrowserNodeWebviewController,\n listeners: new Set(),\n refCount: 0,\n registeredGuestId: null,\n registeringGuestId: null,\n state,\n webview: null\n } as BrowserNodeWebviewControllerEntry;\n\n entry.controller = {\n dismissDevToolsContextMenu() {\n setBrowserNodeDevToolsContextMenu(entry, null);\n },\n getState() {\n return entry.state;\n },\n async openDevToolsFromContextMenu() {\n setBrowserNodeDevToolsContextMenu(entry, null);\n try {\n await entry.context.feature.hostApi.openDevTools?.({\n nodeId: entry.context.nodeId\n });\n } catch (error) {\n reportBrowserNodeWebviewDiagnostic(\n entry,\n \"devtools.open.failed\",\n {\n error: error instanceof Error ? error.message : String(error),\n webContentsId: readBrowserNodeWebContentsId(entry.webview),\n webviewPartition: entry.state.webviewPartition\n },\n \"warn\"\n );\n throw error;\n }\n },\n release() {\n entry.refCount = Math.max(0, entry.refCount - 1);\n if (entry.refCount > 0) {\n return;\n }\n scheduleBrowserNodeGuestUnregister(entry);\n detachBrowserNodeWebview(entry);\n webviewControllerRegistry.delete(entry.context.nodeId);\n },\n retain() {\n entry.refCount += 1;\n if (entry.refCount > 1) {\n return;\n }\n reconcileBrowserNodeWebviewControllerState(entry, {\n allowHostEffects: true,\n notifyListeners: true,\n rebindWebview: true\n });\n },\n setWebview(element) {\n if (entry.webview === element) {\n return;\n }\n detachBrowserNodeWebview(entry);\n entry.webview = element;\n attachBrowserNodeWebview(entry);\n },\n sync() {\n reconcileBrowserNodeWebviewControllerState(entry, {\n allowHostEffects: true,\n notifyListeners: true,\n rebindWebview: true\n });\n },\n subscribe(listener) {\n entry.listeners.add(listener);\n return () => {\n entry.listeners.delete(listener);\n };\n }\n };\n\n return entry;\n}\n\nfunction resolveBrowserNodeWebviewControllerState(\n context: BrowserNodeWebviewControllerContext\n): BrowserNodeWebviewControllerState {\n const webviewPartition = resolveBrowserSessionPartition({\n profileId: context.profileId,\n sessionMode: context.sessionMode,\n sessionPartition: context.sessionPartition\n });\n return {\n devToolsContextMenu: null,\n shouldRenderWebview: context.lifecycle !== \"cold\",\n webviewKey: `${context.nodeId}:${webviewPartition}`,\n webviewPartition,\n webviewSrc: browserNodeInitialWebviewSrc\n };\n}\n\nfunction reconcileBrowserNodeWebviewControllerState(\n entry: BrowserNodeWebviewControllerEntry,\n options: {\n allowHostEffects: boolean;\n notifyListeners: boolean;\n rebindWebview: boolean;\n }\n): void {\n const nextState = resolveBrowserNodeWebviewControllerState(entry.context);\n const changed =\n entry.state.devToolsContextMenu !== nextState.devToolsContextMenu ||\n entry.state.shouldRenderWebview !== nextState.shouldRenderWebview ||\n entry.state.webviewKey !== nextState.webviewKey ||\n entry.state.webviewPartition !== nextState.webviewPartition ||\n entry.state.webviewSrc !== nextState.webviewSrc;\n\n if (options.allowHostEffects) {\n if (entry.context.lifecycle === \"cold\") {\n scheduleBrowserNodeGuestUnregister(entry);\n } else {\n clearPendingBrowserNodeGuestUnregister(entry.context.nodeId);\n void entry.context.feature.hostApi\n .prepareSession({\n navigationPolicy: entry.context.navigationPolicy,\n nodeId: entry.context.nodeId,\n profileId: entry.context.profileId,\n sessionMode: entry.context.sessionMode,\n sessionPartition: entry.context.sessionPartition\n })\n .catch(() => undefined);\n }\n }\n\n if (!changed) {\n if (\n options.rebindWebview &&\n entry.webview &&\n entry.attachedListeners.length === 0\n ) {\n attachBrowserNodeWebview(entry);\n }\n return;\n }\n\n entry.state = nextState;\n detachBrowserNodeWebview(entry);\n attachBrowserNodeWebview(entry);\n if (options.notifyListeners) {\n notifyBrowserNodeWebviewControllerListeners(entry);\n }\n}\n\nfunction setBrowserNodeDevToolsContextMenu(\n entry: BrowserNodeWebviewControllerEntry,\n devToolsContextMenu: BrowserNodeWebviewContextMenuPoint | null\n): void {\n if (\n entry.state.devToolsContextMenu?.x === devToolsContextMenu?.x &&\n entry.state.devToolsContextMenu?.y === devToolsContextMenu?.y\n ) {\n return;\n }\n entry.state = {\n ...entry.state,\n devToolsContextMenu\n };\n notifyBrowserNodeWebviewControllerListeners(entry);\n}\n\nfunction notifyBrowserNodeWebviewControllerListeners(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n for (const listener of entry.listeners) {\n listener();\n }\n}\n\nfunction clearPendingBrowserNodeGuestUnregister(nodeId: string): void {\n const timerId = pendingUnregisterTimersByNodeId.get(nodeId);\n if (timerId !== undefined) {\n globalThis.clearTimeout(timerId);\n pendingUnregisterTimersByNodeId.delete(nodeId);\n }\n pendingGuestIdsByNodeId.delete(nodeId);\n}\n\nfunction scheduleBrowserNodeGuestUnregister(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n const guestId = entry.registeredGuestId;\n const nodeId = entry.context.nodeId;\n entry.registeringGuestId = null;\n if (guestId === null) {\n clearPendingBrowserNodeGuestUnregister(nodeId);\n return;\n }\n\n entry.registeredGuestId = null;\n clearPendingBrowserNodeGuestUnregister(nodeId);\n pendingGuestIdsByNodeId.set(nodeId, guestId);\n const timerId = globalThis.setTimeout(() => {\n pendingUnregisterTimersByNodeId.delete(nodeId);\n const pendingGuestId = pendingGuestIdsByNodeId.get(nodeId);\n pendingGuestIdsByNodeId.delete(nodeId);\n if (\n typeof pendingGuestId !== \"number\" ||\n !Number.isFinite(pendingGuestId)\n ) {\n return;\n }\n\n void entry.context.feature.hostApi\n .unregisterGuest({\n nodeId: entry.context.nodeId,\n webContentsId: pendingGuestId\n })\n .catch(() => undefined);\n }, browserGuestUnregisterGraceMs);\n pendingUnregisterTimersByNodeId.set(nodeId, timerId);\n}\n\nfunction detachBrowserNodeWebview(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n if (!entry.webview) {\n entry.attachedListeners = [];\n return;\n }\n for (const record of entry.attachedListeners) {\n entry.webview.removeEventListener(record.event, record.listener);\n }\n entry.attachedListeners = [];\n}\n\nfunction attachBrowserNodeWebview(\n entry: BrowserNodeWebviewControllerEntry\n): void {\n const webview = entry.webview;\n if (!webview || !entry.state.shouldRenderWebview) {\n return;\n }\n\n const registerGuest = async (): Promise<void> => {\n const guestId = webview.getWebContentsId?.();\n if (\n typeof guestId !== \"number\" ||\n !Number.isFinite(guestId) ||\n guestId <= 0 ||\n entry.registeredGuestId === guestId ||\n entry.registeringGuestId === guestId\n ) {\n return;\n }\n\n clearPendingBrowserNodeGuestUnregister(entry.context.nodeId);\n entry.registeringGuestId = guestId;\n try {\n await entry.context.feature.hostApi.registerGuest({\n navigationPolicy: entry.context.navigationPolicy,\n nodeId: entry.context.nodeId,\n profileId: entry.context.profileId,\n sessionMode: entry.context.sessionMode,\n sessionPartition: entry.context.sessionPartition,\n webContentsId: guestId\n });\n entry.registeredGuestId = guestId;\n } finally {\n if (entry.registeringGuestId === guestId) {\n entry.registeringGuestId = null;\n }\n }\n };\n\n const handleDidAttach: EventListener = () => {\n void registerGuest().catch(() => undefined);\n };\n const handleDomReady: EventListener = () => {\n void registerGuest().catch(() => undefined);\n };\n const handleGuestInteraction: EventListener = () => {\n entry.context.onGuestInteraction?.();\n };\n const handleDevToolsContextMenu: EventListener = (event) => {\n const hasNativeContextMenu =\n entry.context.feature.hostApi.showDevToolsContextMenu !== undefined;\n const hasInlineContextMenu =\n entry.context.feature.hostApi.openDevTools !== undefined;\n if (!hasNativeContextMenu && !hasInlineContextMenu) {\n return;\n }\n event.preventDefault();\n const point = resolveBrowserNodeContextMenuPoint(event, webview);\n if (hasNativeContextMenu) {\n void entry.context.feature.hostApi\n .showDevToolsContextMenu?.({\n label: entry.context.feature.i18n.t(\"actions.openDevTools\"),\n nodeId: entry.context.nodeId,\n point\n })\n .catch((error: unknown) => {\n reportBrowserNodeWebviewDiagnostic(\n entry,\n \"devtools.native-context-menu.failed\",\n {\n error: error instanceof Error ? error.message : String(error),\n webContentsId: readBrowserNodeWebContentsId(webview),\n webviewPartition: entry.state.webviewPartition\n },\n \"warn\"\n );\n });\n return;\n }\n setBrowserNodeDevToolsContextMenu(entry, point);\n };\n\n const records = [\n { event: \"did-attach\", listener: handleDidAttach },\n { event: \"dom-ready\", listener: handleDomReady },\n { event: \"context-menu\", listener: handleDevToolsContextMenu },\n { event: \"contextmenu\", listener: handleDevToolsContextMenu },\n { event: \"focus\", listener: handleGuestInteraction },\n { event: \"ipc-message\", listener: handleGuestInteraction }\n ];\n for (const record of records) {\n webview.addEventListener(record.event, record.listener);\n }\n entry.attachedListeners = records;\n}\n\nfunction resolveBrowserNodeContextMenuPoint(\n event: Event,\n webview: BrowserNodeWebviewTag\n): BrowserNodeWebviewContextMenuPoint {\n const eventWithPoint = event as Event & {\n clientX?: unknown;\n clientY?: unknown;\n params?: { x?: unknown; y?: unknown };\n };\n const clientX = readFiniteNumber(eventWithPoint.clientX);\n const clientY = readFiniteNumber(eventWithPoint.clientY);\n if (clientX !== null && clientY !== null) {\n return { x: clientX, y: clientY };\n }\n\n const paramX = readFiniteNumber(eventWithPoint.params?.x);\n const paramY = readFiniteNumber(eventWithPoint.params?.y);\n if (paramX !== null && paramY !== null) {\n return { x: paramX, y: paramY };\n }\n\n const rect = webview.getBoundingClientRect();\n return {\n x: rect.left,\n y: rect.top\n };\n}\n\nfunction readFiniteNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n\nfunction readBrowserNodeWebContentsId(\n webview: BrowserNodeWebviewTag | null\n): number | null {\n const webContentsId = webview?.getWebContentsId?.();\n return typeof webContentsId === \"number\" && Number.isFinite(webContentsId)\n ? webContentsId\n : null;\n}\n\nfunction reportBrowserNodeWebviewDiagnostic(\n entry: BrowserNodeWebviewControllerEntry,\n event: string,\n details: Record<string, unknown>,\n level: \"debug\" | \"info\" | \"warn\" | \"error\" = \"info\"\n): void {\n entry.context.feature.reportDiagnostic?.({\n details: {\n ...details,\n nodeId: entry.context.nodeId\n },\n event,\n level\n });\n}\n"],"mappings":"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","names":["useEffect","useEffect","useMemo","useExternalStoreSnapshot","useMemo","useEffect","useExternalStoreSnapshot","useEffect"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/url.ts"],"sourcesContent":["const allowedBrowserProtocols = new Set([\"http:\", \"https:\"]);\nconst likelyHostPattern =\n /^(localhost|(\\d{1,3}\\.){3}\\d{1,3}|(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,})(?::\\d{1,5})?(?:[/?#][^\\s]*)?$/i;\nconst explicitProtocolPattern = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//;\nconst loopbackHostPattern =\n /^(localhost|127(?:\\.\\d{1,3}){3})(?::\\d{1,5})?(?:[/?#][^\\s]*)?$/i;\n\nfunction defaultSchemeForHostInput(value: string): \"http\" | \"https\" {\n return loopbackHostPattern.test(value) ? \"http\" : \"https\";\n}\n\nexport type BrowserNavigationUrlErrorCode =\n | \"invalid-url\"\n | \"unsupported-protocol\";\n\nexport interface BrowserNavigationUrlResolution {\n errorCode: BrowserNavigationUrlErrorCode | null;\n errorParams?: Record<string, string>;\n url: string | null;\n}\n\nexport type BrowserSearchUrlResolver = (query: string) => string | null;\n\nexport function resolveBrowserNavigationUrl(\n rawUrl: string\n): BrowserNavigationUrlResolution {\n const trimmed = rawUrl.trim();\n if (trimmed.length === 0) {\n return { errorCode: null, url: null };\n }\n\n if (explicitProtocolPattern.test(trimmed)) {\n try {\n const parsed = new URL(trimmed);\n if (!allowedBrowserProtocols.has(parsed.protocol)) {\n return {\n errorCode: \"unsupported-protocol\",\n errorParams: { protocol: parsed.protocol },\n url: null\n };\n }\n\n return { errorCode: null, url: parsed.toString() };\n } catch {\n return { errorCode: \"invalid-url\", url: null };\n }\n }\n\n if (!likelyHostPattern.test(trimmed)) {\n return { errorCode: \"invalid-url\", url: null };\n }\n\n try {\n const parsed = new URL(\n `${defaultSchemeForHostInput(trimmed)}://${trimmed}`\n );\n return { errorCode: null, url: parsed.toString() };\n } catch {\n return { errorCode: \"invalid-url\", url: null };\n }\n}\n\nexport type BrowserAddressInputResolution = BrowserNavigationUrlResolution;\n\nexport function resolveBrowserAddressInput(\n rawInput: string,\n options: {\n resolveSearchUrl?: BrowserSearchUrlResolver;\n } = {}\n): BrowserAddressInputResolution {\n const trimmed = rawInput.trim();\n if (trimmed.length === 0) {\n return { errorCode: null, url: null };\n }\n\n const navigation = resolveBrowserNavigationUrl(trimmed);\n if (navigation.url) {\n return navigation;\n }\n\n const searchUrl = options.resolveSearchUrl?.(trimmed);\n if (!searchUrl) {\n return navigation;\n }\n\n return resolveBrowserNavigationUrl(searchUrl);\n}\n\nexport function normalizeBrowserComparableUrl(rawUrl: string): string | null {\n const resolved = resolveBrowserNavigationUrl(rawUrl);\n return resolved.errorCode === null ? resolved.url : null;\n}\n\nexport function resolveHostBrowserNavigationUrl(\n rawUrl: string\n): BrowserNavigationUrlResolution {\n const trimmed = rawUrl.trim();\n if (trimmed.length === 0) {\n return { errorCode: null, url: null };\n }\n\n if (trimmed.startsWith(\"file://\")) {\n try {\n return { errorCode: null, url: new URL(trimmed).toString() };\n } catch {\n return { errorCode: \"invalid-url\", url: null };\n }\n }\n\n return resolveBrowserNavigationUrl(trimmed);\n}\n\nexport function normalizeHostBrowserComparableUrl(\n rawUrl: string\n): string | null {\n const trimmed = rawUrl.trim();\n if (trimmed.startsWith(\"file://\")) {\n try {\n return new URL(trimmed).toString();\n } catch {\n return null;\n }\n }\n\n return normalizeBrowserComparableUrl(trimmed);\n}\n"],"mappings":";AAAA,IAAM,0BAA0B,oBAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;AAC3D,IAAM,oBACJ;AACF,IAAM,0BAA0B;AAChC,IAAM,sBACJ;AAEF,SAAS,0BAA0B,OAAiC;AAClE,SAAO,oBAAoB,KAAK,KAAK,IAAI,SAAS;AACpD;AAcO,SAAS,4BACd,QACgC;AAChC,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,WAAW,MAAM,KAAK,KAAK;AAAA,EACtC;AAEA,MAAI,wBAAwB,KAAK,OAAO,GAAG;AACzC,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,OAAO;AAC9B,UAAI,CAAC,wBAAwB,IAAI,OAAO,QAAQ,GAAG;AACjD,eAAO;AAAA,UACL,WAAW;AAAA,UACX,aAAa,EAAE,UAAU,OAAO,SAAS;AAAA,UACzC,KAAK;AAAA,QACP;AAAA,MACF;AAEA,aAAO,EAAE,WAAW,MAAM,KAAK,OAAO,SAAS,EAAE;AAAA,IACnD,QAAQ;AACN,aAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,CAAC,kBAAkB,KAAK,OAAO,GAAG;AACpC,WAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,EAC/C;AAEA,MAAI;AACF,UAAM,SAAS,IAAI;AAAA,MACjB,GAAG,0BAA0B,OAAO,CAAC,MAAM,OAAO;AAAA,IACpD;AACA,WAAO,EAAE,WAAW,MAAM,KAAK,OAAO,SAAS,EAAE;AAAA,EACnD,QAAQ;AACN,WAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,EAC/C;AACF;AAIO,SAAS,2BACd,UACA,UAEI,CAAC,GAC0B;AAC/B,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,WAAW,MAAM,KAAK,KAAK;AAAA,EACtC;AAEA,QAAM,aAAa,4BAA4B,OAAO;AACtD,MAAI,WAAW,KAAK;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,QAAQ,mBAAmB,OAAO;AACpD,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SAAO,4BAA4B,SAAS;AAC9C;AAEO,SAAS,8BAA8B,QAA+B;AAC3E,QAAM,WAAW,4BAA4B,MAAM;AACnD,SAAO,SAAS,cAAc,OAAO,SAAS,MAAM;AACtD;AAEO,SAAS,gCACd,QACgC;AAChC,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,EAAE,WAAW,MAAM,KAAK,KAAK;AAAA,EACtC;AAEA,MAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,QAAI;AACF,aAAO,EAAE,WAAW,MAAM,KAAK,IAAI,IAAI,OAAO,EAAE,SAAS,EAAE;AAAA,IAC7D,QAAQ;AACN,aAAO,EAAE,WAAW,eAAe,KAAK,KAAK;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO,4BAA4B,OAAO;AAC5C;AAEO,SAAS,kCACd,QACe;AACf,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,QAAI;AACF,aAAO,IAAI,IAAI,OAAO,EAAE,SAAS;AAAA,IACnC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,8BAA8B,OAAO;AAC9C;","names":[]}
|