function configureStartupRenderer(app, env = process.env, platform = process.platform) { const sessionName = String(env && env.SESSIONNAME || ''); if (platform === 'win32' && /^RDP-/i.test(sessionName)) app.disableHardwareAcceleration(); return app; } function resolveStartupLanguage(config) { return config && config.globalSettings && config.globalSettings.language === 'de' ? 'de' : 'en'; } function createStartupFailureDocument(language) { const german = language === 'de'; const title = german ? 'Oberfläche konnte nicht geladen werden' : 'The interface could not load'; const detail = german ? 'Multi Hoster Uploader konnte die Oberfläche nach einem sicheren Wiederherstellungsversuch nicht laden.' : 'Multi Hoster Uploader could not load the interface after a safe recovery attempt.'; const close = german ? 'Schließen' : 'Close'; return `Multi Hoster Uploader

${title}

${detail}

`; } function createStartupRecoveryCoordinator({ load, reload, reveal, showFailure, close, readyTimeoutMs = 15000, scheduleReadyDeadline = setTimeout, cancelReadyDeadline = clearTimeout }) { let initialLoad; let crashReloads = 0; let terminalFailure; let recovery; let readyDeadline; let rendererDocument = 0; let awaitingReady = false; let stopped = false; function clearRendererDeadline() { if (readyDeadline !== undefined) cancelReadyDeadline(readyDeadline); readyDeadline = undefined; } function abandonRendererDocument() { awaitingReady = false; clearRendererDeadline(); } function endWithFailure(failure) { if (stopped) return Promise.resolve(false); if (!terminalFailure) { abandonRendererDocument(); terminalFailure = (async () => { if (typeof showFailure !== 'function') { await close(failure); return; } try { await showFailure(failure); reveal(); } catch (surfaceError) { await close({ ...failure, surfaceError }); } })(); } return terminalFailure; } function recoverRenderer(phase, details) { if (stopped) return Promise.resolve(false); if (terminalFailure) return terminalFailure; if (recovery) return recovery; abandonRendererDocument(); const currentRecovery = (async () => { if (crashReloads >= 1) { return endWithFailure({ phase, attempt: crashReloads + 1, details }); } crashReloads++; try { await reload(); return true; } catch (error) { if (stopped) return false; return endWithFailure({ phase: 'renderer-reload', attempt: crashReloads, details, error }); } })(); recovery = currentRecovery; currentRecovery.then( () => { if (recovery === currentRecovery) recovery = undefined; }, () => { if (recovery === currentRecovery) recovery = undefined; } ); return currentRecovery; } return { loadInitial(...args) { if (stopped) return Promise.resolve(false); if (terminalFailure) return terminalFailure; if (!initialLoad) { initialLoad = (async () => { for (let attempt = 1; attempt <= 2; attempt++) { if (stopped) return false; try { return await load(...args); } catch (error) { if (stopped) return false; if (attempt === 2) { await endWithFailure({ phase: 'initial-load', attempt, error }); } } } })(); } return initialLoad; }, rendererCrashed(details) { return recoverRenderer('renderer-crash', details); }, rendererInitializationFailed(details) { return recoverRenderer('renderer-initialization', details); }, rendererLoadStarted() { if (stopped || terminalFailure) return false; clearRendererDeadline(); rendererDocument++; awaitingReady = true; return true; }, rendererLoaded() { if (stopped || terminalFailure || !awaitingReady) return false; clearRendererDeadline(); const document = rendererDocument; readyDeadline = scheduleReadyDeadline(() => { if (stopped || terminalFailure || !awaitingReady || rendererDocument !== document) return false; readyDeadline = undefined; return recoverRenderer('renderer-ready-timeout', { timeoutMs: readyTimeoutMs }); }, readyTimeoutMs); if (readyDeadline && typeof readyDeadline.unref === 'function') readyDeadline.unref(); return true; }, rendererReady() { if (stopped || terminalFailure) return false; abandonRendererDocument(); crashReloads = 0; reveal(); return true; }, dispose() { if (stopped) return false; stopped = true; abandonRendererDocument(); return true; } }; } function createStartupRendererHandlers({ window, coordinator, onReady, onInitializationFailed }) { let disposed = false; function accepts(event) { return !disposed && window && !window.isDestroyed() && event && event.sender === window.webContents; } return { documentLoadStarted() { if (disposed) return false; return coordinator.rendererLoadStarted(); }, documentLoaded() { if (disposed) return false; return coordinator.rendererLoaded(); }, rendererCrashed(details) { if (disposed) return false; return coordinator.rendererCrashed(details); }, rendererInitializationFailed(event, details) { if (!accepts(event)) return false; if (typeof onInitializationFailed === 'function') onInitializationFailed(details); return coordinator.rendererInitializationFailed(details); }, rendererReady(event) { if (!accepts(event)) return false; const ready = coordinator.rendererReady(); if (ready && typeof onReady === 'function') onReady(); return ready; }, dispose() { if (disposed) return false; disposed = true; return coordinator.dispose(); } }; } function createStartupWindow(BrowserWindow, options) { const window = new BrowserWindow({ ...options, show: false }); window.once('ready-to-show', () => { window.show(); }); return { window, load(target, onLoadError, options) { return window.loadFile(target, options).catch(onLoadError); } }; } module.exports = { configureStartupRenderer, createStartupFailureDocument, createStartupRecoveryCoordinator, createStartupRendererHandlers, createStartupWindow, resolveStartupLanguage };