feat(desktop): add a setting and flag to disable updates (#3483)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-15 00:33:11 +02:00
1 parent 3a74a6f97a
commit 674b4d26d1
58 files changed
+1477 -42

No files matched your search

@@ -70,6 +70,7 @@ interface PersistedDesktopWindowBehaviorSettings {
interface PersistedDesktopTroubleshootingSettings {
disableHardwareAcceleration?: boolean;
disableModuleUpdates?: boolean;
}
const INSTANCE_ENDPOINT_ARGS = ['--fluxer-instance'];
@@ -82,6 +83,7 @@ let configPath: string | null = null;
function getDefaultDesktopTroubleshootingSettings(): DesktopTroubleshootingSettings {
return {
disableHardwareAcceleration: false,
disableModuleUpdates: false,
};
}
@@ -156,6 +158,9 @@ function sanitizePersistedDesktopTroubleshootingSettings(
if (typeof value.disableHardwareAcceleration === 'boolean') {
settings.disableHardwareAcceleration = value.disableHardwareAcceleration;
}
if (typeof value.disableModuleUpdates === 'boolean') {
settings.disableModuleUpdates = value.disableModuleUpdates;
}
return Object.keys(settings).length > 0 ? settings : undefined;
}
@@ -425,6 +430,10 @@ function normalizeDesktopTroubleshootingSettings(
typeof settings?.disableHardwareAcceleration === 'boolean'
? settings.disableHardwareAcceleration
: defaults.disableHardwareAcceleration,
disableModuleUpdates:
typeof settings?.disableModuleUpdates === 'boolean'
? settings.disableModuleUpdates
: defaults.disableModuleUpdates,
};
}
@@ -433,6 +442,7 @@ function serializeDesktopTroubleshootingSettings(
): PersistedDesktopTroubleshootingSettings {
return {
disableHardwareAcceleration: settings.disableHardwareAcceleration,
disableModuleUpdates: settings.disableModuleUpdates,
};
}
+4
View File
@@ -32,6 +32,7 @@ import type {
NativeAudioStartResult,
NativeScreenCaptureLifecycleMessage,
SetDesktopTroubleshootingDisableHardwareAccelerationOptions,
SetDesktopTroubleshootingDisableModuleUpdatesOptions,
SpellcheckBundledDictionary,
SpellcheckEngine,
SpellcheckResolvedEngineInfo,
@@ -261,6 +262,9 @@ export interface ElectronAPI {
setDesktopDisableHardwareAcceleration: (
options: SetDesktopTroubleshootingDisableHardwareAccelerationOptions,
) => Promise<DesktopTroubleshootingSettings>;
setDesktopDisableModuleUpdates: (
options: SetDesktopTroubleshootingDisableModuleUpdatesOptions,
) => Promise<DesktopTroubleshootingSettings>;
onUpdaterEvent: (callback: (event: UpdaterEvent) => void) => () => void;
updaterCheck: (context: UpdaterContext) => Promise<void>;
windowMinimize: () => void;
+6 -3
View File
@@ -159,7 +159,8 @@ async function runModuleBootstrap(): Promise<void> {
const {configureUserDataPath} = await import('@electron/common/UserDataPath');
const {armNativeProbeCache} = await import('@electron/main/NativeProbeCache');
const {isStartMinimizedLaunch} = await import('@electron/main/AutostartLaunch');
const {areModuleUpdatesDisabled, isDesktopUpdateRequested} = await import('@electron/main/LaunchOptions');
const {areModuleUpdatesDisabled} = await import('@electron/main/DesktopDebugInfo');
const {isDesktopUpdateRequested, shouldDisableModuleUpdatesForLaunch} = await import('@electron/main/LaunchOptions');
const {relaunchStableLaunchPath} = await import('@electron/main/LinuxLaunchPath');
const {getDesktopLocalAppProtocol} = await import('@electron/main/LocalAppProtocol');
const {
@@ -410,9 +411,10 @@ async function runModuleBootstrap(): Promise<void> {
logger.warn('Failed to record whether an update is waiting', error);
}
};
const moduleUpdatesForcedOff = shouldDisableModuleUpdatesForLaunch();
const moduleUpdatesDisabled = areModuleUpdatesDisabled();
if (moduleUpdatesDisabled) {
logger.info('Module updates are disabled by FLUXER_DISABLE_MODULE_UPDATES');
logger.info('Module updates are disabled for this launch');
}
const updater = new ModuleUpdater({
store,
@@ -421,7 +423,8 @@ async function runModuleBootstrap(): Promise<void> {
bundledRendererVersion: BUNDLED_RENDERER_VERSION,
preferUnversionedBundle: app.isPackaged,
forceStartupUpdate: store.shellVersionChanged || updateWasPending || isDesktopUpdateRequested(),
moduleUpdatesDisabled,
moduleUpdatesDisabled: moduleUpdatesForcedOff,
moduleUpdatesDisabledBySetting: moduleUpdatesDisabled && !moduleUpdatesForcedOff,
selfUpdateShellFirst:
shellUpdatePlan.capability === ShellUpdateCapability.SELF_UPDATE
? async (latestVersion) => {
@@ -275,26 +275,3 @@ describe('Bootstrap entry point', () => {
);
});
});
describe('FLUXER_DISABLE_MODULE_UPDATES', () => {
test('reads the environment variable like the other FLUXER_DISABLE switches', async () => {
const {areModuleUpdatesDisabled} = await import('./LaunchOptions.ts');
const previous = process.env.FLUXER_DISABLE_MODULE_UPDATES;
try {
delete process.env.FLUXER_DISABLE_MODULE_UPDATES;
assert.equal(areModuleUpdatesDisabled(), false);
for (const value of ['1', 'true', 'YES', 'on']) {
process.env.FLUXER_DISABLE_MODULE_UPDATES = value;
assert.equal(areModuleUpdatesDisabled(), true);
}
process.env.FLUXER_DISABLE_MODULE_UPDATES = '0';
assert.equal(areModuleUpdatesDisabled(), false);
} finally {
if (previous === undefined) {
delete process.env.FLUXER_DISABLE_MODULE_UPDATES;
} else {
process.env.FLUXER_DISABLE_MODULE_UPDATES = previous;
}
}
});
});
+12 -2
View File
@@ -12,7 +12,12 @@ import {
readDesktopAccountStoreTelemetry,
} from '@electron/main/DesktopAccountStoreTelemetry';
import {type DesktopAppStoreState, readDesktopAppStoreState} from '@electron/main/DesktopAppStoreHealth';
import {getArgValue, hasFlag, isSafeModeLaunch} from '@electron/main/LaunchOptions';
import {
getArgValue,
hasFlag,
isSafeModeLaunch,
shouldDisableModuleUpdatesForLaunch,
} from '@electron/main/LaunchOptions';
import {getDesktopInfo} from '@electron/main/PlatformInfo';
import {
formatDesktopOsName,
@@ -86,6 +91,7 @@ export function resolveEffectiveDesktopTroubleshootingSettings(
disableHardwareAcceleration:
platform !== 'darwin' &&
(settings.disableHardwareAcceleration || shouldDisableHardwareAccelerationForLaunch(argv)),
disableModuleUpdates: settings.disableModuleUpdates || shouldDisableModuleUpdatesForLaunch(argv),
};
}
@@ -100,6 +106,10 @@ export function getLaunchDesktopTroubleshootingSettings(): DesktopTroubleshootin
return launchTroubleshootingSettings;
}
export function areModuleUpdatesDisabled(): boolean {
return getLaunchDesktopTroubleshootingSettings().disableModuleUpdates;
}
export function shouldOpenDevToolsOnLaunch(argv: ReadonlyArray<string>): boolean {
return hasFlag(argv, OPEN_DEVTOOLS_ARGS);
}
@@ -265,7 +275,7 @@ export function formatDesktopDebugInfo(info: DesktopDebugInfo): string {
`Account store: ${formatAccountStoreState(info.accountStore)}`,
`Account store telemetry: ${formatDesktopAccountStoreTelemetry(info.accountStoreTelemetry)}`,
`Logs: ${info.logFilePath ?? info.logsPath ?? '(unavailable)'}`,
`Troubleshooting: disableHardwareAcceleration=${info.troubleshooting.disableHardwareAcceleration}`,
`Troubleshooting: disableHardwareAcceleration=${info.troubleshooting.disableHardwareAcceleration}, disableModuleUpdates=${info.troubleshooting.disableModuleUpdates}`,
`Window behavior: ${formatWindowBehavior(info.windowBehavior)}`,
`Runtime: packaged=${info.packaged}, portable=${info.portable}, pid=${info.pid}, cwd=${info.cwd}`,
`Sandbox: flatpak=${info.desktopInfo.flatpak}, flatpakAppId=${info.desktopInfo.flatpakAppId ?? '(none)'}`,
+1 -1
View File
@@ -11,9 +11,9 @@ import type {
TrayActionPayload,
TrayRuntimeStatePayload,
} from '@electron/common/Types';
import {areModuleUpdatesDisabled} from '@electron/main/DesktopDebugInfo';
import {getDesktopUpdateState, observeDesktopUpdateState} from '@electron/main/DesktopUpdateGate';
import {checkForUpdatesFromShell, startDesktopUpdateFromShell} from '@electron/main/DesktopUpdatePrompt';
import {areModuleUpdatesDisabled} from '@electron/main/LaunchOptions';
import {relaunchStableLaunchPath} from '@electron/main/LinuxLaunchPath';
import {onLocaleChange, t} from '@electron/main/MainI18n';
import {renderTrayIcon, resolveTrayIconAppearance} from '@electron/main/TrayIconImage';
@@ -19,7 +19,8 @@ globalThis.__fluxerDesktopTrayIconTestSettings__ = settings;
installTestModuleStub(
'@electron/common/DesktopConfig',
'export const getDesktopWindowBehaviorSettings = () => ({...globalThis.__fluxerDesktopTrayIconTestSettings__});',
`export const getDesktopWindowBehaviorSettings = () => ({...globalThis.__fluxerDesktopTrayIconTestSettings__});
export const getDesktopTroubleshootingSettings = () => ({disableHardwareAcceleration: false, disableModuleUpdates: false});`,
);
installTestModuleStub(
'@electron/main/DesktopUpdatePrompt',
+8
View File
@@ -73,6 +73,7 @@ import {
relaunchAndExit,
setHardwareAccelerationDisabled,
setHardwareAccelerationDisabledAndRestart,
setModuleUpdatesDisabledAndRestart,
} from '@electron/main/Troubleshooting';
import {parseUnreadBadge, UNREAD_BADGE_DOT} from '@electron/main/UnreadBadge';
import {registerVoiceBackgroundMediaCacheHandlers} from '@electron/main/VoiceBackgroundMediaCache';
@@ -243,6 +244,13 @@ export function registerIpcHandlers(): void {
return getLaunchDesktopTroubleshootingSettings();
},
);
ipcMain.handle(
'desktop-troubleshooting-set-disable-module-updates',
(_event, payload: {disable: boolean}): DesktopTroubleshootingSettings => {
setModuleUpdatesDisabledAndRestart(Boolean(payload?.disable));
return getLaunchDesktopTroubleshootingSettings();
},
);
ipcMain.on('streaming-priority-acquire', (event) => {
acquireStreamingPriority(event.sender);
});
+4 -3
View File
@@ -24,6 +24,7 @@ const SPELLCHECK_MODE_ARGS = new Set(['--fluxer-spellcheck']);
const DISABLE_V8_CODE_CACHE_ARGS = new Set(['--fluxer-disable-v8-code-cache']);
const DISABLE_NATIVE_GATEWAY_ARGS = new Set(['--fluxer-disable-native-gateway']);
const DESKTOP_UPDATE_ARGS = new Set(['--fluxer-update']);
const DISABLE_MODULE_UPDATES_ARGS = new Set(['--fluxer-disable-module-updates', '--disable-module-updates']);
export function hasFlag(argv: ReadonlyArray<string>, flags: ReadonlySet<string>): boolean {
return argv.some((arg) => flags.has(arg) || [...flags].some((flag) => arg.startsWith(`${flag}=`)));
@@ -159,12 +160,12 @@ export function describeLaunchDiagnosticOptions(argv: ReadonlyArray<string> = pr
spellcheck: getSpellcheckLaunchMode(argv),
v8CodeCacheDisabled: shouldDisableV8CodeCache(argv),
nativeGatewayDisableReason: getNativeGatewayDisableReason(argv),
moduleUpdatesDisabled: areModuleUpdatesDisabled(),
moduleUpdatesDisabled: shouldDisableModuleUpdatesForLaunch(argv),
};
}
export function areModuleUpdatesDisabled(): boolean {
return truthyEnv('FLUXER_DISABLE_MODULE_UPDATES');
export function shouldDisableModuleUpdatesForLaunch(argv: ReadonlyArray<string> = process.argv): boolean {
return hasFlag(argv, DISABLE_MODULE_UPDATES_ARGS) || truthyEnv('FLUXER_DISABLE_MODULE_UPDATES');
}
export function isDesktopUpdateRequested(argv: ReadonlyArray<string> = process.argv): boolean {
+1 -1
View File
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {DESKTOP_APP_NAME} from '@electron/common/DesktopIdentity';
import {areModuleUpdatesDisabled} from '@electron/main/DesktopDebugInfo';
import {checkForUpdatesFromShell} from '@electron/main/DesktopUpdatePrompt';
import {areModuleUpdatesDisabled} from '@electron/main/LaunchOptions';
import {onLocaleChange, t} from '@electron/main/MainI18n';
import {openExternalDeduped} from '@electron/main/OpenExternal';
import {buildTroubleshootingMenuItems} from '@electron/main/Troubleshooting';
@@ -128,6 +128,7 @@ function createUpdater(store, modules, options = {}) {
bundledRendererVersion: options.bundledRendererVersion ?? null,
forceStartupUpdate: options.forceStartupUpdate ?? false,
moduleUpdatesDisabled: options.moduleUpdatesDisabled ?? false,
moduleUpdatesDisabledBySetting: options.moduleUpdatesDisabledBySetting ?? false,
selfUpdateShellFirst: options.selfUpdateShellFirst,
onState: options.onState,
fetch: async (url, init) => {
@@ -574,6 +575,41 @@ describe('ModuleUpdater with module updates disabled', () => {
assert.deepEqual(requests, []);
assert.deepEqual(sleeps, []);
});
test('the saved setting launches the verified set without fetching', async () => {
const userDataPath = createUserData();
const store = await openStore(userDataPath);
installModuleOnDisk(getModuleStoreRoot(userDataPath), 'fluxer_renderer', RENDERER_SHA, [['index.js', 'renderer']]);
await store.commit({fluxer_renderer: RENDERER_SHA});
assert.equal((await createUpdater(store, {fluxer_renderer: RENDERER_SHA}).updater.run()).status, 'launching');
const {updater, requests} = createUpdater(
store,
{fluxer_renderer: NEXT_RENDERER_SHA},
{moduleUpdatesDisabledBySetting: true},
);
const outcome = await updater.run();
assert.equal(outcome.status, 'unreachable-launch');
assert.deepEqual(outcome.committed, {fluxer_renderer: RENDERER_SHA});
assert.deepEqual(requests, []);
});
test('the saved setting goes to the update server when nothing can launch', async () => {
const store = await openStore(createUserData());
const {updater, requests} = createUpdater(
store,
{fluxer_renderer: RENDERER_SHA},
{moduleUpdatesDisabledBySetting: true, respond: missingPackages()},
);
const outcome = await updater.run();
assert.equal(outcome.status, 'blocked-update-required');
assert.equal(outcome.reason, 'required-module-unavailable');
assert.equal(outcome.updateServerUnreachable, false);
assert.ok(requests.some((url) => String(url).endsWith('/modules.json')));
});
});
describe('ModuleUpdater checks without downloading and installs only when asked', () => {
+9 -7
View File
@@ -268,6 +268,7 @@ interface ModuleUpdaterOptions {
readonly preferUnversionedBundle?: boolean;
readonly forceStartupUpdate?: boolean;
readonly moduleUpdatesDisabled?: boolean;
readonly moduleUpdatesDisabledBySetting?: boolean;
readonly selfUpdateShellFirst?: (latestVersion: string) => Promise<{readonly reason: string}>;
readonly onState?: (state: ModuleUpdaterSplashState) => void;
readonly report?: (report: ModuleUpdaterReport) => void;
@@ -288,6 +289,7 @@ export class ModuleUpdater {
private readonly hasOfflineRenderer: boolean;
private readonly forceStartupUpdate: boolean;
private readonly moduleUpdatesDisabled: boolean;
private readonly moduleUpdatesDisabledBySetting: boolean;
private readonly selfUpdateShellFirst: ((latestVersion: string) => Promise<{readonly reason: string}>) | null;
private readonly shellFirstAttempts = new Map<string, {readonly reason: string} | null>();
private readonly manifestFeed: ModuleManifestFeedIdentity;
@@ -317,6 +319,7 @@ export class ModuleUpdater {
this.hasOfflineRenderer = options.hasOfflineRenderer ?? false;
this.forceStartupUpdate = options.forceStartupUpdate ?? false;
this.moduleUpdatesDisabled = options.moduleUpdatesDisabled ?? false;
this.moduleUpdatesDisabledBySetting = options.moduleUpdatesDisabledBySetting ?? false;
this.selfUpdateShellFirst = options.selfUpdateShellFirst ?? null;
const releaseChannel = options.releaseChannel ?? BUILD_CHANNEL;
this.platform = options.platform ?? process.platform;
@@ -421,17 +424,16 @@ export class ModuleUpdater {
return reverted;
}
}
if (this.moduleUpdatesDisabled) {
if (this.moduleUpdatesDisabled || this.moduleUpdatesDisabledBySetting) {
const decision = await this.planner.evaluateUnreachableLaunch(this.startupUpdateEnforced);
if (decision.kind === ModuleUnreachableLaunchDecision.LAUNCH) {
return await this.launchUnreachable();
}
return this.blockUpdateRequired(
decision.reason,
[],
'module updates are disabled by FLUXER_DISABLE_MODULE_UPDATES',
{updateServerUnreachable: true},
);
if (this.moduleUpdatesDisabled) {
return this.blockUpdateRequired(decision.reason, [], 'module updates are disabled', {
updateServerUnreachable: true,
});
}
}
if (this.platform === 'linux' && !(await this.startupUpdateRequired())) {
return await this.launchIfAtFloor();
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import assert from 'node:assert/strict';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import {describe, test} from 'node:test';
import {installElectronStub} from './LocalAppTestSupport.test.mjs';
installElectronStub();
const {getDesktopTroubleshootingSettings, loadDesktopConfig, setDesktopTroubleshootingSettings} = await import(
'../common/DesktopConfig.ts'
);
const {shouldDisableModuleUpdatesForLaunch} = await import('./LaunchOptions.ts');
const {areModuleUpdatesDisabled, resolveEffectiveDesktopTroubleshootingSettings} = await import(
'./DesktopDebugInfo.ts'
);
function loadSettings(troubleshooting) {
const userDataPath = fs.mkdtempSync(path.join(os.tmpdir(), 'fluxer-desktop-module-updates-setting-test-'));
fs.writeFileSync(path.join(userDataPath, 'settings.json'), JSON.stringify({troubleshooting}));
loadDesktopConfig(userDataPath);
return userDataPath;
}
function readPersisted(userDataPath) {
return JSON.parse(fs.readFileSync(path.join(userDataPath, 'settings.json'), 'utf8')).troubleshooting;
}
function withModuleUpdatesEnv(value, run) {
const previous = process.env.FLUXER_DISABLE_MODULE_UPDATES;
try {
if (value === undefined) {
delete process.env.FLUXER_DISABLE_MODULE_UPDATES;
} else {
process.env.FLUXER_DISABLE_MODULE_UPDATES = value;
}
run();
} finally {
if (previous === undefined) {
delete process.env.FLUXER_DISABLE_MODULE_UPDATES;
} else {
process.env.FLUXER_DISABLE_MODULE_UPDATES = previous;
}
}
}
describe('disabling module updates', () => {
test('reads the environment variable like the other FLUXER_DISABLE switches', () => {
withModuleUpdatesEnv(undefined, () => assert.equal(shouldDisableModuleUpdatesForLaunch([]), false));
for (const value of ['1', 'true', 'YES', 'on']) {
withModuleUpdatesEnv(value, () => assert.equal(shouldDisableModuleUpdatesForLaunch([]), true, value));
}
withModuleUpdatesEnv('0', () => assert.equal(shouldDisableModuleUpdatesForLaunch([]), false));
});
test('honours the launch flag with or without the fluxer prefix', () => {
withModuleUpdatesEnv(undefined, () => {
for (const flag of [
'--disable-module-updates',
'--fluxer-disable-module-updates',
'--disable-module-updates=1',
]) {
assert.equal(shouldDisableModuleUpdatesForLaunch([flag]), true, flag);
}
assert.equal(shouldDisableModuleUpdatesForLaunch(['--fluxer-update']), false);
});
});
test('defaults to updating and drops values that are not booleans', () => {
loadSettings(undefined);
assert.equal(getDesktopTroubleshootingSettings().disableModuleUpdates, false);
for (const value of ['true', 1, null, {}]) {
loadSettings({disableModuleUpdates: value});
assert.equal(getDesktopTroubleshootingSettings().disableModuleUpdates, false, String(value));
}
});
test('the launch flag or the persisted setting disables updates for the launch', () => {
withModuleUpdatesEnv(undefined, () => {
const settings = {disableHardwareAcceleration: false, disableModuleUpdates: false};
assert.equal(resolveEffectiveDesktopTroubleshootingSettings(settings, [], 'win32').disableModuleUpdates, false);
assert.equal(
resolveEffectiveDesktopTroubleshootingSettings(settings, ['--disable-module-updates'], 'darwin')
.disableModuleUpdates,
true,
);
assert.equal(
resolveEffectiveDesktopTroubleshootingSettings({...settings, disableModuleUpdates: true}, [], 'linux')
.disableModuleUpdates,
true,
);
});
});
test('turning the setting back off restores updating without touching hardware acceleration', () => {
const userDataPath = loadSettings({disableHardwareAcceleration: true, disableModuleUpdates: true});
assert.equal(getDesktopTroubleshootingSettings().disableModuleUpdates, true);
setDesktopTroubleshootingSettings({disableModuleUpdates: false});
assert.deepEqual(readPersisted(userDataPath), {disableHardwareAcceleration: true, disableModuleUpdates: false});
loadDesktopConfig(userDataPath);
withModuleUpdatesEnv(undefined, () => {
assert.equal(
resolveEffectiveDesktopTroubleshootingSettings(getDesktopTroubleshootingSettings(), [], 'win32')
.disableModuleUpdates,
false,
);
});
});
test('keeps the launch answer when the persisted setting changes without a restart', () => {
withModuleUpdatesEnv(undefined, () => {
loadSettings({disableModuleUpdates: true});
assert.equal(areModuleUpdatesDisabled(), true);
setDesktopTroubleshootingSettings({disableModuleUpdates: false});
assert.equal(areModuleUpdatesDisabled(), true);
});
});
});
@@ -44,6 +44,12 @@ export function setHardwareAccelerationDisabledAndRestart(disable: boolean): voi
relaunchAndExit();
}
export function setModuleUpdatesDisabledAndRestart(disable: boolean): void {
setDesktopTroubleshootingSettings({disableModuleUpdates: disable});
logger.info('Restarting to apply module updates change', {disable});
relaunchAndExit();
}
function reloadMainWindow(): void {
const mainWindow = getMainWindow();
if (!mainWindow || mainWindow.isDestroyed()) {
+2 -1
View File
@@ -49,6 +49,7 @@ import {
recordDesktopAppStoreSuccess,
} from '@electron/main/DesktopAppStoreHealth';
import {
areModuleUpdatesDisabled,
formatDesktopDebugInfo,
getDesktopDebugInfo,
getLaunchNetLogPath,
@@ -73,7 +74,7 @@ import {
registerIpcHandlers,
} from '@electron/main/IpcHandlers';
import {initializeJumpList} from '@electron/main/JumpList';
import {areModuleUpdatesDisabled, describeLaunchDiagnosticOptions} from '@electron/main/LaunchOptions';
import {describeLaunchDiagnosticOptions} from '@electron/main/LaunchOptions';
import {cleanupLegacyHarvestHandlers, registerLegacyHarvestHandlers} from '@electron/main/LegacyHarvestIpc';
import {initializeLegacyOriginHarvest} from '@electron/main/LegacyOriginHarvest';
import {cleanupVirtmic, registerVirtmicHandlers} from '@electron/main/LinuxAudioCapture';
+5
View File
@@ -45,6 +45,7 @@ import type {
NotificationOptions,
NotificationResult,
SetDesktopTroubleshootingDisableHardwareAccelerationOptions,
SetDesktopTroubleshootingDisableModuleUpdatesOptions,
SpellcheckBundledDictionary,
SpellcheckResolvedEngineInfo,
SpellcheckState,
@@ -443,6 +444,10 @@ const api: ElectronAPI = {
options: SetDesktopTroubleshootingDisableHardwareAccelerationOptions,
): Promise<DesktopTroubleshootingSettings> =>
ipcRenderer.invoke('desktop-troubleshooting-set-disable-hardware-acceleration', options),
setDesktopDisableModuleUpdates: (
options: SetDesktopTroubleshootingDisableModuleUpdatesOptions,
): Promise<DesktopTroubleshootingSettings> =>
ipcRenderer.invoke('desktop-troubleshooting-set-disable-module-updates', options),
onUpdaterEvent: (callback: (event: UpdaterEvent) => void): (() => void) => {
const handler = (_event: Electron.IpcRendererEvent, data: UpdaterEvent) => callback(data);
ipcRenderer.on('updater-event', handler);