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/README.md +159 -111
- package/dist/{chunk-CMBFI77K.mjs → chunk-GB6VLKJZ.mjs} +48 -28
- package/dist/{chunk-5BZLJPHJ.mjs → chunk-GXZSAUBR.mjs} +1 -8
- package/dist/chunk-OUZLSVQC.mjs +148 -0
- package/dist/index.d.mts +102 -80
- package/dist/index.d.ts +102 -80
- package/dist/index.js +156 -95
- package/dist/index.mjs +100 -44
- package/dist/noDep-TvZoKVF8.d.mts +31 -0
- package/dist/noDep-TvZoKVF8.d.ts +31 -0
- package/dist/utils.d.mts +91 -46
- package/dist/utils.d.ts +91 -46
- package/dist/utils.js +153 -99
- package/dist/utils.mjs +18 -20
- package/dist/vite.d.mts +208 -41
- package/dist/vite.d.ts +208 -41
- package/dist/vite.js +249 -124
- package/dist/vite.mjs +226 -100
- package/package.json +21 -10
- package/dist/chunk-6UZHBPFT.mjs +0 -113
- package/dist/updateJson-synsK-Pt.d.mts +0 -11
- package/dist/updateJson-synsK-Pt.d.ts +0 -11
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
|
-
|
|
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
|
|
29
|
-
var
|
|
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/
|
|
33
|
-
var
|
|
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/
|
|
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
|
|
48
|
-
return
|
|
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
|
|
51
|
-
|
|
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
|
|
54
|
-
return import_electron.app.
|
|
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/
|
|
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
|
-
|
|
84
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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/
|
|
261
|
-
var
|
|
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
|
-
|
|
270
|
-
|
|
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
|
-
|
|
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
|
|
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 ${
|
|
295
|
-
return await compare(
|
|
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,
|
|
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,
|
|
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}/${
|
|
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
|
|
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
|
|
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
|
-
|
|
475
|
+
onInstall = defaultOnInstall,
|
|
421
476
|
beforeStart,
|
|
422
477
|
onStartError
|
|
423
478
|
} = hooks || {};
|
|
424
|
-
function handleError(
|
|
425
|
-
|
|
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
|
|
431
|
-
const
|
|
432
|
-
if ((0,
|
|
433
|
-
|
|
434
|
-
(0,
|
|
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 =
|
|
437
|
-
const entry = (0,
|
|
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(
|
|
498
|
+
handleError(error, logger);
|
|
442
499
|
}
|
|
443
500
|
}
|
|
444
501
|
let timer = setTimeout(() => {
|
|
445
|
-
handleError("start app timeout, please
|
|
502
|
+
handleError("start app timeout, please start app with `initApp(options).startupWithUpdater(options)`");
|
|
446
503
|
}, 3e3);
|
|
447
504
|
return {
|
|
448
|
-
async
|
|
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
|
-
|
|
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-
|
|
3
|
+
} from "./chunk-GXZSAUBR.mjs";
|
|
5
4
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
getPathFromAppNameAsar,
|
|
6
|
+
getVersions,
|
|
7
|
+
is,
|
|
8
|
+
restartApp,
|
|
10
9
|
waitAppReady
|
|
11
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-OUZLSVQC.mjs";
|
|
12
11
|
import {
|
|
13
12
|
__require,
|
|
13
|
+
isUpdateJSON,
|
|
14
14
|
parseVersion,
|
|
15
15
|
unzipFile
|
|
16
|
-
} from "./chunk-
|
|
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/
|
|
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/
|
|
141
|
-
var
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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
|
|
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 ${
|
|
175
|
-
return await compare(
|
|
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}/${
|
|
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
|
|
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
|
|
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
|
-
|
|
350
|
+
onInstall = defaultOnInstall,
|
|
301
351
|
beforeStart,
|
|
302
352
|
onStartError
|
|
303
353
|
} = hooks || {};
|
|
304
|
-
function handleError(
|
|
305
|
-
|
|
306
|
-
|
|
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
|
|
311
|
-
const
|
|
312
|
-
if (existsSync2(
|
|
313
|
-
|
|
314
|
-
renameSync(
|
|
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 =
|
|
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(
|
|
373
|
+
handleError(error, logger);
|
|
322
374
|
}
|
|
323
375
|
}
|
|
324
376
|
let timer = setTimeout(() => {
|
|
325
|
-
handleError("start app timeout, please
|
|
377
|
+
handleError("start app timeout, please start app with `initApp(options).startupWithUpdater(options)`");
|
|
326
378
|
}, 3e3);
|
|
327
379
|
return {
|
|
328
|
-
async
|
|
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
|
-
|
|
393
|
+
DownloadError,
|
|
394
|
+
MinimumVersionError,
|
|
395
|
+
Updater,
|
|
396
|
+
VerifyFailedError,
|
|
342
397
|
createUpdater,
|
|
343
|
-
initApp
|
|
398
|
+
initApp,
|
|
399
|
+
startupWithUpdater
|
|
344
400
|
};
|