fix: support dev server previews over relay

This commit is contained in:
Bohdan Triapitsyn
2026-09-03 11:49:34 +03:00
parent da6ab52a65
commit a87f068256
16 changed files with 504 additions and 36 deletions
+12 -1
View File
@@ -1,4 +1,4 @@
import { app, BrowserWindow, dialog, ipcMain, Menu, nativeTheme, net as electronNet, Notification, powerMonitor, powerSaveBlocker, protocol, screen, session, shell, webContents } from 'electron';
import { app, BrowserWindow, dialog, ipcMain, Menu, MessageChannelMain, nativeTheme, net as electronNet, Notification, powerMonitor, powerSaveBlocker, protocol, screen, session, shell, webContents } from 'electron';
import contextMenu from 'electron-context-menu';
import log from 'electron-log/main.js';
import dgram from 'node:dgram';
@@ -33,6 +33,7 @@ import {
} from './linux-autostart.mjs';
import { unsupportedAppSpecificOpenError, validateLocalPath } from './path-open-utils.mjs';
import { shouldAllowBrowserPanelCertificateError } from './browser-panel-security.mjs';
import { createRelayDevTunnelBridge } from './relay-dev-tunnel.mjs';
import { attachRendererRecovery } from './renderer-recovery.mjs';
import { mintOutsideFileGrant } from '@openchamber/web/server/lib/fs/routes.js';
@@ -3839,6 +3840,7 @@ const runSpecChain = (specs, appName) => {
// The tunnel client lives in the web package (it already has a WebSocket
// client) and is loaded only if the user actually previews a remote dev server.
let devTunnelClientPromise = null;
const relayDevTunnelBridge = createRelayDevTunnelBridge({ createMessageChannel: () => new MessageChannelMain(), logger: log });
const getDevTunnelClient = async () => {
if (!devTunnelClientPromise) {
devTunnelClientPromise = import('@openchamber/web/server/lib/dev-tunnel/client.js')
@@ -3852,6 +3854,7 @@ const getDevTunnelClient = async () => {
};
const closeAllDevTunnels = () => {
relayDevTunnelBridge.closeAll();
if (!devTunnelClientPromise) return;
const pending = devTunnelClientPromise;
devTunnelClientPromise = null;
@@ -3959,6 +3962,11 @@ const handleInvoke = async (browserWindow, command, args = {}) => {
if (!baseUrl) throw new Error('baseUrl is required');
if (!(port > 0 && port <= 65535)) throw new Error('A valid port is required');
if (args.relay === true) {
const targetKey = typeof args.targetKey === 'string' ? args.targetKey.trim() : '';
return relayDevTunnelBridge.open({ targetKey, remotePort: port, webContents: browserWindow?.webContents });
}
const headers = {};
const requestHeaders = args.requestHeaders && typeof args.requestHeaders === 'object' ? args.requestHeaders : {};
for (const [name, value] of Object.entries(requestHeaders)) {
@@ -3981,6 +3989,9 @@ const handleInvoke = async (browserWindow, command, args = {}) => {
return { closed: client.close({ baseUrl, port }) };
}
case 'desktop_relay_dev_tunnel_close_all':
return { closed: relayDevTunnelBridge.closeForWebContents(browserWindow?.webContents.id) };
/**
* Forces prefers-color-scheme for one previewed page.
*