desktop/ serves the normal frontend build over a privileged app://j621 scheme, so localStorage, OPFS, Web Workers, WebCodecs and history routing behave exactly like Chrome. Development points at the Vite dev server; `npm run smoke` runs headless Electron and checks the bundled app. External links open in the system browser, and download navigations (?download=1 or media URLs) are rerouted through webContents.downloadURL, since preventing them cancels the download. The setup screen names the shell's origin when the connection test fails, and the deploy docs list app://j621 for CORS_ALLOWED_ORIGINS.
28 lines
1.0 KiB
TypeScript
28 lines
1.0 KiB
TypeScript
/**
|
|
* The only bridge between the desktop shell and the SPA. Keep it tiny: the
|
|
* renderer is the normal web build and must not need Electron to work.
|
|
*/
|
|
import { contextBridge, ipcRenderer } from "electron";
|
|
|
|
contextBridge.exposeInMainWorld("j621Desktop", {
|
|
isDesktop: true as const,
|
|
platform: process.platform,
|
|
// The SPA's own origin (`app://j621`), shown by the setup screen when it
|
|
// has to explain which origin to allow in the backend's CORS settings.
|
|
origin: window.location.origin,
|
|
getVersion: (): Promise<string> => ipcRenderer.invoke("j621:version"),
|
|
});
|
|
|
|
// Menu → "Open backend in browser": read the SPA's stored backend URL and
|
|
// hand it to the main process after checking it is a real web URL.
|
|
ipcRenderer.on("j621:open-backend", () => {
|
|
let url = "";
|
|
try {
|
|
url = window.localStorage.getItem("j621.backend") ?? "";
|
|
} catch {
|
|
// Storage can be unavailable in rare cases; nothing to open then.
|
|
}
|
|
if (url === "none") url = "";
|
|
if (url) void ipcRenderer.invoke("j621:open-external", url);
|
|
});
|