import { app } from 'electron'; import * as path from 'path'; import { createWindow, getMainWindow } from '../window/create-window'; const CUSTOM_PROTOCOL = 'toju'; const DEEP_LINK_PREFIX = `${CUSTOM_PROTOCOL}://`; const DEV_SINGLE_INSTANCE_EXIT_CODE_ENV = 'METOYOU_SINGLE_INSTANCE_EXIT_CODE'; let pendingDeepLink: string | null = null; function resolveDevSingleInstanceExitCode(): number | null { const rawValue = process.env[DEV_SINGLE_INSTANCE_EXIT_CODE_ENV]; if (!rawValue) { return null; } const parsedValue = Number.parseInt(rawValue, 10); return Number.isInteger(parsedValue) && parsedValue > 0 ? parsedValue : null; } function extractDeepLink(argv: string[]): string | null { return argv.find((argument) => typeof argument === 'string' && argument.startsWith(DEEP_LINK_PREFIX)) || null; } function focusMainWindow(): void { const mainWindow = getMainWindow(); if (!mainWindow || mainWindow.isDestroyed()) { return; } if (mainWindow.isMinimized()) { mainWindow.restore(); } mainWindow.show(); mainWindow.focus(); } function forwardDeepLink(url: string): void { const mainWindow = getMainWindow(); if (!mainWindow || mainWindow.isDestroyed() || mainWindow.webContents.isLoadingMainFrame()) { pendingDeepLink = url; if (app.isReady() && (!mainWindow || mainWindow.isDestroyed())) { void createWindow(); } return; } focusMainWindow(); mainWindow.webContents.send('deep-link-received', url); } function registerProtocolClient(): void { if (process.defaultApp) { const appEntrypoint = process.argv[1]; if (appEntrypoint) { app.setAsDefaultProtocolClient(CUSTOM_PROTOCOL, process.execPath, [path.resolve(appEntrypoint)]); return; } } app.setAsDefaultProtocolClient(CUSTOM_PROTOCOL); } export function initializeDeepLinkHandling(): boolean { const hasSingleInstanceLock = app.requestSingleInstanceLock(); if (!hasSingleInstanceLock) { const devExitCode = resolveDevSingleInstanceExitCode(); if (devExitCode != null) { app.exit(devExitCode); } else { app.quit(); } return false; } registerProtocolClient(); const initialDeepLink = extractDeepLink(process.argv); if (initialDeepLink) { pendingDeepLink = initialDeepLink; } app.on('second-instance', (_event, argv) => { focusMainWindow(); const deepLink = extractDeepLink(argv); if (deepLink) { forwardDeepLink(deepLink); } }); app.on('open-url', (event, url) => { event.preventDefault(); forwardDeepLink(url); }); return true; } export function consumePendingDeepLink(): string | null { const deepLink = pendingDeepLink; pendingDeepLink = null; return deepLink; }