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

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/dist/index.cjs CHANGED
@@ -1,250 +1,202 @@
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 fs3 = require('fs');
4
+ var events = require('events');
5
+ var electron = require('electron');
6
+ var path = require('path');
33
7
 
34
- // src/updater/core.ts
35
- var import_node_fs3 = require("fs");
36
- var import_electron2 = require("electron");
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var fs3__default = /*#__PURE__*/_interopDefault(fs3);
11
+ var path__default = /*#__PURE__*/_interopDefault(path);
12
+
13
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
14
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
15
+ }) : x)(function(x) {
16
+ if (typeof require !== "undefined") return require.apply(this, arguments);
17
+ throw Error('Dynamic require of "' + x + '" is not supported');
18
+ });
37
19
 
38
20
  // src/utils/version.ts
39
21
  function isUpdateJSON(json) {
40
- const is = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
22
+ const is = (j) => !!(j && j.minimumVersion && j.signature && j.version);
41
23
  return is(json) && is(json?.beta);
42
24
  }
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
25
  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);
26
+ process.platform === "win32";
27
+ process.platform === "darwin";
28
+ process.platform === "linux";
29
+ function getPathFromAppNameAsar(...paths) {
30
+ return isDev ? "DEV.asar" : path__default.default.join(path__default.default.dirname(electron.app.getAppPath()), `${electron.app.name}.asar`, ...paths);
54
31
  }
55
32
  function getAppVersion() {
56
- return isDev ? getEntryVersion() : (0, import_node_fs.readFileSync)(getPathFromAppNameAsar("version"), "utf-8");
33
+ return isDev ? getEntryVersion() : fs3__default.default.readFileSync(getPathFromAppNameAsar("version"), "utf-8");
57
34
  }
58
35
  function getEntryVersion() {
59
- return import_electron.app.getVersion();
36
+ return electron.app.getVersion();
60
37
  }
61
38
  function restartApp() {
62
- import_electron.app.relaunch();
63
- import_electron.app.quit();
39
+ electron.app.relaunch();
40
+ electron.app.quit();
64
41
  }
65
42
 
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
- });
84
- }
85
-
86
- // src/updater/types.ts
43
+ // src/entry/types.ts
87
44
  var ErrorInfo = {
88
- download: "Download failed",
89
- validate: "Validate failed",
90
- param: "Missing params",
91
- version: "Unsatisfied version"
45
+ download: "Download Failed",
46
+ validate: "Validate Failed",
47
+ param: "Missing Params",
48
+ network: "Network Error"
92
49
  };
93
50
  var UpdaterError = class extends Error {
51
+ code;
94
52
  constructor(msg, info) {
95
- super(msg + ": " + info);
53
+ super("[" + ErrorInfo[msg] + "] " + info);
54
+ this.code = msg;
96
55
  }
97
56
  };
98
57
 
99
- // src/updater/core.ts
100
- var Updater = class {
58
+ // src/entry/updater.ts
59
+ var Updater = class extends events.EventEmitter {
101
60
  CERT = __EIU_SIGNATURE_CERT__;
102
61
  info;
103
- options;
104
- asarPath;
105
- gzipPath;
106
- tmpFilePath;
107
62
  provider;
108
63
  /**
109
- * updater logger
64
+ * Updater logger
110
65
  */
111
66
  logger;
112
67
  /**
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
- * }
68
+ * Whether to receive beta update
119
69
  */
120
- onDownloading;
70
+ receiveBeta;
121
71
  /**
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
72
+ * Whether force update in DEV
127
73
  */
128
- handleURL;
74
+ forceUpdate;
129
75
  /**
130
- * whether receive beta version
76
+ * Initialize incremental updater
77
+ * @param options UpdaterOption
131
78
  */
132
- get receiveBeta() {
133
- return !!this.options.receiveBeta;
134
- }
135
- set receiveBeta(receiveBeta) {
136
- this.options.receiveBeta = receiveBeta;
137
- }
138
- /**
139
- * initialize incremental updater
140
- * @param provider update provider
141
- * @param option UpdaterOption
142
- */
143
- constructor(provider, option = {}) {
144
- this.provider = provider;
145
- this.options = option;
146
- if (option.SIGNATURE_CERT) {
147
- this.CERT = option.SIGNATURE_CERT;
79
+ constructor(options = {}) {
80
+ super();
81
+ this.provider = options.provider;
82
+ this.receiveBeta = options.receiveBeta;
83
+ this.CERT = options.SIGNATURE_CERT || __EIU_SIGNATURE_CERT__;
84
+ this.logger = options.logger;
85
+ if (isDev && !this.logger) {
86
+ this.logger = {
87
+ info: (...args) => console.log("[EIU-INFO ]", ...args),
88
+ debug: (...args) => console.log("[EIU-DEBUG]", ...args),
89
+ warn: (...args) => console.log("[EIU-WARN ]", ...args),
90
+ error: (...args) => console.error("[EIU-ERROR]", ...args)
91
+ };
92
+ this.logger.info("no logger set, enable dev-only logger");
148
93
  }
149
- if (option.logger) {
150
- this.logger = option.logger;
94
+ if (!this.provider) {
95
+ this.logger?.debug("No update provider, please setup provider before checking update");
151
96
  }
152
- this.asarPath = getPathFromAppNameAsar();
153
- this.gzipPath = `${this.asarPath}.gz`;
154
- this.tmpFilePath = `${this.asarPath}.tmp`;
155
97
  }
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})`);
98
+ checkProvider() {
99
+ if (!this.provider) {
100
+ throw new UpdaterError("param", "missing update provider");
166
101
  }
167
- this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
168
- return await isLowerVersion(appVersion, version);
169
102
  }
170
- async parseData(format, data) {
171
- if ((0, import_node_fs3.existsSync)(this.tmpFilePath)) {
172
- 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);
178
- }
103
+ async fetch(format, data) {
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) {
130
+ this.checkProvider();
131
+ const emitUnavailable = (msg) => {
132
+ this.logger?.info(msg);
133
+ this.emit("update-unavailable", msg);
134
+ return false;
135
+ };
136
+ const _data = await this.fetch("json", data);
137
+ if (!_data) {
138
+ return emitUnavailable("failed to get update info");
139
+ }
140
+ let { signature, version, minimumVersion, beta } = _data;
141
+ if (this.receiveBeta) {
142
+ version = beta.version;
143
+ signature = beta.signature;
144
+ minimumVersion = beta.minimumVersion;
145
+ }
146
+ this.logger?.debug(`checked update, version: ${version}, 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();
197
153
  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;
154
+ if (isLowerVersion(entryVersion, minimumVersion)) {
155
+ return emitUnavailable(`entry version (${entryVersion}) < minimumVersion (${minimumVersion})`);
204
156
  }
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 };
157
+ this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
158
+ if (!isLowerVersion(appVersion, version)) {
159
+ return emitUnavailable(`current version (${appVersion}) < new version (${version})`);
213
160
  }
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
- };
161
+ this.logger?.info(`update available: ${version}`);
162
+ this.info = { signature, minimumVersion, version };
163
+ this.emit("update-available", this.info);
164
+ return true;
165
+ } catch {
166
+ this.err("Fail to parse version", "validate", "fail to parse version string");
167
+ return false;
220
168
  }
221
169
  }
222
- async download(data, sig) {
170
+ async downloadUpdate(data, info) {
171
+ this.checkProvider();
172
+ const _sig = info?.signature ?? this.info?.signature;
173
+ const _version = info?.version ?? this.info?.version;
174
+ if (!_sig || !_version) {
175
+ this.err("download failed", "param", "no update signature, please call `checkUpdate` first or manually setup params");
176
+ return false;
177
+ }
178
+ const buffer = await this.fetch("buffer", data ? Buffer.from(data) : void 0);
179
+ if (!buffer) {
180
+ this.err("download failed", "param", "no update asar file buffer");
181
+ return false;
182
+ }
183
+ this.logger?.debug("verify start");
184
+ if (!await this.provider.verifySignaure(buffer, _version, _sig, this.CERT)) {
185
+ this.err("download failed", "validate", "invalid update asar file");
186
+ return false;
187
+ }
188
+ this.logger?.debug("verify success");
223
189
  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
- this.logger?.debug(`extract to ${this.tmpFilePath}`);
238
- await unzipFile(this.gzipPath, this.tmpFilePath);
239
- this.logger?.info(`download success, version: ${_ver}`);
190
+ const tmpFilePath = getPathFromAppNameAsar() + ".tmp";
191
+ this.logger?.debug(`install to ${tmpFilePath}`);
192
+ fs3__default.default.writeFileSync(tmpFilePath, await this.provider.unzipFile(buffer));
193
+ this.logger?.info(`download success, version: ${_version}`);
240
194
  this.info = void 0;
241
- return { success: true };
195
+ this.emit("update-downloaded");
196
+ return true;
242
197
  } 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
- };
198
+ this.err("download failed", "download", `fail to unwrap asar file, ${error}`);
199
+ return false;
248
200
  }
249
201
  }
250
202
  /**
@@ -255,31 +207,20 @@ var Updater = class {
255
207
  restartApp();
256
208
  }
257
209
  };
258
-
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
- // src/entry.ts
210
+ async function autoUpdate(updater) {
211
+ if (await updater.checkUpdate() && await updater.downloadUpdate()) {
212
+ updater.quitAndInstall();
213
+ }
214
+ }
273
215
  function startupWithUpdater(fn) {
274
216
  return fn;
275
217
  }
276
218
  var defaultOnInstall = (install, _, __, logger) => {
277
219
  install();
278
- logger.info(`update success!`);
220
+ logger?.info(`update success!`);
279
221
  };
280
- async function initApp(appOptions) {
222
+ async function initApp(appOptions = {}) {
281
223
  const {
282
- provider,
283
224
  updater,
284
225
  onInstall = defaultOnInstall,
285
226
  beforeStart,
@@ -287,36 +228,35 @@ async function initApp(appOptions) {
287
228
  } = appOptions;
288
229
  let updaterInstance;
289
230
  if (typeof updater === "object" || !updater) {
290
- updaterInstance = new Updater(provider, updater);
231
+ updaterInstance = new Updater(updater);
291
232
  } else {
292
233
  updaterInstance = await updater();
293
234
  }
294
- const logger = updaterInstance.logger || console;
235
+ const logger = updaterInstance.logger;
295
236
  try {
296
237
  const appNameAsarPath = getPathFromAppNameAsar();
297
238
  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);
239
+ if (fs3__default.default.existsSync(tempAsarPath)) {
240
+ logger?.info(`installing new asar: ${tempAsarPath}`);
241
+ await onInstall(() => fs3__default.default.renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
301
242
  }
302
- const mainFilePath = (0, import_node_path2.join)(
303
- isDev ? (0, import_node_path2.join)(import_electron4.app.getAppPath(), __EIU_MAIN_DEV_DIR__) : appNameAsarPath,
243
+ const mainFilePath = path__default.default.join(
244
+ isDev ? path__default.default.join(electron.app.getAppPath(), __EIU_MAIN_DEV_DIR__) : appNameAsarPath,
304
245
  "main",
305
246
  __EIU_MAIN_FILE__
306
247
  );
307
248
  await beforeStart?.(mainFilePath, logger);
308
- require(mainFilePath)(updaterInstance);
249
+ __require(mainFilePath)(updaterInstance);
309
250
  } catch (error) {
310
- logger.error("startup error", error);
251
+ logger?.error("startup error", error);
311
252
  onStartError?.(error, logger);
312
- import_electron4.app.quit();
253
+ electron.app.quit();
313
254
  }
314
255
  }
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
- });
256
+
257
+ exports.ErrorInfo = ErrorInfo;
258
+ exports.Updater = Updater;
259
+ exports.UpdaterError = UpdaterError;
260
+ exports.autoUpdate = autoUpdate;
261
+ exports.initApp = initApp;
262
+ exports.startupWithUpdater = startupWithUpdater;