@nextop-os/browser-node 0.0.14 → 0.0.16

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.
@@ -1,551 +0,0 @@
1
- import {
2
- resolveBrowserSessionPartition
3
- } from "./chunk-OTK5YBCK.js";
4
-
5
- // src/react/BrowserNode.tsx
6
- import {
7
- ArrowLeftIcon,
8
- ArrowRightIcon,
9
- LaunchIcon,
10
- LoadingIcon,
11
- RefreshIcon,
12
- cn
13
- } from "@nextop-os/ui-system";
14
- import {
15
- useCallback as useCallback2,
16
- useEffect as useEffect2,
17
- useRef as useRef2,
18
- useState as useState2,
19
- useSyncExternalStore
20
- } from "react";
21
-
22
- // src/react/useBrowserNodeWebview.ts
23
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
24
- var browserGuestUnregisterGraceMs = 250;
25
- var pendingUnregisterTimersByNodeId = /* @__PURE__ */ new Map();
26
- var pendingUnregisterIdsByNodeId = /* @__PURE__ */ new Map();
27
- function resolveWebviewSrc(url) {
28
- const trimmed = url.trim();
29
- return trimmed.length > 0 ? trimmed : "about:blank";
30
- }
31
- function useBrowserNodeWebview({
32
- feature,
33
- initialUrl,
34
- lifecycle,
35
- nodeId,
36
- onGuestInteraction,
37
- profileId,
38
- sessionMode
39
- }) {
40
- const webviewRef = useRef(null);
41
- const registeredGuestIdRef = useRef(null);
42
- const registeringGuestIdRef = useRef(null);
43
- const [shouldRenderWebview, setShouldRenderWebview] = useState(
44
- lifecycle !== "cold"
45
- );
46
- const [webviewSrc, setWebviewSrc] = useState(
47
- () => resolveWebviewSrc(initialUrl)
48
- );
49
- const webviewPartition = useMemo(
50
- () => resolveBrowserSessionPartition({ profileId, sessionMode }),
51
- [profileId, sessionMode]
52
- );
53
- const webviewKey = `${nodeId}:${webviewPartition}`;
54
- const cancelPendingUnregister = useCallback(() => {
55
- const timerId = pendingUnregisterTimersByNodeId.get(nodeId);
56
- if (timerId === void 0) {
57
- return;
58
- }
59
- globalThis.clearTimeout(timerId);
60
- pendingUnregisterTimersByNodeId.delete(nodeId);
61
- pendingUnregisterIdsByNodeId.delete(nodeId);
62
- }, [nodeId]);
63
- const scheduleGuestUnregister = useCallback(() => {
64
- const guestId = registeredGuestIdRef.current;
65
- registeringGuestIdRef.current = null;
66
- if (guestId === null) {
67
- cancelPendingUnregister();
68
- return;
69
- }
70
- registeredGuestIdRef.current = null;
71
- cancelPendingUnregister();
72
- pendingUnregisterIdsByNodeId.set(nodeId, guestId);
73
- const timerId = globalThis.setTimeout(() => {
74
- const pendingGuestId = pendingUnregisterIdsByNodeId.get(nodeId);
75
- pendingUnregisterTimersByNodeId.delete(nodeId);
76
- pendingUnregisterIdsByNodeId.delete(nodeId);
77
- if (typeof pendingGuestId !== "number" || !Number.isFinite(pendingGuestId)) {
78
- return;
79
- }
80
- void feature.hostApi.unregisterGuest({
81
- nodeId,
82
- webContentsId: pendingGuestId
83
- }).catch(() => void 0);
84
- }, browserGuestUnregisterGraceMs);
85
- pendingUnregisterTimersByNodeId.set(nodeId, timerId);
86
- }, [cancelPendingUnregister, feature.hostApi, nodeId]);
87
- const activate = useCallback(
88
- async (nextUrl) => {
89
- try {
90
- await feature.hostApi.activate({
91
- nodeId,
92
- profileId,
93
- sessionMode,
94
- url: nextUrl
95
- });
96
- return true;
97
- } catch {
98
- return false;
99
- }
100
- },
101
- [feature.hostApi, nodeId, profileId, sessionMode]
102
- );
103
- useEffect(() => feature.connect(), [feature]);
104
- useEffect(() => {
105
- if (lifecycle === "cold") {
106
- setWebviewSrc(resolveWebviewSrc(initialUrl));
107
- scheduleGuestUnregister();
108
- setShouldRenderWebview(false);
109
- return;
110
- }
111
- cancelPendingUnregister();
112
- setShouldRenderWebview(true);
113
- void feature.hostApi.prepareSession({
114
- nodeId,
115
- profileId,
116
- sessionMode
117
- }).catch(() => void 0);
118
- }, [
119
- cancelPendingUnregister,
120
- feature.hostApi,
121
- initialUrl,
122
- lifecycle,
123
- nodeId,
124
- profileId,
125
- scheduleGuestUnregister,
126
- sessionMode
127
- ]);
128
- useEffect(() => {
129
- const webview = webviewRef.current;
130
- if (!webview || !shouldRenderWebview) {
131
- return;
132
- }
133
- const registerGuest = async () => {
134
- const guestId = webview.getWebContentsId?.();
135
- if (typeof guestId !== "number" || !Number.isFinite(guestId) || guestId <= 0 || registeredGuestIdRef.current === guestId || registeringGuestIdRef.current === guestId) {
136
- return;
137
- }
138
- cancelPendingUnregister();
139
- registeringGuestIdRef.current = guestId;
140
- try {
141
- await feature.hostApi.registerGuest({
142
- nodeId,
143
- profileId,
144
- sessionMode,
145
- webContentsId: guestId
146
- });
147
- registeredGuestIdRef.current = guestId;
148
- } finally {
149
- if (registeringGuestIdRef.current === guestId) {
150
- registeringGuestIdRef.current = null;
151
- }
152
- }
153
- };
154
- const handleDidAttach = () => {
155
- void registerGuest().catch(() => void 0);
156
- };
157
- const handleDomReady = () => {
158
- void registerGuest().catch(() => void 0);
159
- };
160
- webview.addEventListener("did-attach", handleDidAttach);
161
- webview.addEventListener("dom-ready", handleDomReady);
162
- return () => {
163
- webview.removeEventListener("did-attach", handleDidAttach);
164
- webview.removeEventListener("dom-ready", handleDomReady);
165
- };
166
- }, [
167
- cancelPendingUnregister,
168
- feature.hostApi,
169
- nodeId,
170
- profileId,
171
- sessionMode,
172
- shouldRenderWebview,
173
- webviewKey
174
- ]);
175
- useEffect(() => {
176
- const webview = webviewRef.current;
177
- if (!webview || !shouldRenderWebview) {
178
- return;
179
- }
180
- const handleGuestInteraction = () => {
181
- onGuestInteraction?.();
182
- };
183
- webview.addEventListener("focus", handleGuestInteraction);
184
- webview.addEventListener("ipc-message", handleGuestInteraction);
185
- return () => {
186
- webview.removeEventListener("focus", handleGuestInteraction);
187
- webview.removeEventListener("ipc-message", handleGuestInteraction);
188
- };
189
- }, [onGuestInteraction, shouldRenderWebview, webviewKey]);
190
- useEffect(() => () => scheduleGuestUnregister(), [scheduleGuestUnregister]);
191
- return {
192
- activate,
193
- shouldRenderWebview,
194
- webviewKey,
195
- webviewPartition,
196
- webviewRef,
197
- webviewSrc
198
- };
199
- }
200
-
201
- // src/react/BrowserNode.tsx
202
- import { jsx, jsxs } from "react/jsx-runtime";
203
- function BrowserNode({
204
- defaultUrl,
205
- feature,
206
- nodeId,
207
- onFocusRequest,
208
- profileId = null,
209
- sessionMode = "shared",
210
- showHeader = true
211
- }) {
212
- const subscribeRuntimeStore = useCallback2(
213
- (listener) => feature.runtimeStore.subscribe(listener),
214
- [feature.runtimeStore]
215
- );
216
- const runtime = useSyncExternalStore(
217
- subscribeRuntimeStore,
218
- () => feature.runtimeStore.getNodeState(nodeId),
219
- () => feature.runtimeStore.getNodeState(nodeId)
220
- );
221
- const resolvedRuntimeUrl = runtime.url?.trim() ?? "";
222
- const displayUrl = resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;
223
- const [draftUrl, setDraftUrl] = useState2(displayUrl);
224
- const lastColdActivationUrlRef = useRef2(null);
225
- const errorMessage = runtime.error ? formatBrowserNodeErrorMessage(feature, runtime.error) : null;
226
- const {
227
- activate,
228
- shouldRenderWebview,
229
- webviewKey,
230
- webviewPartition,
231
- webviewRef,
232
- webviewSrc
233
- } = useBrowserNodeWebview({
234
- feature,
235
- initialUrl: defaultUrl,
236
- lifecycle: runtime.lifecycle,
237
- nodeId,
238
- onGuestInteraction: onFocusRequest,
239
- profileId,
240
- sessionMode
241
- });
242
- useEffect2(() => {
243
- setDraftUrl(displayUrl);
244
- }, [displayUrl]);
245
- useEffect2(() => {
246
- if (runtime.lifecycle !== "cold" || runtime.isLoading || runtime.error) {
247
- return;
248
- }
249
- const trimmed = defaultUrl.trim();
250
- if (trimmed.length === 0 || lastColdActivationUrlRef.current === trimmed) {
251
- return;
252
- }
253
- let cancelled = false;
254
- activate(trimmed).then((ok) => {
255
- if (!cancelled && ok) {
256
- lastColdActivationUrlRef.current = trimmed;
257
- }
258
- }).catch(() => void 0);
259
- return () => {
260
- cancelled = true;
261
- };
262
- }, [
263
- activate,
264
- defaultUrl,
265
- runtime.error,
266
- runtime.isLoading,
267
- runtime.lifecycle
268
- ]);
269
- const submitDraftUrl = () => submitBrowserNodeDraftUrl({ draftUrl, feature, nodeId, setDraftUrl });
270
- return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 flex-col overflow-hidden bg-background", children: [
271
- showHeader ? /* @__PURE__ */ jsx(
272
- BrowserNodeHeader,
273
- {
274
- canGoBack: runtime.canGoBack,
275
- canGoForward: runtime.canGoForward,
276
- draftUrl,
277
- feature,
278
- isCold: runtime.lifecycle === "cold",
279
- isLoading: runtime.isLoading,
280
- nodeId,
281
- onDraftUrlChange: setDraftUrl,
282
- onFocusRequest,
283
- onSubmitUrl: submitDraftUrl
284
- }
285
- ) : null,
286
- /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-background", children: [
287
- shouldRenderWebview ? /* @__PURE__ */ jsx(
288
- "webview",
289
- {
290
- ref: (element) => {
291
- webviewRef.current = element;
292
- },
293
- className: "absolute inset-0 h-full w-full border-0 bg-background",
294
- "data-browser-node-webview": "true",
295
- partition: webviewPartition,
296
- src: webviewSrc
297
- },
298
- webviewKey
299
- ) : null,
300
- errorMessage ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-end p-3 text-center", children: /* @__PURE__ */ jsxs(
301
- "div",
302
- {
303
- 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",
304
- role: "status",
305
- "aria-live": "polite",
306
- children: [
307
- /* @__PURE__ */ jsx("div", { className: "font-medium", children: feature.i18n.t("loadFailed") }),
308
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: errorMessage })
309
- ]
310
- }
311
- ) }) : null
312
- ] })
313
- ] });
314
- }
315
- function BrowserNodeWorkbenchHeader({
316
- className,
317
- defaultActions,
318
- defaultUrl,
319
- dragHandleProps,
320
- feature,
321
- nodeId,
322
- onCloseRequest,
323
- onFocusRequest
324
- }) {
325
- const subscribeRuntimeStore = useCallback2(
326
- (listener) => feature.runtimeStore.subscribe(listener),
327
- [feature.runtimeStore]
328
- );
329
- const runtime = useSyncExternalStore(
330
- subscribeRuntimeStore,
331
- () => feature.runtimeStore.getNodeState(nodeId),
332
- () => feature.runtimeStore.getNodeState(nodeId)
333
- );
334
- const resolvedRuntimeUrl = runtime.url?.trim() ?? "";
335
- const activationUrl = resolvedRuntimeUrl.length > 0 ? resolvedRuntimeUrl : defaultUrl;
336
- const [draftUrl, setDraftUrl] = useState2(activationUrl);
337
- useEffect2(() => {
338
- setDraftUrl(activationUrl);
339
- }, [activationUrl]);
340
- const submitDraftUrl = () => submitBrowserNodeDraftUrl({
341
- draftUrl,
342
- feature,
343
- nodeId,
344
- setDraftUrl
345
- });
346
- return /* @__PURE__ */ jsx(
347
- BrowserNodeHeader,
348
- {
349
- canGoBack: runtime.canGoBack,
350
- canGoForward: runtime.canGoForward,
351
- className,
352
- defaultActions,
353
- draftUrl,
354
- dragHandleProps,
355
- feature,
356
- isCold: runtime.lifecycle === "cold",
357
- isLoading: runtime.isLoading,
358
- nodeId,
359
- onCloseRequest,
360
- onDraftUrlChange: setDraftUrl,
361
- onFocusRequest,
362
- onSubmitUrl: submitDraftUrl,
363
- withBorder: false
364
- }
365
- );
366
- }
367
- function BrowserNodeHeader({
368
- canGoBack,
369
- canGoForward,
370
- className,
371
- defaultActions,
372
- draftUrl,
373
- dragHandleProps,
374
- feature,
375
- isCold = false,
376
- isLoading,
377
- nodeId,
378
- onCloseRequest,
379
- onDraftUrlChange,
380
- onFocusRequest,
381
- onSubmitUrl,
382
- withBorder = true
383
- }) {
384
- return /* @__PURE__ */ jsxs(
385
- "div",
386
- {
387
- className: cn(
388
- "flex h-[var(--workbench-header-height,38px)] min-h-[var(--workbench-header-height,38px)] items-center gap-2 bg-panel px-2 pl-3",
389
- withBorder ? "border-b border-border" : null,
390
- className
391
- ),
392
- "data-browser-node-header": "true",
393
- onDoubleClick: (event) => {
394
- if (event.target instanceof Element && event.target.closest(".nodrag")) {
395
- return;
396
- }
397
- event.stopPropagation();
398
- dragHandleProps?.onDoubleClick?.(event);
399
- },
400
- children: [
401
- /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1", children: [
402
- /* @__PURE__ */ jsx(
403
- BrowserNodeHeaderButton,
404
- {
405
- disabled: !canGoBack,
406
- label: feature.i18n.t("actions.back"),
407
- onClick: () => {
408
- void feature.hostApi.goBack({ nodeId }).catch(() => void 0);
409
- },
410
- children: /* @__PURE__ */ jsx(ArrowLeftIcon, { className: "size-4" })
411
- }
412
- ),
413
- /* @__PURE__ */ jsx(
414
- BrowserNodeHeaderButton,
415
- {
416
- disabled: !canGoForward,
417
- label: feature.i18n.t("actions.forward"),
418
- onClick: () => {
419
- void feature.hostApi.goForward({ nodeId }).catch(() => void 0);
420
- },
421
- children: /* @__PURE__ */ jsx(ArrowRightIcon, { className: "size-4" })
422
- }
423
- ),
424
- /* @__PURE__ */ jsx(
425
- BrowserNodeHeaderButton,
426
- {
427
- label: feature.i18n.t("actions.reload"),
428
- onClick: () => {
429
- void feature.hostApi.reload({ nodeId }).catch(() => void 0);
430
- },
431
- children: /* @__PURE__ */ jsx(RefreshIcon, { className: "size-4" })
432
- }
433
- )
434
- ] }),
435
- /* @__PURE__ */ jsx(
436
- "div",
437
- {
438
- ...dragHandleProps,
439
- className: "h-full w-8 shrink-0 cursor-grab active:cursor-grabbing",
440
- "data-browser-node-drag-gutter": "true",
441
- "data-node-drag-handle": "true",
442
- "aria-hidden": "true"
443
- }
444
- ),
445
- /* @__PURE__ */ jsxs(
446
- "form",
447
- {
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-background/80 px-2 focus-within:ring-2 focus-within:ring-ring/60",
449
- onSubmit: (event) => {
450
- event.preventDefault();
451
- event.stopPropagation();
452
- onSubmitUrl();
453
- },
454
- children: [
455
- /* @__PURE__ */ jsx(LaunchIcon, { className: "size-4 shrink-0 text-muted-foreground" }),
456
- /* @__PURE__ */ jsx(
457
- "input",
458
- {
459
- "aria-label": feature.i18n.t("addressLabel"),
460
- className: "h-full min-w-0 flex-1 border-0 bg-transparent text-[13px] leading-none text-foreground outline-none placeholder:text-muted-foreground",
461
- placeholder: feature.i18n.t("addressPlaceholder"),
462
- value: draftUrl,
463
- onChange: (event) => onDraftUrlChange(event.target.value),
464
- onFocus: onFocusRequest
465
- }
466
- ),
467
- isLoading ? /* @__PURE__ */ jsx(LoadingIcon, { className: "size-4 shrink-0 animate-spin text-muted-foreground" }) : null
468
- ]
469
- }
470
- ),
471
- defaultActions ? /* @__PURE__ */ jsxs("div", { className: "nodrag flex shrink-0 items-center gap-1.5", children: [
472
- isCold ? /* @__PURE__ */ jsx(
473
- "span",
474
- {
475
- 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",
476
- "aria-label": feature.i18n.t("coldStatus"),
477
- children: feature.i18n.t("coldStatus")
478
- }
479
- ) : null,
480
- /* @__PURE__ */ jsx(
481
- "span",
482
- {
483
- className: "contents",
484
- onClickCapture: (event) => {
485
- if (!onCloseRequest || !(event.target instanceof Element) || !event.target.closest('[data-workbench-action="close"]')) {
486
- return;
487
- }
488
- onCloseRequest();
489
- },
490
- children: defaultActions
491
- }
492
- )
493
- ] }) : null
494
- ]
495
- }
496
- );
497
- }
498
- function submitBrowserNodeDraftUrl({
499
- draftUrl,
500
- feature,
501
- nodeId,
502
- setDraftUrl
503
- }) {
504
- const resolved = feature.resolveAddressInput(draftUrl);
505
- if (!resolved.url) {
506
- return;
507
- }
508
- setDraftUrl(resolved.url);
509
- void feature.hostApi.navigate({
510
- nodeId,
511
- url: resolved.url
512
- }).catch(() => void 0);
513
- }
514
- function formatBrowserNodeErrorMessage(feature, error) {
515
- switch (error.code) {
516
- case "invalid-url":
517
- return feature.i18n.t("errors.invalidUrl", error.params);
518
- case "navigation-failed":
519
- return feature.i18n.t("errors.navigationFailed", error.params);
520
- case "unsupported-protocol":
521
- return feature.i18n.t("errors.unsupportedProtocol", error.params);
522
- case "unsupported-url":
523
- return feature.i18n.t("errors.unsupportedUrl", error.params);
524
- }
525
- }
526
- function BrowserNodeHeaderButton({
527
- children,
528
- disabled,
529
- label,
530
- onClick
531
- }) {
532
- return /* @__PURE__ */ jsx(
533
- "button",
534
- {
535
- "aria-label": label,
536
- 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",
537
- disabled,
538
- title: label,
539
- type: "button",
540
- onClick,
541
- children
542
- }
543
- );
544
- }
545
-
546
- export {
547
- BrowserNode,
548
- BrowserNodeWorkbenchHeader,
549
- BrowserNodeHeader
550
- };
551
- //# sourceMappingURL=chunk-VQTJWLWO.js.map
@@ -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"]}