@nextop-os/browser-node 0.0.15 → 0.0.17

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