electron-incremental-update 2.0.0-beta.1 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -181,7 +181,7 @@ initApp({
181
181
  in `electron/main/index.ts`
182
182
 
183
183
  ```ts
184
- import { startupWithUpdater, UpdaterError } from 'electron-incremental-update'
184
+ import { UpdaterError, startupWithUpdater } from 'electron-incremental-update'
185
185
  import { getPathFromAppNameAsar, getVersions } from 'electron-incremental-update/utils'
186
186
  import { app } from 'electron'
187
187
 
@@ -199,7 +199,7 @@ export default startupWithUpdater((updater) => {
199
199
  }
200
200
  updater.logger = console
201
201
  updater.receiveBeta = true
202
-
202
+
203
203
  updater.checkUpdate().then(async (result) => {
204
204
  if (result === undefined) {
205
205
  console.log('Update Unavailable')
@@ -276,7 +276,7 @@ import Database from 'better-sqlite3'
276
276
 
277
277
  const db = new Database(':memory:', { nativeBinding: './better_sqlite3.node' })
278
278
 
279
- export function test() {
279
+ export function test(): void {
280
280
  db.exec(
281
281
  'DROP TABLE IF EXISTS employees; '
282
282
  + 'CREATE TABLE IF NOT EXISTS employees (name TEXT, salary INTEGER)',
@@ -0,0 +1,43 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import { brotliDecompress } from 'node:zlib';
3
+ import { createHash, createCipheriv, createSign, createPrivateKey, createDecipheriv, createVerify } from 'node:crypto';
4
+
5
+ // src/utils/unzip.ts
6
+ async function defaultUnzipFile(buffer, targetFilePath) {
7
+ return new Promise((resolve, reject) => {
8
+ brotliDecompress(buffer, (err, buffer2) => {
9
+ if (err) {
10
+ reject(err);
11
+ }
12
+ writeFileSync(targetFilePath, buffer2);
13
+ resolve();
14
+ });
15
+ });
16
+ }
17
+ function hashBuffer(data, length) {
18
+ const hash = createHash("SHA256").update(data).digest("binary");
19
+ return Buffer.from(hash).subarray(0, length);
20
+ }
21
+ function aesEncrypt(plainText, key, iv) {
22
+ const cipher = createCipheriv("aes-256-cbc", key, iv);
23
+ return cipher.update(plainText, "utf8", "base64url") + cipher.final("base64url");
24
+ }
25
+ function defaultSignature(buffer, privateKey, cert, version) {
26
+ const sig = createSign("RSA-SHA256").update(buffer).sign(createPrivateKey(privateKey), "base64");
27
+ return aesEncrypt(`${sig}%${version}`, hashBuffer(cert, 32), hashBuffer(buffer, 16));
28
+ }
29
+ function aesDecrypt(encryptedText, key, iv) {
30
+ const decipher = createDecipheriv("aes-256-cbc", key, iv);
31
+ return decipher.update(encryptedText, "base64url", "utf8") + decipher.final("utf8");
32
+ }
33
+ function defaultVerify(buffer, signature, cert) {
34
+ try {
35
+ const [sig, version] = aesDecrypt(signature, hashBuffer(cert, 32), hashBuffer(buffer, 16)).split("%");
36
+ const result = createVerify("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
37
+ return result ? version : void 0;
38
+ } catch {
39
+ return void 0;
40
+ }
41
+ }
42
+
43
+ export { aesDecrypt, aesEncrypt, defaultSignature, defaultUnzipFile, defaultVerify, hashBuffer };
@@ -0,0 +1,76 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/utils/version.ts
9
+ function handleUnexpectedErrors(callback) {
10
+ process.on("uncaughtException", callback);
11
+ process.on("unhandledRejection", callback);
12
+ }
13
+ function parseVersion(version) {
14
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([a-z0-9.-]+))?/i.exec(version);
15
+ if (!match) {
16
+ throw new TypeError(`invalid version: ${version}`);
17
+ }
18
+ const [major, minor, patch] = match.slice(1, 4).map(Number);
19
+ const ret = {
20
+ major,
21
+ minor,
22
+ patch,
23
+ stage: "",
24
+ stageVersion: -1
25
+ };
26
+ if (match[4]) {
27
+ let [stage, _v] = match[4].split(".");
28
+ ret.stage = stage;
29
+ ret.stageVersion = Number(_v) || -1;
30
+ }
31
+ if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch) || Number.isNaN(ret.stageVersion)) {
32
+ throw new TypeError(`invalid version: ${version}`);
33
+ }
34
+ return ret;
35
+ }
36
+ function defaultIsLowerVersion(oldVer, newVer) {
37
+ const oldV = parseVersion(oldVer);
38
+ const newV = parseVersion(newVer);
39
+ function compareStrings(str1, str2) {
40
+ if (str1 === "") {
41
+ return str2 !== "";
42
+ } else if (str2 === "") {
43
+ return true;
44
+ }
45
+ return str1 < str2;
46
+ }
47
+ for (let key of Object.keys(oldV)) {
48
+ if (key === "stage" && compareStrings(oldV[key], newV[key])) {
49
+ return true;
50
+ } else if (oldV[key] !== newV[key]) {
51
+ return oldV[key] < newV[key];
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+ function isUpdateJSON(json) {
57
+ const is = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
58
+ return is(json) && is(json?.beta);
59
+ }
60
+ function defaultVersionJsonGenerator(existingJson, buffer, signature, version, minimumVersion) {
61
+ existingJson.beta = {
62
+ version,
63
+ minimumVersion,
64
+ signature,
65
+ size: buffer.length
66
+ };
67
+ if (!parseVersion(version).stage) {
68
+ existingJson.version = version;
69
+ existingJson.minimumVersion = minimumVersion;
70
+ existingJson.signature = signature;
71
+ existingJson.size = buffer.length;
72
+ }
73
+ return existingJson;
74
+ }
75
+
76
+ export { __require, defaultIsLowerVersion, defaultVersionJsonGenerator, handleUnexpectedErrors, isUpdateJSON, parseVersion };
@@ -0,0 +1,77 @@
1
+ import { __require } from './chunk-BVFQWBLK.js';
2
+ import { readFileSync, existsSync, mkdirSync } from 'node:fs';
3
+ import { join, dirname } from 'node:path';
4
+ import { app } from 'electron';
5
+
6
+ var isDev = __EIU_IS_DEV__;
7
+ var isWin = process.platform === "win32";
8
+ var isMac = process.platform === "darwin";
9
+ var isLinux = process.platform === "linux";
10
+ function getPathFromAppNameAsar(...path) {
11
+ return isDev ? "DEV.asar" : join(dirname(app.getAppPath()), `${app.name}.asar`, ...path);
12
+ }
13
+ function getAppVersion() {
14
+ return isDev ? getEntryVersion() : readFileSync(getPathFromAppNameAsar("version"), "utf-8");
15
+ }
16
+ function getEntryVersion() {
17
+ return app.getVersion();
18
+ }
19
+ function requireNative(moduleName) {
20
+ return __require(join(app.getAppPath(), __EIU_ENTRY_DIST_PATH__, moduleName));
21
+ }
22
+ function restartApp() {
23
+ app.relaunch();
24
+ app.quit();
25
+ }
26
+ function setAppUserModelId(id) {
27
+ if (isWin) {
28
+ app.setAppUserModelId(id ?? `org.${app.name}`);
29
+ }
30
+ }
31
+ function disableHWAccForWin7() {
32
+ if (__require("node:os").release().startsWith("6.1")) {
33
+ app.disableHardwareAcceleration();
34
+ }
35
+ }
36
+ function singleInstance(window) {
37
+ const result = app.requestSingleInstanceLock();
38
+ if (result) {
39
+ app.on("second-instance", () => {
40
+ if (window) {
41
+ window.show();
42
+ if (window.isMinimized()) {
43
+ window.restore();
44
+ }
45
+ window.focus();
46
+ }
47
+ });
48
+ } else {
49
+ app.quit();
50
+ }
51
+ return result;
52
+ }
53
+ function setPortableAppDataPath(dirName = "data") {
54
+ const portablePath = join(dirname(app.getPath("exe")), dirName);
55
+ if (!existsSync(portablePath)) {
56
+ mkdirSync(portablePath);
57
+ }
58
+ app.setPath("appData", portablePath);
59
+ }
60
+ function loadPage(win, htmlFilePath = "index.html") {
61
+ if (isDev) {
62
+ win.loadURL(process.env.VITE_DEV_SERVER_URL + htmlFilePath);
63
+ } else {
64
+ win.loadFile(getPathFromAppNameAsar("renderer", htmlFilePath));
65
+ }
66
+ }
67
+ function getPathFromPreload(...paths) {
68
+ return isDev ? join(app.getAppPath(), __EIU_ELECTRON_DIST_PATH__, "preload", ...paths) : getPathFromAppNameAsar("preload", ...paths);
69
+ }
70
+ function getPathFromPublic(...paths) {
71
+ return isDev ? join(app.getAppPath(), "public", ...paths) : getPathFromAppNameAsar("renderer", ...paths);
72
+ }
73
+ function getPathFromEntryAsar(...paths) {
74
+ return join(app.getAppPath(), __EIU_ENTRY_DIST_PATH__, ...paths);
75
+ }
76
+
77
+ export { disableHWAccForWin7, getAppVersion, getEntryVersion, getPathFromAppNameAsar, getPathFromEntryAsar, getPathFromPreload, getPathFromPublic, isDev, isLinux, isMac, isWin, loadPage, requireNative, restartApp, setAppUserModelId, setPortableAppDataPath, singleInstance };
package/dist/index.cjs CHANGED
@@ -1,86 +1,38 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
19
2
 
20
- // src/entry.ts
21
- var entry_exports = {};
22
- __export(entry_exports, {
23
- ErrorInfo: () => ErrorInfo,
24
- Updater: () => Updater,
25
- UpdaterError: () => UpdaterError,
26
- initApp: () => initApp,
27
- startupWithUpdater: () => startupWithUpdater
28
- });
29
- module.exports = __toCommonJS(entry_exports);
30
- var import_node_path2 = require("path");
31
- var import_node_fs5 = require("fs");
32
- var import_electron4 = require("electron");
3
+ var path = require('path');
4
+ var fs = require('fs');
5
+ var electron = require('electron');
6
+ var events = require('events');
33
7
 
34
- // src/updater/core.ts
35
- var import_node_fs3 = require("fs");
36
- var import_electron2 = require("electron");
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
37
14
 
38
15
  // src/utils/version.ts
39
16
  function isUpdateJSON(json) {
40
17
  const is = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
41
18
  return is(json) && is(json?.beta);
42
19
  }
43
-
44
- // src/utils/electron.ts
45
- var import_node_fs = require("fs");
46
- var import_node_path = require("path");
47
- var import_electron = require("electron");
48
20
  var isDev = __EIU_IS_DEV__;
49
- var isWin = process.platform === "win32";
50
- var isMac = process.platform === "darwin";
51
- var isLinux = process.platform === "linux";
52
- function getPathFromAppNameAsar(...path) {
53
- return isDev ? "DEV.asar" : (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getAppPath()), `${import_electron.app.name}.asar`, ...path);
21
+ process.platform === "win32";
22
+ process.platform === "darwin";
23
+ process.platform === "linux";
24
+ function getPathFromAppNameAsar(...path$1) {
25
+ return isDev ? "DEV.asar" : path.join(path.dirname(electron.app.getAppPath()), `${electron.app.name}.asar`, ...path$1);
54
26
  }
55
27
  function getAppVersion() {
56
- return isDev ? getEntryVersion() : (0, import_node_fs.readFileSync)(getPathFromAppNameAsar("version"), "utf-8");
28
+ return isDev ? getEntryVersion() : fs.readFileSync(getPathFromAppNameAsar("version"), "utf-8");
57
29
  }
58
30
  function getEntryVersion() {
59
- return import_electron.app.getVersion();
31
+ return electron.app.getVersion();
60
32
  }
61
33
  function restartApp() {
62
- import_electron.app.relaunch();
63
- import_electron.app.quit();
64
- }
65
-
66
- // src/utils/unzip.ts
67
- var import_node_fs2 = require("fs");
68
- var import_node_zlib = require("zlib");
69
- async function unzipFile(gzipPath, targetFilePath = gzipPath.slice(0, -3)) {
70
- if (!(0, import_node_fs2.existsSync)(gzipPath)) {
71
- throw new Error(`path to zipped file not exist: ${gzipPath}`);
72
- }
73
- const compressedBuffer = (0, import_node_fs2.readFileSync)(gzipPath);
74
- return new Promise((resolve, reject) => {
75
- (0, import_node_zlib.brotliDecompress)(compressedBuffer, (err, buffer) => {
76
- (0, import_node_fs2.rmSync)(gzipPath);
77
- if (err) {
78
- reject(err);
79
- }
80
- (0, import_node_fs2.writeFileSync)(targetFilePath, buffer);
81
- resolve(null);
82
- });
83
- });
34
+ electron.app.relaunch();
35
+ electron.app.quit();
84
36
  }
85
37
 
86
38
  // src/updater/types.ts
@@ -88,21 +40,21 @@ var ErrorInfo = {
88
40
  download: "Download failed",
89
41
  validate: "Validate failed",
90
42
  param: "Missing params",
91
- version: "Unsatisfied version"
43
+ network: "Network error"
92
44
  };
93
45
  var UpdaterError = class extends Error {
46
+ code;
94
47
  constructor(msg, info) {
95
- super(msg + ": " + info);
48
+ super(ErrorInfo[msg] + ": " + info);
49
+ this.code = msg;
96
50
  }
97
51
  };
98
52
 
99
53
  // src/updater/core.ts
100
- var Updater = class {
54
+ var Updater = class extends events.EventEmitter {
101
55
  CERT = __EIU_SIGNATURE_CERT__;
102
56
  info;
103
- options;
104
57
  asarPath;
105
- gzipPath;
106
58
  tmpFilePath;
107
59
  provider;
108
60
  /**
@@ -110,141 +62,134 @@ var Updater = class {
110
62
  */
111
63
  logger;
112
64
  /**
113
- * downloading progress hook
114
- * @param progress download progress
115
- * @example
116
- * updater.onDownloading = ({ percent, total, current }) => {
117
- * console.log(`download progress: ${percent}, total: ${total}, current: ${current}`)
118
- * }
65
+ * whether to receive beta update
119
66
  */
120
- onDownloading;
67
+ receiveBeta;
121
68
  /**
122
- * URL handler hook
123
- *
124
- * for Github, there are some {@link https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34 public CDN links}
125
- * @param url source url
126
- * @param isDownloadAsar whether is download asar
69
+ * whether force update in DEV
127
70
  */
128
- handleURL;
129
- /**
130
- * whether receive beta version
131
- */
132
- get receiveBeta() {
133
- return !!this.options.receiveBeta;
134
- }
135
- set receiveBeta(receiveBeta) {
136
- this.options.receiveBeta = receiveBeta;
137
- }
71
+ forceUpdate;
138
72
  /**
139
73
  * initialize incremental updater
140
74
  * @param provider update provider
141
75
  * @param option UpdaterOption
142
76
  */
143
77
  constructor(provider, option = {}) {
78
+ super();
144
79
  this.provider = provider;
145
- this.options = option;
80
+ this.receiveBeta = option.receiveBeta;
146
81
  if (option.SIGNATURE_CERT) {
147
82
  this.CERT = option.SIGNATURE_CERT;
148
83
  }
149
84
  if (option.logger) {
150
85
  this.logger = option.logger;
151
86
  }
87
+ if (isDev && !this.logger) {
88
+ this.logger = {
89
+ info: (...args) => console.log("[EIU-INFO ]", ...args),
90
+ debug: (...args) => console.log("[EIU-DEBUG]", ...args),
91
+ warn: (...args) => console.log("[EIU-WARN ]", ...args),
92
+ error: (...args) => console.error("[EIU-ERROR]", ...args)
93
+ };
94
+ this.logger.info("no logger set, enable dev-only logger");
95
+ }
152
96
  this.asarPath = getPathFromAppNameAsar();
153
- this.gzipPath = `${this.asarPath}.gz`;
154
97
  this.tmpFilePath = `${this.asarPath}.tmp`;
155
98
  }
156
- async needUpdate(version, minVersion) {
157
- if (isDev) {
158
- this.logger?.warn(`in dev mode, skip check update`);
159
- return false;
160
- }
161
- const isLowerVersion = this.provider.isLowerVersion;
162
- const entryVersion = getEntryVersion();
163
- const appVersion = getAppVersion();
164
- if (await isLowerVersion(entryVersion, minVersion)) {
165
- throw new UpdaterError(ErrorInfo.version, `entry version (${entryVersion}) < minimumVersion (${minVersion})`);
166
- }
167
- this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
168
- return await isLowerVersion(appVersion, version);
169
- }
170
- async parseData(format, data) {
171
- if ((0, import_node_fs3.existsSync)(this.tmpFilePath)) {
99
+ async fetch(format, data) {
100
+ if (fs.existsSync(this.tmpFilePath)) {
172
101
  this.logger?.warn(`remove tmp file: ${this.tmpFilePath}`);
173
- (0, import_node_fs3.rmSync)(this.tmpFilePath);
174
- }
175
- if ((0, import_node_fs3.existsSync)(this.gzipPath)) {
176
- this.logger?.warn(`remove .gz file: ${this.gzipPath}`);
177
- (0, import_node_fs3.rmSync)(this.gzipPath);
102
+ fs.rmSync(this.tmpFilePath);
178
103
  }
179
104
  if (typeof data === "object") {
180
105
  if (format === "json" && isUpdateJSON(data) || format === "buffer" && Buffer.isBuffer(data)) {
181
106
  return data;
182
107
  } else {
183
- throw new UpdaterError(ErrorInfo.param, `invalid type at format '${format}': ${JSON.stringify(data)}`);
108
+ this.err("invalid type", "param", `invalid type at format '${format}': ${JSON.stringify(data)}`);
109
+ return;
184
110
  }
185
111
  }
186
112
  this.logger?.debug(`download from ${this.provider.name}`);
187
113
  try {
188
- const result = format === "json" ? await this.provider.downloadJSON(data ?? __EIU_VERSION_PATH__) : await this.provider.downloadBuffer(import_electron2.app.name, this.info, this.onDownloading);
114
+ const result = format === "json" ? await this.provider.downloadJSON(data ?? __EIU_VERSION_PATH__) : await this.provider.downloadAsar(electron.app.name, this.info, (data2) => this.emit("download-progress", data2));
189
115
  this.logger?.debug(`download ${format} success${format === "buffer" ? `, file size: ${result.length}` : ""}`);
190
116
  return result;
191
117
  } catch (e) {
192
- this.logger?.warn(`download ${format} failed: ${e}`);
193
- throw new UpdaterError(ErrorInfo.download, `download ${format} failed: ${e}`);
118
+ this.err(`fetch ${format} failed`, "network", `download ${format} failed: ${e}`);
194
119
  }
195
120
  }
121
+ /**
122
+ * handle error message and emit error event
123
+ */
124
+ err(msg, code, errorInfo) {
125
+ const err = new UpdaterError(code, errorInfo);
126
+ this.logger?.error(msg, err);
127
+ this.emit("error", err);
128
+ }
196
129
  async checkUpdate(data) {
197
- try {
198
- let { signature, size, version, minimumVersion, beta } = await this.parseData("json", data);
199
- if (this.receiveBeta) {
200
- version = beta.version;
201
- signature = beta.signature;
202
- minimumVersion = beta.minimumVersion;
203
- size = beta.size;
204
- }
205
- this.logger?.debug(`checked update, version: ${version}, size: ${size}, signature: ${signature}`);
206
- if (!await this.needUpdate(version, minimumVersion)) {
207
- this.logger?.info(`update unavailable: ${version} is the latest version`);
208
- return { success: false, data: version };
209
- } else {
210
- this.logger?.info(`update available: ${version}`);
211
- this.info = { signature, minimumVersion, version, size };
212
- return { success: true, data: this.info };
213
- }
214
- } catch (error) {
215
- this.logger?.error("check update failed", error);
216
- return {
217
- success: false,
218
- data: error instanceof UpdaterError ? error : new UpdaterError(ErrorInfo.download, error.toString())
219
- };
130
+ const emitUnavailable = (msg) => {
131
+ this.logger?.info(msg);
132
+ this.emit("update-unavailable", msg);
133
+ return false;
134
+ };
135
+ const _data = await this.fetch("json", data);
136
+ if (!_data) {
137
+ return emitUnavailable("failed to get update info");
138
+ }
139
+ let { signature, size, version, minimumVersion, beta } = _data;
140
+ if (this.receiveBeta) {
141
+ version = beta.version;
142
+ signature = beta.signature;
143
+ minimumVersion = beta.minimumVersion;
144
+ size = beta.size;
220
145
  }
146
+ this.logger?.debug(`checked update, version: ${version}, size: ${size}, signature: ${signature}`);
147
+ if (isDev && !this.forceUpdate && !data) {
148
+ return emitUnavailable("skip check update in dev mode, to force update, set `updater.forceUpdate` to true or call checkUpdate with UpdateJSON");
149
+ }
150
+ const isLowerVersion = this.provider.isLowerVersion;
151
+ const entryVersion = getEntryVersion();
152
+ const appVersion = getAppVersion();
153
+ if (isLowerVersion(entryVersion, minimumVersion)) {
154
+ return emitUnavailable(`entry version (${entryVersion}) < minimumVersion (${minimumVersion})`);
155
+ }
156
+ this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
157
+ if (!isLowerVersion(appVersion, version)) {
158
+ return emitUnavailable(`current version (${appVersion}) < new version (${version})`);
159
+ }
160
+ this.logger?.info(`update available: ${version}`);
161
+ this.info = { signature, minimumVersion, version, size };
162
+ this.emit("update-available", this.info);
163
+ return true;
221
164
  }
222
165
  async download(data, sig) {
166
+ const _sig = sig ?? this.info?.signature;
167
+ if (!_sig) {
168
+ this.err("download failed", "param", "no update signature, please call `checkUpdate` first");
169
+ return false;
170
+ }
171
+ const buffer = await this.fetch("buffer", data ? Buffer.from(data) : void 0);
172
+ if (!buffer) {
173
+ this.err("download failed", "param", "no update asar file buffer");
174
+ return false;
175
+ }
176
+ this.logger?.debug("verify start");
177
+ const _ver = await this.provider.verifySignaure(buffer, _sig, this.CERT);
178
+ if (!_ver) {
179
+ this.err("download failed", "validate", "invalid signature / certificate pair");
180
+ return false;
181
+ }
182
+ this.logger?.debug("verify success");
223
183
  try {
224
- if (!this.info) {
225
- throw new UpdaterError(ErrorInfo.param, "no update info");
226
- }
227
- const _sig = sig ?? this.info.signature;
228
- const buffer = await this.parseData("buffer", data);
229
- this.logger?.debug("verify start");
230
- const _ver = await this.provider.verifySignaure(buffer, _sig, this.CERT);
231
- if (!_ver) {
232
- throw new UpdaterError(ErrorInfo.validate, "invalid signature or certificate");
233
- }
234
- this.logger?.debug("verify success");
235
- this.logger?.debug(`write to ${this.gzipPath}`);
236
- (0, import_node_fs3.writeFileSync)(this.gzipPath, buffer);
237
184
  this.logger?.debug(`extract to ${this.tmpFilePath}`);
238
- await unzipFile(this.gzipPath, this.tmpFilePath);
185
+ await this.provider.unzipFile(buffer, this.tmpFilePath);
239
186
  this.logger?.info(`download success, version: ${_ver}`);
240
187
  this.info = void 0;
241
- return { success: true };
188
+ this.emit("update-downloaded");
189
+ return true;
242
190
  } catch (error) {
243
- this.logger?.error("download asar failed", error);
244
- return {
245
- success: false,
246
- data: error instanceof UpdaterError ? error : new UpdaterError(ErrorInfo.download, error.toString())
247
- };
191
+ this.err("download failed", "download", `fail to unwrap asar file, ${error}`);
192
+ return false;
248
193
  }
249
194
  }
250
195
  /**
@@ -254,28 +199,28 @@ var Updater = class {
254
199
  this.logger?.info("quit and install");
255
200
  restartApp();
256
201
  }
202
+ /**
203
+ * setup provider URL handler
204
+ *
205
+ * @example
206
+ * updater.setURLHandler((url, isDownloadingAsar) => {
207
+ * if (isDownloadingAsar) {
208
+ * return url.replace('https://raw.githubusercontent.com', 'https://cdn.jsdelivr.net/gh')
209
+ * }
210
+ * })
211
+ */
212
+ setURLHandler(handler) {
213
+ this.provider.urlHandler = handler;
214
+ }
257
215
  };
258
216
 
259
- // src/utils/zip.ts
260
- var import_node_fs4 = require("fs");
261
- var import_node_zlib2 = require("zlib");
262
-
263
- // src/utils/crypto/decrypt.ts
264
- var import_node_crypto2 = require("crypto");
265
-
266
- // src/utils/crypto/utils.ts
267
- var import_node_crypto = require("crypto");
268
-
269
- // src/utils/crypto/encrypt.ts
270
- var import_node_crypto3 = require("crypto");
271
-
272
217
  // src/entry.ts
273
218
  function startupWithUpdater(fn) {
274
219
  return fn;
275
220
  }
276
221
  var defaultOnInstall = (install, _, __, logger) => {
277
222
  install();
278
- logger.info(`update success!`);
223
+ logger?.info(`update success!`);
279
224
  };
280
225
  async function initApp(appOptions) {
281
226
  const {
@@ -291,32 +236,38 @@ async function initApp(appOptions) {
291
236
  } else {
292
237
  updaterInstance = await updater();
293
238
  }
294
- const logger = updaterInstance.logger || console;
239
+ let logger = updaterInstance.logger;
240
+ if (isDev && !logger) {
241
+ logger = {
242
+ info: (...args) => console.log("[EIU-INFO ]", ...args),
243
+ debug: (...args) => console.log("[EIU-DEBUG]", ...args),
244
+ warn: (...args) => console.log("[EIU-WARN ]", ...args),
245
+ error: (...args) => console.error("[EIU-ERROR]", ...args)
246
+ };
247
+ }
295
248
  try {
296
249
  const appNameAsarPath = getPathFromAppNameAsar();
297
250
  const tempAsarPath = `${appNameAsarPath}.tmp`;
298
- if ((0, import_node_fs5.existsSync)(tempAsarPath)) {
299
- logger.info(`installing new asar: ${tempAsarPath}`);
300
- await onInstall(() => (0, import_node_fs5.renameSync)(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
251
+ if (fs.existsSync(tempAsarPath)) {
252
+ logger?.info(`installing new asar: ${tempAsarPath}`);
253
+ await onInstall(() => fs.renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
301
254
  }
302
- const mainFilePath = (0, import_node_path2.join)(
303
- isDev ? (0, import_node_path2.join)(import_electron4.app.getAppPath(), __EIU_MAIN_DEV_DIR__) : appNameAsarPath,
255
+ const mainFilePath = path.join(
256
+ isDev ? path.join(electron.app.getAppPath(), __EIU_MAIN_DEV_DIR__) : appNameAsarPath,
304
257
  "main",
305
258
  __EIU_MAIN_FILE__
306
259
  );
307
260
  await beforeStart?.(mainFilePath, logger);
308
- require(mainFilePath)(updaterInstance);
261
+ __require(mainFilePath)(updaterInstance);
309
262
  } catch (error) {
310
- logger.error("startup error", error);
263
+ logger?.error("startup error", error);
311
264
  onStartError?.(error, logger);
312
- import_electron4.app.quit();
265
+ electron.app.quit();
313
266
  }
314
267
  }
315
- // Annotate the CommonJS export names for ESM import in node:
316
- 0 && (module.exports = {
317
- ErrorInfo,
318
- Updater,
319
- UpdaterError,
320
- initApp,
321
- startupWithUpdater
322
- });
268
+
269
+ exports.ErrorInfo = ErrorInfo;
270
+ exports.Updater = Updater;
271
+ exports.UpdaterError = UpdaterError;
272
+ exports.initApp = initApp;
273
+ exports.startupWithUpdater = startupWithUpdater;