• Registers IPC handlers and event forwarding for auto-update operations. Manages update checking, downloading, installation, and progress events.

    Parameters

    • mainWindow: BrowserWindow

      Main application window for security validation and event forwarding.

    Returns void

    export function addUpdateEventListeners(mainWindow: BrowserWindow): void {
    // Disable automatic download and install to give renderer control
    autoUpdater.autoDownload = false;
    autoUpdater.autoInstallOnAppQuit = false;

    // Handle update channel selection: persist preference and configure prerelease flag
    secureHandle(
    "updates:set-channel",
    (_event: Electron.IpcMainInvokeEvent, channel: "stable" | "beta") => {
    try {
    store.set("update_channel", channel);
    autoUpdater.allowPrerelease = channel === "beta";
    console.info(
    `[Update Listeners] ✅ Update channel set to ${channel} (allowPrerelease=${autoUpdater.allowPrerelease})`,
    );
    return { success: true };
    } catch (err) {
    console.error(
    "[Update Listeners] ❌ Failed to set update channel:",
    err,
    );
    return { success: false, error: String(err) };
    }
    },
    mainWindow,
    );

    // Handle update check requests and return update information
    secureHandle(
    UPDATE_CHECK_CHANNEL,
    async (
    _event: Electron.IpcMainInvokeEvent,
    payload?: CheckForUpdatesPayload,
    ): Promise<{
    updateAvailable: boolean;
    version?: string;
    releaseNotes?: string;
    releaseDate?: string;
    }> => {
    return await withGroupAsync(
    "[Update Listeners] Checking for updates",
    async () => {
    try {
    // Apply prerelease preference from payload
    autoUpdater.allowPrerelease = Boolean(payload?.allowPrerelease);
    console.log(
    `[Update Listeners] allowPrerelease: ${autoUpdater.allowPrerelease}`,
    );

    const result = await autoUpdater.checkForUpdates();

    if (result?.updateInfo) {
    const updateInfo = result.updateInfo;
    const currentVersion = autoUpdater.currentVersion.version;
    const latestVersion = updateInfo.version;
    const updateAvailable = currentVersion !== latestVersion;

    console.log(
    `[Update Listeners] Current version: ${currentVersion}, Latest version: ${latestVersion}`,
    );

    return {
    updateAvailable,
    version: updateInfo.version,
    releaseNotes: normalizeReleaseNotes(
    updateInfo.releaseNotes as ReleaseNotes,
    ),
    releaseDate: updateInfo.releaseDate,
    };
    }

    return { updateAvailable: false };
    } catch (error) {
    console.error(
    "[Update Listeners] Error checking for updates:",
    error,
    );
    throw error;
    }
    },
    );
    },
    mainWindow,
    );

    // Handle update download requests
    secureHandle(
    UPDATE_DOWNLOAD_CHANNEL,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    async (_event: Electron.IpcMainInvokeEvent): Promise<void> => {
    return await withGroupAsync(
    "[Update Listeners] Starting update download",
    async () => {
    try {
    await autoUpdater.downloadUpdate();
    console.log("[Update Listeners] Update download started");
    } catch (error) {
    console.error(
    "[Update Listeners] Error downloading update:",
    error,
    );
    throw error;
    }
    },
    );
    },
    mainWindow,
    );

    // Handle update installation requests
    secureHandle(
    UPDATE_INSTALL_CHANNEL,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    async (_event: Electron.IpcMainInvokeEvent): Promise<void> => {
    return await withGroupAsync(
    "[Update Listeners] Installing update",
    async () => {
    try {
    console.log("[Update Listeners] Quitting and installing update");
    autoUpdater.quitAndInstall(false, true);
    } catch (error) {
    console.error("[Update Listeners] Error installing update:", error);
    throw error;
    }
    },
    );
    },
    mainWindow,
    );

    // Forward update-available event to renderer
    autoUpdater.on("update-available", (info: UpdateInfo) => {
    console.log("[Update Listeners] Update available:", info.version);
    mainWindow.webContents.send(UPDATE_AVAILABLE_EVENT, {
    version: info.version,
    releaseNotes: normalizeReleaseNotes(info.releaseNotes as ReleaseNotes),
    releaseDate: info.releaseDate,
    });
    });

    // Forward download-progress event to renderer with real-time updates
    autoUpdater.on("download-progress", (progress: ProgressInfo) => {
    console.log(
    `[Update Listeners] Download progress: ${Math.round(progress.percent)}%`,
    );
    mainWindow.webContents.send(UPDATE_DOWNLOAD_PROGRESS_EVENT, {
    percent: progress.percent,
    bytesPerSecond: progress.bytesPerSecond,
    transferred: progress.transferred,
    total: progress.total,
    });
    });

    // Forward update-downloaded event to renderer
    autoUpdater.on("update-downloaded", (info: UpdateInfo) => {
    console.log("[Update Listeners] Update downloaded:", info.version);
    mainWindow.webContents.send(UPDATE_DOWNLOADED_EVENT, {
    version: info.version,
    });
    });

    // Forward error event to renderer with error details
    autoUpdater.on("error", (error: Error) => {
    console.error("[Update Listeners] Update error:", error);
    mainWindow.webContents.send(UPDATE_ERROR_EVENT, {
    message: error.message,
    stack: error.stack,
    name: error.name,
    });
    });

    console.log("[Update Listeners] Update event listeners registered");
    }