electron-incremental-update 0.9.0 → 1.0.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.js CHANGED
@@ -20,41 +20,85 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
- IncrementalUpdater: () => IncrementalUpdater,
23
+ DownloadError: () => DownloadError,
24
+ MinimumVersionError: () => MinimumVersionError,
25
+ Updater: () => Updater,
26
+ VerifyFailedError: () => VerifyFailedError,
24
27
  createUpdater: () => createUpdater,
25
- initApp: () => initApp
28
+ initApp: () => initApp,
29
+ startupWithUpdater: () => startupWithUpdater
26
30
  });
27
31
  module.exports = __toCommonJS(src_exports);
28
- var import_node_path3 = require("path");
29
- var import_node_fs5 = require("fs");
32
+ var import_node_path2 = require("path");
33
+ var import_node_fs4 = require("fs");
30
34
  var import_electron4 = require("electron");
31
35
 
32
- // src/updater/index.ts
33
- var import_node_fs4 = require("fs");
36
+ // src/updater/core.ts
37
+ var import_node_fs3 = require("fs");
34
38
  var import_promises = require("fs/promises");
39
+ var import_electron3 = require("electron");
35
40
 
36
- // src/utils/core.ts
41
+ // src/utils/electron.ts
37
42
  var import_node_fs = require("fs");
38
43
  var import_node_path = require("path");
44
+ var import_node_os = require("os");
39
45
  var import_electron = require("electron");
40
- var DEFAULT_APP_NAME = "product";
41
46
  var is = {
42
47
  dev: !import_electron.app.isPackaged,
43
48
  win: process.platform === "win32",
44
49
  mac: process.platform === "darwin",
45
50
  linux: process.platform === "linux"
46
51
  };
47
- function getProductAsarPath(name = DEFAULT_APP_NAME) {
48
- return !import_electron.app.isPackaged ? (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getAppPath()), `${name}.asar`) : "DEV.asar";
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);
49
54
  }
50
- function getElectronVersion() {
51
- return import_electron.app.getVersion();
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();
52
68
  }
53
- function getAppVersion(name = DEFAULT_APP_NAME) {
54
- return import_electron.app.isPackaged ? (0, import_node_fs.readFileSync)((0, import_node_path.join)(getProductAsarPath(name), "version"), "utf-8") : getElectronVersion();
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
+ }
80
+
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
+ });
55
99
  }
56
100
 
57
- // src/utils/version.ts
101
+ // src/utils/noDep.ts
58
102
  function parseVersion(version) {
59
103
  const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\.-]+))?/i;
60
104
  const match = semver.exec(version);
@@ -79,41 +123,9 @@ function parseVersion(version) {
79
123
  }
80
124
  return ret;
81
125
  }
82
-
83
- // src/utils/zip.ts
84
- var import_node_fs2 = require("fs");
85
- var import_node_zlib = require("zlib");
86
- async function unzipFile(gzipPath, targetFilePath = gzipPath.slice(0, -3)) {
87
- if (!(0, import_node_fs2.existsSync)(gzipPath)) {
88
- throw new Error(`path to zipped file not exist: ${gzipPath}`);
89
- }
90
- const compressedBuffer = (0, import_node_fs2.readFileSync)(gzipPath);
91
- return new Promise((resolve2, reject) => {
92
- (0, import_node_zlib.gunzip)(compressedBuffer, (err, buffer) => {
93
- (0, import_node_fs2.rmSync)(gzipPath);
94
- if (err) {
95
- reject(err);
96
- }
97
- (0, import_node_fs2.writeFileSync)(targetFilePath, buffer);
98
- resolve2(null);
99
- });
100
- });
101
- }
102
-
103
- // src/utils/utils.ts
104
- var import_node_path2 = require("path");
105
- var import_node_fs3 = require("fs");
106
- var import_electron2 = require("electron");
107
- function waitAppReady(timeout = 1e3) {
108
- return import_electron2.app.isReady() ? Promise.resolve() : new Promise((resolve2, reject) => {
109
- const _ = setTimeout(() => {
110
- reject(new Error("app is not ready"));
111
- }, timeout);
112
- import_electron2.app.whenReady().then(() => {
113
- clearTimeout(_);
114
- resolve2();
115
- });
116
- });
126
+ function isUpdateJSON(json) {
127
+ const is2 = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
128
+ return is2(json) && is2(json?.beta);
117
129
  }
118
130
 
119
131
  // src/crypto.ts
@@ -138,12 +150,6 @@ var verify = (buffer, signature, cert) => {
138
150
  }
139
151
  };
140
152
 
141
- // src/updateJson.ts
142
- function isUpdateJSON(json) {
143
- const is2 = (j) => "signature" in j && "version" in j && "size" in j && "minimumVersion" in j;
144
- return is2(json) && "beta" in json && is2(json.beta);
145
- }
146
-
147
153
  // src/updater/types.ts
148
154
  var MinimumVersionError = class extends Error {
149
155
  currentVersion;
@@ -169,12 +175,12 @@ var DownloadError = class extends Error {
169
175
  }
170
176
  };
171
177
 
172
- // src/updater/defaultFunctions.ts
173
- var import_electron3 = require("electron");
178
+ // src/updater/defaultFunctions/download.ts
179
+ var import_electron2 = require("electron");
174
180
  var downloadJSONDefault = async (url, headers) => {
175
181
  await waitAppReady();
176
182
  return new Promise((resolve2, reject) => {
177
- const request = import_electron3.net.request({
183
+ const request = import_electron2.net.request({
178
184
  url,
179
185
  method: "GET",
180
186
  redirect: "follow"
@@ -208,7 +214,7 @@ var downloadBufferDefault = async (url, headers, total, onDownloading) => {
208
214
  await waitAppReady();
209
215
  let current = 0;
210
216
  return new Promise((resolve2, reject) => {
211
- const request = import_electron3.net.request({
217
+ const request = import_electron2.net.request({
212
218
  url,
213
219
  method: "GET",
214
220
  redirect: "follow"
@@ -236,6 +242,8 @@ var downloadBufferDefault = async (url, headers, total, onDownloading) => {
236
242
  request.end();
237
243
  });
238
244
  };
245
+
246
+ // src/updater/defaultFunctions/compareVersion.ts
239
247
  var compareVersionDefault = (version1, version2) => {
240
248
  const oldV = parseVersion(version1);
241
249
  const newV = parseVersion(version2);
@@ -257,49 +265,60 @@ var compareVersionDefault = (version1, version2) => {
257
265
  return false;
258
266
  };
259
267
 
260
- // src/updater/index.ts
261
- var IncrementalUpdater = class {
268
+ // src/updater/core.ts
269
+ var Updater = class {
262
270
  info;
263
271
  option;
264
272
  asarPath;
265
273
  gzipPath;
266
274
  tmpFilePath;
275
+ /**
276
+ * updater logger
277
+ */
267
278
  logger;
279
+ /**
280
+ * downloading progress hook
281
+ * @param progress download progress
282
+ * @example
283
+ * updater.onDownloading = ({ percent, total, current }) => {
284
+ * console.log(`download progress: ${percent}, total: ${total}, current: ${current}`)
285
+ * }
286
+ */
268
287
  onDownloading;
269
- get productName() {
270
- return this.option.productName;
271
- }
288
+ /**
289
+ * whether receive beta version
290
+ */
272
291
  get receiveBeta() {
273
292
  return !!this.option.receiveBeta;
274
293
  }
275
294
  set receiveBeta(receiveBeta) {
276
295
  this.option.receiveBeta = receiveBeta;
277
296
  }
297
+ /**
298
+ * initialize incremental updater
299
+ * @param option UpdaterOption
300
+ */
278
301
  constructor(option) {
279
302
  this.option = option;
280
- if (!option.productName) {
281
- this.option.productName = DEFAULT_APP_NAME;
282
- }
283
- this.asarPath = getProductAsarPath(this.productName);
303
+ this.asarPath = getPathFromAppNameAsar();
284
304
  this.gzipPath = `${this.asarPath}.gz`;
285
305
  this.tmpFilePath = `${this.asarPath}.tmp`;
286
306
  }
287
307
  async needUpdate(version, minVersion) {
288
308
  const compare = this.option.overrideFunctions?.compareVersion ?? compareVersionDefault;
289
- const productVersion = getAppVersion(this.option.productName);
290
- const entryVersion = getElectronVersion();
309
+ const { appVersion, entryVersion } = getVersions();
291
310
  if (await compare(entryVersion, minVersion)) {
292
311
  throw new MinimumVersionError(entryVersion, minVersion);
293
312
  }
294
- this.logger?.info(`check update: current version is ${productVersion}, new version is ${version}`);
295
- return await compare(productVersion, version);
313
+ this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
314
+ return await compare(appVersion, version);
296
315
  }
297
316
  async parseData(format, data) {
298
- if ((0, import_node_fs4.existsSync)(this.tmpFilePath)) {
317
+ if ((0, import_node_fs3.existsSync)(this.tmpFilePath)) {
299
318
  this.logger?.warn(`remove tmp file: ${this.tmpFilePath}`);
300
319
  await (0, import_promises.rm)(this.tmpFilePath);
301
320
  }
302
- if ((0, import_node_fs4.existsSync)(this.gzipPath)) {
321
+ if ((0, import_node_fs3.existsSync)(this.gzipPath)) {
303
322
  this.logger?.warn(`remove .gz file: ${this.gzipPath}`);
304
323
  await (0, import_promises.rm)(this.gzipPath);
305
324
  }
@@ -327,7 +346,7 @@ var IncrementalUpdater = class {
327
346
  } : {
328
347
  name: "releaseAsarURL",
329
348
  url: this.option.releaseAsarURL,
330
- repoFallback: `${this.option.repository}/releases/download/v${this.info?.version}/${this.productName}-${this.info?.version}.asar.gz`,
349
+ repoFallback: `${this.option.repository}/releases/download/v${this.info?.version}/${import_electron3.app.name}-${this.info?.version}.asar.gz`,
331
350
  fn: this.option.overrideFunctions?.downloadBuffer ?? downloadBufferDefault
332
351
  };
333
352
  data ??= config.url;
@@ -350,6 +369,16 @@ var IncrementalUpdater = class {
350
369
  throw new DownloadError(e.toString());
351
370
  }
352
371
  }
372
+ /**
373
+ * check update info
374
+ *
375
+ * if you want to update **offline**, you can set `data` and `sig` add update info
376
+ * @param data custom download URL of `updatejson` or existing update json
377
+ * @returns
378
+ * - Available:`{size: number, version: string}`
379
+ * - Unavailable: `undefined`
380
+ * - Fail: `CheckResultError`
381
+ */
353
382
  async checkUpdate(data) {
354
383
  try {
355
384
  let { signature, size, version, minimumVersion, beta } = await this.parseData("json", data);
@@ -371,13 +400,23 @@ var IncrementalUpdater = class {
371
400
  version,
372
401
  size
373
402
  };
374
- return { size, version };
403
+ return this.info;
375
404
  }
376
405
  } catch (error) {
377
406
  this.logger?.error("check update failed", error);
378
407
  return error;
379
408
  }
380
409
  }
410
+ /**
411
+ * download update
412
+ *
413
+ * if you want to update **offline**, you can set both `data` and `sig` to verify and install
414
+ * @param data custom download URL of `asar.gz` or existing `asar.gz` buffer
415
+ * @param sig signature
416
+ * @returns
417
+ * - `true`: success
418
+ * - `DownloadResultError`: fail
419
+ */
381
420
  async download(data, sig) {
382
421
  try {
383
422
  const _sig = sig ?? this.info?.signature;
@@ -404,48 +443,66 @@ var IncrementalUpdater = class {
404
443
  return error;
405
444
  }
406
445
  }
446
+ /**
447
+ * quit App and install
448
+ */
449
+ quitAndInstall() {
450
+ this.logger?.info("quit and install");
451
+ restartApp();
452
+ }
407
453
  };
454
+
455
+ // src/updater/index.ts
408
456
  function createUpdater(option) {
409
- return new IncrementalUpdater(option);
457
+ return new Updater(option);
410
458
  }
411
459
 
412
460
  // src/index.ts
461
+ function startupWithUpdater(fn) {
462
+ return fn;
463
+ }
464
+ var defaultOnInstall = (install, _, __, logger) => {
465
+ install();
466
+ logger?.info(`update success!`);
467
+ };
413
468
  function initApp(appOptions) {
414
469
  const {
415
- electronDevDistPath = "dist-electron",
470
+ electronDevDistPath = "../dist-electron",
416
471
  mainPath = "main/index.js",
417
472
  hooks
418
473
  } = appOptions || {};
419
474
  const {
420
- beforeDoUpdate,
475
+ onInstall = defaultOnInstall,
421
476
  beforeStart,
422
477
  onStartError
423
478
  } = hooks || {};
424
- function handleError(msg) {
425
- onStartError?.(new Error(msg));
479
+ function handleError(err, logger) {
480
+ console.error(err);
481
+ onStartError?.(err, logger);
426
482
  import_electron4.app.quit();
427
483
  }
428
484
  async function startup(updater) {
485
+ const logger = updater.logger;
429
486
  try {
430
- const asarPath = getProductAsarPath(updater.productName);
431
- const updateAsarPath = `${asarPath}.tmp`;
432
- if ((0, import_node_fs5.existsSync)(updateAsarPath)) {
433
- await beforeDoUpdate?.(asarPath, updateAsarPath);
434
- (0, import_node_fs5.renameSync)(updateAsarPath, asarPath);
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);
435
492
  }
436
- const mainDir = import_electron4.app.isPackaged ? asarPath : electronDevDistPath;
437
- const entry = (0, import_node_path3.resolve)(__dirname, mainDir, mainPath);
438
- await beforeStart?.(entry);
493
+ const mainDir = is.dev ? electronDevDistPath : appNameAsarPath;
494
+ const entry = (0, import_node_path2.resolve)(__dirname, mainDir, mainPath);
495
+ await beforeStart?.(entry, logger);
439
496
  require(entry)(updater);
440
497
  } catch (error) {
441
- handleError(`failed to start app, ${error}`);
498
+ handleError(error, logger);
442
499
  }
443
500
  }
444
501
  let timer = setTimeout(() => {
445
- handleError("start app timeout, please call .setUpdater() to set updater and start");
502
+ handleError("start app timeout, please start app with `initApp(options).startupWithUpdater(options)`");
446
503
  }, 3e3);
447
504
  return {
448
- async setUpdater(updater) {
505
+ async startupWithUpdater(updater) {
449
506
  clearTimeout(timer);
450
507
  if (typeof updater === "object") {
451
508
  await startup(createUpdater(updater));
@@ -459,7 +516,11 @@ function initApp(appOptions) {
459
516
  }
460
517
  // Annotate the CommonJS export names for ESM import in node:
461
518
  0 && (module.exports = {
462
- IncrementalUpdater,
519
+ DownloadError,
520
+ MinimumVersionError,
521
+ Updater,
522
+ VerifyFailedError,
463
523
  createUpdater,
464
- initApp
524
+ initApp,
525
+ startupWithUpdater
465
526
  });
package/dist/index.mjs CHANGED
@@ -1,28 +1,29 @@
1
1
  import {
2
- isUpdateJSON,
3
2
  verify
4
- } from "./chunk-5BZLJPHJ.mjs";
3
+ } from "./chunk-GXZSAUBR.mjs";
5
4
  import {
6
- DEFAULT_APP_NAME,
7
- getAppVersion,
8
- getElectronVersion,
9
- getProductAsarPath,
5
+ getPathFromAppNameAsar,
6
+ getVersions,
7
+ is,
8
+ restartApp,
10
9
  waitAppReady
11
- } from "./chunk-6UZHBPFT.mjs";
10
+ } from "./chunk-OUZLSVQC.mjs";
12
11
  import {
13
12
  __require,
13
+ isUpdateJSON,
14
14
  parseVersion,
15
15
  unzipFile
16
- } from "./chunk-CMBFI77K.mjs";
16
+ } from "./chunk-GB6VLKJZ.mjs";
17
17
 
18
18
  // src/index.ts
19
19
  import { resolve } from "node:path";
20
20
  import { existsSync as existsSync2, renameSync } from "node:fs";
21
- import { app } from "electron";
21
+ import { app as app2 } from "electron";
22
22
 
23
- // src/updater/index.ts
23
+ // src/updater/core.ts
24
24
  import { existsSync } from "node:fs";
25
25
  import { rm, writeFile } from "node:fs/promises";
26
+ import { app } from "electron";
26
27
 
27
28
  // src/updater/types.ts
28
29
  var MinimumVersionError = class extends Error {
@@ -49,7 +50,7 @@ var DownloadError = class extends Error {
49
50
  }
50
51
  };
51
52
 
52
- // src/updater/defaultFunctions.ts
53
+ // src/updater/defaultFunctions/download.ts
53
54
  import { net } from "electron";
54
55
  var downloadJSONDefault = async (url, headers) => {
55
56
  await waitAppReady();
@@ -116,6 +117,8 @@ var downloadBufferDefault = async (url, headers, total, onDownloading) => {
116
117
  request.end();
117
118
  });
118
119
  };
120
+
121
+ // src/updater/defaultFunctions/compareVersion.ts
119
122
  var compareVersionDefault = (version1, version2) => {
120
123
  const oldV = parseVersion(version1);
121
124
  const newV = parseVersion(version2);
@@ -137,42 +140,53 @@ var compareVersionDefault = (version1, version2) => {
137
140
  return false;
138
141
  };
139
142
 
140
- // src/updater/index.ts
141
- var IncrementalUpdater = class {
143
+ // src/updater/core.ts
144
+ var Updater = class {
142
145
  info;
143
146
  option;
144
147
  asarPath;
145
148
  gzipPath;
146
149
  tmpFilePath;
150
+ /**
151
+ * updater logger
152
+ */
147
153
  logger;
154
+ /**
155
+ * downloading progress hook
156
+ * @param progress download progress
157
+ * @example
158
+ * updater.onDownloading = ({ percent, total, current }) => {
159
+ * console.log(`download progress: ${percent}, total: ${total}, current: ${current}`)
160
+ * }
161
+ */
148
162
  onDownloading;
149
- get productName() {
150
- return this.option.productName;
151
- }
163
+ /**
164
+ * whether receive beta version
165
+ */
152
166
  get receiveBeta() {
153
167
  return !!this.option.receiveBeta;
154
168
  }
155
169
  set receiveBeta(receiveBeta) {
156
170
  this.option.receiveBeta = receiveBeta;
157
171
  }
172
+ /**
173
+ * initialize incremental updater
174
+ * @param option UpdaterOption
175
+ */
158
176
  constructor(option) {
159
177
  this.option = option;
160
- if (!option.productName) {
161
- this.option.productName = DEFAULT_APP_NAME;
162
- }
163
- this.asarPath = getProductAsarPath(this.productName);
178
+ this.asarPath = getPathFromAppNameAsar();
164
179
  this.gzipPath = `${this.asarPath}.gz`;
165
180
  this.tmpFilePath = `${this.asarPath}.tmp`;
166
181
  }
167
182
  async needUpdate(version, minVersion) {
168
183
  const compare = this.option.overrideFunctions?.compareVersion ?? compareVersionDefault;
169
- const productVersion = getAppVersion(this.option.productName);
170
- const entryVersion = getElectronVersion();
184
+ const { appVersion, entryVersion } = getVersions();
171
185
  if (await compare(entryVersion, minVersion)) {
172
186
  throw new MinimumVersionError(entryVersion, minVersion);
173
187
  }
174
- this.logger?.info(`check update: current version is ${productVersion}, new version is ${version}`);
175
- return await compare(productVersion, version);
188
+ this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
189
+ return await compare(appVersion, version);
176
190
  }
177
191
  async parseData(format, data) {
178
192
  if (existsSync(this.tmpFilePath)) {
@@ -207,7 +221,7 @@ var IncrementalUpdater = class {
207
221
  } : {
208
222
  name: "releaseAsarURL",
209
223
  url: this.option.releaseAsarURL,
210
- repoFallback: `${this.option.repository}/releases/download/v${this.info?.version}/${this.productName}-${this.info?.version}.asar.gz`,
224
+ repoFallback: `${this.option.repository}/releases/download/v${this.info?.version}/${app.name}-${this.info?.version}.asar.gz`,
211
225
  fn: this.option.overrideFunctions?.downloadBuffer ?? downloadBufferDefault
212
226
  };
213
227
  data ??= config.url;
@@ -230,6 +244,16 @@ var IncrementalUpdater = class {
230
244
  throw new DownloadError(e.toString());
231
245
  }
232
246
  }
247
+ /**
248
+ * check update info
249
+ *
250
+ * if you want to update **offline**, you can set `data` and `sig` add update info
251
+ * @param data custom download URL of `updatejson` or existing update json
252
+ * @returns
253
+ * - Available:`{size: number, version: string}`
254
+ * - Unavailable: `undefined`
255
+ * - Fail: `CheckResultError`
256
+ */
233
257
  async checkUpdate(data) {
234
258
  try {
235
259
  let { signature, size, version, minimumVersion, beta } = await this.parseData("json", data);
@@ -251,13 +275,23 @@ var IncrementalUpdater = class {
251
275
  version,
252
276
  size
253
277
  };
254
- return { size, version };
278
+ return this.info;
255
279
  }
256
280
  } catch (error) {
257
281
  this.logger?.error("check update failed", error);
258
282
  return error;
259
283
  }
260
284
  }
285
+ /**
286
+ * download update
287
+ *
288
+ * if you want to update **offline**, you can set both `data` and `sig` to verify and install
289
+ * @param data custom download URL of `asar.gz` or existing `asar.gz` buffer
290
+ * @param sig signature
291
+ * @returns
292
+ * - `true`: success
293
+ * - `DownloadResultError`: fail
294
+ */
261
295
  async download(data, sig) {
262
296
  try {
263
297
  const _sig = sig ?? this.info?.signature;
@@ -284,48 +318,66 @@ var IncrementalUpdater = class {
284
318
  return error;
285
319
  }
286
320
  }
321
+ /**
322
+ * quit App and install
323
+ */
324
+ quitAndInstall() {
325
+ this.logger?.info("quit and install");
326
+ restartApp();
327
+ }
287
328
  };
329
+
330
+ // src/updater/index.ts
288
331
  function createUpdater(option) {
289
- return new IncrementalUpdater(option);
332
+ return new Updater(option);
290
333
  }
291
334
 
292
335
  // src/index.ts
336
+ function startupWithUpdater(fn) {
337
+ return fn;
338
+ }
339
+ var defaultOnInstall = (install, _, __, logger) => {
340
+ install();
341
+ logger?.info(`update success!`);
342
+ };
293
343
  function initApp(appOptions) {
294
344
  const {
295
- electronDevDistPath = "dist-electron",
345
+ electronDevDistPath = "../dist-electron",
296
346
  mainPath = "main/index.js",
297
347
  hooks
298
348
  } = appOptions || {};
299
349
  const {
300
- beforeDoUpdate,
350
+ onInstall = defaultOnInstall,
301
351
  beforeStart,
302
352
  onStartError
303
353
  } = hooks || {};
304
- function handleError(msg) {
305
- onStartError?.(new Error(msg));
306
- app.quit();
354
+ function handleError(err, logger) {
355
+ console.error(err);
356
+ onStartError?.(err, logger);
357
+ app2.quit();
307
358
  }
308
359
  async function startup(updater) {
360
+ const logger = updater.logger;
309
361
  try {
310
- const asarPath = getProductAsarPath(updater.productName);
311
- const updateAsarPath = `${asarPath}.tmp`;
312
- if (existsSync2(updateAsarPath)) {
313
- await beforeDoUpdate?.(asarPath, updateAsarPath);
314
- renameSync(updateAsarPath, asarPath);
362
+ const appNameAsarPath = getPathFromAppNameAsar();
363
+ const tempAsarPath = `${appNameAsarPath}.tmp`;
364
+ if (existsSync2(tempAsarPath)) {
365
+ logger?.info(`installing new asar: ${tempAsarPath}`);
366
+ await onInstall(() => renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
315
367
  }
316
- const mainDir = app.isPackaged ? asarPath : electronDevDistPath;
368
+ const mainDir = is.dev ? electronDevDistPath : appNameAsarPath;
317
369
  const entry = resolve(__dirname, mainDir, mainPath);
318
- await beforeStart?.(entry);
370
+ await beforeStart?.(entry, logger);
319
371
  __require(entry)(updater);
320
372
  } catch (error) {
321
- handleError(`failed to start app, ${error}`);
373
+ handleError(error, logger);
322
374
  }
323
375
  }
324
376
  let timer = setTimeout(() => {
325
- handleError("start app timeout, please call .setUpdater() to set updater and start");
377
+ handleError("start app timeout, please start app with `initApp(options).startupWithUpdater(options)`");
326
378
  }, 3e3);
327
379
  return {
328
- async setUpdater(updater) {
380
+ async startupWithUpdater(updater) {
329
381
  clearTimeout(timer);
330
382
  if (typeof updater === "object") {
331
383
  await startup(createUpdater(updater));
@@ -338,7 +390,11 @@ function initApp(appOptions) {
338
390
  };
339
391
  }
340
392
  export {
341
- IncrementalUpdater,
393
+ DownloadError,
394
+ MinimumVersionError,
395
+ Updater,
396
+ VerifyFailedError,
342
397
  createUpdater,
343
- initApp
398
+ initApp,
399
+ startupWithUpdater
344
400
  };