@nextop-os/browser-node 0.0.14 → 0.0.15
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-VQTJWLWO.js → chunk-TLA56UW3.js} +8 -5
- package/dist/chunk-TLA56UW3.js.map +1 -0
- package/dist/electron-main/index.d.ts +13 -1
- package/dist/electron-main/index.js +60 -2
- package/dist/electron-main/index.js.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/workbench/index.js +1 -2
- package/dist/workbench/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-VQTJWLWO.js.map +0 -1
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
ArrowLeftIcon,
|
|
8
8
|
ArrowRightIcon,
|
|
9
|
+
Button,
|
|
9
10
|
LaunchIcon,
|
|
10
11
|
LoadingIcon,
|
|
11
12
|
RefreshIcon,
|
|
@@ -385,7 +386,7 @@ function BrowserNodeHeader({
|
|
|
385
386
|
"div",
|
|
386
387
|
{
|
|
387
388
|
className: cn(
|
|
388
|
-
"flex h-[var(--workbench-header-height,38px)] min-h-[var(--workbench-header-height,38px)] items-center gap-2 bg-
|
|
389
|
+
"flex h-[var(--workbench-header-height,38px)] min-h-[var(--workbench-header-height,38px)] items-center gap-2 bg-[var(--workbench-window-header-bg)] px-2 pl-3",
|
|
389
390
|
withBorder ? "border-b border-border" : null,
|
|
390
391
|
className
|
|
391
392
|
),
|
|
@@ -445,7 +446,7 @@ function BrowserNodeHeader({
|
|
|
445
446
|
/* @__PURE__ */ jsxs(
|
|
446
447
|
"form",
|
|
447
448
|
{
|
|
448
|
-
className: "nodrag flex h-8 min-h-8 min-w-0 flex-1 items-center gap-1.5 rounded-md border border-border bg-
|
|
449
|
+
className: "nodrag flex h-8 min-h-8 min-w-0 flex-1 items-center gap-1.5 rounded-md border border-border bg-[var(--workbench-field-bg)] px-2 focus-within:ring-2 focus-within:ring-ring/60",
|
|
449
450
|
onSubmit: (event) => {
|
|
450
451
|
event.preventDefault();
|
|
451
452
|
event.stopPropagation();
|
|
@@ -530,13 +531,15 @@ function BrowserNodeHeaderButton({
|
|
|
530
531
|
onClick
|
|
531
532
|
}) {
|
|
532
533
|
return /* @__PURE__ */ jsx(
|
|
533
|
-
|
|
534
|
+
Button,
|
|
534
535
|
{
|
|
535
536
|
"aria-label": label,
|
|
536
|
-
className: "
|
|
537
|
+
className: "rounded-md",
|
|
537
538
|
disabled,
|
|
539
|
+
size: "icon",
|
|
538
540
|
title: label,
|
|
539
541
|
type: "button",
|
|
542
|
+
variant: "chrome",
|
|
540
543
|
onClick,
|
|
541
544
|
children
|
|
542
545
|
}
|
|
@@ -548,4 +551,4 @@ export {
|
|
|
548
551
|
BrowserNodeWorkbenchHeader,
|
|
549
552
|
BrowserNodeHeader
|
|
550
553
|
};
|
|
551
|
-
//# sourceMappingURL=chunk-
|
|
554
|
+
//# sourceMappingURL=chunk-TLA56UW3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/BrowserNode.tsx","../src/react/useBrowserNodeWebview.ts"],"sourcesContent":["import {\n ArrowLeftIcon,\n ArrowRightIcon,\n Button,\n LaunchIcon,\n LoadingIcon,\n RefreshIcon,\n cn\n} from \"@nextop-os/ui-system\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore\n} from \"react\";\nimport type { HTMLAttributes, JSX, ReactNode } from \"react\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport { useBrowserNodeWebview } from \"./useBrowserNodeWebview.ts\";\n\nexport interface BrowserNodeProps {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n nodeId: string;\n onFocusRequest?: () => void;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n showHeader?: boolean;\n}\n\nexport function BrowserNode({\n defaultUrl,\n feature,\n nodeId,\n onFocusRequest,\n profileId = null,\n sessionMode = \"shared\",\n showHeader = true\n}: BrowserNodeProps): JSX.Element {\n const subscribeRuntimeStore = useCallback(\n (listener: () => void) => feature.runtimeStore.subscribe(listener),\n [feature.runtimeStore]\n );\n const runtime = useSyncExternalStore(\n subscribeRuntimeStore,\n () => feature.runtimeStore.getNodeState(nodeId),\n () => feature.runtimeStore.getNodeState(nodeId)\n );\n const resolvedRuntimeUrl = runtime.url?.trim() ?? \"\";\n const displayUrl =\n resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;\n const [draftUrl, setDraftUrl] = useState(displayUrl);\n const lastColdActivationUrlRef = useRef<string | null>(null);\n const errorMessage = runtime.error\n ? formatBrowserNodeErrorMessage(feature, runtime.error)\n : null;\n const {\n activate,\n shouldRenderWebview,\n webviewKey,\n webviewPartition,\n webviewRef,\n webviewSrc\n } = useBrowserNodeWebview({\n feature,\n initialUrl: defaultUrl,\n lifecycle: runtime.lifecycle,\n nodeId,\n onGuestInteraction: onFocusRequest,\n profileId,\n sessionMode\n });\n\n useEffect(() => {\n setDraftUrl(displayUrl);\n }, [displayUrl]);\n\n useEffect(() => {\n if (runtime.lifecycle !== \"cold\" || runtime.isLoading || runtime.error) {\n return;\n }\n\n const trimmed = defaultUrl.trim();\n if (trimmed.length === 0 || lastColdActivationUrlRef.current === trimmed) {\n return;\n }\n\n let cancelled = false;\n activate(trimmed)\n .then((ok) => {\n if (!cancelled && ok) {\n lastColdActivationUrlRef.current = trimmed;\n }\n })\n .catch(() => undefined);\n\n return () => {\n cancelled = true;\n };\n }, [\n activate,\n defaultUrl,\n runtime.error,\n runtime.isLoading,\n runtime.lifecycle\n ]);\n\n const submitDraftUrl = () =>\n submitBrowserNodeDraftUrl({ draftUrl, feature, nodeId, setDraftUrl });\n\n return (\n <div className=\"flex h-full min-h-0 flex-col overflow-hidden bg-background\">\n {showHeader ? (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n draftUrl={draftUrl}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n nodeId={nodeId}\n onDraftUrlChange={setDraftUrl}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={submitDraftUrl}\n />\n ) : null}\n <div className=\"relative min-h-0 flex-1 overflow-hidden bg-background\">\n {shouldRenderWebview ? (\n <webview\n key={webviewKey}\n ref={(element) => {\n webviewRef.current = element;\n }}\n className=\"absolute inset-0 h-full w-full border-0 bg-background\"\n data-browser-node-webview=\"true\"\n partition={webviewPartition}\n src={webviewSrc}\n />\n ) : null}\n {errorMessage ? (\n <div className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-end p-3 text-center\">\n <div\n className=\"max-w-[min(320px,100%)] rounded-md border border-border bg-card/95 px-3 py-2 text-sm text-card-foreground shadow-panel\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div className=\"font-medium\">{feature.i18n.t(\"loadFailed\")}</div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {errorMessage}\n </div>\n </div>\n </div>\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 subscribeRuntimeStore = useCallback(\n (listener: () => void) => feature.runtimeStore.subscribe(listener),\n [feature.runtimeStore]\n );\n const runtime = useSyncExternalStore(\n subscribeRuntimeStore,\n () => feature.runtimeStore.getNodeState(nodeId),\n () => feature.runtimeStore.getNodeState(nodeId)\n );\n const resolvedRuntimeUrl = runtime.url?.trim() ?? \"\";\n const activationUrl =\n resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;\n const [draftUrl, setDraftUrl] = useState(activationUrl);\n\n useEffect(() => {\n setDraftUrl(activationUrl);\n }, [activationUrl]);\n\n const submitDraftUrl = () =>\n submitBrowserNodeDraftUrl({\n draftUrl,\n feature,\n nodeId,\n setDraftUrl\n });\n\n return (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n className={className}\n defaultActions={defaultActions}\n draftUrl={draftUrl}\n dragHandleProps={dragHandleProps}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n nodeId={nodeId}\n onCloseRequest={onCloseRequest}\n onDraftUrlChange={setDraftUrl}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={submitDraftUrl}\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 nodeId,\n onCloseRequest,\n onDraftUrlChange,\n onFocusRequest,\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 nodeId: string;\n onCloseRequest?: () => void;\n onDraftUrlChange: (nextUrl: string) => void;\n onFocusRequest?: () => void;\n onSubmitUrl: () => void;\n withBorder?: boolean;\n}): JSX.Element {\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(--workbench-window-header-bg)] 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={() => {\n void feature.hostApi.goBack({ nodeId }).catch(() => undefined);\n }}\n >\n <ArrowLeftIcon className=\"size-4\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n disabled={!canGoForward}\n label={feature.i18n.t(\"actions.forward\")}\n onClick={() => {\n void feature.hostApi.goForward({ nodeId }).catch(() => undefined);\n }}\n >\n <ArrowRightIcon className=\"size-4\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n label={feature.i18n.t(\"actions.reload\")}\n onClick={() => {\n void feature.hostApi.reload({ nodeId }).catch(() => undefined);\n }}\n >\n <RefreshIcon className=\"size-4\" />\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 flex h-8 min-h-8 min-w-0 flex-1 items-center gap-1.5 rounded-md border border-border bg-[var(--workbench-field-bg)] px-2 focus-within:ring-2 focus-within:ring-ring/60\"\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onSubmitUrl();\n }}\n >\n <LaunchIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n <input\n aria-label={feature.i18n.t(\"addressLabel\")}\n className=\"h-full min-w-0 flex-1 border-0 bg-transparent text-[13px] leading-none text-foreground outline-none placeholder:text-muted-foreground\"\n placeholder={feature.i18n.t(\"addressPlaceholder\")}\n value={draftUrl}\n onChange={(event) => onDraftUrlChange(event.target.value)}\n onFocus={onFocusRequest}\n />\n {isLoading ? (\n <LoadingIcon className=\"size-4 shrink-0 animate-spin text-muted-foreground\" />\n ) : null}\n </form>\n {defaultActions ? (\n <div className=\"nodrag flex shrink-0 items-center gap-1.5\">\n {isCold ? (\n <span\n className=\"inline-flex h-[26px] min-w-7 items-center justify-center rounded-md bg-muted/80 px-2 text-[10px] font-semibold lowercase tracking-[0.08em] text-muted-foreground\"\n aria-label={feature.i18n.t(\"coldStatus\")}\n >\n {feature.i18n.t(\"coldStatus\")}\n </span>\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 submitBrowserNodeDraftUrl({\n draftUrl,\n feature,\n nodeId,\n setDraftUrl\n}: {\n draftUrl: string;\n feature: BrowserNodeFeature;\n nodeId: string;\n setDraftUrl: (nextUrl: string) => void;\n}) {\n const resolved = feature.resolveAddressInput(draftUrl);\n if (!resolved.url) {\n return;\n }\n\n setDraftUrl(resolved.url);\n void feature.hostApi\n .navigate({\n nodeId,\n url: resolved.url\n })\n .catch(() => undefined);\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 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 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\"\n title={label}\n type=\"button\"\n variant=\"chrome\"\n onClick={onClick}\n >\n {children}\n </Button>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\nimport { resolveBrowserSessionPartition } from \"../core/session.ts\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeLifecycle,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport type { BrowserNodeWebviewTag } from \"./webviewTag.ts\";\n\nconst browserGuestUnregisterGraceMs = 250;\nconst pendingUnregisterTimersByNodeId = new Map<\n string,\n ReturnType<typeof globalThis.setTimeout>\n>();\nconst pendingUnregisterIdsByNodeId = new Map<string, number>();\n\nfunction resolveWebviewSrc(url: string): string {\n const trimmed = url.trim();\n return trimmed.length > 0 ? trimmed : \"about:blank\";\n}\n\nexport function useBrowserNodeWebview({\n feature,\n initialUrl,\n lifecycle,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode\n}: {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n}): {\n activate: (desiredUrl: string) => Promise<boolean>;\n shouldRenderWebview: boolean;\n webviewKey: string;\n webviewPartition: string;\n webviewRef: RefObject<BrowserNodeWebviewTag | null>;\n webviewSrc: string;\n} {\n const webviewRef = useRef<BrowserNodeWebviewTag | null>(null);\n const registeredGuestIdRef = useRef<number | null>(null);\n const registeringGuestIdRef = useRef<number | null>(null);\n const [shouldRenderWebview, setShouldRenderWebview] = useState(\n lifecycle !== \"cold\"\n );\n const [webviewSrc, setWebviewSrc] = useState(() =>\n resolveWebviewSrc(initialUrl)\n );\n const webviewPartition = useMemo(\n () => resolveBrowserSessionPartition({ profileId, sessionMode }),\n [profileId, sessionMode]\n );\n const webviewKey = `${nodeId}:${webviewPartition}`;\n\n const cancelPendingUnregister = useCallback(() => {\n const timerId = pendingUnregisterTimersByNodeId.get(nodeId);\n if (timerId === undefined) {\n return;\n }\n\n globalThis.clearTimeout(timerId);\n pendingUnregisterTimersByNodeId.delete(nodeId);\n pendingUnregisterIdsByNodeId.delete(nodeId);\n }, [nodeId]);\n\n const scheduleGuestUnregister = useCallback(() => {\n const guestId = registeredGuestIdRef.current;\n registeringGuestIdRef.current = null;\n if (guestId === null) {\n cancelPendingUnregister();\n return;\n }\n\n registeredGuestIdRef.current = null;\n cancelPendingUnregister();\n pendingUnregisterIdsByNodeId.set(nodeId, guestId);\n const timerId = globalThis.setTimeout(() => {\n const pendingGuestId = pendingUnregisterIdsByNodeId.get(nodeId);\n pendingUnregisterTimersByNodeId.delete(nodeId);\n pendingUnregisterIdsByNodeId.delete(nodeId);\n if (\n typeof pendingGuestId !== \"number\" ||\n !Number.isFinite(pendingGuestId)\n ) {\n return;\n }\n\n void feature.hostApi\n .unregisterGuest({\n nodeId,\n webContentsId: pendingGuestId\n })\n .catch(() => undefined);\n }, browserGuestUnregisterGraceMs);\n pendingUnregisterTimersByNodeId.set(nodeId, timerId);\n }, [cancelPendingUnregister, feature.hostApi, nodeId]);\n\n const activate = useCallback(\n async (nextUrl: string): Promise<boolean> => {\n try {\n await feature.hostApi.activate({\n nodeId,\n profileId,\n sessionMode,\n url: nextUrl\n });\n return true;\n } catch {\n return false;\n }\n },\n [feature.hostApi, nodeId, profileId, sessionMode]\n );\n\n useEffect(() => feature.connect(), [feature]);\n\n useEffect(() => {\n if (lifecycle === \"cold\") {\n setWebviewSrc(resolveWebviewSrc(initialUrl));\n scheduleGuestUnregister();\n setShouldRenderWebview(false);\n return;\n }\n\n cancelPendingUnregister();\n setShouldRenderWebview(true);\n void feature.hostApi\n .prepareSession({\n nodeId,\n profileId,\n sessionMode\n })\n .catch(() => undefined);\n }, [\n cancelPendingUnregister,\n feature.hostApi,\n initialUrl,\n lifecycle,\n nodeId,\n profileId,\n scheduleGuestUnregister,\n sessionMode\n ]);\n\n useEffect(() => {\n const webview = webviewRef.current;\n if (!webview || !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 registeredGuestIdRef.current === guestId ||\n registeringGuestIdRef.current === guestId\n ) {\n return;\n }\n\n cancelPendingUnregister();\n registeringGuestIdRef.current = guestId;\n try {\n await feature.hostApi.registerGuest({\n nodeId,\n profileId,\n sessionMode,\n webContentsId: guestId\n });\n registeredGuestIdRef.current = guestId;\n } finally {\n if (registeringGuestIdRef.current === guestId) {\n registeringGuestIdRef.current = null;\n }\n }\n };\n\n const handleDidAttach = () => {\n void registerGuest().catch(() => undefined);\n };\n const handleDomReady = () => {\n void registerGuest().catch(() => undefined);\n };\n\n webview.addEventListener(\"did-attach\", handleDidAttach);\n webview.addEventListener(\"dom-ready\", handleDomReady);\n\n return () => {\n webview.removeEventListener(\"did-attach\", handleDidAttach);\n webview.removeEventListener(\"dom-ready\", handleDomReady);\n };\n }, [\n cancelPendingUnregister,\n feature.hostApi,\n nodeId,\n profileId,\n sessionMode,\n shouldRenderWebview,\n webviewKey\n ]);\n\n useEffect(() => {\n const webview = webviewRef.current;\n if (!webview || !shouldRenderWebview) {\n return;\n }\n\n const handleGuestInteraction = () => {\n onGuestInteraction?.();\n };\n\n webview.addEventListener(\"focus\", handleGuestInteraction);\n webview.addEventListener(\"ipc-message\", handleGuestInteraction);\n\n return () => {\n webview.removeEventListener(\"focus\", handleGuestInteraction);\n webview.removeEventListener(\"ipc-message\", handleGuestInteraction);\n };\n }, [onGuestInteraction, shouldRenderWebview, webviewKey]);\n\n useEffect(() => () => scheduleGuestUnregister(), [scheduleGuestUnregister]);\n\n return {\n activate,\n shouldRenderWebview,\n webviewKey,\n webviewPartition,\n webviewRef,\n webviewSrc\n };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useCallback","useState","useRef","useEffect"]}
|
|
@@ -18,6 +18,7 @@ interface BrowserGuestManager {
|
|
|
18
18
|
capturePreview(input: BrowserNodeNodeIdInput): Promise<string | null>;
|
|
19
19
|
close(input: BrowserNodeNodeIdInput): Promise<void>;
|
|
20
20
|
debugDump(input: BrowserNodeNodeIdInput): BrowserNodeDebugDump | null;
|
|
21
|
+
dispose(): void;
|
|
21
22
|
goBack(input: BrowserNodeNodeIdInput): Promise<void>;
|
|
22
23
|
goForward(input: BrowserNodeNodeIdInput): Promise<void>;
|
|
23
24
|
navigate(input: BrowserNodeNavigateInput): Promise<void>;
|
|
@@ -26,12 +27,15 @@ interface BrowserGuestManager {
|
|
|
26
27
|
reload(input: BrowserNodeNodeIdInput): Promise<void>;
|
|
27
28
|
unregisterGuest(input: BrowserNodeUnregisterGuestInput): Promise<void>;
|
|
28
29
|
}
|
|
30
|
+
type BrowserPreferredColorScheme = "dark" | "light";
|
|
29
31
|
interface BrowserGuestManagerInput {
|
|
30
32
|
emit: (event: BrowserNodeEvent) => void;
|
|
33
|
+
getPreferredColorScheme?: () => BrowserPreferredColorScheme;
|
|
31
34
|
logger?: BrowserNodeElectronLogger;
|
|
32
35
|
openExternal: (url: string) => Promise<void> | void;
|
|
33
36
|
previewRouteResolver?: BrowserNodePreviewRouteResolver;
|
|
34
37
|
resolveWebContents: (webContentsId: number) => BrowserGuestWebContents | null;
|
|
38
|
+
subscribePreferredColorScheme?: (listener: (scheme: BrowserPreferredColorScheme) => void) => () => void;
|
|
35
39
|
}
|
|
36
40
|
interface BrowserNodeElectronLogger {
|
|
37
41
|
debug?(message: string, metadata?: Record<string, unknown>): void;
|
|
@@ -42,6 +46,7 @@ interface BrowserGuestWebContents {
|
|
|
42
46
|
canGoBack(): boolean;
|
|
43
47
|
canGoForward(): boolean;
|
|
44
48
|
capturePage?(): Promise<BrowserGuestNativeImage>;
|
|
49
|
+
debugger?: BrowserGuestWebContentsDebugger;
|
|
45
50
|
getTitle(): string;
|
|
46
51
|
getURL(): string;
|
|
47
52
|
goBack(): void;
|
|
@@ -58,6 +63,11 @@ interface BrowserGuestWebContents {
|
|
|
58
63
|
action: "allow" | "deny";
|
|
59
64
|
}): void;
|
|
60
65
|
}
|
|
66
|
+
interface BrowserGuestWebContentsDebugger {
|
|
67
|
+
attach(protocolVersion?: string): void;
|
|
68
|
+
isAttached(): boolean;
|
|
69
|
+
sendCommand(method: string, commandParams?: Record<string, unknown>): Promise<unknown>;
|
|
70
|
+
}
|
|
61
71
|
interface BrowserGuestNativeImage {
|
|
62
72
|
getSize?(): {
|
|
63
73
|
height: number;
|
|
@@ -72,7 +82,7 @@ interface BrowserGuestNativeImage {
|
|
|
72
82
|
toDataURL(): string;
|
|
73
83
|
}
|
|
74
84
|
|
|
75
|
-
declare function createBrowserGuestManager({ emit, logger, openExternal, previewRouteResolver, resolveWebContents }: BrowserGuestManagerInput): BrowserGuestManager;
|
|
85
|
+
declare function createBrowserGuestManager({ emit, getPreferredColorScheme, logger, openExternal, previewRouteResolver, resolveWebContents, subscribePreferredColorScheme }: BrowserGuestManagerInput): BrowserGuestManager;
|
|
76
86
|
|
|
77
87
|
interface BrowserNodeElectronMainChannels {
|
|
78
88
|
readonly activate: string;
|
|
@@ -91,6 +101,7 @@ interface BrowserNodeElectronMainChannels {
|
|
|
91
101
|
interface RegisterBrowserNodeElectronMainInput {
|
|
92
102
|
readonly channels: BrowserNodeElectronMainChannels;
|
|
93
103
|
readonly getOwnerWindow: (event: unknown) => BrowserWindow | null;
|
|
104
|
+
readonly getPreferredColorScheme?: () => BrowserPreferredColorScheme;
|
|
94
105
|
readonly logger?: BrowserNodeElectronLogger;
|
|
95
106
|
readonly openExternal: (url: string) => Promise<void> | void;
|
|
96
107
|
readonly registerHandler: <TPayload, TResult>(channel: string, handler: (event: unknown, payload: TPayload) => Promise<TResult> | TResult) => void;
|
|
@@ -99,6 +110,7 @@ interface RegisterBrowserNodeElectronMainInput {
|
|
|
99
110
|
ownerWindow: BrowserWindow;
|
|
100
111
|
webContentsId: number;
|
|
101
112
|
}) => BrowserGuestWebContents | null;
|
|
113
|
+
readonly subscribePreferredColorScheme?: (listener: (scheme: BrowserPreferredColorScheme) => void) => () => void;
|
|
102
114
|
}
|
|
103
115
|
declare function registerBrowserNodeElectronMain(input: RegisterBrowserNodeElectronMainInput): void;
|
|
104
116
|
|
|
@@ -17,6 +17,7 @@ function createNoopBrowserNodePreviewRouteResolver() {
|
|
|
17
17
|
var browserPreviewMaxWidth = 260;
|
|
18
18
|
var browserPreviewMaxHeight = 170;
|
|
19
19
|
var abortedNavigationErrorCode = -3;
|
|
20
|
+
var prefersColorSchemeFeatureName = "prefers-color-scheme";
|
|
20
21
|
function resolveBrowserNodeUrlError(resolved) {
|
|
21
22
|
if (resolved.errorCode === "invalid-url") {
|
|
22
23
|
return { code: "invalid-url" };
|
|
@@ -54,15 +55,46 @@ function resizeBrowserPreviewImage(image) {
|
|
|
54
55
|
function isAbortedNavigationError(input) {
|
|
55
56
|
return input.errorCode === abortedNavigationErrorCode || input.errorDescription === "ERR_ABORTED";
|
|
56
57
|
}
|
|
58
|
+
async function applyPreferredColorSchemeToGuest(session, logger, scheme) {
|
|
59
|
+
const contents = session.contents;
|
|
60
|
+
if (!contents || contents.isDestroyed() || !contents.debugger || scheme === null || session.appliedColorScheme === scheme) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
if (!contents.debugger.isAttached()) {
|
|
65
|
+
contents.debugger.attach();
|
|
66
|
+
}
|
|
67
|
+
await contents.debugger.sendCommand("Emulation.setEmulatedMedia", {
|
|
68
|
+
features: [
|
|
69
|
+
{
|
|
70
|
+
name: prefersColorSchemeFeatureName,
|
|
71
|
+
value: scheme
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
});
|
|
75
|
+
session.appliedColorScheme = scheme;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
session.appliedColorScheme = null;
|
|
78
|
+
logger?.warn?.("Browser Node failed to sync guest color scheme", {
|
|
79
|
+
error: error instanceof Error ? error.message : String(error),
|
|
80
|
+
nodeId: session.nodeId,
|
|
81
|
+
scheme,
|
|
82
|
+
webContentsId: session.webContentsId
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
57
86
|
function createBrowserGuestManager({
|
|
58
87
|
emit,
|
|
88
|
+
getPreferredColorScheme,
|
|
59
89
|
logger,
|
|
60
90
|
openExternal,
|
|
61
91
|
previewRouteResolver = createNoopBrowserNodePreviewRouteResolver(),
|
|
62
|
-
resolveWebContents
|
|
92
|
+
resolveWebContents,
|
|
93
|
+
subscribePreferredColorScheme
|
|
63
94
|
}) {
|
|
64
95
|
const sessions = /* @__PURE__ */ new Map();
|
|
65
96
|
const nodeIdByWebContentsId = /* @__PURE__ */ new Map();
|
|
97
|
+
let preferredColorScheme = getPreferredColorScheme?.() ?? null;
|
|
66
98
|
const getSession = (nodeId, input) => {
|
|
67
99
|
const existing = sessions.get(nodeId);
|
|
68
100
|
if (existing) {
|
|
@@ -78,6 +110,7 @@ function createBrowserGuestManager({
|
|
|
78
110
|
return existing;
|
|
79
111
|
}
|
|
80
112
|
const session = {
|
|
113
|
+
appliedColorScheme: null,
|
|
81
114
|
contents: null,
|
|
82
115
|
desiredUrl: input?.url ?? "about:blank",
|
|
83
116
|
lifecycle: "cold",
|
|
@@ -115,12 +148,23 @@ function createBrowserGuestManager({
|
|
|
115
148
|
}
|
|
116
149
|
session.listeners = [];
|
|
117
150
|
session.contents = null;
|
|
151
|
+
session.appliedColorScheme = null;
|
|
118
152
|
session.webContentsId = null;
|
|
119
153
|
if (webContentsId !== null && nodeIdByWebContentsId.get(webContentsId) === session.nodeId) {
|
|
120
154
|
nodeIdByWebContentsId.delete(webContentsId);
|
|
121
155
|
}
|
|
122
156
|
publishState(session);
|
|
123
157
|
};
|
|
158
|
+
const syncPreferredColorScheme = (scheme) => {
|
|
159
|
+
preferredColorScheme = scheme;
|
|
160
|
+
for (const session of sessions.values()) {
|
|
161
|
+
session.appliedColorScheme = null;
|
|
162
|
+
void applyPreferredColorSchemeToGuest(session, logger, scheme).catch(
|
|
163
|
+
() => void 0
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const unsubscribePreferredColorScheme = subscribePreferredColorScheme?.(syncPreferredColorScheme) ?? null;
|
|
124
168
|
const attachGuestListeners = (session) => {
|
|
125
169
|
const contents = session.contents;
|
|
126
170
|
if (!contents) {
|
|
@@ -318,6 +362,11 @@ function createBrowserGuestManager({
|
|
|
318
362
|
session.lifecycle = "active";
|
|
319
363
|
contents.setWindowOpenHandler?.(({ url }) => openExternalFromGuest(url));
|
|
320
364
|
attachGuestListeners(session);
|
|
365
|
+
await applyPreferredColorSchemeToGuest(
|
|
366
|
+
session,
|
|
367
|
+
logger,
|
|
368
|
+
preferredColorScheme
|
|
369
|
+
);
|
|
321
370
|
await loadDesiredUrl(session);
|
|
322
371
|
},
|
|
323
372
|
reload(input) {
|
|
@@ -335,6 +384,9 @@ function createBrowserGuestManager({
|
|
|
335
384
|
session.lifecycle = "cold";
|
|
336
385
|
detachGuest(session);
|
|
337
386
|
return Promise.resolve();
|
|
387
|
+
},
|
|
388
|
+
dispose() {
|
|
389
|
+
unsubscribePreferredColorScheme?.();
|
|
338
390
|
}
|
|
339
391
|
};
|
|
340
392
|
}
|
|
@@ -357,13 +409,19 @@ function registerBrowserNodeElectronMain(input) {
|
|
|
357
409
|
ownerWindow.webContents.send(input.channels.event, browserEvent);
|
|
358
410
|
}
|
|
359
411
|
},
|
|
412
|
+
getPreferredColorScheme: input.getPreferredColorScheme,
|
|
360
413
|
logger: input.logger,
|
|
361
414
|
openExternal: input.openExternal,
|
|
362
415
|
resolveWebContents: (webContentsId) => input.resolveWebContents({
|
|
363
416
|
event,
|
|
364
417
|
ownerWindow,
|
|
365
418
|
webContentsId
|
|
366
|
-
})
|
|
419
|
+
}),
|
|
420
|
+
subscribePreferredColorScheme: input.subscribePreferredColorScheme
|
|
421
|
+
});
|
|
422
|
+
ownerWindow.once("closed", () => {
|
|
423
|
+
manager.dispose();
|
|
424
|
+
managersByWindow.delete(ownerWindow);
|
|
367
425
|
});
|
|
368
426
|
managersByWindow.set(ownerWindow, manager);
|
|
369
427
|
return manager;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/electron-main/previewRoute.ts","../../src/electron-main/guestManager.ts","../../src/electron-main/registerElectronMain.ts","../../src/electron-main/webviewSecurity.ts"],"sourcesContent":["export interface BrowserNodePreviewRoute {\n readonly sourceUrl: string;\n readonly targetUrl: string;\n}\n\nexport interface BrowserNodePreviewRouteResolver {\n resolveRoutes(input: {\n nodeId: string;\n url: string;\n }): BrowserNodePreviewRoute[] | Promise<BrowserNodePreviewRoute[]>;\n}\n\nexport function createNoopBrowserNodePreviewRouteResolver(): BrowserNodePreviewRouteResolver {\n return {\n resolveRoutes: () => []\n };\n}\n","import type {\n BrowserNodeLifecycle,\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport {\n normalizeBrowserComparableUrl,\n resolveBrowserNavigationUrl,\n type BrowserNavigationUrlResolution\n} from \"../core/url.ts\";\nimport { createNoopBrowserNodePreviewRouteResolver } from \"./previewRoute.ts\";\nimport type {\n BrowserGuestManager,\n BrowserGuestManagerInput,\n BrowserGuestNativeImage,\n BrowserGuestWebContents\n} from \"./types.ts\";\n\nconst browserPreviewMaxWidth = 260;\nconst browserPreviewMaxHeight = 170;\nconst abortedNavigationErrorCode = -3;\n\ninterface BrowserGuestSession {\n contents: BrowserGuestWebContents | null;\n desiredUrl: string;\n lifecycle: BrowserNodeLifecycle;\n listeners: Array<{\n event: string;\n listener: (...args: unknown[]) => void;\n }>;\n nodeId: string;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n webContentsId: number | null;\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\nexport function createBrowserGuestManager({\n emit,\n logger,\n openExternal,\n previewRouteResolver = createNoopBrowserNodePreviewRouteResolver(),\n resolveWebContents\n}: BrowserGuestManagerInput): BrowserGuestManager {\n const sessions = new Map<string, BrowserGuestSession>();\n const nodeIdByWebContentsId = new Map<number, string>();\n\n const getSession = (\n nodeId: string,\n input?: {\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\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?.url !== undefined) {\n existing.desiredUrl = input.url;\n }\n return existing;\n }\n\n const session: BrowserGuestSession = {\n contents: null,\n desiredUrl: input?.url ?? \"about:blank\",\n lifecycle: \"cold\",\n listeners: [],\n nodeId,\n profileId: input?.profileId ?? null,\n sessionMode: input?.sessionMode ?? \"shared\",\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 ? contents.canGoBack() : false,\n canGoForward: contents ? contents.canGoForward() : 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.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 attachGuestListeners = (session: BrowserGuestSession): void => {\n const contents = session.contents;\n if (!contents) {\n return;\n }\n\n const onStateChange = () => publishState(session);\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 if (isAbortedNavigationError({ errorCode, errorDescription })) {\n publishState(session);\n return;\n }\n emit({\n code: \"navigation-failed\",\n diagnosticMessage: errorDescription,\n nodeId: session.nodeId,\n params: errorCode === undefined ? undefined : { errorCode },\n type: \"error\"\n });\n publishState(session);\n };\n const onDestroyed = () => detachGuest(session);\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: onStateChange },\n { event: \"did-navigate-in-page\", listener: onStateChange },\n { event: \"page-title-updated\", listener: onStateChange },\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 = resolveBrowserNavigationUrl(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\n const routes = await previewRouteResolver.resolveRoutes({\n nodeId: session.nodeId,\n url: resolved.url\n });\n const routedUrl =\n routes.find((route) => route.sourceUrl === resolved.url)?.targetUrl ??\n resolved.url;\n const currentComparable = normalizeBrowserComparableUrl(contents.getURL());\n const nextComparable = normalizeBrowserComparableUrl(routedUrl);\n if (currentComparable && currentComparable === nextComparable) {\n publishState(session);\n return;\n }\n\n await contents.loadURL(routedUrl);\n publishState(session);\n };\n\n const openExternalFromGuest = (url: string): { action: \"deny\" } => {\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n void Promise.resolve(openExternal(resolved.url)).catch(\n (error: unknown) => {\n logger?.warn?.(\"Browser Node openExternal failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n );\n }\n return { action: \"deny\" };\n };\n\n return {\n async activate(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 profileId: input.profileId,\n sessionMode: input.sessionMode,\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 ? contents.canGoBack() : false,\n canGoForward: contents ? contents.canGoForward() : 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 title: contents ? contents.getTitle() : 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() && contents.canGoBack()) {\n contents.goBack();\n }\n return Promise.resolve();\n },\n goForward(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed() && contents.canGoForward()) {\n contents.goForward();\n }\n return Promise.resolve();\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, { url: resolved.url });\n session.lifecycle = \"active\";\n await loadDesiredUrl(session);\n },\n prepareSession(input) {\n getSession(input.nodeId, {\n profileId: input.profileId,\n sessionMode: input.sessionMode\n });\n return Promise.resolve();\n },\n async registerGuest(input) {\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 profileId: input.profileId,\n sessionMode: input.sessionMode\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 contents.setWindowOpenHandler?.(({ url }) => openExternalFromGuest(url));\n attachGuestListeners(session);\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 };\n}\n","import type { BrowserWindow } from \"electron\";\nimport type {\n BrowserNodeActivationInput,\n BrowserNodeNavigateInput,\n BrowserNodeNodeIdInput,\n BrowserNodePrepareSessionInput,\n BrowserNodeRegisterGuestInput,\n BrowserNodeUnregisterGuestInput\n} from \"../core/types.ts\";\nimport { createBrowserGuestManager } from \"./guestManager.ts\";\nimport type {\n BrowserGuestManager,\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 navigate: string;\n readonly prepareSession: string;\n readonly registerGuest: string;\n readonly reload: string;\n readonly unregisterGuest: string;\n}\n\nexport interface RegisterBrowserNodeElectronMainInput {\n readonly channels: BrowserNodeElectronMainChannels;\n readonly getOwnerWindow: (event: unknown) => BrowserWindow | null;\n readonly logger?: BrowserNodeElectronLogger;\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 resolveWebContents: (input: {\n event: unknown;\n ownerWindow: BrowserWindow;\n webContentsId: number;\n }) => BrowserGuestWebContents | null;\n}\n\nexport function registerBrowserNodeElectronMain(\n input: RegisterBrowserNodeElectronMainInput\n): void {\n const managersByWindow = new WeakMap<BrowserWindow, BrowserGuestManager>();\n const resolveManager = (event: unknown): BrowserGuestManager => {\n const ownerWindow = input.getOwnerWindow(event);\n if (!ownerWindow) {\n throw new Error(\"Browser Node IPC requires an owner window\");\n }\n\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 logger: input.logger,\n openExternal: input.openExternal,\n resolveWebContents: (webContentsId) =>\n input.resolveWebContents({\n event,\n ownerWindow,\n webContentsId\n })\n });\n managersByWindow.set(ownerWindow, manager);\n return manager;\n };\n\n input.registerHandler(input.channels.prepareSession, (event, payload) =>\n resolveManager(event).prepareSession(\n payload as BrowserNodePrepareSessionInput\n )\n );\n input.registerHandler(input.channels.activate, (event, payload) =>\n resolveManager(event).activate(payload as BrowserNodeActivationInput)\n );\n if (input.channels.capturePreview) {\n input.registerHandler(input.channels.capturePreview, (event, payload) =>\n resolveManager(event).capturePreview(payload as BrowserNodeNodeIdInput)\n );\n }\n input.registerHandler(input.channels.registerGuest, (event, payload) =>\n resolveManager(event).registerGuest(\n payload as BrowserNodeRegisterGuestInput\n )\n );\n input.registerHandler(input.channels.unregisterGuest, (event, payload) =>\n resolveManager(event).unregisterGuest(\n payload as BrowserNodeUnregisterGuestInput\n )\n );\n input.registerHandler(input.channels.navigate, (event, payload) =>\n resolveManager(event).navigate(payload as BrowserNodeNavigateInput)\n );\n input.registerHandler(input.channels.goBack, (event, payload) =>\n resolveManager(event).goBack(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.goForward, (event, payload) =>\n resolveManager(event).goForward(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.reload, (event, payload) =>\n resolveManager(event).reload(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.close, (event, payload) =>\n resolveManager(event).close(payload as BrowserNodeNodeIdInput)\n );\n if (input.channels.debugDump) {\n input.registerHandler(input.channels.debugDump, (event, payload) =>\n resolveManager(event).debugDump(payload as BrowserNodeNodeIdInput)\n );\n }\n}\n","import type { Event, WebContents, WebPreferences } from \"electron\";\nimport { isBrowserSessionPartitionAllowed } from \"../core/session.ts\";\nimport { resolveBrowserNavigationUrl } from \"../core/url.ts\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nexport interface BrowserWebviewSecurityInput {\n params: Record<string, string>;\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\nexport function isBrowserNodeWebviewAttach(\n params: Record<string, string>\n): boolean {\n return (\n params[\"data-browser-node-webview\"] === \"true\" ||\n isBrowserSessionPartitionAllowed(params.partition)\n );\n}\n\nexport function enforceBrowserWebviewSecurity({\n params,\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 (!partition || !isBrowserSessionPartitionAllowed(partition)) {\n return {\n allowed: false,\n reason: \"Unsupported Browser Node session partition\"\n };\n }\n\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 return { allowed: true, reason: null };\n}\n\nexport interface InstallBrowserWebviewSecurityInput {\n contents: WebContents;\n logger?: BrowserNodeElectronLogger;\n onGuestAttached?: (guestContents: WebContents) => void;\n openExternal: (url: string) => Promise<void> | void;\n shouldHandleWebview?: BrowserNodeWebviewMatcher;\n}\n\nexport function installBrowserWebviewSecurity({\n contents,\n logger,\n onGuestAttached,\n openExternal,\n shouldHandleWebview = isBrowserNodeWebviewAttach\n}: InstallBrowserWebviewSecurityInput): () => void {\n let pendingBrowserAttachCount = 0;\n\n const handleWillAttachWebview = (\n event: Event,\n webPreferences: WebPreferences,\n params: Record<string, string>\n ) => {\n if (!shouldHandleWebview(params)) {\n return;\n }\n\n pendingBrowserAttachCount += 1;\n const result = enforceBrowserWebviewSecurity({ params, webPreferences });\n if (!result.allowed) {\n pendingBrowserAttachCount = Math.max(0, pendingBrowserAttachCount - 1);\n logger?.warn?.(\"Browser Node webview blocked\", { reason: result.reason });\n event.preventDefault();\n }\n };\n\n const handleDidAttachWebview = (\n _event: Event,\n guestContents: WebContents\n ) => {\n if (pendingBrowserAttachCount <= 0) {\n return;\n }\n pendingBrowserAttachCount -= 1;\n\n onGuestAttached?.(guestContents);\n guestContents.setWindowOpenHandler(({ url }) => {\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n void Promise.resolve(openExternal(resolved.url)).catch(() => undefined);\n }\n return { action: \"deny\" };\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/previewRoute.ts","../../src/electron-main/guestManager.ts","../../src/electron-main/registerElectronMain.ts","../../src/electron-main/webviewSecurity.ts"],"sourcesContent":["export interface BrowserNodePreviewRoute {\n readonly sourceUrl: string;\n readonly targetUrl: string;\n}\n\nexport interface BrowserNodePreviewRouteResolver {\n resolveRoutes(input: {\n nodeId: string;\n url: string;\n }): BrowserNodePreviewRoute[] | Promise<BrowserNodePreviewRoute[]>;\n}\n\nexport function createNoopBrowserNodePreviewRouteResolver(): BrowserNodePreviewRouteResolver {\n return {\n resolveRoutes: () => []\n };\n}\n","import type {\n BrowserNodeLifecycle,\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport {\n normalizeBrowserComparableUrl,\n resolveBrowserNavigationUrl,\n type BrowserNavigationUrlResolution\n} from \"../core/url.ts\";\nimport { createNoopBrowserNodePreviewRouteResolver } from \"./previewRoute.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;\nconst prefersColorSchemeFeatureName = \"prefers-color-scheme\";\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 nodeId: string;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n webContentsId: number | null;\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\nasync function applyPreferredColorSchemeToGuest(\n session: BrowserGuestSession,\n logger: BrowserGuestManagerInput[\"logger\"],\n scheme: BrowserPreferredColorScheme | null\n): Promise<void> {\n const contents = session.contents;\n if (\n !contents ||\n contents.isDestroyed() ||\n !contents.debugger ||\n scheme === null ||\n session.appliedColorScheme === scheme\n ) {\n return;\n }\n\n try {\n if (!contents.debugger.isAttached()) {\n contents.debugger.attach();\n }\n await contents.debugger.sendCommand(\"Emulation.setEmulatedMedia\", {\n features: [\n {\n name: prefersColorSchemeFeatureName,\n value: scheme\n }\n ]\n });\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 previewRouteResolver = createNoopBrowserNodePreviewRouteResolver(),\n resolveWebContents,\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 profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\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?.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 nodeId,\n profileId: input?.profileId ?? null,\n sessionMode: input?.sessionMode ?? \"shared\",\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 ? contents.canGoBack() : false,\n canGoForward: contents ? contents.canGoForward() : 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 syncPreferredColorScheme = (scheme: BrowserPreferredColorScheme) => {\n preferredColorScheme = scheme;\n for (const session of sessions.values()) {\n session.appliedColorScheme = null;\n void applyPreferredColorSchemeToGuest(session, logger, scheme).catch(\n () => undefined\n );\n }\n };\n\n const unsubscribePreferredColorScheme =\n subscribePreferredColorScheme?.(syncPreferredColorScheme) ?? 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 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 if (isAbortedNavigationError({ errorCode, errorDescription })) {\n publishState(session);\n return;\n }\n emit({\n code: \"navigation-failed\",\n diagnosticMessage: errorDescription,\n nodeId: session.nodeId,\n params: errorCode === undefined ? undefined : { errorCode },\n type: \"error\"\n });\n publishState(session);\n };\n const onDestroyed = () => detachGuest(session);\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: onStateChange },\n { event: \"did-navigate-in-page\", listener: onStateChange },\n { event: \"page-title-updated\", listener: onStateChange },\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 = resolveBrowserNavigationUrl(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\n const routes = await previewRouteResolver.resolveRoutes({\n nodeId: session.nodeId,\n url: resolved.url\n });\n const routedUrl =\n routes.find((route) => route.sourceUrl === resolved.url)?.targetUrl ??\n resolved.url;\n const currentComparable = normalizeBrowserComparableUrl(contents.getURL());\n const nextComparable = normalizeBrowserComparableUrl(routedUrl);\n if (currentComparable && currentComparable === nextComparable) {\n publishState(session);\n return;\n }\n\n await contents.loadURL(routedUrl);\n publishState(session);\n };\n\n const openExternalFromGuest = (url: string): { action: \"deny\" } => {\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n void Promise.resolve(openExternal(resolved.url)).catch(\n (error: unknown) => {\n logger?.warn?.(\"Browser Node openExternal failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n );\n }\n return { action: \"deny\" };\n };\n\n return {\n async activate(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 profileId: input.profileId,\n sessionMode: input.sessionMode,\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 ? contents.canGoBack() : false,\n canGoForward: contents ? contents.canGoForward() : 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 title: contents ? contents.getTitle() : 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() && contents.canGoBack()) {\n contents.goBack();\n }\n return Promise.resolve();\n },\n goForward(input) {\n const contents = sessions.get(input.nodeId)?.contents;\n if (contents && !contents.isDestroyed() && contents.canGoForward()) {\n contents.goForward();\n }\n return Promise.resolve();\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, { url: resolved.url });\n session.lifecycle = \"active\";\n await loadDesiredUrl(session);\n },\n prepareSession(input) {\n getSession(input.nodeId, {\n profileId: input.profileId,\n sessionMode: input.sessionMode\n });\n return Promise.resolve();\n },\n async registerGuest(input) {\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 profileId: input.profileId,\n sessionMode: input.sessionMode\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 contents.setWindowOpenHandler?.(({ url }) => openExternalFromGuest(url));\n attachGuestListeners(session);\n await applyPreferredColorSchemeToGuest(\n session,\n logger,\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 type {\n BrowserNodeActivationInput,\n BrowserNodeNavigateInput,\n BrowserNodeNodeIdInput,\n BrowserNodePrepareSessionInput,\n BrowserNodeRegisterGuestInput,\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 navigate: string;\n readonly prepareSession: string;\n readonly registerGuest: string;\n readonly reload: string;\n readonly unregisterGuest: string;\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 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 resolveWebContents: (input: {\n event: unknown;\n ownerWindow: BrowserWindow;\n webContentsId: number;\n }) => BrowserGuestWebContents | null;\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 resolveManager = (event: unknown): BrowserGuestManager => {\n const ownerWindow = input.getOwnerWindow(event);\n if (!ownerWindow) {\n throw new Error(\"Browser Node IPC requires an owner window\");\n }\n\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 resolveWebContents: (webContentsId) =>\n input.resolveWebContents({\n event,\n ownerWindow,\n webContentsId\n }),\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 input.registerHandler(input.channels.prepareSession, (event, payload) =>\n resolveManager(event).prepareSession(\n payload as BrowserNodePrepareSessionInput\n )\n );\n input.registerHandler(input.channels.activate, (event, payload) =>\n resolveManager(event).activate(payload as BrowserNodeActivationInput)\n );\n if (input.channels.capturePreview) {\n input.registerHandler(input.channels.capturePreview, (event, payload) =>\n resolveManager(event).capturePreview(payload as BrowserNodeNodeIdInput)\n );\n }\n input.registerHandler(input.channels.registerGuest, (event, payload) =>\n resolveManager(event).registerGuest(\n payload as BrowserNodeRegisterGuestInput\n )\n );\n input.registerHandler(input.channels.unregisterGuest, (event, payload) =>\n resolveManager(event).unregisterGuest(\n payload as BrowserNodeUnregisterGuestInput\n )\n );\n input.registerHandler(input.channels.navigate, (event, payload) =>\n resolveManager(event).navigate(payload as BrowserNodeNavigateInput)\n );\n input.registerHandler(input.channels.goBack, (event, payload) =>\n resolveManager(event).goBack(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.goForward, (event, payload) =>\n resolveManager(event).goForward(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.reload, (event, payload) =>\n resolveManager(event).reload(payload as BrowserNodeNodeIdInput)\n );\n input.registerHandler(input.channels.close, (event, payload) =>\n resolveManager(event).close(payload as BrowserNodeNodeIdInput)\n );\n if (input.channels.debugDump) {\n input.registerHandler(input.channels.debugDump, (event, payload) =>\n resolveManager(event).debugDump(payload as BrowserNodeNodeIdInput)\n );\n }\n}\n","import type { Event, WebContents, WebPreferences } from \"electron\";\nimport { isBrowserSessionPartitionAllowed } from \"../core/session.ts\";\nimport { resolveBrowserNavigationUrl } from \"../core/url.ts\";\nimport type { BrowserNodeElectronLogger } from \"./types.ts\";\n\nexport interface BrowserWebviewSecurityInput {\n params: Record<string, string>;\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\nexport function isBrowserNodeWebviewAttach(\n params: Record<string, string>\n): boolean {\n return (\n params[\"data-browser-node-webview\"] === \"true\" ||\n isBrowserSessionPartitionAllowed(params.partition)\n );\n}\n\nexport function enforceBrowserWebviewSecurity({\n params,\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 (!partition || !isBrowserSessionPartitionAllowed(partition)) {\n return {\n allowed: false,\n reason: \"Unsupported Browser Node session partition\"\n };\n }\n\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 return { allowed: true, reason: null };\n}\n\nexport interface InstallBrowserWebviewSecurityInput {\n contents: WebContents;\n logger?: BrowserNodeElectronLogger;\n onGuestAttached?: (guestContents: WebContents) => void;\n openExternal: (url: string) => Promise<void> | void;\n shouldHandleWebview?: BrowserNodeWebviewMatcher;\n}\n\nexport function installBrowserWebviewSecurity({\n contents,\n logger,\n onGuestAttached,\n openExternal,\n shouldHandleWebview = isBrowserNodeWebviewAttach\n}: InstallBrowserWebviewSecurityInput): () => void {\n let pendingBrowserAttachCount = 0;\n\n const handleWillAttachWebview = (\n event: Event,\n webPreferences: WebPreferences,\n params: Record<string, string>\n ) => {\n if (!shouldHandleWebview(params)) {\n return;\n }\n\n pendingBrowserAttachCount += 1;\n const result = enforceBrowserWebviewSecurity({ params, webPreferences });\n if (!result.allowed) {\n pendingBrowserAttachCount = Math.max(0, pendingBrowserAttachCount - 1);\n logger?.warn?.(\"Browser Node webview blocked\", { reason: result.reason });\n event.preventDefault();\n }\n };\n\n const handleDidAttachWebview = (\n _event: Event,\n guestContents: WebContents\n ) => {\n if (pendingBrowserAttachCount <= 0) {\n return;\n }\n pendingBrowserAttachCount -= 1;\n\n onGuestAttached?.(guestContents);\n guestContents.setWindowOpenHandler(({ url }) => {\n const resolved = resolveBrowserNavigationUrl(url);\n if (resolved.url) {\n void Promise.resolve(openExternal(resolved.url)).catch(() => undefined);\n }\n return { action: \"deny\" };\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":[]}
|
package/dist/react/index.js
CHANGED
package/dist/workbench/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserNode,
|
|
3
3
|
BrowserNodeWorkbenchHeader
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-TLA56UW3.js";
|
|
5
5
|
import "../chunk-OTK5YBCK.js";
|
|
6
6
|
|
|
7
7
|
// src/workbench/index.ts
|
|
@@ -48,7 +48,6 @@ function createBrowserNodeDefinition({
|
|
|
48
48
|
node,
|
|
49
49
|
windowActions
|
|
50
50
|
}) => createElement(BrowserNodeWorkbenchHeader, {
|
|
51
|
-
className: "bg-transparent",
|
|
52
51
|
defaultActions,
|
|
53
52
|
defaultUrl: resolveBrowserNodeInitialUrl({
|
|
54
53
|
activation,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/workbench/index.ts"],"sourcesContent":["import { createElement, type ReactNode } from \"react\";\nimport type {\n WorkbenchHostActivation,\n WorkbenchHostDockEntry,\n WorkbenchFrame,\n WorkbenchHostNodeDefinition\n} from \"@nextop-os/workbench-surface\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport {\n BrowserNode,\n BrowserNodeWorkbenchHeader\n} from \"../react/BrowserNode.tsx\";\n\nexport interface BrowserNodeOpenUrlActivationPayload {\n title?: string;\n url: string;\n}\n\nexport interface BrowserNodeExternalState {\n title?: string | null;\n url?: string | null;\n}\n\nexport interface CreateBrowserNodeDefinitionInput {\n defaultUrl: string;\n dockIcon?: ReactNode;\n feature: BrowserNodeFeature;\n frame?: WorkbenchFrame;\n typeId?: string;\n}\n\nconst defaultBrowserNodeFrame: WorkbenchFrame = {\n height: 560,\n width: 920,\n x: 220,\n y: 120\n};\n\nexport const defaultBrowserNodeTypeId = \"browser\";\nconst defaultBrowserNodeDockIconUrl = new URL(\n \"../assets/workspace-dock-website.png\",\n import.meta.url\n).href;\n\nexport function createBrowserNodeDefinition({\n defaultUrl,\n feature,\n frame = defaultBrowserNodeFrame,\n typeId = defaultBrowserNodeTypeId\n}: CreateBrowserNodeDefinitionInput): WorkbenchHostNodeDefinition<BrowserNodeExternalState> {\n return {\n frame,\n instance: {\n mode: \"multi\"\n },\n renderBody: (context) =>\n createElement(BrowserNode, {\n defaultUrl: resolveBrowserNodeInitialUrl({\n activation: context.activation,\n defaultUrl,\n externalNodeState: context.externalNodeState\n }),\n feature,\n nodeId: context.node.id,\n onFocusRequest: context.isFocused ? undefined : () => context.focus(),\n showHeader: false\n }),\n renderHeader: ({\n defaultActions,\n activation,\n dragHandleProps,\n externalNodeState,\n isFocused,\n node,\n windowActions\n }) =>\n createElement(BrowserNodeWorkbenchHeader, {\n
|
|
1
|
+
{"version":3,"sources":["../../src/workbench/index.ts"],"sourcesContent":["import { createElement, type ReactNode } from \"react\";\nimport type {\n WorkbenchHostActivation,\n WorkbenchHostDockEntry,\n WorkbenchFrame,\n WorkbenchHostNodeDefinition\n} from \"@nextop-os/workbench-surface\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport {\n BrowserNode,\n BrowserNodeWorkbenchHeader\n} from \"../react/BrowserNode.tsx\";\n\nexport interface BrowserNodeOpenUrlActivationPayload {\n title?: string;\n url: string;\n}\n\nexport interface BrowserNodeExternalState {\n title?: string | null;\n url?: string | null;\n}\n\nexport interface CreateBrowserNodeDefinitionInput {\n defaultUrl: string;\n dockIcon?: ReactNode;\n feature: BrowserNodeFeature;\n frame?: WorkbenchFrame;\n typeId?: string;\n}\n\nconst defaultBrowserNodeFrame: WorkbenchFrame = {\n height: 560,\n width: 920,\n x: 220,\n y: 120\n};\n\nexport const defaultBrowserNodeTypeId = \"browser\";\nconst defaultBrowserNodeDockIconUrl = new URL(\n \"../assets/workspace-dock-website.png\",\n import.meta.url\n).href;\n\nexport function createBrowserNodeDefinition({\n defaultUrl,\n feature,\n frame = defaultBrowserNodeFrame,\n typeId = defaultBrowserNodeTypeId\n}: CreateBrowserNodeDefinitionInput): WorkbenchHostNodeDefinition<BrowserNodeExternalState> {\n return {\n frame,\n instance: {\n mode: \"multi\"\n },\n renderBody: (context) =>\n createElement(BrowserNode, {\n defaultUrl: resolveBrowserNodeInitialUrl({\n activation: context.activation,\n defaultUrl,\n externalNodeState: context.externalNodeState\n }),\n feature,\n nodeId: context.node.id,\n onFocusRequest: context.isFocused ? undefined : () => context.focus(),\n showHeader: false\n }),\n renderHeader: ({\n defaultActions,\n activation,\n dragHandleProps,\n externalNodeState,\n isFocused,\n node,\n windowActions\n }) =>\n createElement(BrowserNodeWorkbenchHeader, {\n defaultActions,\n defaultUrl: resolveBrowserNodeInitialUrl({\n activation,\n defaultUrl,\n externalNodeState\n }),\n dragHandleProps,\n feature,\n nodeId: node.id,\n onCloseRequest: () => {\n void feature.hostApi\n .close({ nodeId: node.id })\n .catch(() => undefined);\n },\n onFocusRequest: isFocused ? undefined : () => windowActions.focus()\n }),\n title: feature.i18n.t(\"title\"),\n typeId,\n window: {\n closable: true,\n defaultOpen: false,\n minimizable: true,\n restoreOnLoad: true\n }\n };\n}\n\nexport function createBrowserDockEntry(input: {\n dockIcon?: ReactNode;\n feature: BrowserNodeFeature;\n id?: string;\n order?: number;\n sectionId?: string;\n typeId?: string;\n}): WorkbenchHostDockEntry {\n return {\n capturePopupItemPreview: ({ node }) =>\n input.feature.hostApi.capturePreview?.({ nodeId: node.id }) ?? null,\n icon: input.dockIcon ?? createElement(BrowserNodeDockIcon),\n id: input.id ?? defaultBrowserNodeTypeId,\n label: input.feature.i18n.t(\"dockLabel\"),\n launchBehavior: \"enabled\",\n matchNode: (node) =>\n node.data.typeId === (input.typeId ?? defaultBrowserNodeTypeId),\n order: input.order,\n resolvePopupItem: ({ node }) => {\n const runtime = input.feature.runtimeStore.getNodeState(node.id);\n return {\n subtitle: runtime.url?.trim() || node.data.instanceId,\n title: runtime.title?.trim() || node.title\n };\n },\n sectionId: input.sectionId,\n typeId: input.typeId ?? defaultBrowserNodeTypeId,\n visibility: \"always\"\n };\n}\n\nfunction resolveBrowserNodeInitialUrl({\n activation,\n defaultUrl,\n externalNodeState\n}: {\n activation: WorkbenchHostActivation | null;\n defaultUrl: string;\n externalNodeState?: BrowserNodeExternalState | null;\n}): string {\n return (\n readBrowserOpenUrlActivationPayload(activation)?.url ??\n normalizeBrowserNodeInitialUrl(externalNodeState?.url) ??\n defaultUrl\n );\n}\n\nfunction normalizeBrowserNodeInitialUrl(\n value: string | null | undefined\n): string | null {\n const trimmed = value?.trim() ?? \"\";\n return trimmed.length > 0 ? trimmed : null;\n}\n\nfunction BrowserNodeDockIcon() {\n return createElement(\"img\", {\n alt: \"\",\n \"aria-hidden\": \"true\",\n \"data-browser-node-dock-icon\": \"true\",\n draggable: false,\n src: defaultBrowserNodeDockIconUrl\n });\n}\n\nfunction readBrowserOpenUrlActivationPayload(\n activation: WorkbenchHostActivation | null\n): BrowserNodeOpenUrlActivationPayload | null {\n if (\n activation?.type !== \"open-url\" ||\n !activation.payload ||\n typeof activation.payload !== \"object\"\n ) {\n return null;\n }\n\n const typed =\n activation.payload as Partial<BrowserNodeOpenUrlActivationPayload>;\n return typeof typed.url === \"string\"\n ? {\n title: typeof typed.title === \"string\" ? typed.title : undefined,\n url: typed.url\n }\n : null;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextop-os/browser-node",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"directory": "packages/browser/workbench-node"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@nextop-os/ui-i18n-runtime": "0.0.
|
|
48
|
-
"@nextop-os/ui-system": "0.0.
|
|
49
|
-
"@nextop-os/workbench-surface": "0.0.
|
|
47
|
+
"@nextop-os/ui-i18n-runtime": "0.0.15",
|
|
48
|
+
"@nextop-os/ui-system": "0.0.15",
|
|
49
|
+
"@nextop-os/workbench-surface": "0.0.15"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/node": "^24.0.1",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/BrowserNode.tsx","../src/react/useBrowserNodeWebview.ts"],"sourcesContent":["import {\n ArrowLeftIcon,\n ArrowRightIcon,\n LaunchIcon,\n LoadingIcon,\n RefreshIcon,\n cn\n} from \"@nextop-os/ui-system\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore\n} from \"react\";\nimport type { HTMLAttributes, JSX, ReactNode } from \"react\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeRuntimeError,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport { useBrowserNodeWebview } from \"./useBrowserNodeWebview.ts\";\n\nexport interface BrowserNodeProps {\n defaultUrl: string;\n feature: BrowserNodeFeature;\n nodeId: string;\n onFocusRequest?: () => void;\n profileId?: string | null;\n sessionMode?: BrowserNodeSessionMode;\n showHeader?: boolean;\n}\n\nexport function BrowserNode({\n defaultUrl,\n feature,\n nodeId,\n onFocusRequest,\n profileId = null,\n sessionMode = \"shared\",\n showHeader = true\n}: BrowserNodeProps): JSX.Element {\n const subscribeRuntimeStore = useCallback(\n (listener: () => void) => feature.runtimeStore.subscribe(listener),\n [feature.runtimeStore]\n );\n const runtime = useSyncExternalStore(\n subscribeRuntimeStore,\n () => feature.runtimeStore.getNodeState(nodeId),\n () => feature.runtimeStore.getNodeState(nodeId)\n );\n const resolvedRuntimeUrl = runtime.url?.trim() ?? \"\";\n const displayUrl =\n resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;\n const [draftUrl, setDraftUrl] = useState(displayUrl);\n const lastColdActivationUrlRef = useRef<string | null>(null);\n const errorMessage = runtime.error\n ? formatBrowserNodeErrorMessage(feature, runtime.error)\n : null;\n const {\n activate,\n shouldRenderWebview,\n webviewKey,\n webviewPartition,\n webviewRef,\n webviewSrc\n } = useBrowserNodeWebview({\n feature,\n initialUrl: defaultUrl,\n lifecycle: runtime.lifecycle,\n nodeId,\n onGuestInteraction: onFocusRequest,\n profileId,\n sessionMode\n });\n\n useEffect(() => {\n setDraftUrl(displayUrl);\n }, [displayUrl]);\n\n useEffect(() => {\n if (runtime.lifecycle !== \"cold\" || runtime.isLoading || runtime.error) {\n return;\n }\n\n const trimmed = defaultUrl.trim();\n if (trimmed.length === 0 || lastColdActivationUrlRef.current === trimmed) {\n return;\n }\n\n let cancelled = false;\n activate(trimmed)\n .then((ok) => {\n if (!cancelled && ok) {\n lastColdActivationUrlRef.current = trimmed;\n }\n })\n .catch(() => undefined);\n\n return () => {\n cancelled = true;\n };\n }, [\n activate,\n defaultUrl,\n runtime.error,\n runtime.isLoading,\n runtime.lifecycle\n ]);\n\n const submitDraftUrl = () =>\n submitBrowserNodeDraftUrl({ draftUrl, feature, nodeId, setDraftUrl });\n\n return (\n <div className=\"flex h-full min-h-0 flex-col overflow-hidden bg-background\">\n {showHeader ? (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n draftUrl={draftUrl}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n nodeId={nodeId}\n onDraftUrlChange={setDraftUrl}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={submitDraftUrl}\n />\n ) : null}\n <div className=\"relative min-h-0 flex-1 overflow-hidden bg-background\">\n {shouldRenderWebview ? (\n <webview\n key={webviewKey}\n ref={(element) => {\n webviewRef.current = element;\n }}\n className=\"absolute inset-0 h-full w-full border-0 bg-background\"\n data-browser-node-webview=\"true\"\n partition={webviewPartition}\n src={webviewSrc}\n />\n ) : null}\n {errorMessage ? (\n <div className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-end p-3 text-center\">\n <div\n className=\"max-w-[min(320px,100%)] rounded-md border border-border bg-card/95 px-3 py-2 text-sm text-card-foreground shadow-panel\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div className=\"font-medium\">{feature.i18n.t(\"loadFailed\")}</div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {errorMessage}\n </div>\n </div>\n </div>\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 subscribeRuntimeStore = useCallback(\n (listener: () => void) => feature.runtimeStore.subscribe(listener),\n [feature.runtimeStore]\n );\n const runtime = useSyncExternalStore(\n subscribeRuntimeStore,\n () => feature.runtimeStore.getNodeState(nodeId),\n () => feature.runtimeStore.getNodeState(nodeId)\n );\n const resolvedRuntimeUrl = runtime.url?.trim() ?? \"\";\n const activationUrl =\n resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;\n const [draftUrl, setDraftUrl] = useState(activationUrl);\n\n useEffect(() => {\n setDraftUrl(activationUrl);\n }, [activationUrl]);\n\n const submitDraftUrl = () =>\n submitBrowserNodeDraftUrl({\n draftUrl,\n feature,\n nodeId,\n setDraftUrl\n });\n\n return (\n <BrowserNodeHeader\n canGoBack={runtime.canGoBack}\n canGoForward={runtime.canGoForward}\n className={className}\n defaultActions={defaultActions}\n draftUrl={draftUrl}\n dragHandleProps={dragHandleProps}\n feature={feature}\n isCold={runtime.lifecycle === \"cold\"}\n isLoading={runtime.isLoading}\n nodeId={nodeId}\n onCloseRequest={onCloseRequest}\n onDraftUrlChange={setDraftUrl}\n onFocusRequest={onFocusRequest}\n onSubmitUrl={submitDraftUrl}\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 nodeId,\n onCloseRequest,\n onDraftUrlChange,\n onFocusRequest,\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 nodeId: string;\n onCloseRequest?: () => void;\n onDraftUrlChange: (nextUrl: string) => void;\n onFocusRequest?: () => void;\n onSubmitUrl: () => void;\n withBorder?: boolean;\n}): JSX.Element {\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-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={() => {\n void feature.hostApi.goBack({ nodeId }).catch(() => undefined);\n }}\n >\n <ArrowLeftIcon className=\"size-4\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n disabled={!canGoForward}\n label={feature.i18n.t(\"actions.forward\")}\n onClick={() => {\n void feature.hostApi.goForward({ nodeId }).catch(() => undefined);\n }}\n >\n <ArrowRightIcon className=\"size-4\" />\n </BrowserNodeHeaderButton>\n <BrowserNodeHeaderButton\n label={feature.i18n.t(\"actions.reload\")}\n onClick={() => {\n void feature.hostApi.reload({ nodeId }).catch(() => undefined);\n }}\n >\n <RefreshIcon className=\"size-4\" />\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 flex h-8 min-h-8 min-w-0 flex-1 items-center gap-1.5 rounded-md border border-border bg-background/80 px-2 focus-within:ring-2 focus-within:ring-ring/60\"\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onSubmitUrl();\n }}\n >\n <LaunchIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n <input\n aria-label={feature.i18n.t(\"addressLabel\")}\n className=\"h-full min-w-0 flex-1 border-0 bg-transparent text-[13px] leading-none text-foreground outline-none placeholder:text-muted-foreground\"\n placeholder={feature.i18n.t(\"addressPlaceholder\")}\n value={draftUrl}\n onChange={(event) => onDraftUrlChange(event.target.value)}\n onFocus={onFocusRequest}\n />\n {isLoading ? (\n <LoadingIcon className=\"size-4 shrink-0 animate-spin text-muted-foreground\" />\n ) : null}\n </form>\n {defaultActions ? (\n <div className=\"nodrag flex shrink-0 items-center gap-1.5\">\n {isCold ? (\n <span\n className=\"inline-flex h-[26px] min-w-7 items-center justify-center rounded-md bg-muted/80 px-2 text-[10px] font-semibold lowercase tracking-[0.08em] text-muted-foreground\"\n aria-label={feature.i18n.t(\"coldStatus\")}\n >\n {feature.i18n.t(\"coldStatus\")}\n </span>\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 submitBrowserNodeDraftUrl({\n draftUrl,\n feature,\n nodeId,\n setDraftUrl\n}: {\n draftUrl: string;\n feature: BrowserNodeFeature;\n nodeId: string;\n setDraftUrl: (nextUrl: string) => void;\n}) {\n const resolved = feature.resolveAddressInput(draftUrl);\n if (!resolved.url) {\n return;\n }\n\n setDraftUrl(resolved.url);\n void feature.hostApi\n .navigate({\n nodeId,\n url: resolved.url\n })\n .catch(() => undefined);\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 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 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=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40\"\n disabled={disabled}\n title={label}\n type=\"button\"\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\nimport { resolveBrowserSessionPartition } from \"../core/session.ts\";\nimport type { BrowserNodeFeature } from \"../core/feature.ts\";\nimport type {\n BrowserNodeLifecycle,\n BrowserNodeSessionMode\n} from \"../core/types.ts\";\nimport type { BrowserNodeWebviewTag } from \"./webviewTag.ts\";\n\nconst browserGuestUnregisterGraceMs = 250;\nconst pendingUnregisterTimersByNodeId = new Map<\n string,\n ReturnType<typeof globalThis.setTimeout>\n>();\nconst pendingUnregisterIdsByNodeId = new Map<string, number>();\n\nfunction resolveWebviewSrc(url: string): string {\n const trimmed = url.trim();\n return trimmed.length > 0 ? trimmed : \"about:blank\";\n}\n\nexport function useBrowserNodeWebview({\n feature,\n initialUrl,\n lifecycle,\n nodeId,\n onGuestInteraction,\n profileId,\n sessionMode\n}: {\n feature: BrowserNodeFeature;\n initialUrl: string;\n lifecycle: BrowserNodeLifecycle;\n nodeId: string;\n onGuestInteraction?: () => void;\n profileId: string | null;\n sessionMode: BrowserNodeSessionMode;\n}): {\n activate: (desiredUrl: string) => Promise<boolean>;\n shouldRenderWebview: boolean;\n webviewKey: string;\n webviewPartition: string;\n webviewRef: RefObject<BrowserNodeWebviewTag | null>;\n webviewSrc: string;\n} {\n const webviewRef = useRef<BrowserNodeWebviewTag | null>(null);\n const registeredGuestIdRef = useRef<number | null>(null);\n const registeringGuestIdRef = useRef<number | null>(null);\n const [shouldRenderWebview, setShouldRenderWebview] = useState(\n lifecycle !== \"cold\"\n );\n const [webviewSrc, setWebviewSrc] = useState(() =>\n resolveWebviewSrc(initialUrl)\n );\n const webviewPartition = useMemo(\n () => resolveBrowserSessionPartition({ profileId, sessionMode }),\n [profileId, sessionMode]\n );\n const webviewKey = `${nodeId}:${webviewPartition}`;\n\n const cancelPendingUnregister = useCallback(() => {\n const timerId = pendingUnregisterTimersByNodeId.get(nodeId);\n if (timerId === undefined) {\n return;\n }\n\n globalThis.clearTimeout(timerId);\n pendingUnregisterTimersByNodeId.delete(nodeId);\n pendingUnregisterIdsByNodeId.delete(nodeId);\n }, [nodeId]);\n\n const scheduleGuestUnregister = useCallback(() => {\n const guestId = registeredGuestIdRef.current;\n registeringGuestIdRef.current = null;\n if (guestId === null) {\n cancelPendingUnregister();\n return;\n }\n\n registeredGuestIdRef.current = null;\n cancelPendingUnregister();\n pendingUnregisterIdsByNodeId.set(nodeId, guestId);\n const timerId = globalThis.setTimeout(() => {\n const pendingGuestId = pendingUnregisterIdsByNodeId.get(nodeId);\n pendingUnregisterTimersByNodeId.delete(nodeId);\n pendingUnregisterIdsByNodeId.delete(nodeId);\n if (\n typeof pendingGuestId !== \"number\" ||\n !Number.isFinite(pendingGuestId)\n ) {\n return;\n }\n\n void feature.hostApi\n .unregisterGuest({\n nodeId,\n webContentsId: pendingGuestId\n })\n .catch(() => undefined);\n }, browserGuestUnregisterGraceMs);\n pendingUnregisterTimersByNodeId.set(nodeId, timerId);\n }, [cancelPendingUnregister, feature.hostApi, nodeId]);\n\n const activate = useCallback(\n async (nextUrl: string): Promise<boolean> => {\n try {\n await feature.hostApi.activate({\n nodeId,\n profileId,\n sessionMode,\n url: nextUrl\n });\n return true;\n } catch {\n return false;\n }\n },\n [feature.hostApi, nodeId, profileId, sessionMode]\n );\n\n useEffect(() => feature.connect(), [feature]);\n\n useEffect(() => {\n if (lifecycle === \"cold\") {\n setWebviewSrc(resolveWebviewSrc(initialUrl));\n scheduleGuestUnregister();\n setShouldRenderWebview(false);\n return;\n }\n\n cancelPendingUnregister();\n setShouldRenderWebview(true);\n void feature.hostApi\n .prepareSession({\n nodeId,\n profileId,\n sessionMode\n })\n .catch(() => undefined);\n }, [\n cancelPendingUnregister,\n feature.hostApi,\n initialUrl,\n lifecycle,\n nodeId,\n profileId,\n scheduleGuestUnregister,\n sessionMode\n ]);\n\n useEffect(() => {\n const webview = webviewRef.current;\n if (!webview || !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 registeredGuestIdRef.current === guestId ||\n registeringGuestIdRef.current === guestId\n ) {\n return;\n }\n\n cancelPendingUnregister();\n registeringGuestIdRef.current = guestId;\n try {\n await feature.hostApi.registerGuest({\n nodeId,\n profileId,\n sessionMode,\n webContentsId: guestId\n });\n registeredGuestIdRef.current = guestId;\n } finally {\n if (registeringGuestIdRef.current === guestId) {\n registeringGuestIdRef.current = null;\n }\n }\n };\n\n const handleDidAttach = () => {\n void registerGuest().catch(() => undefined);\n };\n const handleDomReady = () => {\n void registerGuest().catch(() => undefined);\n };\n\n webview.addEventListener(\"did-attach\", handleDidAttach);\n webview.addEventListener(\"dom-ready\", handleDomReady);\n\n return () => {\n webview.removeEventListener(\"did-attach\", handleDidAttach);\n webview.removeEventListener(\"dom-ready\", handleDomReady);\n };\n }, [\n cancelPendingUnregister,\n feature.hostApi,\n nodeId,\n profileId,\n sessionMode,\n shouldRenderWebview,\n webviewKey\n ]);\n\n useEffect(() => {\n const webview = webviewRef.current;\n if (!webview || !shouldRenderWebview) {\n return;\n }\n\n const handleGuestInteraction = () => {\n onGuestInteraction?.();\n };\n\n webview.addEventListener(\"focus\", handleGuestInteraction);\n webview.addEventListener(\"ipc-message\", handleGuestInteraction);\n\n return () => {\n webview.removeEventListener(\"focus\", handleGuestInteraction);\n webview.removeEventListener(\"ipc-message\", handleGuestInteraction);\n };\n }, [onGuestInteraction, shouldRenderWebview, webviewKey]);\n\n useEffect(() => () => scheduleGuestUnregister(), [scheduleGuestUnregister]);\n\n return {\n activate,\n shouldRenderWebview,\n webviewKey,\n webviewPartition,\n webviewRef,\n webviewSrc\n };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useCallback","useState","useRef","useEffect"]}
|