@todesktop/runtime
Advanced tools
Comparing version 0.1.2 to 0.2.0-0
import { EventEmitter2 } from "eventemitter2"; | ||
import { LoggerInterface } from "./Logger"; | ||
import { UpdateInfo } from "./updaterAgents"; | ||
export declare type AutoUpdaterConstructorOptions = { | ||
readonly autoCheckInterval?: number; | ||
readonly logger: LoggerInterface; | ||
readonly shouldAutoCheckOnLaunch?: boolean; | ||
readonly autoCheckInterval?: number; | ||
readonly shouldNotify?: boolean; | ||
@@ -25,3 +27,3 @@ }; | ||
constructor({ autoCheckInterval, // 10 min | ||
shouldAutoCheckOnLaunch, shouldNotify, }?: AutoUpdaterConstructorOptions); | ||
logger, shouldAutoCheckOnLaunch, shouldNotify, }: AutoUpdaterConstructorOptions); | ||
checkForUpdates({ source, }?: { | ||
@@ -28,0 +30,0 @@ source?: Source; |
@@ -15,3 +15,3 @@ "use strict"; | ||
}; | ||
var _createdAt, _hasAppFinishedLaunching, _hasNotified, _hasUpdateReadyToInstall, _isActive, _pendingCheckSources, _pendingUpdateCheckPromise, _shouldNotify, _updaterAgent; | ||
var _createdAt, _hasAppFinishedLaunching, _hasNotified, _hasUpdateReadyToInstall, _isActive, _logger, _pendingCheckSources, _pendingUpdateCheckPromise, _shouldNotify, _updaterAgent; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -26,3 +26,2 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-ignore | ||
const getConfig_1 = require("./getConfig"); | ||
const logger_1 = require("./logger"); | ||
const setTimeout_1 = require("./setTimeout"); | ||
@@ -38,3 +37,3 @@ const updaterAgents_1 = require("./updaterAgents"); | ||
constructor({ autoCheckInterval = 10 * 60 * 1000, // 10 min | ||
shouldAutoCheckOnLaunch = true, shouldNotify = true, } = {}) { | ||
logger, shouldAutoCheckOnLaunch = true, shouldNotify = true, }) { | ||
super(); | ||
@@ -46,2 +45,3 @@ _createdAt.set(this, Date.now()); | ||
_isActive.set(this, electron.app.isPackaged); | ||
_logger.set(this, void 0); | ||
_pendingCheckSources.set(this, []); | ||
@@ -51,2 +51,3 @@ _pendingUpdateCheckPromise.set(this, void 0); | ||
_updaterAgent.set(this, void 0); | ||
__classPrivateFieldSet(this, _logger, logger); | ||
__classPrivateFieldSet(this, _shouldNotify, shouldNotify); | ||
@@ -57,5 +58,8 @@ if (__classPrivateFieldGet(this, _isActive)) { | ||
else { | ||
console.log("@todesktop/runtime: skipping autoUpdater initialization because application is not packed."); | ||
const message = "@todesktop/runtime: skipping autoUpdater initialization because application is not packed."; | ||
console.log(message); | ||
this._log("info", message); | ||
} | ||
electron.app.on("will-finish-launching", () => { | ||
this._log("debug", "electron will-finish-launching event emitted"); | ||
__classPrivateFieldSet(this, _hasAppFinishedLaunching, true); | ||
@@ -75,4 +79,7 @@ if (!__classPrivateFieldGet(this, _isActive)) { | ||
async checkForUpdates({ source = BuiltInSources.programmaticCall, } = {}) { | ||
this._log("info", ".checkForUpdates called"); | ||
if (!__classPrivateFieldGet(this, _hasAppFinishedLaunching)) { | ||
throw new Error("Cannot checkForUpdates before app is ready (see https://www.electronjs.org/docs/api/app#event-ready)"); | ||
const error = new Error("Cannot checkForUpdates before app is ready (see https://www.electronjs.org/docs/api/app#event-ready)"); | ||
this._log("error", error); | ||
throw error; | ||
} | ||
@@ -87,9 +94,13 @@ if (!__classPrivateFieldGet(this, _isActive)) { | ||
restartAndInstall() { | ||
this._log("info", ".restartAndInstall called"); | ||
if (!__classPrivateFieldGet(this, _hasUpdateReadyToInstall)) { | ||
throw new Error("Cannot restart and install. There is no update downloaded"); | ||
const error = new Error("Cannot restart and install. There is no update downloaded"); | ||
this._log("error", error); | ||
throw error; | ||
} | ||
this._log("debug", "Calling electron-updater's .quitAndInstall"); | ||
__classPrivateFieldGet(this, _updaterAgent).restartAndInstall(); | ||
} | ||
async _actuallyPerformCheck() { | ||
this._log("_actuallyPerformCheck called"); | ||
this._log("debug", "_actuallyPerformCheck called"); | ||
let updateInfo; | ||
@@ -100,2 +111,3 @@ try { | ||
catch (e) { | ||
this._log("debug", "Error during check & download; resetting this.hasUpdateReadyToInstall to be safe"); | ||
// When there's an error during the download, electron-updater wipes its temp directory | ||
@@ -105,3 +117,2 @@ __classPrivateFieldSet(this, _hasUpdateReadyToInstall, false); | ||
} | ||
this._log("autoUpdater.checkForUpdates complete"); | ||
// Reset the collected sources | ||
@@ -114,2 +125,3 @@ const previouslyPendingCheckSources = [ | ||
if (!updateInfo) { | ||
this._log("debug", "No update available"); | ||
// To be safe | ||
@@ -121,2 +133,3 @@ __classPrivateFieldSet(this, _hasUpdateReadyToInstall, false); | ||
} | ||
this._log("debug", "Update available", updateInfo); | ||
__classPrivateFieldSet(this, _hasUpdateReadyToInstall, true); | ||
@@ -128,2 +141,3 @@ // Emit the event | ||
}; | ||
this._log("debug", "Emitting update-downloaded event"); | ||
const emitPromise = this.emitAsync("update-downloaded", eventPayload); | ||
@@ -157,8 +171,8 @@ /* | ||
setTimeout_1.default(() => { | ||
this._log("before notify call in setTimeout"); | ||
this._log("debug", "before notify call in setTimeout"); | ||
notify(); | ||
}, 500); | ||
emitPromise | ||
.catch(() => { | ||
this._log("emitPromise.catch called"); | ||
.catch((e) => { | ||
this._log("debug", "event callback errored", e); | ||
// Ignore the error but immediately continue with the default behaviour | ||
@@ -173,3 +187,3 @@ notify(); | ||
} | ||
this._log("calling notify after event listener Promise settled"); | ||
this._log("debug", "calling notify after event listener Promise settled"); | ||
// This won't do anything if they took too long to respond | ||
@@ -183,4 +197,4 @@ notify(); | ||
__classPrivateFieldSet(this, _pendingCheckSources, []); | ||
emitPromise.catch(() => { | ||
this._log("emitPromise.catch called"); | ||
emitPromise.catch((e) => { | ||
this._log("debug", "event callback errored", e); | ||
// ignore | ||
@@ -194,3 +208,3 @@ }); | ||
const checkAfterTimeout = () => { | ||
this._log("checkAfterTimeout"); | ||
this._log("debug", "checking for update on interval"); | ||
setTimeout_1.default(async () => { | ||
@@ -204,2 +218,3 @@ try { | ||
catch (e) { | ||
this._log("error", e); | ||
// Ignore and continute to check on interval | ||
@@ -213,2 +228,3 @@ checkAfterTimeout(); | ||
async _autoCheckOnLaunch() { | ||
this._log("debug", "checking for update on launch"); | ||
try { | ||
@@ -220,2 +236,3 @@ await this._check({ | ||
catch (e) { | ||
this._log("error", e); | ||
// Ignore. Auto-check on interval and programmatic API still supported | ||
@@ -233,5 +250,5 @@ } | ||
__classPrivateFieldGet(this, _pendingCheckSources).push(source); | ||
this._log("_check called", { | ||
this._log("debug", "_check called", { | ||
source, | ||
sources: __classPrivateFieldGet(this, _pendingCheckSources), | ||
pendingCheckSources: __classPrivateFieldGet(this, _pendingCheckSources), | ||
}); | ||
@@ -242,3 +259,2 @@ if (__classPrivateFieldGet(this, _pendingUpdateCheckPromise)) { | ||
const onEnd = () => { | ||
this._log("onEnd called"); | ||
__classPrivateFieldSet(this, _pendingUpdateCheckPromise, null); | ||
@@ -274,21 +290,20 @@ }; | ||
fs.existsSync(path.join(electron.app.getAppPath(), "../Update.exe"))) { | ||
this._log("Setting up SquirrelWindowsUpdaterAgent"); | ||
this._log("debug", "Setting up SquirrelWindowsUpdaterAgent"); | ||
__classPrivateFieldSet(this, _updaterAgent, new updaterAgents_1.SquirrelWindowsUpdaterAgent({ | ||
log: (...args) => { | ||
this._log("SquirrelWindowsUpdaterAgent:", ...args); | ||
log: (level, ...args) => { | ||
this._log(level, "SquirrelWindowsUpdaterAgent:", ...args); | ||
}, | ||
logger: __classPrivateFieldGet(this, _logger), | ||
})); | ||
return; | ||
} | ||
this._log("Setting up UpdaterAgent"); | ||
this._log("debug", "Setting up UpdaterAgent"); | ||
__classPrivateFieldSet(this, _updaterAgent, new updaterAgents_1.UpdaterAgent({ | ||
log: (...args) => { | ||
this._log("UpdaterAgent:", ...args); | ||
log: (level, ...args) => { | ||
this._log(level, "UpdaterAgent:", ...args); | ||
}, | ||
logger: __classPrivateFieldGet(this, _logger), | ||
})); | ||
} | ||
_log(...args) { | ||
if (!logger_1.default) { | ||
return; | ||
} | ||
_log(level, ...args) { | ||
let timeSinceCreatedAt; | ||
@@ -302,3 +317,3 @@ // This can fail when there's a ReferenceError in a test and Date is overwritten | ||
} | ||
logger_1.default.info(`AutoUpdater (${electron.app.name})${timeSinceCreatedAt}: ` + | ||
__classPrivateFieldGet(this, _logger)[level](`AutoUpdater (${electron.app.name})${timeSinceCreatedAt}: ` + | ||
args.map((arg) => JSON.stringify(arg)).join(" ")); | ||
@@ -308,2 +323,3 @@ } | ||
electron.autoUpdater.on("before-quit-for-update", (...args) => { | ||
this._log("info", "before-quit-for-update", ...args); | ||
this.emit("before-quit-for-update", ...args); | ||
@@ -314,2 +330,2 @@ }); | ||
exports.default = AutoUpdater; | ||
_createdAt = new WeakMap(), _hasAppFinishedLaunching = new WeakMap(), _hasNotified = new WeakMap(), _hasUpdateReadyToInstall = new WeakMap(), _isActive = new WeakMap(), _pendingCheckSources = new WeakMap(), _pendingUpdateCheckPromise = new WeakMap(), _shouldNotify = new WeakMap(), _updaterAgent = new WeakMap(); | ||
_createdAt = new WeakMap(), _hasAppFinishedLaunching = new WeakMap(), _hasNotified = new WeakMap(), _hasUpdateReadyToInstall = new WeakMap(), _isActive = new WeakMap(), _logger = new WeakMap(), _pendingCheckSources = new WeakMap(), _pendingUpdateCheckPromise = new WeakMap(), _shouldNotify = new WeakMap(), _updaterAgent = new WeakMap(); |
@@ -5,7 +5,11 @@ "use strict"; | ||
const cache_1 = require("./cache"); | ||
const Logger_1 = require("./Logger"); | ||
class ToDesktop { | ||
// This initializes everything. It must be called (at the top of their main script) | ||
init({ autoUpdater = true } = {}) { | ||
init({ autoUpdater = true, logger: customLogger, } = {}) { | ||
const logger = new Logger_1.default(customLogger); | ||
if (autoUpdater) { | ||
this.autoUpdater = new AutoUpdater_1.default(); | ||
this.autoUpdater = new AutoUpdater_1.default({ | ||
logger, | ||
}); | ||
} | ||
@@ -16,2 +20,3 @@ else { | ||
autoCheckInterval: 0, | ||
logger, | ||
shouldAutoCheckOnLaunch: false, | ||
@@ -18,0 +23,0 @@ shouldNotify: false, |
@@ -1,2 +0,17 @@ | ||
declare let logger: any; | ||
export default logger; | ||
declare type LogMethod = (...args: unknown[]) => void; | ||
export interface LoggerInterface { | ||
error: LogMethod; | ||
info: LogMethod; | ||
warn: LogMethod; | ||
} | ||
export default class Logger { | ||
#private; | ||
constructor(customLogger?: LoggerInterface); | ||
debug(...args: unknown[]): void; | ||
error(...args: unknown[]): void; | ||
info(...args: unknown[]): void; | ||
warn(...args: unknown[]): void; | ||
private _initializeDiskLogger; | ||
private _log; | ||
} | ||
export {}; |
"use strict"; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) { | ||
if (!privateMap.has(receiver)) { | ||
throw new TypeError("attempted to set private field on non-instance"); | ||
} | ||
privateMap.set(receiver, value); | ||
return value; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) { | ||
if (!privateMap.has(receiver)) { | ||
throw new TypeError("attempted to get private field on non-instance"); | ||
} | ||
return privateMap.get(receiver); | ||
}; | ||
var _customLogger, _diskLogger, _shouldDebugOnCI; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Set to true to enable extra logging | ||
const shouldDebugOnCI = false; | ||
// Needs to be any because winston is only imported in dev/test | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
let logger; | ||
if (process.env.AVA_PATH && !logger) { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const winston = require("winston"); | ||
const baseTransports = [ | ||
// | ||
// - Write all logs with level `error` and below to `error.log` | ||
// - Write all logs with level `info` and below to `combined.log` | ||
// | ||
new winston.transports.File({ filename: "error.log", level: "error" }), | ||
new winston.transports.File({ filename: "combined.log" }), | ||
]; | ||
const extraTransports = []; | ||
if (process.env.CI && shouldDebugOnCI) { | ||
extraTransports.push(new winston.transports.Console({ format: winston.format.simple() })); | ||
class Logger { | ||
constructor(customLogger) { | ||
_customLogger.set(this, void 0); | ||
_diskLogger.set(this, void 0); | ||
// Set to true to enable extra logging | ||
_shouldDebugOnCI.set(this, void 0); | ||
__classPrivateFieldSet(this, _customLogger, customLogger); | ||
if (process.env.AVA_PATH) { | ||
__classPrivateFieldSet(this, _diskLogger, this._initializeDiskLogger()); | ||
} | ||
} | ||
logger = winston.createLogger({ | ||
level: "info", | ||
format: winston.format.json(), | ||
transports: [...baseTransports, ...extraTransports], | ||
}); | ||
debug(...args) { | ||
this._log("debug", ...args); | ||
} | ||
error(...args) { | ||
this._log("error", ...args); | ||
} | ||
info(...args) { | ||
this._log("info", ...args); | ||
} | ||
warn(...args) { | ||
this._log("warn", ...args); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
_initializeDiskLogger() { | ||
// Needs to be any because winston is only imported in dev/test | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const winston = require("winston"); | ||
const baseTransports = [ | ||
/* | ||
- Write all logs with level `error` and below to `error.log` | ||
- Write all logs with level `info` and below to `combined.log` | ||
*/ | ||
new winston.transports.File({ filename: "error.log", level: "error" }), | ||
new winston.transports.File({ filename: "combined.log" }), | ||
]; | ||
const extraTransports = []; | ||
if (process.env.CI && __classPrivateFieldGet(this, _shouldDebugOnCI)) { | ||
extraTransports.push(new winston.transports.Console({ format: winston.format.simple() })); | ||
} | ||
return winston.createLogger({ | ||
level: "info", | ||
format: winston.format.json(), | ||
transports: [...baseTransports, ...extraTransports], | ||
}); | ||
} | ||
_log(level, ...args) { | ||
if (__classPrivateFieldGet(this, _diskLogger)) { | ||
__classPrivateFieldGet(this, _diskLogger)[level](...args); | ||
} | ||
if (__classPrivateFieldGet(this, _customLogger) && __classPrivateFieldGet(this, _customLogger)[level]) { | ||
__classPrivateFieldGet(this, _customLogger)[level](...args); | ||
} | ||
} | ||
} | ||
exports.default = logger; | ||
exports.default = Logger; | ||
_customLogger = new WeakMap(), _diskLogger = new WeakMap(), _shouldDebugOnCI = new WeakMap(); |
import * as electronUpdater from "electron-updater"; | ||
import { LoggerInterface } from "./Logger"; | ||
export declare type UpdateInfo = { | ||
@@ -12,4 +13,5 @@ readonly releaseDate: electronUpdater.UpdateInfo["releaseDate"]; | ||
#private; | ||
constructor({ log }: { | ||
constructor({ log, logger, }: { | ||
log: (...args: unknown[]) => void; | ||
logger: LoggerInterface; | ||
}); | ||
@@ -21,4 +23,5 @@ checkAndDownload(): Promise<UpdateInfo | null>; | ||
#private; | ||
constructor({ log }: { | ||
constructor({ log, logger, }: { | ||
log: (...args: unknown[]) => void; | ||
logger: LoggerInterface; | ||
}); | ||
@@ -25,0 +28,0 @@ checkAndDownload(): Promise<UpdateInfo | null>; |
@@ -23,5 +23,7 @@ "use strict"; | ||
class UpdaterAgent { | ||
constructor({ log }) { | ||
constructor({ log, logger, }) { | ||
_log.set(this, void 0); | ||
__classPrivateFieldSet(this, _log, log); | ||
// electron-updater will use this logger (includes the user's custom one) | ||
electronUpdater.autoUpdater.logger = logger; | ||
const config = getConfig_1.default(); | ||
@@ -47,3 +49,3 @@ /* | ||
const newVersion = updateCheckResult.updateInfo.version; | ||
__classPrivateFieldGet(this, _log).call(this, "Analysing autoUpdater.checkForUpdates result", { | ||
__classPrivateFieldGet(this, _log).call(this, "debug", "Analysing autoUpdater.checkForUpdates result", { | ||
currentVersion, | ||
@@ -76,3 +78,3 @@ newVersion, | ||
class SquirrelWindowsUpdaterAgent { | ||
constructor({ log }) { | ||
constructor({ log, logger, }) { | ||
_log_1.set(this, void 0); | ||
@@ -105,3 +107,3 @@ __classPrivateFieldSet(this, _log_1, log); | ||
// @ts-ignore | ||
electron.autoUpdater.on(eventName, (...args) => __classPrivateFieldGet(this, _log_1).call(this, `autoUpdater event: ${eventName}`, ...args)); | ||
electron.autoUpdater.on(eventName, (...args) => __classPrivateFieldGet(this, _log_1).call(this, "debug", `autoUpdater event: ${eventName}`, ...args)); | ||
}); | ||
@@ -108,0 +110,0 @@ /* |
@@ -7,3 +7,3 @@ { | ||
"name": "@todesktop/runtime", | ||
"version": "0.1.2", | ||
"version": "0.2.0-0", | ||
"license": "MIT", | ||
@@ -10,0 +10,0 @@ "author": "Adam Lynch <contact@adamlynch.com> (http://adamlynch.com/)", |
@@ -74,3 +74,3 @@ # @todesktop/runtime | ||
- [`.init(options)`](#initoptions) | ||
- [`async .autoUpdater.checkForUpdates(options)`](#async-autoupdatercheckforupdatesoptions) | ||
- [`.autoUpdater.checkForUpdates(options)`](#autoupdatercheckforupdatesoptions) | ||
- [`.autoUpdater.on(eventName, callback)`](#autoupdateroneventname-callback) | ||
@@ -102,4 +102,22 @@ - [`.autoUpdater.restartAndInstall()`](#autoupdaterrestartandinstall) | ||
### `async .autoUpdater.checkForUpdates(options)` | ||
##### `options.customLogger` (Optional) | ||
Default: `undefined` | ||
To debug, you can pass a custom logger object. You can pass [electron-log](https://www.npmjs.com/package/electron-log) (recommended), [winston](https://www.npmjs.com/package/winston), or another logger with the following interface: `{ error(), info(), warn() }`. Include a `debug()` method to get even more information. | ||
Example using electron-log: | ||
```javascript | ||
const electronLog = require("electron-log"); | ||
const todesktop = require("@todesktop/runtime"); | ||
electronLog.transports.file.level = "debug"; | ||
todesktop.init({ | ||
customLogger: electronLog | ||
}); | ||
``` | ||
### `.autoUpdater.checkForUpdates(options)` | ||
This performs a check for updates and downloads it. Only call this after the application is [ready](https://www.electronjs.org/docs/api/app#event-ready). | ||
@@ -219,5 +237,9 @@ | ||
## Debugging | ||
See the [`customLogger option`](#optionscustomlogger-optional). | ||
## More documentation | ||
See https://docs.todesktop.com/cli/using-the-todesktop-cli |
42768
779
243