@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.
@@ -3,21 +3,465 @@ import {
3
3
  resolveBrowserNavigationUrl
4
4
  } from "../chunk-2ZAMKGGP.js";
5
5
  import {
6
- isBrowserSessionPartitionAllowed
6
+ isBrowserSessionPartitionAllowed,
7
+ resolveBrowserSessionPartition
7
8
  } from "../chunk-OTK5YBCK.js";
8
9
 
9
- // src/electron-main/previewRoute.ts
10
- function createNoopBrowserNodePreviewRouteResolver() {
10
+ // src/electron-main/loopbackPreviewProxy.ts
11
+ import {
12
+ createServer,
13
+ request as httpRequest
14
+ } from "http";
15
+ import { request as httpsRequest } from "https";
16
+ import { createRequire } from "module";
17
+ import { pipeline } from "stream";
18
+ var require2 = createRequire(import.meta.url);
19
+ var wsModule = require2("ws");
20
+ var WebSocket = wsModule;
21
+ var { WebSocketServer } = wsModule;
22
+ var defaultLoopbackPreviewCacheTtlMs = 3e4;
23
+ var loopbackHostPattern = /^(localhost|127(?:\.\d{1,3}){0,3})$/i;
24
+ var hopByHopHeaders = /* @__PURE__ */ new Set([
25
+ "connection",
26
+ "keep-alive",
27
+ "proxy-authenticate",
28
+ "proxy-authorization",
29
+ "proxy-connection",
30
+ "te",
31
+ "trailer",
32
+ "transfer-encoding",
33
+ "upgrade"
34
+ ]);
35
+ function createBrowserNodeLoopbackPreviewProxy({
36
+ logger,
37
+ resolveSession,
38
+ routing
39
+ }) {
40
+ const configuredSessions = /* @__PURE__ */ new WeakSet();
41
+ const targetCache = /* @__PURE__ */ new Map();
42
+ const downstreamWebSocketServer = new WebSocketServer({ noServer: true });
43
+ let server = null;
44
+ let serverStartPromise = null;
45
+ const cacheTtlMs = routing.cacheTtlMs ?? defaultLoopbackPreviewCacheTtlMs;
46
+ const fallback = routing.fallback ?? "direct";
47
+ const pruneExpiredTargets = (now) => {
48
+ for (const [cacheKey, cachedTarget] of targetCache.entries()) {
49
+ if (cachedTarget.expiresAt <= now) {
50
+ targetCache.delete(cacheKey);
51
+ }
52
+ }
53
+ };
54
+ const start = async () => {
55
+ if (server?.listening) {
56
+ return addressForTesting();
57
+ }
58
+ if (serverStartPromise) {
59
+ return serverStartPromise;
60
+ }
61
+ serverStartPromise = new Promise((resolve, reject) => {
62
+ const nextServer = createServer((request, response) => {
63
+ void handleRequest(request, response);
64
+ });
65
+ nextServer.on("upgrade", (request, socket, head) => {
66
+ void handleUpgrade(request, socket, head);
67
+ });
68
+ const cleanup = () => {
69
+ nextServer.removeListener("error", onError);
70
+ nextServer.removeListener("listening", onListening);
71
+ };
72
+ const onError = (error) => {
73
+ cleanup();
74
+ reject(error);
75
+ };
76
+ const onListening = () => {
77
+ cleanup();
78
+ server = nextServer;
79
+ resolve(addressForTesting());
80
+ };
81
+ nextServer.once("error", onError);
82
+ nextServer.once("listening", onListening);
83
+ nextServer.listen(0, "127.0.0.1");
84
+ }).finally(() => {
85
+ serverStartPromise = null;
86
+ });
87
+ return serverStartPromise;
88
+ };
89
+ const resolveLoopbackTarget = async (originalUrl) => {
90
+ const port = Number(originalUrl.port);
91
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
92
+ return null;
93
+ }
94
+ const now = Date.now();
95
+ pruneExpiredTargets(now);
96
+ const cacheKey = originalUrl.toString();
97
+ const cached = targetCache.get(cacheKey);
98
+ if (cached && cached.expiresAt > now) {
99
+ return cached.target;
100
+ }
101
+ const nextTarget = await Promise.resolve(
102
+ routing.resolver.resolveTarget({
103
+ port,
104
+ url: originalUrl.toString()
105
+ })
106
+ );
107
+ const target = normalizeLoopbackPreviewTarget(nextTarget);
108
+ targetCache.set(cacheKey, {
109
+ expiresAt: now + Math.max(0, cacheTtlMs),
110
+ target
111
+ });
112
+ return target;
113
+ };
114
+ const configureSession = async (input) => {
115
+ const nextSession = await resolveSession(input);
116
+ if (configuredSessions.has(nextSession)) {
117
+ return;
118
+ }
119
+ const address = await start();
120
+ await nextSession.setProxy({
121
+ mode: "fixed_servers",
122
+ proxyBypassRules: "<-loopback>",
123
+ proxyRules: `http=${address};https=${address};ws=${address}`
124
+ });
125
+ configuredSessions.add(nextSession);
126
+ };
127
+ const dispose = async () => {
128
+ targetCache.clear();
129
+ downstreamWebSocketServer.close();
130
+ const activeServer = server;
131
+ server = null;
132
+ if (!activeServer || !activeServer.listening) {
133
+ return;
134
+ }
135
+ await new Promise((resolve) => {
136
+ activeServer.close(() => resolve());
137
+ });
138
+ };
139
+ const handleRequest = async (request, response) => {
140
+ const originalUrl = resolveProxyRequestUrl(request);
141
+ if (!originalUrl) {
142
+ response.writeHead(400);
143
+ response.end("invalid proxy request");
144
+ return;
145
+ }
146
+ if (originalUrl.protocol !== "http:" && originalUrl.protocol !== "https:") {
147
+ response.writeHead(400);
148
+ response.end("unsupported proxy request");
149
+ return;
150
+ }
151
+ const targetContext = await resolveTargetRequestContext(originalUrl);
152
+ if (!targetContext.targetUrl) {
153
+ response.writeHead(502);
154
+ response.end("unable to resolve loopback preview target");
155
+ return;
156
+ }
157
+ const headers = filterProxyHeaders(request.headers);
158
+ headers.set("host", targetContext.targetUrl.host);
159
+ const forward = targetContext.targetUrl.protocol === "https:" ? httpsRequest : httpRequest;
160
+ const upstream = forward(
161
+ targetContext.targetUrl,
162
+ {
163
+ headers: Object.fromEntries(headers.entries()),
164
+ method: request.method
165
+ },
166
+ (upstreamResponse) => {
167
+ const responseHeaders = filterProxyHeaders(upstreamResponse.headers);
168
+ const location = responseHeaders.get("location");
169
+ if (location && targetContext.loopbackTarget) {
170
+ const rewritten = rewriteLoopbackLocation({
171
+ location,
172
+ originalUrl,
173
+ targetUrl: targetContext.loopbackTarget.targetUrl
174
+ });
175
+ if (rewritten) {
176
+ responseHeaders.set("location", rewritten);
177
+ }
178
+ }
179
+ response.writeHead(
180
+ upstreamResponse.statusCode ?? 502,
181
+ upstreamResponse.statusMessage,
182
+ Object.fromEntries(responseHeaders.entries())
183
+ );
184
+ pipeline(upstreamResponse, response, () => void 0);
185
+ }
186
+ );
187
+ upstream.on("error", (error) => {
188
+ logger?.warn?.("Browser Node loopback preview request failed", {
189
+ error: normalizeProxyError(error),
190
+ originalUrl: originalUrl.toString(),
191
+ targetUrl: targetContext.targetUrl?.toString() ?? null,
192
+ workspaceId: targetContext.loopbackTarget?.workspaceId ?? null
193
+ });
194
+ if (!response.headersSent) {
195
+ response.writeHead(502);
196
+ }
197
+ response.end(
198
+ `loopback preview upstream request failed: ${normalizeProxyError(error)}`
199
+ );
200
+ });
201
+ pipeline(request, upstream, () => void 0);
202
+ };
203
+ const handleUpgrade = async (request, socket, head) => {
204
+ const originalUrl = resolveProxyRequestUrl(request, "ws:");
205
+ if (!originalUrl) {
206
+ socket.destroy();
207
+ return;
208
+ }
209
+ if (originalUrl.protocol !== "ws:" && originalUrl.protocol !== "wss:") {
210
+ socket.destroy();
211
+ return;
212
+ }
213
+ const targetContext = await resolveTargetRequestContext(originalUrl);
214
+ const targetUrl = targetContext.targetUrl;
215
+ if (!targetUrl) {
216
+ socket.destroy();
217
+ return;
218
+ }
219
+ downstreamWebSocketServer.handleUpgrade(
220
+ request,
221
+ socket,
222
+ head,
223
+ (downstream) => {
224
+ const headers = Object.fromEntries(
225
+ filterProxyHeaders(request.headers).entries()
226
+ );
227
+ headers.host = targetUrl.host;
228
+ const upstream = new WebSocket(targetUrl, { headers });
229
+ const pendingMessages = [];
230
+ downstream.on("message", (data, isBinary) => {
231
+ if (upstream.readyState === WebSocket.OPEN) {
232
+ upstream.send(data, { binary: isBinary });
233
+ return;
234
+ }
235
+ pendingMessages.push({ data, isBinary });
236
+ });
237
+ upstream.once("open", () => {
238
+ for (const nextMessage of pendingMessages.splice(0)) {
239
+ upstream.send(nextMessage.data, { binary: nextMessage.isBinary });
240
+ }
241
+ });
242
+ upstream.on("message", (data, isBinary) => {
243
+ if (downstream.readyState === WebSocket.OPEN) {
244
+ downstream.send(data, { binary: isBinary });
245
+ }
246
+ });
247
+ upstream.once("close", (code, reason) => {
248
+ if (downstream.readyState === WebSocket.OPEN || downstream.readyState === WebSocket.CONNECTING) {
249
+ downstream.close(normalizeWebSocketCloseCode(code), reason);
250
+ }
251
+ });
252
+ downstream.once("close", (code, reason) => {
253
+ if (upstream.readyState === WebSocket.OPEN || upstream.readyState === WebSocket.CONNECTING) {
254
+ upstream.close(normalizeWebSocketCloseCode(code), reason);
255
+ }
256
+ });
257
+ upstream.once("error", (error) => {
258
+ logger?.warn?.("Browser Node loopback preview websocket failed", {
259
+ error: normalizeProxyError(error),
260
+ originalUrl: originalUrl.toString(),
261
+ targetUrl: targetContext.targetUrl?.toString() ?? null,
262
+ workspaceId: targetContext.loopbackTarget?.workspaceId ?? null
263
+ });
264
+ downstream.close(1011, "loopback preview websocket upstream failed");
265
+ });
266
+ }
267
+ );
268
+ };
269
+ const resolveTargetRequestContext = async (originalUrl) => {
270
+ if (!isLoopbackUrl(originalUrl)) {
271
+ return {
272
+ loopbackTarget: null,
273
+ targetUrl: cloneUrl(originalUrl)
274
+ };
275
+ }
276
+ const loopbackTarget = await resolveLoopbackTarget(originalUrl);
277
+ if (loopbackTarget) {
278
+ return {
279
+ loopbackTarget,
280
+ targetUrl: buildTargetRequestUrl(loopbackTarget.targetUrl, originalUrl)
281
+ };
282
+ }
283
+ if (fallback === "direct") {
284
+ return {
285
+ loopbackTarget: null,
286
+ targetUrl: cloneUrl(originalUrl)
287
+ };
288
+ }
289
+ return {
290
+ loopbackTarget: null,
291
+ targetUrl: null
292
+ };
293
+ };
294
+ const addressForTesting = () => {
295
+ const address = server?.address();
296
+ if (!address || typeof address === "string") {
297
+ throw new Error("Browser Node loopback preview proxy is not listening");
298
+ }
299
+ return `127.0.0.1:${address.port}`;
300
+ };
301
+ const serverForTesting = () => {
302
+ if (!server) {
303
+ throw new Error("Browser Node loopback preview proxy is not started");
304
+ }
305
+ return server;
306
+ };
11
307
  return {
12
- resolveRoutes: () => []
308
+ addressForTesting,
309
+ configureSession,
310
+ dispose,
311
+ serverForTesting
13
312
  };
14
313
  }
314
+ function normalizeLoopbackPreviewTarget(input) {
315
+ if (!input) {
316
+ return null;
317
+ }
318
+ const normalizedTargetUrl = input.targetUrl.trim();
319
+ if (normalizedTargetUrl.length === 0) {
320
+ return null;
321
+ }
322
+ try {
323
+ const parsed = new URL(normalizedTargetUrl);
324
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
325
+ return null;
326
+ }
327
+ return {
328
+ targetUrl: parsed.toString(),
329
+ workspaceId: input.workspaceId
330
+ };
331
+ } catch {
332
+ return null;
333
+ }
334
+ }
335
+ function resolveProxyRequestUrl(request, defaultProtocol = "http:") {
336
+ const rawUrl = request.url ?? "";
337
+ try {
338
+ if (/^[a-z][a-z\d+\-.]*:\/\//i.test(rawUrl)) {
339
+ return new URL(rawUrl);
340
+ }
341
+ const host = request.headers.host;
342
+ if (typeof host !== "string" || host.trim().length === 0) {
343
+ return null;
344
+ }
345
+ const path = rawUrl.startsWith("/") ? rawUrl : `/${rawUrl}`;
346
+ return new URL(`${defaultProtocol}//${host}${path}`);
347
+ } catch {
348
+ return null;
349
+ }
350
+ }
351
+ function filterProxyHeaders(input) {
352
+ const output = new Headers();
353
+ const appendValue = (key, value) => {
354
+ if (hopByHopHeaders.has(key.toLowerCase())) {
355
+ return;
356
+ }
357
+ output.append(key, value);
358
+ };
359
+ if (input instanceof Headers) {
360
+ input.forEach((value, key) => {
361
+ appendValue(key, value);
362
+ });
363
+ return output;
364
+ }
365
+ for (const [key, value] of Object.entries(input)) {
366
+ if (Array.isArray(value)) {
367
+ for (const nextValue of value) {
368
+ appendValue(key, nextValue);
369
+ }
370
+ continue;
371
+ }
372
+ if (typeof value === "string") {
373
+ appendValue(key, value);
374
+ }
375
+ }
376
+ return output;
377
+ }
378
+ function isLoopbackUrl(url) {
379
+ return (url.protocol === "http:" || url.protocol === "https:" || url.protocol === "ws:" || url.protocol === "wss:") && loopbackHostPattern.test(url.hostname) && url.port.length > 0;
380
+ }
381
+ function buildTargetRequestUrl(targetUrl, originalUrl) {
382
+ try {
383
+ const base = new URL(targetUrl);
384
+ const normalizedBasePath = normalizeBasePath(base.pathname);
385
+ const nextUrl = new URL(base.toString());
386
+ nextUrl.pathname = joinBasePath(normalizedBasePath, originalUrl.pathname);
387
+ nextUrl.search = originalUrl.search;
388
+ nextUrl.hash = "";
389
+ if (originalUrl.protocol === "ws:" || originalUrl.protocol === "wss:") {
390
+ nextUrl.protocol = nextUrl.protocol === "https:" ? "wss:" : "ws:";
391
+ }
392
+ return nextUrl;
393
+ } catch {
394
+ return null;
395
+ }
396
+ }
397
+ function rewriteLoopbackLocation({
398
+ location,
399
+ originalUrl,
400
+ targetUrl
401
+ }) {
402
+ try {
403
+ const targetBase = new URL(targetUrl);
404
+ const resolvedLocation = new URL(location, targetBase);
405
+ if (resolvedLocation.origin !== targetBase.origin) {
406
+ return location;
407
+ }
408
+ const basePath = normalizeBasePath(targetBase.pathname);
409
+ const strippedPath = stripBasePath(basePath, resolvedLocation.pathname) ?? resolvedLocation.pathname;
410
+ const loopbackUrl = new URL(originalUrl.origin);
411
+ resolvedLocation.protocol = loopbackUrl.protocol;
412
+ resolvedLocation.host = loopbackUrl.host;
413
+ resolvedLocation.pathname = strippedPath;
414
+ resolvedLocation.username = "";
415
+ resolvedLocation.password = "";
416
+ return resolvedLocation.toString();
417
+ } catch {
418
+ return location;
419
+ }
420
+ }
421
+ function normalizeBasePath(pathname) {
422
+ const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
423
+ return normalized.endsWith("/") ? normalized : `${normalized}/`;
424
+ }
425
+ function joinBasePath(basePath, requestPath) {
426
+ const normalizedRequestPath = requestPath === "/" ? "" : requestPath.replace(/^\/+/, "");
427
+ return normalizedRequestPath.length > 0 ? `${basePath}${normalizedRequestPath}`.replace(/\/{2,}/g, "/") : basePath;
428
+ }
429
+ function stripBasePath(basePath, pathname) {
430
+ const normalizedPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
431
+ if (normalizedPath === basePath.slice(0, -1)) {
432
+ return "/";
433
+ }
434
+ if (!normalizedPath.startsWith(basePath)) {
435
+ return null;
436
+ }
437
+ const suffix = normalizedPath.slice(basePath.length);
438
+ return suffix.length > 0 ? `/${suffix}` : "/";
439
+ }
440
+ function cloneUrl(url) {
441
+ try {
442
+ return new URL(url.toString());
443
+ } catch {
444
+ return null;
445
+ }
446
+ }
447
+ function normalizeProxyError(error) {
448
+ if (error instanceof Error) {
449
+ const code = typeof error.code === "string" ? ` ${error.code}` : "";
450
+ return `${error.message}${code}`;
451
+ }
452
+ return String(error);
453
+ }
454
+ function normalizeWebSocketCloseCode(code) {
455
+ if (code === 1e3 || code >= 3e3 && code <= 4999) {
456
+ return code;
457
+ }
458
+ return 1e3;
459
+ }
15
460
 
16
461
  // src/electron-main/guestManager.ts
17
462
  var browserPreviewMaxWidth = 260;
18
463
  var browserPreviewMaxHeight = 170;
19
464
  var abortedNavigationErrorCode = -3;
20
- var prefersColorSchemeFeatureName = "prefers-color-scheme";
21
465
  function resolveBrowserNodeUrlError(resolved) {
22
466
  if (resolved.errorCode === "invalid-url") {
23
467
  return { code: "invalid-url" };
@@ -55,23 +499,13 @@ function resizeBrowserPreviewImage(image) {
55
499
  function isAbortedNavigationError(input) {
56
500
  return input.errorCode === abortedNavigationErrorCode || input.errorDescription === "ERR_ABORTED";
57
501
  }
58
- async function applyPreferredColorSchemeToGuest(session, logger, scheme) {
502
+ async function applyPreferredColorSchemeToGuest(session, logger, syncPreferredColorScheme, scheme) {
59
503
  const contents = session.contents;
60
- if (!contents || contents.isDestroyed() || !contents.debugger || scheme === null || session.appliedColorScheme === scheme) {
504
+ if (!contents || contents.isDestroyed() || !syncPreferredColorScheme || scheme === null || session.appliedColorScheme === scheme) {
61
505
  return;
62
506
  }
63
507
  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
- });
508
+ await syncPreferredColorScheme(contents, scheme);
75
509
  session.appliedColorScheme = scheme;
76
510
  } catch (error) {
77
511
  session.appliedColorScheme = null;
@@ -88,8 +522,9 @@ function createBrowserGuestManager({
88
522
  getPreferredColorScheme,
89
523
  logger,
90
524
  openExternal,
91
- previewRouteResolver = createNoopBrowserNodePreviewRouteResolver(),
525
+ prepareSession,
92
526
  resolveWebContents,
527
+ syncPreferredColorScheme,
93
528
  subscribePreferredColorScheme
94
529
  }) {
95
530
  const sessions = /* @__PURE__ */ new Map();
@@ -155,16 +590,19 @@ function createBrowserGuestManager({
155
590
  }
156
591
  publishState(session);
157
592
  };
158
- const syncPreferredColorScheme = (scheme) => {
593
+ const handlePreferredColorSchemeChange = (scheme) => {
159
594
  preferredColorScheme = scheme;
160
595
  for (const session of sessions.values()) {
161
596
  session.appliedColorScheme = null;
162
- void applyPreferredColorSchemeToGuest(session, logger, scheme).catch(
163
- () => void 0
164
- );
597
+ void applyPreferredColorSchemeToGuest(
598
+ session,
599
+ logger,
600
+ syncPreferredColorScheme,
601
+ scheme
602
+ ).catch(() => void 0);
165
603
  }
166
604
  };
167
- const unsubscribePreferredColorScheme = subscribePreferredColorScheme?.(syncPreferredColorScheme) ?? null;
605
+ const unsubscribePreferredColorScheme = subscribePreferredColorScheme?.(handlePreferredColorSchemeChange) ?? null;
168
606
  const attachGuestListeners = (session) => {
169
607
  const contents = session.contents;
170
608
  if (!contents) {
@@ -218,18 +656,13 @@ function createBrowserGuestManager({
218
656
  publishState(session);
219
657
  return;
220
658
  }
221
- const routes = await previewRouteResolver.resolveRoutes({
222
- nodeId: session.nodeId,
223
- url: resolved.url
224
- });
225
- const routedUrl = routes.find((route) => route.sourceUrl === resolved.url)?.targetUrl ?? resolved.url;
226
659
  const currentComparable = normalizeBrowserComparableUrl(contents.getURL());
227
- const nextComparable = normalizeBrowserComparableUrl(routedUrl);
660
+ const nextComparable = normalizeBrowserComparableUrl(resolved.url);
228
661
  if (currentComparable && currentComparable === nextComparable) {
229
662
  publishState(session);
230
663
  return;
231
664
  }
232
- await contents.loadURL(routedUrl);
665
+ await contents.loadURL(resolved.url);
233
666
  publishState(session);
234
667
  };
235
668
  const openExternalFromGuest = (url) => {
@@ -325,14 +758,19 @@ function createBrowserGuestManager({
325
758
  session.lifecycle = "active";
326
759
  await loadDesiredUrl(session);
327
760
  },
328
- prepareSession(input) {
761
+ async prepareSession(input) {
762
+ await prepareSession?.(input);
329
763
  getSession(input.nodeId, {
330
764
  profileId: input.profileId,
331
765
  sessionMode: input.sessionMode
332
766
  });
333
- return Promise.resolve();
334
767
  },
335
768
  async registerGuest(input) {
769
+ await prepareSession?.({
770
+ nodeId: input.nodeId,
771
+ profileId: input.profileId,
772
+ sessionMode: input.sessionMode
773
+ });
336
774
  const contents = resolveWebContents(input.webContentsId);
337
775
  if (!contents || contents.isDestroyed()) {
338
776
  throw new Error(
@@ -365,6 +803,7 @@ function createBrowserGuestManager({
365
803
  await applyPreferredColorSchemeToGuest(
366
804
  session,
367
805
  logger,
806
+ syncPreferredColorScheme,
368
807
  preferredColorScheme
369
808
  );
370
809
  await loadDesiredUrl(session);
@@ -394,6 +833,19 @@ function createBrowserGuestManager({
394
833
  // src/electron-main/registerElectronMain.ts
395
834
  function registerBrowserNodeElectronMain(input) {
396
835
  const managersByWindow = /* @__PURE__ */ new WeakMap();
836
+ const loopbackPreviewProxy = input.loopbackPreviewRouting !== void 0 ? createBrowserNodeLoopbackPreviewProxy({
837
+ logger: input.logger,
838
+ resolveSession: async ({ profileId, sessionMode }) => {
839
+ const { session } = await import("electron");
840
+ return session.fromPartition(
841
+ resolveBrowserSessionPartition({
842
+ profileId,
843
+ sessionMode
844
+ })
845
+ );
846
+ },
847
+ routing: input.loopbackPreviewRouting
848
+ }) : null;
397
849
  const resolveManager = (event) => {
398
850
  const ownerWindow = input.getOwnerWindow(event);
399
851
  if (!ownerWindow) {
@@ -412,11 +864,13 @@ function registerBrowserNodeElectronMain(input) {
412
864
  getPreferredColorScheme: input.getPreferredColorScheme,
413
865
  logger: input.logger,
414
866
  openExternal: input.openExternal,
867
+ prepareSession: loopbackPreviewProxy !== null ? (payload) => loopbackPreviewProxy.configureSession(payload) : void 0,
415
868
  resolveWebContents: (webContentsId) => input.resolveWebContents({
416
869
  event,
417
870
  ownerWindow,
418
871
  webContentsId
419
872
  }),
873
+ syncPreferredColorScheme: input.syncPreferredColorScheme,
420
874
  subscribePreferredColorScheme: input.subscribePreferredColorScheme
421
875
  });
422
876
  ownerWindow.once("closed", () => {
@@ -557,8 +1011,6 @@ function installBrowserWebviewSecurity({
557
1011
  };
558
1012
  }
559
1013
  export {
560
- createBrowserGuestManager,
561
- createNoopBrowserNodePreviewRouteResolver,
562
1014
  enforceBrowserWebviewSecurity,
563
1015
  installBrowserWebviewSecurity,
564
1016
  isBrowserNodeWebviewAttach,