electron-incremental-update 1.0.3 → 1.2.0

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.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { U as UpdateInfo, a as UpdateJSON } from './noDep-TvZoKVF8.js';
1
+ import { U as UpdateInfo, a as UpdateJSON } from './pure-GoN_3MEj.js';
2
2
 
3
3
  declare class MinimumVersionError extends Error {
4
4
  currentVersion: string;
@@ -83,19 +83,10 @@ type UpdaterDownloadConfig = {
83
83
  };
84
84
  interface UpdaterOption {
85
85
  /**
86
- * public key of signature, which will be auto generated by plugin
87
- * @example
88
- * ```ts
89
- * // just empty here, auto filled by plugin
90
- * const SIGNATURE_CERT = ''
91
- *
92
- * const updater = createUpdater({
93
- * SIGNATURE_CERT,
94
- * ...
95
- * })
96
- * ```
86
+ * public key of signature, which will be auto generated by plugin,
87
+ * generate by `selfsigned` if not set
97
88
  */
98
- SIGNATURE_CERT: string;
89
+ SIGNATURE_CERT?: string;
99
90
  /**
100
91
  * repository url, e.g. `https://github.com/electron/electron`
101
92
  *
@@ -126,6 +117,7 @@ interface UpdaterOption {
126
117
  }
127
118
 
128
119
  declare class Updater {
120
+ private CERT;
129
121
  private info?;
130
122
  private option;
131
123
  private asarPath;
@@ -153,7 +145,7 @@ declare class Updater {
153
145
  * initialize incremental updater
154
146
  * @param option UpdaterOption
155
147
  */
156
- constructor(option: UpdaterOption);
148
+ constructor(option?: UpdaterOption);
157
149
  private needUpdate;
158
150
  /**
159
151
  * this function is used to parse download data.
@@ -200,11 +192,15 @@ declare class Updater {
200
192
  * @param option updater option
201
193
  * @returns updater
202
194
  */
203
- declare function createUpdater(option: UpdaterOption): Updater;
195
+ declare function createUpdater(option?: UpdaterOption): Updater;
204
196
 
205
197
  type Promisable<T> = T | Promise<T>;
206
198
  type OnInstallFunction = (install: VoidFunction, tempAsarPath: string, appNameAsarPath: string, logger?: Logger) => Promisable<void>;
207
199
  type AppOption = {
200
+ /**
201
+ * updater options
202
+ */
203
+ updater?: (() => Promisable<Updater>) | UpdaterOption;
208
204
  /**
209
205
  * path of electron output dist when in development
210
206
  * @default '../dist-electron'
@@ -252,13 +248,6 @@ type AppOption = {
252
248
  * })
253
249
  */
254
250
  declare function startupWithUpdater(fn: (updater: Updater) => Promisable<void>): (updater: Updater) => Promisable<void>;
255
- type StartupWithUpdater = {
256
- /**
257
- * starup app
258
- * @param updater updater option or create function
259
- */
260
- startupWithUpdater: (updater: (() => Promisable<Updater>) | UpdaterOption) => void;
261
- };
262
251
  /**
263
252
  * initialize app
264
253
  * @example
@@ -266,20 +255,22 @@ type StartupWithUpdater = {
266
255
  * import { getGithubReleaseCdnGroup, initApp, parseGithubCdnURL } from 'electron-incremental-update'
267
256
  * import { repository } from '../package.json'
268
257
  *
269
- * const SIGNATURE_CERT = '' // auto generate certificate when start app
270
258
  * const { cdnPrefix: asarPrefix } = getGithubReleaseCdnGroup()[0]
271
259
  * const { cdnPrefix: jsonPrefix } = getGithubFileCdnGroup()[0]
272
- * initApp({ onStart: console.log })
260
+ *
261
+ * initApp({
273
262
  * // can be updater option or function that return updater
274
- * .startupWithUpdater({
275
- * SIGNATURE_CERT,
263
+ * updater: {
264
+ * SIGNATURE_CERT: 'custom certificate',
276
265
  * repository,
277
266
  * updateJsonURL: parseGithubCdnURL(repository, jsonPrefix, 'version.json'),
278
267
  * releaseAsarURL: parseGithubCdnURL(repository, asarPrefix, `download/latest/${app.name}.asar.gz`),
279
268
  * receiveBeta: true,
280
- * })
269
+ * },
270
+ * onStart: console.log
271
+ * })
281
272
  * ```
282
273
  */
283
- declare function initApp(appOptions?: AppOption): StartupWithUpdater;
274
+ declare function initApp(appOptions?: AppOption): Promise<void>;
284
275
 
285
276
  export { type AppOption, type CheckResult, type CheckResultError, DownloadError, type DownloadResult, type DownloadResultError, type DownloadingInfo, type Logger, MinimumVersionError, Updater, type UpdaterDownloadConfig, type UpdaterOption, type UpdaterOverrideFunctions, VerifyFailedError, createUpdater, initApp, startupWithUpdater };
package/dist/index.js CHANGED
@@ -1,149 +1,45 @@
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 key2 of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key2) && key2 !== except)
14
- __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ import {
2
+ __require,
3
+ getPathFromAppNameAsar,
4
+ getVersions,
5
+ is,
6
+ isUpdateJSON,
7
+ parseVersion,
8
+ restartApp,
9
+ unzipFile,
10
+ waitAppReady
11
+ } from "./chunk-RQCTJY4L.js";
19
12
 
20
13
  // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- DownloadError: () => DownloadError,
24
- MinimumVersionError: () => MinimumVersionError,
25
- Updater: () => Updater,
26
- VerifyFailedError: () => VerifyFailedError,
27
- createUpdater: () => createUpdater,
28
- initApp: () => initApp,
29
- startupWithUpdater: () => startupWithUpdater
30
- });
31
- module.exports = __toCommonJS(src_exports);
32
- var import_node_path2 = require("path");
33
- var import_node_fs4 = require("fs");
34
- var import_electron4 = require("electron");
14
+ import { resolve } from "node:path";
15
+ import { existsSync as existsSync2, renameSync } from "node:fs";
16
+ import { app as app2 } from "electron";
35
17
 
36
18
  // src/updater/core.ts
37
- var import_node_fs3 = require("fs");
38
- var import_promises = require("fs/promises");
39
- var import_electron3 = require("electron");
40
-
41
- // src/utils/electron.ts
42
- var import_node_fs = require("fs");
43
- var import_node_path = require("path");
44
- var import_node_os = require("os");
45
- var import_electron = require("electron");
46
- var is = {
47
- dev: !import_electron.app.isPackaged,
48
- win: process.platform === "win32",
49
- mac: process.platform === "darwin",
50
- linux: process.platform === "linux"
51
- };
52
- function getPathFromAppNameAsar(...path) {
53
- return is.dev ? "DEV.asar" : (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getAppPath()), `${import_electron.app.name}.asar`, ...path);
54
- }
55
- function getVersions() {
56
- const platform = is.win ? "Windows" : is.mac ? "MacOS" : process.platform.toUpperCase();
57
- return {
58
- appVersion: is.dev ? import_electron.app.getVersion() : (0, import_node_fs.readFileSync)(getPathFromAppNameAsar("version"), "utf-8"),
59
- entryVersion: import_electron.app.getVersion(),
60
- electronVersion: process.versions.electron,
61
- nodeVersion: process.versions.node,
62
- systemVersion: `${platform} ${(0, import_node_os.release)()}`
63
- };
64
- }
65
- function restartApp() {
66
- import_electron.app.relaunch();
67
- import_electron.app.quit();
68
- }
69
- function waitAppReady(timeout = 1e3) {
70
- return import_electron.app.isReady() ? Promise.resolve() : new Promise((resolve2, reject) => {
71
- const _ = setTimeout(() => {
72
- reject(new Error("app is not ready"));
73
- }, timeout);
74
- import_electron.app.whenReady().then(() => {
75
- clearTimeout(_);
76
- resolve2();
77
- });
78
- });
79
- }
19
+ import { existsSync, rmSync, writeFileSync } from "node:fs";
20
+ import { app } from "electron";
80
21
 
81
- // src/utils/zip.ts
82
- var import_node_fs2 = require("fs");
83
- var import_node_zlib = require("zlib");
84
- async function unzipFile(gzipPath, targetFilePath = gzipPath.slice(0, -3)) {
85
- if (!(0, import_node_fs2.existsSync)(gzipPath)) {
86
- throw new Error(`path to zipped file not exist: ${gzipPath}`);
87
- }
88
- const compressedBuffer = (0, import_node_fs2.readFileSync)(gzipPath);
89
- return new Promise((resolve2, reject) => {
90
- (0, import_node_zlib.gunzip)(compressedBuffer, (err, buffer) => {
91
- (0, import_node_fs2.rmSync)(gzipPath);
92
- if (err) {
93
- reject(err);
94
- }
95
- (0, import_node_fs2.writeFileSync)(targetFilePath, buffer);
96
- resolve2(null);
97
- });
98
- });
99
- }
22
+ // src/crypto/dec.ts
23
+ import { createDecipheriv, createVerify } from "node:crypto";
100
24
 
101
- // src/utils/noDep.ts
102
- function parseVersion(version) {
103
- const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\.-]+))?/i;
104
- const match = semver.exec(version);
105
- if (!match) {
106
- throw new TypeError(`invalid version: ${version}`);
107
- }
108
- const [major, minor, patch] = match.slice(1, 4).map(Number);
109
- const ret = {
110
- major,
111
- minor,
112
- patch,
113
- stage: "",
114
- stageVersion: -1
115
- };
116
- if (match[4]) {
117
- let [stage, _v] = match[4].split(".");
118
- ret.stage = stage;
119
- ret.stageVersion = Number(_v) || -1;
120
- }
121
- if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch) || Number.isNaN(ret.stageVersion)) {
122
- throw new TypeError(`invalid version: ${version}`);
123
- }
124
- return ret;
125
- }
126
- function isUpdateJSON(json) {
127
- const is2 = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
128
- return is2(json) && is2(json?.beta);
25
+ // src/crypto/utils.ts
26
+ import { createHash } from "node:crypto";
27
+ function hashString(data, length) {
28
+ const hash = createHash("SHA256").update(data).digest("binary");
29
+ return Buffer.from(hash).subarray(0, length);
129
30
  }
130
31
 
131
- // src/crypto.ts
132
- var import_node_crypto = require("crypto");
133
- function decrypt(encryptedText, key2, iv) {
134
- const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-cbc", key2, iv);
32
+ // src/crypto/dec.ts
33
+ function decrypt(encryptedText, key, iv) {
34
+ const decipher = createDecipheriv("aes-256-cbc", key, iv);
135
35
  let decrypted = decipher.update(encryptedText, "base64url", "utf8");
136
36
  decrypted += decipher.final("utf8");
137
37
  return decrypted;
138
38
  }
139
- function key(data, length) {
140
- const hash = (0, import_node_crypto.createHash)("SHA256").update(data).digest("binary");
141
- return Buffer.from(hash).subarray(0, length);
142
- }
143
39
  var verify = (buffer, signature, cert) => {
144
40
  try {
145
- const [sig, version] = decrypt(signature, key(cert, 32), key(buffer, 16)).split("%");
146
- const result = (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
41
+ const [sig, version] = decrypt(signature, hashString(cert, 32), hashString(buffer, 16)).split("%");
42
+ const result = createVerify("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
147
43
  return result ? version : false;
148
44
  } catch (error) {
149
45
  return false;
@@ -176,17 +72,17 @@ var DownloadError = class extends Error {
176
72
  };
177
73
 
178
74
  // src/updater/defaultFunctions/download.ts
179
- var import_electron2 = require("electron");
75
+ import { net } from "electron";
180
76
  var downloadJSONDefault = async (url, headers) => {
181
77
  await waitAppReady();
182
78
  return new Promise((resolve2, reject) => {
183
- const request = import_electron2.net.request({
79
+ const request = net.request({
184
80
  url,
185
81
  method: "GET",
186
82
  redirect: "follow"
187
83
  });
188
- Object.keys(headers).forEach((key2) => {
189
- request.setHeader(key2, headers[key2]);
84
+ Object.keys(headers).forEach((key) => {
85
+ request.setHeader(key, headers[key]);
190
86
  });
191
87
  request.on("response", (res) => {
192
88
  let data = "";
@@ -214,13 +110,13 @@ var downloadBufferDefault = async (url, headers, total, onDownloading) => {
214
110
  await waitAppReady();
215
111
  let current = 0;
216
112
  return new Promise((resolve2, reject) => {
217
- const request = import_electron2.net.request({
113
+ const request = net.request({
218
114
  url,
219
115
  method: "GET",
220
116
  redirect: "follow"
221
117
  });
222
- Object.keys(headers).forEach((key2) => {
223
- request.setHeader(key2, headers[key2]);
118
+ Object.keys(headers).forEach((key) => {
119
+ request.setHeader(key, headers[key]);
224
120
  });
225
121
  request.on("response", (res) => {
226
122
  let data = [];
@@ -255,11 +151,11 @@ var compareVersionDefault = (version1, version2) => {
255
151
  }
256
152
  return str1 < str2;
257
153
  }
258
- for (let key2 of Object.keys(oldV)) {
259
- if (key2 === "stage" && compareStrings(oldV[key2], newV[key2])) {
154
+ for (let key of Object.keys(oldV)) {
155
+ if (key === "stage" && compareStrings(oldV[key], newV[key])) {
260
156
  return true;
261
- } else if (oldV[key2] !== newV[key2]) {
262
- return oldV[key2] < newV[key2];
157
+ } else if (oldV[key] !== newV[key]) {
158
+ return oldV[key] < newV[key];
263
159
  }
264
160
  }
265
161
  return false;
@@ -267,6 +163,7 @@ var compareVersionDefault = (version1, version2) => {
267
163
 
268
164
  // src/updater/core.ts
269
165
  var Updater = class {
166
+ CERT = __SIGNATURE_CERT__;
270
167
  info;
271
168
  option;
272
169
  asarPath;
@@ -298,8 +195,11 @@ var Updater = class {
298
195
  * initialize incremental updater
299
196
  * @param option UpdaterOption
300
197
  */
301
- constructor(option) {
198
+ constructor(option = {}) {
302
199
  this.option = option;
200
+ if (option.SIGNATURE_CERT) {
201
+ this.CERT = option.SIGNATURE_CERT;
202
+ }
303
203
  this.asarPath = getPathFromAppNameAsar();
304
204
  this.gzipPath = `${this.asarPath}.gz`;
305
205
  this.tmpFilePath = `${this.asarPath}.tmp`;
@@ -314,13 +214,13 @@ var Updater = class {
314
214
  return await compare(appVersion, version);
315
215
  }
316
216
  async parseData(format, data) {
317
- if ((0, import_node_fs3.existsSync)(this.tmpFilePath)) {
217
+ if (existsSync(this.tmpFilePath)) {
318
218
  this.logger?.warn(`remove tmp file: ${this.tmpFilePath}`);
319
- await (0, import_promises.rm)(this.tmpFilePath);
219
+ rmSync(this.tmpFilePath);
320
220
  }
321
- if ((0, import_node_fs3.existsSync)(this.gzipPath)) {
221
+ if (existsSync(this.gzipPath)) {
322
222
  this.logger?.warn(`remove .gz file: ${this.gzipPath}`);
323
- await (0, import_promises.rm)(this.gzipPath);
223
+ rmSync(this.gzipPath);
324
224
  }
325
225
  if (!["string", "object", "undefined"].includes(typeof data)) {
326
226
  throw new TypeError(`invalid type at format '${format}': ${data}`);
@@ -346,7 +246,7 @@ var Updater = class {
346
246
  } : {
347
247
  name: "releaseAsarURL",
348
248
  url: this.option.releaseAsarURL,
349
- repoFallback: `${this.option.repository}/releases/download/v${this.info?.version}/${import_electron3.app.name}-${this.info?.version}.asar.gz`,
249
+ repoFallback: `${this.option.repository}/releases/download/v${this.info?.version}/${app.name}-${this.info?.version}.asar.gz`,
350
250
  fn: this.option.overrideFunctions?.downloadBuffer ?? downloadBufferDefault
351
251
  };
352
252
  data ??= config.url;
@@ -426,13 +326,13 @@ var Updater = class {
426
326
  const buffer = await this.parseData("buffer", data);
427
327
  this.logger?.info("verify start");
428
328
  const _verify = this.option.overrideFunctions?.verifySignaure ?? verify;
429
- const _ver = await _verify(buffer, _sig, this.option.SIGNATURE_CERT);
329
+ const _ver = await _verify(buffer, _sig, this.CERT);
430
330
  if (!_ver) {
431
- throw new VerifyFailedError(_sig, this.option.SIGNATURE_CERT);
331
+ throw new VerifyFailedError(_sig, this.CERT);
432
332
  }
433
333
  this.logger?.info("verify success");
434
334
  this.logger?.info(`write to ${this.gzipPath}`);
435
- await (0, import_promises.writeFile)(this.gzipPath, buffer);
335
+ writeFileSync(this.gzipPath, buffer);
436
336
  this.logger?.info(`extract to ${this.tmpFilePath}`);
437
337
  await unzipFile(this.gzipPath, this.tmpFilePath);
438
338
  this.logger?.info(`download success, version: ${_ver}`);
@@ -465,8 +365,9 @@ var defaultOnInstall = (install, _, __, logger) => {
465
365
  install();
466
366
  logger?.info(`update success!`);
467
367
  };
468
- function initApp(appOptions) {
368
+ async function initApp(appOptions = {}) {
469
369
  const {
370
+ updater,
470
371
  electronDevDistPath = "../dist-electron",
471
372
  mainPath = "main/index.js",
472
373
  hooks
@@ -476,46 +377,34 @@ function initApp(appOptions) {
476
377
  beforeStart,
477
378
  onStartError
478
379
  } = hooks || {};
479
- function handleError(err, logger) {
380
+ function handleError(err, logger2) {
480
381
  console.error(err);
481
- onStartError?.(err, logger);
482
- import_electron4.app.quit();
382
+ onStartError?.(err, logger2);
383
+ app2.quit();
483
384
  }
484
- async function startup(updater) {
485
- const logger = updater.logger;
486
- try {
487
- const appNameAsarPath = getPathFromAppNameAsar();
488
- const tempAsarPath = `${appNameAsarPath}.tmp`;
489
- if ((0, import_node_fs4.existsSync)(tempAsarPath)) {
490
- logger?.info(`installing new asar: ${tempAsarPath}`);
491
- await onInstall(() => (0, import_node_fs4.renameSync)(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
492
- }
493
- const mainDir = is.dev ? electronDevDistPath : appNameAsarPath;
494
- const entry = (0, import_node_path2.resolve)(__dirname, mainDir, mainPath);
495
- await beforeStart?.(entry, logger);
496
- require(entry)(updater);
497
- } catch (error) {
498
- handleError(error, logger);
499
- }
385
+ let updaterInstance;
386
+ if (typeof updater === "object" || !updater) {
387
+ updaterInstance = createUpdater(updater);
388
+ } else {
389
+ updaterInstance = await updater();
500
390
  }
501
- let timer = setTimeout(() => {
502
- handleError("start app timeout, please start app with `initApp(options).startupWithUpdater(options)`");
503
- }, 3e3);
504
- return {
505
- async startupWithUpdater(updater) {
506
- clearTimeout(timer);
507
- if (typeof updater === "object") {
508
- await startup(createUpdater(updater));
509
- } else if (typeof updater === "function") {
510
- await startup(await updater());
511
- } else {
512
- handleError("invalid updater option or updater is not a function");
513
- }
391
+ const logger = updaterInstance.logger;
392
+ try {
393
+ const appNameAsarPath = getPathFromAppNameAsar();
394
+ const tempAsarPath = `${appNameAsarPath}.tmp`;
395
+ if (existsSync2(tempAsarPath)) {
396
+ logger?.info(`installing new asar: ${tempAsarPath}`);
397
+ await onInstall(() => renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
514
398
  }
515
- };
399
+ const mainDir = is.dev ? electronDevDistPath : appNameAsarPath;
400
+ const entry = resolve(__dirname, mainDir, mainPath);
401
+ await beforeStart?.(entry, logger);
402
+ __require(entry)(updaterInstance);
403
+ } catch (error) {
404
+ handleError(error, logger);
405
+ }
516
406
  }
517
- // Annotate the CommonJS export names for ESM import in node:
518
- 0 && (module.exports = {
407
+ export {
519
408
  DownloadError,
520
409
  MinimumVersionError,
521
410
  Updater,
@@ -523,4 +412,4 @@ function initApp(appOptions) {
523
412
  createUpdater,
524
413
  initApp,
525
414
  startupWithUpdater
526
- });
415
+ };