"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateSourceType = void 0;
exports.updateElectronApp = updateElectronApp;
exports.makeUserNotifier = makeUserNotifier;
const ms_1 = __importDefault(require("ms"));
const github_url_to_object_1 = __importDefault(require("github-url-to-object"));
const node_assert_1 = __importDefault(require("node:assert"));
const node_fs_1 = __importDefault(require("node:fs"));
const node_os_1 = __importDefault(require("node:os"));
const node_path_1 = __importDefault(require("node:path"));
const node_util_1 = require("node:util");
const electron_1 = require("electron");
var UpdateSourceType;
(function (UpdateSourceType) {
    UpdateSourceType[UpdateSourceType["ElectronPublicUpdateService"] = 0] = "ElectronPublicUpdateService";
    UpdateSourceType[UpdateSourceType["StaticStorage"] = 1] = "StaticStorage";
})(UpdateSourceType || (exports.UpdateSourceType = UpdateSourceType = {}));
// eslint-disable-next-line @typescript-eslint/no-require-imports
const pkg = require('../package.json');
const userAgent = (0, node_util_1.format)('%s/%s (%s: %s)', pkg.name, pkg.version, node_os_1.default.platform(), node_os_1.default.arch());
const supportedPlatforms = ['darwin', 'win32'];
const isHttpsUrl = (maybeURL) => {
    try {
        const { protocol } = new URL(maybeURL);
        return protocol === 'https:';
    }
    catch (_a) {
        return false;
    }
};
function updateElectronApp(opts = {}) {
    // check for bad input early, so it will be logged during development
    const safeOpts = validateInput(opts);
    // don't attempt to update during development
    if (!electron_1.app.isPackaged) {
        const message = 'update-electron-app config looks good; aborting updates since app is in development mode';
        if (opts.logger) {
            opts.logger.log(message);
        }
        else {
            console.log(message);
        }
        return;
    }
    if (electron_1.app.isReady()) {
        initUpdater(safeOpts);
    }
    else {
        electron_1.app.on('ready', () => initUpdater(safeOpts));
    }
}
function initUpdater(opts) {
    const { updateSource, updateInterval, logger } = opts;
    // exit early on unsupported platforms, e.g. `linux`
    if (!supportedPlatforms.includes(process === null || process === void 0 ? void 0 : process.platform)) {
        log(`Electron's autoUpdater does not support the '${process.platform}' platform. Ref: https://www.electronjs.org/docs/latest/api/auto-updater#platform-notices`);
        return;
    }
    let feedURL;
    let serverType = 'default';
    switch (updateSource.type) {
        case UpdateSourceType.ElectronPublicUpdateService: {
            const formatSegment = process.windowsStore ? '/msix' : '';
            feedURL = `${updateSource.host}/${updateSource.repo}/${process.platform}-${process.arch}${formatSegment}/${electron_1.app.getVersion()}`;
            break;
        }
        case UpdateSourceType.StaticStorage: {
            feedURL = updateSource.baseUrl;
            if (process.platform === 'darwin') {
                feedURL += '/RELEASES.json';
                serverType = 'json';
            }
            break;
        }
    }
    const requestHeaders = { 'User-Agent': userAgent };
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function log(...args) {
        logger.log(...args);
    }
    log('feedURL', feedURL);
    log('requestHeaders', requestHeaders);
    electron_1.autoUpdater.setFeedURL({
        url: feedURL,
        headers: requestHeaders,
        serverType,
    });
    electron_1.autoUpdater.on('error', (err) => {
        log('updater error');
        log(err);
    });
    electron_1.autoUpdater.on('checking-for-update', () => {
        log('checking-for-update');
    });
    electron_1.autoUpdater.on('update-available', () => {
        log('update-available; downloading...');
    });
    electron_1.autoUpdater.on('update-not-available', () => {
        log('update-not-available');
    });
    if (opts.notifyUser) {
        electron_1.autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateURL) => {
            log('update-downloaded', [event, releaseNotes, releaseName, releaseDate, updateURL]);
            if (typeof opts.onNotifyUser !== 'function') {
                (0, node_assert_1.default)(opts.onNotifyUser === undefined, 'onNotifyUser option must be a callback function or undefined');
                log('update-downloaded: notifyUser is true, opening default dialog');
                opts.onNotifyUser = makeUserNotifier();
            }
            else {
                log('update-downloaded: notifyUser is true, running custom onNotifyUser callback');
            }
            opts.onNotifyUser({
                event,
                releaseNotes,
                releaseDate,
                releaseName,
                updateURL,
            });
        });
    }
    // check for updates right away and keep checking later
    electron_1.autoUpdater.checkForUpdates();
    setInterval(() => {
        electron_1.autoUpdater.checkForUpdates();
    }, (0, ms_1.default)(updateInterval));
}
/**
 * Helper function that generates a callback for use with {@link IUpdateElectronAppOptions.onNotifyUser}.
 *
 * @param dialogProps - Text to display in the dialog.
 */
function makeUserNotifier(dialogProps) {
    const defaultDialogMessages = {
        title: 'Application Update',
        detail: 'A new version has been downloaded. Restart the application to apply the updates.',
        restartButtonText: 'Restart',
        laterButtonText: 'Later',
    };
    const assignedDialog = Object.assign({}, defaultDialogMessages, dialogProps);
    return (info) => {
        const { releaseNotes, releaseName } = info;
        const { title, restartButtonText, laterButtonText, detail } = assignedDialog;
        const dialogOpts = {
            type: 'info',
            buttons: [restartButtonText, laterButtonText],
            title,
            message: process.platform === 'win32' ? releaseNotes : releaseName,
            detail,
        };
        electron_1.dialog.showMessageBox(dialogOpts).then(({ response }) => {
            if (response === 0) {
                electron_1.autoUpdater.quitAndInstall();
            }
        });
    };
}
function guessRepo() {
    var _a;
    const pkgBuf = node_fs_1.default.readFileSync(node_path_1.default.join(electron_1.app.getAppPath(), 'package.json'));
    const pkg = JSON.parse(pkgBuf.toString());
    const repoString = ((_a = pkg.repository) === null || _a === void 0 ? void 0 : _a.url) || pkg.repository;
    const repoObject = (0, github_url_to_object_1.default)(repoString);
    (0, node_assert_1.default)(repoObject, "repo not found. Add repository string to your app's package.json file");
    return `${repoObject.user}/${repoObject.repo}`;
}
function validateInput(opts) {
    var _a;
    const defaults = {
        host: 'https://update.electronjs.org',
        updateInterval: '10 minutes',
        logger: console,
        notifyUser: true,
    };
    const { host, updateInterval, logger, notifyUser, onNotifyUser } = Object.assign({}, defaults, opts);
    let updateSource = opts.updateSource;
    // Handle migration from old properties + default to update service
    if (!updateSource) {
        updateSource = {
            type: UpdateSourceType.ElectronPublicUpdateService,
            repo: opts.repo || guessRepo(),
            host,
        };
    }
    switch (updateSource.type) {
        case UpdateSourceType.ElectronPublicUpdateService: {
            (0, node_assert_1.default)((_a = updateSource.repo) === null || _a === void 0 ? void 0 : _a.includes('/'), 'repo is required and should be in the format `owner/repo`');
            if (!updateSource.host) {
                updateSource.host = host;
            }
            (0, node_assert_1.default)(updateSource.host && isHttpsUrl(updateSource.host), 'host must be a valid HTTPS URL');
            break;
        }
        case UpdateSourceType.StaticStorage: {
            (0, node_assert_1.default)(updateSource.baseUrl && isHttpsUrl(updateSource.baseUrl), 'baseUrl must be a valid HTTPS URL');
            break;
        }
    }
    (0, node_assert_1.default)(typeof updateInterval === 'string' && updateInterval.match(/^\d+/), 'updateInterval must be a human-friendly string interval like `20 minutes`');
    (0, node_assert_1.default)((0, ms_1.default)(updateInterval) >= 5 * 60 * 1000, 'updateInterval must be `5 minutes` or more');
    (0, node_assert_1.default)((0, ms_1.default)(updateInterval) < 2 ** 31, 'updateInterval must fit in a signed 32-bit integer');
    (0, node_assert_1.default)(logger && typeof logger.log, 'function');
    return { updateSource, updateInterval, logger, notifyUser, onNotifyUser };
}
//# sourceMappingURL=index.js.map