UNPKG

23.6 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.NoOpLogger = exports.AppUpdater = void 0;
7
8function _builderUtilRuntime() {
9 const data = require("builder-util-runtime");
10
11 _builderUtilRuntime = function () {
12 return data;
13 };
14
15 return data;
16}
17
18function _crypto() {
19 const data = require("crypto");
20
21 _crypto = function () {
22 return data;
23 };
24
25 return data;
26}
27
28function _electron() {
29 const data = require("electron");
30
31 _electron = function () {
32 return data;
33 };
34
35 return data;
36}
37
38function _events() {
39 const data = require("events");
40
41 _events = function () {
42 return data;
43 };
44
45 return data;
46}
47
48function _fsExtra() {
49 const data = require("fs-extra");
50
51 _fsExtra = function () {
52 return data;
53 };
54
55 return data;
56}
57
58function _jsYaml() {
59 const data = require("js-yaml");
60
61 _jsYaml = function () {
62 return data;
63 };
64
65 return data;
66}
67
68function _lazyVal() {
69 const data = require("lazy-val");
70
71 _lazyVal = function () {
72 return data;
73 };
74
75 return data;
76}
77
78var path = _interopRequireWildcard(require("path"));
79
80function _semver() {
81 const data = require("semver");
82
83 _semver = function () {
84 return data;
85 };
86
87 return data;
88}
89
90function _DownloadedUpdateHelper() {
91 const data = require("./DownloadedUpdateHelper");
92
93 _DownloadedUpdateHelper = function () {
94 return data;
95 };
96
97 return data;
98}
99
100function _ElectronAppAdapter() {
101 const data = require("./ElectronAppAdapter");
102
103 _ElectronAppAdapter = function () {
104 return data;
105 };
106
107 return data;
108}
109
110function _electronHttpExecutor() {
111 const data = require("./electronHttpExecutor");
112
113 _electronHttpExecutor = function () {
114 return data;
115 };
116
117 return data;
118}
119
120function _GenericProvider() {
121 const data = require("./providers/GenericProvider");
122
123 _GenericProvider = function () {
124 return data;
125 };
126
127 return data;
128}
129
130function _main() {
131 const data = require("./main");
132
133 _main = function () {
134 return data;
135 };
136
137 return data;
138}
139
140function _providerFactory() {
141 const data = require("./providerFactory");
142
143 _providerFactory = function () {
144 return data;
145 };
146
147 return data;
148}
149
150function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
151
152function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
153
154class AppUpdater extends _events().EventEmitter {
155 constructor(options, app) {
156 super();
157 /**
158 * Whether to automatically download an update when it is found.
159 */
160
161 this.autoDownload = true;
162 /**
163 * Whether to automatically install a downloaded update on app quit (if `quitAndInstall` was not called before).
164 *
165 * Applicable only on Windows and Linux.
166 */
167
168 this.autoInstallOnAppQuit = true;
169 /**
170 * *GitHub provider only.* Whether to allow update to pre-release versions. Defaults to `true` if application version contains prerelease components (e.g. `0.12.1-alpha.1`, here `alpha` is a prerelease component), otherwise `false`.
171 *
172 * If `true`, downgrade will be allowed (`allowDowngrade` will be set to `true`).
173 */
174
175 this.allowPrerelease = false;
176 /**
177 * *GitHub provider only.* Get all release notes (from current version to latest), not just the latest.
178 * @default false
179 */
180
181 this.fullChangelog = false;
182 /**
183 * Whether to allow version downgrade (when a user from the beta channel wants to go back to the stable channel).
184 *
185 * Taken in account only if channel differs (pre-release version component in terms of semantic versioning).
186 *
187 * @default false
188 */
189
190 this.allowDowngrade = false;
191 this._channel = null;
192 this.downloadedUpdateHelper = null;
193 /**
194 * The request headers.
195 */
196
197 this.requestHeaders = null;
198 this._logger = console; // noinspection JSUnusedGlobalSymbols
199
200 /**
201 * For type safety you can use signals, e.g. `autoUpdater.signals.updateDownloaded(() => {})` instead of `autoUpdater.on('update-available', () => {})`
202 */
203
204 this.signals = new (_main().UpdaterSignal)(this);
205 this._appUpdateConfigPath = null;
206 this.clientPromise = null;
207 this.stagingUserIdPromise = new (_lazyVal().Lazy)(() => this.getOrCreateStagingUserId()); // public, allow to read old config for anyone
208
209 /** @internal */
210
211 this.configOnDisk = new (_lazyVal().Lazy)(() => this.loadUpdateConfig());
212 this.checkForUpdatesPromise = null;
213 this.updateInfoAndProvider = null;
214 /**
215 * @private
216 * @internal
217 */
218
219 this._testOnlyOptions = null;
220 this.on("error", error => {
221 this._logger.error(`Error: ${error.stack || error.message}`);
222 });
223
224 if (app == null) {
225 this.app = new (_ElectronAppAdapter().ElectronAppAdapter)();
226 this.httpExecutor = new (_electronHttpExecutor().ElectronHttpExecutor)((authInfo, callback) => this.emit("login", authInfo, callback));
227 } else {
228 this.app = app;
229 this.httpExecutor = null;
230 }
231
232 const currentVersionString = this.app.version;
233 const currentVersion = (0, _semver().parse)(currentVersionString);
234
235 if (currentVersion == null) {
236 throw (0, _builderUtilRuntime().newError)(`App version is not a valid semver version: "${currentVersionString}"`, "ERR_UPDATER_INVALID_VERSION");
237 }
238
239 this.currentVersion = currentVersion;
240 this.allowPrerelease = hasPrereleaseComponents(currentVersion);
241
242 if (options != null) {
243 this.setFeedURL(options);
244
245 if (typeof options !== "string" && options.requestHeaders) {
246 this.requestHeaders = options.requestHeaders;
247 }
248 }
249 }
250 /**
251 * Get the update channel. Not applicable for GitHub. Doesn't return `channel` from the update configuration, only if was previously set.
252 */
253
254
255 get channel() {
256 return this._channel;
257 }
258 /**
259 * Set the update channel. Not applicable for GitHub. Overrides `channel` in the update configuration.
260 *
261 * `allowDowngrade` will be automatically set to `true`. If this behavior is not suitable for you, simple set `allowDowngrade` explicitly after.
262 */
263
264
265 set channel(value) {
266 if (this._channel != null) {
267 // noinspection SuspiciousTypeOfGuard
268 if (typeof value !== "string") {
269 throw (0, _builderUtilRuntime().newError)(`Channel must be a string, but got: ${value}`, "ERR_UPDATER_INVALID_CHANNEL");
270 } else if (value.length === 0) {
271 throw (0, _builderUtilRuntime().newError)(`Channel must be not an empty string`, "ERR_UPDATER_INVALID_CHANNEL");
272 }
273 }
274
275 this._channel = value;
276 this.allowDowngrade = true;
277 } // noinspection JSMethodCanBeStatic,JSUnusedGlobalSymbols
278
279
280 get netSession() {
281 return (0, _electronHttpExecutor().getNetSession)();
282 }
283 /**
284 * The logger. You can pass [electron-log](https://github.com/megahertz/electron-log), [winston](https://github.com/winstonjs/winston) or another logger with the following interface: `{ info(), warn(), error() }`.
285 * Set it to `null` if you would like to disable a logging feature.
286 */
287
288
289 get logger() {
290 return this._logger;
291 }
292
293 set logger(value) {
294 this._logger = value == null ? new NoOpLogger() : value;
295 } // noinspection JSUnusedGlobalSymbols
296
297 /**
298 * test only
299 * @private
300 */
301
302
303 set updateConfigPath(value) {
304 this.clientPromise = null;
305 this._appUpdateConfigPath = value;
306 this.configOnDisk = new (_lazyVal().Lazy)(() => this.loadUpdateConfig());
307 } //noinspection JSMethodCanBeStatic,JSUnusedGlobalSymbols
308
309
310 getFeedURL() {
311 return "Deprecated. Do not use it.";
312 }
313 /**
314 * Configure update provider. If value is `string`, [GenericServerOptions](/configuration/publish#genericserveroptions) will be set with value as `url`.
315 * @param options If you want to override configuration in the `app-update.yml`.
316 */
317
318
319 setFeedURL(options) {
320 const runtimeOptions = this.createProviderRuntimeOptions(); // https://github.com/electron-userland/electron-builder/issues/1105
321
322 let provider;
323
324 if (typeof options === "string") {
325 provider = new (_GenericProvider().GenericProvider)({
326 provider: "generic",
327 url: options
328 }, this, { ...runtimeOptions,
329 isUseMultipleRangeRequest: (0, _providerFactory().isUrlProbablySupportMultiRangeRequests)(options)
330 });
331 } else {
332 provider = (0, _providerFactory().createClient)(options, this, runtimeOptions);
333 }
334
335 this.clientPromise = Promise.resolve(provider);
336 }
337 /**
338 * Asks the server whether there is an update.
339 */
340
341
342 checkForUpdates() {
343 let checkForUpdatesPromise = this.checkForUpdatesPromise;
344
345 if (checkForUpdatesPromise != null) {
346 this._logger.info("Checking for update (already in progress)");
347
348 return checkForUpdatesPromise;
349 }
350
351 const nullizePromise = () => this.checkForUpdatesPromise = null;
352
353 this._logger.info("Checking for update");
354
355 checkForUpdatesPromise = this.doCheckForUpdates().then(it => {
356 nullizePromise();
357 return it;
358 }).catch(e => {
359 nullizePromise();
360 this.emit("error", e, `Cannot check for updates: ${(e.stack || e).toString()}`);
361 throw e;
362 });
363 this.checkForUpdatesPromise = checkForUpdatesPromise;
364 return checkForUpdatesPromise;
365 }
366
367 isUpdaterActive() {
368 if (!this.app.isPackaged) {
369 this._logger.info("Skip checkForUpdatesAndNotify because application is not packed");
370
371 return false;
372 }
373
374 return true;
375 } // noinspection JSUnusedGlobalSymbols
376
377
378 checkForUpdatesAndNotify(downloadNotification) {
379 if (!this.isUpdaterActive()) {
380 return Promise.resolve(null);
381 }
382
383 return this.checkForUpdates().then(it => {
384 const downloadPromise = it.downloadPromise;
385
386 if (downloadPromise == null) {
387 const debug = this._logger.debug;
388
389 if (debug != null) {
390 debug("checkForUpdatesAndNotify called, downloadPromise is null");
391 }
392
393 return it;
394 }
395
396 downloadPromise.then(() => {
397 const notificationContent = this.formatDownloadNotification(it.updateInfo.version, this.app.name, downloadNotification);
398 new (_electron().Notification)(notificationContent).show();
399 });
400 return it;
401 });
402 }
403
404 formatDownloadNotification(version, appName, downloadNotification) {
405 if (downloadNotification == null) {
406 downloadNotification = {
407 title: "A new update is ready to install",
408 body: `{appName} version {version} has been downloaded and will be automatically installed on exit`
409 };
410 }
411
412 downloadNotification = {
413 title: downloadNotification.title.replace("{appName}", appName).replace("{version}", version),
414 body: downloadNotification.body.replace("{appName}", appName).replace("{version}", version)
415 };
416 return downloadNotification;
417 }
418
419 async isStagingMatch(updateInfo) {
420 const rawStagingPercentage = updateInfo.stagingPercentage;
421 let stagingPercentage = rawStagingPercentage;
422
423 if (stagingPercentage == null) {
424 return true;
425 }
426
427 stagingPercentage = parseInt(stagingPercentage, 10);
428
429 if (isNaN(stagingPercentage)) {
430 this._logger.warn(`Staging percentage is NaN: ${rawStagingPercentage}`);
431
432 return true;
433 } // convert from user 0-100 to internal 0-1
434
435
436 stagingPercentage = stagingPercentage / 100;
437 const stagingUserId = await this.stagingUserIdPromise.value;
438
439 const val = _builderUtilRuntime().UUID.parse(stagingUserId).readUInt32BE(12);
440
441 const percentage = val / 0xFFFFFFFF;
442
443 this._logger.info(`Staging percentage: ${stagingPercentage}, percentage: ${percentage}, user id: ${stagingUserId}`);
444
445 return percentage < stagingPercentage;
446 }
447
448 computeFinalHeaders(headers) {
449 if (this.requestHeaders != null) {
450 Object.assign(headers, this.requestHeaders);
451 }
452
453 return headers;
454 }
455
456 async isUpdateAvailable(updateInfo) {
457 const latestVersion = (0, _semver().parse)(updateInfo.version);
458
459 if (latestVersion == null) {
460 throw (0, _builderUtilRuntime().newError)(`This file could not be downloaded, or the latest version (from update server) does not have a valid semver version: "${updateInfo.version}"`, "ERR_UPDATER_INVALID_VERSION");
461 }
462
463 const currentVersion = this.currentVersion;
464
465 if ((0, _semver().eq)(latestVersion, currentVersion)) {
466 return false;
467 }
468
469 const isStagingMatch = await this.isStagingMatch(updateInfo);
470
471 if (!isStagingMatch) {
472 return false;
473 } // https://github.com/electron-userland/electron-builder/pull/3111#issuecomment-405033227
474 // https://github.com/electron-userland/electron-builder/pull/3111#issuecomment-405030797
475
476
477 const isLatestVersionNewer = (0, _semver().gt)(latestVersion, currentVersion);
478 const isLatestVersionOlder = (0, _semver().lt)(latestVersion, currentVersion);
479
480 if (isLatestVersionNewer) {
481 return true;
482 }
483
484 return this.allowDowngrade && isLatestVersionOlder;
485 }
486
487 async getUpdateInfoAndProvider() {
488 await this.app.whenReady();
489
490 if (this.clientPromise == null) {
491 this.clientPromise = this.configOnDisk.value.then(it => (0, _providerFactory().createClient)(it, this, this.createProviderRuntimeOptions()));
492 }
493
494 const client = await this.clientPromise;
495 const stagingUserId = await this.stagingUserIdPromise.value;
496 client.setRequestHeaders(this.computeFinalHeaders({
497 "x-user-staging-id": stagingUserId
498 }));
499 return {
500 info: await client.getLatestVersion(),
501 provider: client
502 };
503 } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
504
505
506 createProviderRuntimeOptions() {
507 return {
508 isUseMultipleRangeRequest: true,
509 platform: this._testOnlyOptions == null ? process.platform : this._testOnlyOptions.platform,
510 executor: this.httpExecutor
511 };
512 }
513
514 async doCheckForUpdates() {
515 this.emit("checking-for-update");
516 const result = await this.getUpdateInfoAndProvider();
517 const updateInfo = result.info;
518
519 if (!(await this.isUpdateAvailable(updateInfo))) {
520 this._logger.info(`Update for version ${this.currentVersion} is not available (latest version: ${updateInfo.version}, downgrade is ${this.allowDowngrade ? "allowed" : "disallowed"}).`);
521
522 this.emit("update-not-available", updateInfo);
523 return {
524 versionInfo: updateInfo,
525 updateInfo
526 };
527 }
528
529 this.updateInfoAndProvider = result;
530 this.onUpdateAvailable(updateInfo);
531 const cancellationToken = new (_builderUtilRuntime().CancellationToken)(); //noinspection ES6MissingAwait
532
533 return {
534 versionInfo: updateInfo,
535 updateInfo,
536 cancellationToken,
537 downloadPromise: this.autoDownload ? this.downloadUpdate(cancellationToken) : null
538 };
539 }
540
541 onUpdateAvailable(updateInfo) {
542 this._logger.info(`Found version ${updateInfo.version} (url: ${(0, _builderUtilRuntime().asArray)(updateInfo.files).map(it => it.url).join(", ")})`);
543
544 this.emit("update-available", updateInfo);
545 }
546 /**
547 * Start downloading update manually. You can use this method if `autoDownload` option is set to `false`.
548 * @returns {Promise<string>} Path to downloaded file.
549 */
550
551
552 downloadUpdate(cancellationToken = new (_builderUtilRuntime().CancellationToken)()) {
553 const updateInfoAndProvider = this.updateInfoAndProvider;
554
555 if (updateInfoAndProvider == null) {
556 const error = new Error("Please check update first");
557 this.dispatchError(error);
558 return Promise.reject(error);
559 }
560
561 this._logger.info(`Downloading update from ${(0, _builderUtilRuntime().asArray)(updateInfoAndProvider.info.files).map(it => it.url).join(", ")}`);
562
563 const errorHandler = e => {
564 // https://github.com/electron-userland/electron-builder/issues/1150#issuecomment-436891159
565 if (!(e instanceof _builderUtilRuntime().CancellationError)) {
566 try {
567 this.dispatchError(e);
568 } catch (nestedError) {
569 this._logger.warn(`Cannot dispatch error event: ${nestedError.stack || nestedError}`);
570 }
571 }
572
573 return e;
574 };
575
576 try {
577 return this.doDownloadUpdate({
578 updateInfoAndProvider,
579 requestHeaders: this.computeRequestHeaders(updateInfoAndProvider.provider),
580 cancellationToken
581 }).catch(e => {
582 throw errorHandler(e);
583 });
584 } catch (e) {
585 return Promise.reject(errorHandler(e));
586 }
587 }
588
589 dispatchError(e) {
590 this.emit("error", e, (e.stack || e).toString());
591 }
592
593 dispatchUpdateDownloaded(event) {
594 this.emit(_main().UPDATE_DOWNLOADED, event);
595 }
596
597 async loadUpdateConfig() {
598 if (this._appUpdateConfigPath == null) {
599 this._appUpdateConfigPath = this.app.appUpdateConfigPath;
600 }
601
602 return (0, _jsYaml().safeLoad)(await (0, _fsExtra().readFile)(this._appUpdateConfigPath, "utf-8"));
603 }
604
605 computeRequestHeaders(provider) {
606 const fileExtraDownloadHeaders = provider.fileExtraDownloadHeaders;
607
608 if (fileExtraDownloadHeaders != null) {
609 const requestHeaders = this.requestHeaders;
610 return requestHeaders == null ? fileExtraDownloadHeaders : { ...fileExtraDownloadHeaders,
611 ...requestHeaders
612 };
613 }
614
615 return this.computeFinalHeaders({
616 accept: "*/*"
617 });
618 }
619
620 async getOrCreateStagingUserId() {
621 const file = path.join(this.app.userDataPath, ".updaterId");
622
623 try {
624 const id = await (0, _fsExtra().readFile)(file, "utf-8");
625
626 if (_builderUtilRuntime().UUID.check(id)) {
627 return id;
628 } else {
629 this._logger.warn(`Staging user id file exists, but content was invalid: ${id}`);
630 }
631 } catch (e) {
632 if (e.code !== "ENOENT") {
633 this._logger.warn(`Couldn't read staging user ID, creating a blank one: ${e}`);
634 }
635 }
636
637 const id = _builderUtilRuntime().UUID.v5((0, _crypto().randomBytes)(4096), _builderUtilRuntime().UUID.OID);
638
639 this._logger.info(`Generated new staging user ID: ${id}`);
640
641 try {
642 await (0, _fsExtra().outputFile)(file, id);
643 } catch (e) {
644 this._logger.warn(`Couldn't write out staging user ID: ${e}`);
645 }
646
647 return id;
648 }
649 /** @internal */
650
651
652 get isAddNoCacheQuery() {
653 const headers = this.requestHeaders; // https://github.com/electron-userland/electron-builder/issues/3021
654
655 if (headers == null) {
656 return true;
657 }
658
659 for (const headerName of Object.keys(headers)) {
660 const s = headerName.toLowerCase();
661
662 if (s === "authorization" || s === "private-token") {
663 return false;
664 }
665 }
666
667 return true;
668 }
669
670 async getOrCreateDownloadHelper() {
671 let result = this.downloadedUpdateHelper;
672
673 if (result == null) {
674 const dirName = (await this.configOnDisk.value).updaterCacheDirName;
675 const logger = this._logger;
676
677 if (dirName == null) {
678 logger.error("updaterCacheDirName is not specified in app-update.yml Was app build using at least electron-builder 20.34.0?");
679 }
680
681 const cacheDir = path.join(this.app.baseCachePath, dirName || this.app.name);
682
683 if (logger.debug != null) {
684 logger.debug(`updater cache dir: ${cacheDir}`);
685 }
686
687 result = new (_DownloadedUpdateHelper().DownloadedUpdateHelper)(cacheDir);
688 this.downloadedUpdateHelper = result;
689 }
690
691 return result;
692 }
693
694 async executeDownload(taskOptions) {
695 const fileInfo = taskOptions.fileInfo;
696 const downloadOptions = {
697 headers: taskOptions.downloadUpdateOptions.requestHeaders,
698 cancellationToken: taskOptions.downloadUpdateOptions.cancellationToken,
699 sha2: fileInfo.info.sha2,
700 sha512: fileInfo.info.sha512
701 };
702
703 if (this.listenerCount(_main().DOWNLOAD_PROGRESS) > 0) {
704 downloadOptions.onProgress = it => this.emit(_main().DOWNLOAD_PROGRESS, it);
705 }
706
707 const updateInfo = taskOptions.downloadUpdateOptions.updateInfoAndProvider.info;
708 const version = updateInfo.version;
709 const packageInfo = fileInfo.packageInfo;
710
711 function getCacheUpdateFileName() {
712 // NodeJS URL doesn't decode automatically
713 const urlPath = decodeURIComponent(taskOptions.fileInfo.url.pathname);
714
715 if (urlPath.endsWith(`.${taskOptions.fileExtension}`)) {
716 return path.posix.basename(urlPath);
717 } else {
718 // url like /latest, generate name
719 return `update.${taskOptions.fileExtension}`;
720 }
721 }
722
723 const downloadedUpdateHelper = await this.getOrCreateDownloadHelper();
724 const cacheDir = downloadedUpdateHelper.cacheDirForPendingUpdate;
725 await (0, _fsExtra().ensureDir)(cacheDir);
726 const updateFileName = getCacheUpdateFileName();
727 let updateFile = path.join(cacheDir, updateFileName);
728 const packageFile = packageInfo == null ? null : path.join(cacheDir, `package-${version}${path.extname(packageInfo.path) || ".7z"}`);
729
730 const done = async isSaveCache => {
731 await downloadedUpdateHelper.setDownloadedFile(updateFile, packageFile, updateInfo, fileInfo, updateFileName, isSaveCache);
732 await taskOptions.done({ ...updateInfo,
733 downloadedFile: updateFile
734 });
735 return packageFile == null ? [updateFile] : [updateFile, packageFile];
736 };
737
738 const log = this._logger;
739 const cachedUpdateFile = await downloadedUpdateHelper.validateDownloadedPath(updateFile, updateInfo, fileInfo, log);
740
741 if (cachedUpdateFile != null) {
742 updateFile = cachedUpdateFile;
743 return await done(false);
744 }
745
746 const removeFileIfAny = async () => {
747 await downloadedUpdateHelper.clear().catch(() => {// ignore
748 });
749 return await (0, _fsExtra().unlink)(updateFile).catch(() => {// ignore
750 });
751 };
752
753 const tempUpdateFile = await (0, _DownloadedUpdateHelper().createTempUpdateFile)(`temp-${updateFileName}`, cacheDir, log);
754
755 try {
756 await taskOptions.task(tempUpdateFile, downloadOptions, packageFile, removeFileIfAny);
757 await (0, _fsExtra().rename)(tempUpdateFile, updateFile);
758 } catch (e) {
759 await removeFileIfAny();
760
761 if (e instanceof _builderUtilRuntime().CancellationError) {
762 log.info("cancelled");
763 this.emit("update-cancelled", updateInfo);
764 }
765
766 throw e;
767 }
768
769 log.info(`New version ${version} has been downloaded to ${updateFile}`);
770 return await done(true);
771 }
772
773}
774
775exports.AppUpdater = AppUpdater;
776
777function hasPrereleaseComponents(version) {
778 const versionPrereleaseComponent = (0, _semver().prerelease)(version);
779 return versionPrereleaseComponent != null && versionPrereleaseComponent.length > 0;
780}
781/** @private */
782
783
784class NoOpLogger {
785 // eslint-disable-next-line @typescript-eslint/no-unused-vars
786 info(message) {// ignore
787 } // eslint-disable-next-line @typescript-eslint/no-unused-vars
788
789
790 warn(message) {// ignore
791 } // eslint-disable-next-line @typescript-eslint/no-unused-vars
792
793
794 error(message) {// ignore
795 }
796
797} exports.NoOpLogger = NoOpLogger;
798// __ts-babel@6.0.4
799//# sourceMappingURL=AppUpdater.js.map
\No newline at end of file