electron-incremental-update 3.0.0-beta.5 → 3.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 +338 -373
- package/dist/crypto-BSky88mL.cjs +259 -0
- package/dist/crypto-DZzMmoz2.mjs +164 -0
- package/dist/{download-BN4uMS4_.d.mts → download-BVmLiAvB.d.cts} +2 -2
- package/dist/download-BdX4fZYM.mjs +130 -0
- package/dist/{download-DO7iuxEJ.d.cts → download-GONr15zK.d.mts} +2 -2
- package/dist/download-KySXUyWC.cjs +165 -0
- package/dist/{electron-BJCk7uxG.mjs → electron-BrIF1urZ.mjs} +38 -13
- package/dist/electron-CaS0I3S2.cjs +346 -0
- package/dist/index.cjs +66 -34
- package/dist/index.d.cts +10 -13
- package/dist/index.d.mts +10 -13
- package/dist/index.mjs +62 -31
- package/dist/local-C5jw-7o5.mjs +105 -0
- package/dist/local-DbXBG1D9.cjs +118 -0
- package/dist/provider.cjs +24 -43
- package/dist/provider.d.cts +58 -20
- package/dist/provider.d.mts +58 -20
- package/dist/provider.mjs +12 -33
- package/dist/{types-BM9Jfu7q.d.cts → types-q78spjKB.d.cts} +22 -7
- package/dist/{types-DASqEPXE.d.mts → types-q78spjKB.d.mts} +22 -7
- package/dist/utils.cjs +22 -22
- package/dist/utils.d.cts +6 -6
- package/dist/utils.d.mts +6 -6
- package/dist/utils.mjs +4 -5
- package/dist/vite.d.mts +99 -110
- package/dist/vite.mjs +656 -732
- package/package.json +30 -35
- package/dist/electron-C-qmVhAt.cjs +0 -321
- package/dist/version--eVB2A7n.mjs +0 -72
- package/dist/version-aPrLuz_-.cjs +0 -129
- package/dist/zip-BCC7FAQ_.cjs +0 -264
- package/dist/zip-Dwm7s1C9.mjs +0 -185
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_crypto = require("./crypto-BSky88mL.cjs");
|
|
3
|
+
const require_local = require("./local-DbXBG1D9.cjs");
|
|
4
|
+
const require_electron = require("./electron-CaS0I3S2.cjs");
|
|
4
5
|
let node_fs = require("node:fs");
|
|
5
|
-
node_fs =
|
|
6
|
+
node_fs = require_crypto.__toESM(node_fs, 1);
|
|
6
7
|
let node_path = require("node:path");
|
|
7
|
-
node_path =
|
|
8
|
+
node_path = require_crypto.__toESM(node_path, 1);
|
|
9
|
+
let electron = require("electron");
|
|
8
10
|
let node_events = require("node:events");
|
|
9
|
-
|
|
10
11
|
//#region src/entry/types.ts
|
|
11
12
|
var UpdaterError = class extends Error {
|
|
12
13
|
code;
|
|
@@ -15,12 +16,12 @@ var UpdaterError = class extends Error {
|
|
|
15
16
|
this.code = code;
|
|
16
17
|
}
|
|
17
18
|
};
|
|
18
|
-
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/entry/updater.ts
|
|
21
21
|
var Updater = class extends node_events.EventEmitter {
|
|
22
22
|
CERT;
|
|
23
23
|
controller;
|
|
24
|
+
getCurrentAppVersion;
|
|
24
25
|
info;
|
|
25
26
|
tmpFilePath;
|
|
26
27
|
processing = false;
|
|
@@ -47,6 +48,7 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
47
48
|
this.receiveBeta = options.receiveBeta;
|
|
48
49
|
this.CERT = options.SIGNATURE_CERT || __EIU_SIGNATURE_CERT__;
|
|
49
50
|
this.logger = options.logger;
|
|
51
|
+
this.getCurrentAppVersion = options.getAppVersion ?? require_electron.getAppVersion;
|
|
50
52
|
this.controller = new AbortController();
|
|
51
53
|
if (require_electron.isDev && !this.logger) {
|
|
52
54
|
this.logger = {
|
|
@@ -57,10 +59,9 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
57
59
|
};
|
|
58
60
|
this.logger.info("No logger set, enable dev-only logger");
|
|
59
61
|
}
|
|
60
|
-
if (!this.provider) this.logger?.debug("WARN: No update provider");
|
|
61
62
|
}
|
|
62
63
|
async fetch(format, data) {
|
|
63
|
-
if (typeof data === "object") if (format === "json" &&
|
|
64
|
+
if (typeof data === "object") if (format === "json" && require_crypto.isUpdateJSON(data) || format === "buffer" && Buffer.isBuffer(data)) return data;
|
|
64
65
|
else {
|
|
65
66
|
this.err("Invalid type", "ERR_PARAM", `Invalid type at format '${format}': ${JSON.stringify(data)}`);
|
|
66
67
|
return;
|
|
@@ -90,9 +91,12 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
90
91
|
const err = new UpdaterError(code, errorInfo);
|
|
91
92
|
this.logger?.error(`[${code}] ${msg}`, err);
|
|
92
93
|
this.cleanup();
|
|
93
|
-
this.emit("error", err);
|
|
94
|
+
if (this.listenerCount("error") > 0) this.emit("error", err);
|
|
94
95
|
}
|
|
95
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Check update info using default options
|
|
98
|
+
*/
|
|
99
|
+
async checkForUpdates() {
|
|
96
100
|
const emitUnavailable = (msg, code, info) => {
|
|
97
101
|
this.logger?.info(`[${code}] ${msg}`);
|
|
98
102
|
this.logger?.debug("Check update end");
|
|
@@ -100,18 +104,18 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
100
104
|
this.emit("update-not-available", code, msg, info);
|
|
101
105
|
return false;
|
|
102
106
|
};
|
|
107
|
+
if (!this.provider) {
|
|
108
|
+
const msg = "No update json or provider";
|
|
109
|
+
this.err("Check update failed", "ERR_PARAM", msg);
|
|
110
|
+
return emitUnavailable(msg, "UNAVAILABLE_ERROR");
|
|
111
|
+
}
|
|
103
112
|
if (this.processing) {
|
|
104
113
|
this.logger?.info("Updater is already processing, skip check update");
|
|
105
114
|
return false;
|
|
106
115
|
}
|
|
107
116
|
this.processing = true;
|
|
108
117
|
this.logger?.debug("Check update start");
|
|
109
|
-
|
|
110
|
-
const msg = "No update json or provider";
|
|
111
|
-
this.err("Check update failed", "ERR_PARAM", msg);
|
|
112
|
-
return emitUnavailable(msg, "UNAVAILABLE_ERROR");
|
|
113
|
-
}
|
|
114
|
-
const _data = await this.fetch("json", data);
|
|
118
|
+
const _data = await this.fetch("json");
|
|
115
119
|
if (!_data) return emitUnavailable("Failed to get update info", "UNAVAILABLE_ERROR");
|
|
116
120
|
const { signature, version, minimumVersion, url, ...rest } = this.receiveBeta ? _data.beta : _data;
|
|
117
121
|
const info = {
|
|
@@ -124,12 +128,12 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
124
128
|
signature,
|
|
125
129
|
minimumVersion,
|
|
126
130
|
version,
|
|
127
|
-
appVersion:
|
|
131
|
+
appVersion: this.getCurrentAppVersion(),
|
|
128
132
|
entryVersion: require_electron.getEntryVersion(),
|
|
129
133
|
...rest
|
|
130
134
|
};
|
|
131
135
|
this.logger?.debug(`Checked update, version: ${version}, signature: ${signature}`);
|
|
132
|
-
if (require_electron.isDev && !this.forceUpdate
|
|
136
|
+
if (require_electron.isDev && !this.forceUpdate) return emitUnavailable("Skip check update in dev mode. To force update, set `updater.forceUpdate` to `true`", "UNAVAILABLE_DEV");
|
|
133
137
|
const isLowerVersion = this.provider.isLowerVersion;
|
|
134
138
|
try {
|
|
135
139
|
if (isLowerVersion(extraVersionInfo.entryVersion, minimumVersion)) return emitUnavailable(`Entry Version (${extraVersionInfo.entryVersion}) < MinimumVersion (${minimumVersion})`, "UNAVAILABLE_VERSION", extraVersionInfo);
|
|
@@ -147,32 +151,39 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
147
151
|
return emitUnavailable(msg, "UNAVAILABLE_ERROR", extraVersionInfo);
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Download update using default options
|
|
156
|
+
*/
|
|
157
|
+
async downloadUpdate() {
|
|
151
158
|
const emitError = (code, errorInfo) => {
|
|
152
159
|
this.err(`Download update failed`, code, errorInfo);
|
|
153
160
|
this.logger?.debug("Download update end");
|
|
154
161
|
this.processing = false;
|
|
155
162
|
return false;
|
|
156
163
|
};
|
|
164
|
+
if (!this.provider) return emitError("ERR_PARAM", "No update asar buffer and provider");
|
|
157
165
|
if (this.processing) {
|
|
158
166
|
this.logger?.info("Updater is already processing, skip download update");
|
|
159
167
|
return false;
|
|
160
168
|
}
|
|
161
169
|
this.processing = true;
|
|
162
170
|
this.logger?.debug("Download update start");
|
|
163
|
-
const _sig =
|
|
164
|
-
const _version =
|
|
165
|
-
if (!_sig || !_version) return emitError("ERR_PARAM", "No update signature, please call `checkUpdate` first
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
const _sig = this.info?.signature;
|
|
172
|
+
const _version = this.info?.version;
|
|
173
|
+
if (!_sig || !_version) return emitError("ERR_PARAM", "No update signature, please call `checkUpdate` first");
|
|
174
|
+
const buffer = await this.fetch("buffer");
|
|
175
|
+
if (!buffer) {
|
|
176
|
+
this.logger?.debug("Download update end");
|
|
177
|
+
this.processing = false;
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
169
180
|
this.logger?.debug("Validation start");
|
|
170
|
-
if (!await this.provider.
|
|
181
|
+
if (!await this.provider.verifySignature(buffer, _version, _sig, this.CERT)) return emitError("ERR_VALIDATE", "Invalid update asar file");
|
|
171
182
|
this.logger?.debug("Validation end");
|
|
172
183
|
try {
|
|
173
184
|
this.tmpFilePath = `${require_electron.getPathFromAppNameAsar()}.tmp`;
|
|
174
185
|
this.logger?.debug(`Install to ${this.tmpFilePath}`);
|
|
175
|
-
node_fs.default.writeFileSync(this.tmpFilePath, await this.provider.
|
|
186
|
+
node_fs.default.writeFileSync(this.tmpFilePath, await this.provider.decompressFile(buffer));
|
|
176
187
|
this.logger?.info(`Download success, version: ${_version}`);
|
|
177
188
|
this.info = void 0;
|
|
178
189
|
this.emit("update-downloaded");
|
|
@@ -206,7 +217,6 @@ var Updater = class extends node_events.EventEmitter {
|
|
|
206
217
|
async function autoUpdate(updater) {
|
|
207
218
|
if (await updater.checkForUpdates() && await updater.downloadUpdate()) updater.quitAndInstall();
|
|
208
219
|
}
|
|
209
|
-
|
|
210
220
|
//#endregion
|
|
211
221
|
//#region src/entry/core.ts
|
|
212
222
|
/**
|
|
@@ -231,6 +241,25 @@ const defaultOnInstall = (install, _, __, logger) => {
|
|
|
231
241
|
install();
|
|
232
242
|
logger?.info(`update success!`);
|
|
233
243
|
};
|
|
244
|
+
function readDevAsarVersion() {
|
|
245
|
+
try {
|
|
246
|
+
return node_fs.default.readFileSync(require_electron.getPathFromAppNameAsar("version"), "utf-8").trim();
|
|
247
|
+
} catch {
|
|
248
|
+
return electron.app.getVersion();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function resolveUpdaterOption(updater) {
|
|
252
|
+
if (!require_electron.isDev || !__EIU_LOCAL_DEV_UPDATE__ || updater?.provider) return updater;
|
|
253
|
+
return {
|
|
254
|
+
...updater,
|
|
255
|
+
provider: new require_local.LocalDevProvider({
|
|
256
|
+
baseDir: __EIU_LOCAL_DEV_UPDATE_DIR__,
|
|
257
|
+
chunkDelay: __EIU_LOCAL_DEV_UPDATE_CHUNK_DELAY__,
|
|
258
|
+
chunkSize: __EIU_LOCAL_DEV_UPDATE_CHUNK_SIZE__
|
|
259
|
+
}),
|
|
260
|
+
getAppVersion: updater?.getAppVersion ?? readDevAsarVersion
|
|
261
|
+
};
|
|
262
|
+
}
|
|
234
263
|
/**
|
|
235
264
|
* Initialize Electron with updater
|
|
236
265
|
* @example
|
|
@@ -249,7 +278,9 @@ const defaultOnInstall = (install, _, __, logger) => {
|
|
|
249
278
|
async function createElectronApp(appOptions = {}) {
|
|
250
279
|
const appNameAsarPath = require_electron.getPathFromAppNameAsar();
|
|
251
280
|
const { mainPath = require_electron.isDev ? node_path.default.join(electron.app.getAppPath(), __EIU_ELECTRON_DIST_PATH__, "main", __EIU_MAIN_FILE__) : node_path.default.join(node_path.default.dirname(electron.app.getAppPath()), __EIU_ASAR_BASE_NAME__, "main", __EIU_MAIN_FILE__), updater, onInstall = defaultOnInstall, beforeStart, onStartError } = appOptions;
|
|
252
|
-
const
|
|
281
|
+
const useAutoLocalDevProvider = require_electron.isDev && __EIU_LOCAL_DEV_UPDATE__ && typeof updater !== "function";
|
|
282
|
+
const updaterInstance = typeof updater === "object" || !updater ? new Updater(resolveUpdaterOption(updater)) : await updater();
|
|
283
|
+
if (useAutoLocalDevProvider && updaterInstance.provider?.name === "LocalDevProvider") updaterInstance.forceUpdate = true;
|
|
253
284
|
const logger = updaterInstance.logger;
|
|
254
285
|
try {
|
|
255
286
|
const tempAsarPath = `${appNameAsarPath}.tmp`;
|
|
@@ -258,8 +289,10 @@ async function createElectronApp(appOptions = {}) {
|
|
|
258
289
|
await onInstall(() => node_fs.default.renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
|
|
259
290
|
}
|
|
260
291
|
await beforeStart?.(mainPath, logger);
|
|
261
|
-
if (__EIU_IS_ESM__)
|
|
262
|
-
|
|
292
|
+
if (__EIU_IS_ESM__) {
|
|
293
|
+
const { pathToFileURL } = await import("node:url");
|
|
294
|
+
runWithDefaultExport(await import(pathToFileURL(mainPath).href), updaterInstance);
|
|
295
|
+
} else runWithDefaultExport(require(mainPath), updaterInstance);
|
|
263
296
|
} catch (error) {
|
|
264
297
|
logger?.error("Fail to startup", error);
|
|
265
298
|
onStartError?.(error, logger);
|
|
@@ -270,11 +303,10 @@ async function createElectronApp(appOptions = {}) {
|
|
|
270
303
|
* @deprecated Use {@link createElectronApp} instead
|
|
271
304
|
*/
|
|
272
305
|
const initApp = createElectronApp;
|
|
273
|
-
|
|
274
306
|
//#endregion
|
|
275
307
|
exports.Updater = Updater;
|
|
276
308
|
exports.UpdaterError = UpdaterError;
|
|
277
309
|
exports.autoUpdate = autoUpdate;
|
|
278
310
|
exports.createElectronApp = createElectronApp;
|
|
279
311
|
exports.initApp = initApp;
|
|
280
|
-
exports.startupWithUpdater = startupWithUpdater;
|
|
312
|
+
exports.startupWithUpdater = startupWithUpdater;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as Promisable, n as IProvider, o as UpdateInfo, t as DownloadingInfo } from "./types-q78spjKB.cjs";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
|
|
4
4
|
//#region src/entry/types.d.ts
|
|
@@ -34,6 +34,13 @@ interface UpdaterOption {
|
|
|
34
34
|
* Updater logger
|
|
35
35
|
*/
|
|
36
36
|
logger?: Logger;
|
|
37
|
+
/**
|
|
38
|
+
* Override current app version source.
|
|
39
|
+
*
|
|
40
|
+
* This is mainly used by dev tooling where the installed asar version differs
|
|
41
|
+
* from Electron's package version.
|
|
42
|
+
*/
|
|
43
|
+
getAppVersion?: () => string;
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
39
46
|
* Update info with current app version and entry version
|
|
@@ -60,6 +67,7 @@ declare class Updater<T extends UpdateInfoWithExtraVersion = UpdateInfoWithExtra
|
|
|
60
67
|
}> {
|
|
61
68
|
private CERT;
|
|
62
69
|
private controller;
|
|
70
|
+
private getCurrentAppVersion;
|
|
63
71
|
private info?;
|
|
64
72
|
private tmpFilePath?;
|
|
65
73
|
private processing;
|
|
@@ -107,21 +115,10 @@ declare class Updater<T extends UpdateInfoWithExtraVersion = UpdateInfoWithExtra
|
|
|
107
115
|
*/
|
|
108
116
|
checkForUpdates(): Promise<boolean>;
|
|
109
117
|
/**
|
|
110
|
-
* Check update info using existing update json
|
|
111
|
-
* @param data existing update json
|
|
112
|
-
*/
|
|
113
|
-
checkForUpdates(data: UpdateJSON | UpdateJSONWithURL): Promise<boolean>;
|
|
114
|
-
/**
|
|
115
118
|
* Download update using default options
|
|
116
119
|
*/
|
|
117
120
|
downloadUpdate(): Promise<boolean>;
|
|
118
121
|
/**
|
|
119
|
-
* Download update using existing `asar.gz` buffer and signature
|
|
120
|
-
* @param data existing `asar.gz` buffer
|
|
121
|
-
* @param info update info
|
|
122
|
-
*/
|
|
123
|
-
downloadUpdate(data: Uint8Array, info: Omit<UpdateInfo, "minimumVersion">): Promise<boolean>;
|
|
124
|
-
/**
|
|
125
122
|
* quit App and install
|
|
126
123
|
*/
|
|
127
124
|
quitAndInstall(): void;
|
|
@@ -141,7 +138,7 @@ declare function autoUpdate(updater: Updater): Promise<void>;
|
|
|
141
138
|
* @param logger logger
|
|
142
139
|
* @default install(); logger.info('update success!')
|
|
143
140
|
*/
|
|
144
|
-
type OnInstallFunction = (install:
|
|
141
|
+
type OnInstallFunction = (install: () => void, tempAsarPath: string, appNameAsarPath: string, logger?: Logger) => Promisable<void>;
|
|
145
142
|
interface AppOption {
|
|
146
143
|
/**
|
|
147
144
|
* Path to index file that make {@link startupWithUpdater} as default export
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as Promisable, n as IProvider, o as UpdateInfo, t as DownloadingInfo } from "./types-q78spjKB.mjs";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
|
|
4
4
|
//#region src/entry/types.d.ts
|
|
@@ -34,6 +34,13 @@ interface UpdaterOption {
|
|
|
34
34
|
* Updater logger
|
|
35
35
|
*/
|
|
36
36
|
logger?: Logger;
|
|
37
|
+
/**
|
|
38
|
+
* Override current app version source.
|
|
39
|
+
*
|
|
40
|
+
* This is mainly used by dev tooling where the installed asar version differs
|
|
41
|
+
* from Electron's package version.
|
|
42
|
+
*/
|
|
43
|
+
getAppVersion?: () => string;
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
39
46
|
* Update info with current app version and entry version
|
|
@@ -60,6 +67,7 @@ declare class Updater<T extends UpdateInfoWithExtraVersion = UpdateInfoWithExtra
|
|
|
60
67
|
}> {
|
|
61
68
|
private CERT;
|
|
62
69
|
private controller;
|
|
70
|
+
private getCurrentAppVersion;
|
|
63
71
|
private info?;
|
|
64
72
|
private tmpFilePath?;
|
|
65
73
|
private processing;
|
|
@@ -107,21 +115,10 @@ declare class Updater<T extends UpdateInfoWithExtraVersion = UpdateInfoWithExtra
|
|
|
107
115
|
*/
|
|
108
116
|
checkForUpdates(): Promise<boolean>;
|
|
109
117
|
/**
|
|
110
|
-
* Check update info using existing update json
|
|
111
|
-
* @param data existing update json
|
|
112
|
-
*/
|
|
113
|
-
checkForUpdates(data: UpdateJSON | UpdateJSONWithURL): Promise<boolean>;
|
|
114
|
-
/**
|
|
115
118
|
* Download update using default options
|
|
116
119
|
*/
|
|
117
120
|
downloadUpdate(): Promise<boolean>;
|
|
118
121
|
/**
|
|
119
|
-
* Download update using existing `asar.gz` buffer and signature
|
|
120
|
-
* @param data existing `asar.gz` buffer
|
|
121
|
-
* @param info update info
|
|
122
|
-
*/
|
|
123
|
-
downloadUpdate(data: Uint8Array, info: Omit<UpdateInfo, "minimumVersion">): Promise<boolean>;
|
|
124
|
-
/**
|
|
125
122
|
* quit App and install
|
|
126
123
|
*/
|
|
127
124
|
quitAndInstall(): void;
|
|
@@ -141,7 +138,7 @@ declare function autoUpdate(updater: Updater): Promise<void>;
|
|
|
141
138
|
* @param logger logger
|
|
142
139
|
* @default install(); logger.info('update success!')
|
|
143
140
|
*/
|
|
144
|
-
type OnInstallFunction = (install:
|
|
141
|
+
type OnInstallFunction = (install: () => void, tempAsarPath: string, appNameAsarPath: string, logger?: Logger) => Promisable<void>;
|
|
145
142
|
interface AppOption {
|
|
146
143
|
/**
|
|
147
144
|
* Path to index file that make {@link startupWithUpdater} as default export
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { u as isUpdateJSON } from "./crypto-DZzMmoz2.mjs";
|
|
2
|
+
import { t as LocalDevProvider } from "./local-C5jw-7o5.mjs";
|
|
3
|
+
import { a as getPathFromAppNameAsar, f as isDev, i as getEntryVersion, r as getAppVersion, y as restartApp } from "./electron-BrIF1urZ.mjs";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { BrowserWindow, app } from "electron";
|
|
6
7
|
import { EventEmitter } from "node:events";
|
|
7
|
-
|
|
8
8
|
//#region src/entry/types.ts
|
|
9
9
|
var UpdaterError = class extends Error {
|
|
10
10
|
code;
|
|
@@ -13,12 +13,12 @@ var UpdaterError = class extends Error {
|
|
|
13
13
|
this.code = code;
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
|
-
|
|
17
16
|
//#endregion
|
|
18
17
|
//#region src/entry/updater.ts
|
|
19
18
|
var Updater = class extends EventEmitter {
|
|
20
19
|
CERT;
|
|
21
20
|
controller;
|
|
21
|
+
getCurrentAppVersion;
|
|
22
22
|
info;
|
|
23
23
|
tmpFilePath;
|
|
24
24
|
processing = false;
|
|
@@ -45,6 +45,7 @@ var Updater = class extends EventEmitter {
|
|
|
45
45
|
this.receiveBeta = options.receiveBeta;
|
|
46
46
|
this.CERT = options.SIGNATURE_CERT || __EIU_SIGNATURE_CERT__;
|
|
47
47
|
this.logger = options.logger;
|
|
48
|
+
this.getCurrentAppVersion = options.getAppVersion ?? getAppVersion;
|
|
48
49
|
this.controller = new AbortController();
|
|
49
50
|
if (isDev && !this.logger) {
|
|
50
51
|
this.logger = {
|
|
@@ -55,7 +56,6 @@ var Updater = class extends EventEmitter {
|
|
|
55
56
|
};
|
|
56
57
|
this.logger.info("No logger set, enable dev-only logger");
|
|
57
58
|
}
|
|
58
|
-
if (!this.provider) this.logger?.debug("WARN: No update provider");
|
|
59
59
|
}
|
|
60
60
|
async fetch(format, data) {
|
|
61
61
|
if (typeof data === "object") if (format === "json" && isUpdateJSON(data) || format === "buffer" && Buffer.isBuffer(data)) return data;
|
|
@@ -88,9 +88,12 @@ var Updater = class extends EventEmitter {
|
|
|
88
88
|
const err = new UpdaterError(code, errorInfo);
|
|
89
89
|
this.logger?.error(`[${code}] ${msg}`, err);
|
|
90
90
|
this.cleanup();
|
|
91
|
-
this.emit("error", err);
|
|
91
|
+
if (this.listenerCount("error") > 0) this.emit("error", err);
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Check update info using default options
|
|
95
|
+
*/
|
|
96
|
+
async checkForUpdates() {
|
|
94
97
|
const emitUnavailable = (msg, code, info) => {
|
|
95
98
|
this.logger?.info(`[${code}] ${msg}`);
|
|
96
99
|
this.logger?.debug("Check update end");
|
|
@@ -98,18 +101,18 @@ var Updater = class extends EventEmitter {
|
|
|
98
101
|
this.emit("update-not-available", code, msg, info);
|
|
99
102
|
return false;
|
|
100
103
|
};
|
|
104
|
+
if (!this.provider) {
|
|
105
|
+
const msg = "No update json or provider";
|
|
106
|
+
this.err("Check update failed", "ERR_PARAM", msg);
|
|
107
|
+
return emitUnavailable(msg, "UNAVAILABLE_ERROR");
|
|
108
|
+
}
|
|
101
109
|
if (this.processing) {
|
|
102
110
|
this.logger?.info("Updater is already processing, skip check update");
|
|
103
111
|
return false;
|
|
104
112
|
}
|
|
105
113
|
this.processing = true;
|
|
106
114
|
this.logger?.debug("Check update start");
|
|
107
|
-
|
|
108
|
-
const msg = "No update json or provider";
|
|
109
|
-
this.err("Check update failed", "ERR_PARAM", msg);
|
|
110
|
-
return emitUnavailable(msg, "UNAVAILABLE_ERROR");
|
|
111
|
-
}
|
|
112
|
-
const _data = await this.fetch("json", data);
|
|
115
|
+
const _data = await this.fetch("json");
|
|
113
116
|
if (!_data) return emitUnavailable("Failed to get update info", "UNAVAILABLE_ERROR");
|
|
114
117
|
const { signature, version, minimumVersion, url, ...rest } = this.receiveBeta ? _data.beta : _data;
|
|
115
118
|
const info = {
|
|
@@ -122,12 +125,12 @@ var Updater = class extends EventEmitter {
|
|
|
122
125
|
signature,
|
|
123
126
|
minimumVersion,
|
|
124
127
|
version,
|
|
125
|
-
appVersion:
|
|
128
|
+
appVersion: this.getCurrentAppVersion(),
|
|
126
129
|
entryVersion: getEntryVersion(),
|
|
127
130
|
...rest
|
|
128
131
|
};
|
|
129
132
|
this.logger?.debug(`Checked update, version: ${version}, signature: ${signature}`);
|
|
130
|
-
if (isDev && !this.forceUpdate
|
|
133
|
+
if (isDev && !this.forceUpdate) return emitUnavailable("Skip check update in dev mode. To force update, set `updater.forceUpdate` to `true`", "UNAVAILABLE_DEV");
|
|
131
134
|
const isLowerVersion = this.provider.isLowerVersion;
|
|
132
135
|
try {
|
|
133
136
|
if (isLowerVersion(extraVersionInfo.entryVersion, minimumVersion)) return emitUnavailable(`Entry Version (${extraVersionInfo.entryVersion}) < MinimumVersion (${minimumVersion})`, "UNAVAILABLE_VERSION", extraVersionInfo);
|
|
@@ -145,32 +148,39 @@ var Updater = class extends EventEmitter {
|
|
|
145
148
|
return emitUnavailable(msg, "UNAVAILABLE_ERROR", extraVersionInfo);
|
|
146
149
|
}
|
|
147
150
|
}
|
|
148
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Download update using default options
|
|
153
|
+
*/
|
|
154
|
+
async downloadUpdate() {
|
|
149
155
|
const emitError = (code, errorInfo) => {
|
|
150
156
|
this.err(`Download update failed`, code, errorInfo);
|
|
151
157
|
this.logger?.debug("Download update end");
|
|
152
158
|
this.processing = false;
|
|
153
159
|
return false;
|
|
154
160
|
};
|
|
161
|
+
if (!this.provider) return emitError("ERR_PARAM", "No update asar buffer and provider");
|
|
155
162
|
if (this.processing) {
|
|
156
163
|
this.logger?.info("Updater is already processing, skip download update");
|
|
157
164
|
return false;
|
|
158
165
|
}
|
|
159
166
|
this.processing = true;
|
|
160
167
|
this.logger?.debug("Download update start");
|
|
161
|
-
const _sig =
|
|
162
|
-
const _version =
|
|
163
|
-
if (!_sig || !_version) return emitError("ERR_PARAM", "No update signature, please call `checkUpdate` first
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
168
|
+
const _sig = this.info?.signature;
|
|
169
|
+
const _version = this.info?.version;
|
|
170
|
+
if (!_sig || !_version) return emitError("ERR_PARAM", "No update signature, please call `checkUpdate` first");
|
|
171
|
+
const buffer = await this.fetch("buffer");
|
|
172
|
+
if (!buffer) {
|
|
173
|
+
this.logger?.debug("Download update end");
|
|
174
|
+
this.processing = false;
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
167
177
|
this.logger?.debug("Validation start");
|
|
168
|
-
if (!await this.provider.
|
|
178
|
+
if (!await this.provider.verifySignature(buffer, _version, _sig, this.CERT)) return emitError("ERR_VALIDATE", "Invalid update asar file");
|
|
169
179
|
this.logger?.debug("Validation end");
|
|
170
180
|
try {
|
|
171
181
|
this.tmpFilePath = `${getPathFromAppNameAsar()}.tmp`;
|
|
172
182
|
this.logger?.debug(`Install to ${this.tmpFilePath}`);
|
|
173
|
-
fs.writeFileSync(this.tmpFilePath, await this.provider.
|
|
183
|
+
fs.writeFileSync(this.tmpFilePath, await this.provider.decompressFile(buffer));
|
|
174
184
|
this.logger?.info(`Download success, version: ${_version}`);
|
|
175
185
|
this.info = void 0;
|
|
176
186
|
this.emit("update-downloaded");
|
|
@@ -204,7 +214,6 @@ var Updater = class extends EventEmitter {
|
|
|
204
214
|
async function autoUpdate(updater) {
|
|
205
215
|
if (await updater.checkForUpdates() && await updater.downloadUpdate()) updater.quitAndInstall();
|
|
206
216
|
}
|
|
207
|
-
|
|
208
217
|
//#endregion
|
|
209
218
|
//#region src/entry/core.ts
|
|
210
219
|
/**
|
|
@@ -229,6 +238,25 @@ const defaultOnInstall = (install, _, __, logger) => {
|
|
|
229
238
|
install();
|
|
230
239
|
logger?.info(`update success!`);
|
|
231
240
|
};
|
|
241
|
+
function readDevAsarVersion() {
|
|
242
|
+
try {
|
|
243
|
+
return fs.readFileSync(getPathFromAppNameAsar("version"), "utf-8").trim();
|
|
244
|
+
} catch {
|
|
245
|
+
return app.getVersion();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function resolveUpdaterOption(updater) {
|
|
249
|
+
if (!isDev || !__EIU_LOCAL_DEV_UPDATE__ || updater?.provider) return updater;
|
|
250
|
+
return {
|
|
251
|
+
...updater,
|
|
252
|
+
provider: new LocalDevProvider({
|
|
253
|
+
baseDir: __EIU_LOCAL_DEV_UPDATE_DIR__,
|
|
254
|
+
chunkDelay: __EIU_LOCAL_DEV_UPDATE_CHUNK_DELAY__,
|
|
255
|
+
chunkSize: __EIU_LOCAL_DEV_UPDATE_CHUNK_SIZE__
|
|
256
|
+
}),
|
|
257
|
+
getAppVersion: updater?.getAppVersion ?? readDevAsarVersion
|
|
258
|
+
};
|
|
259
|
+
}
|
|
232
260
|
/**
|
|
233
261
|
* Initialize Electron with updater
|
|
234
262
|
* @example
|
|
@@ -247,7 +275,9 @@ const defaultOnInstall = (install, _, __, logger) => {
|
|
|
247
275
|
async function createElectronApp(appOptions = {}) {
|
|
248
276
|
const appNameAsarPath = getPathFromAppNameAsar();
|
|
249
277
|
const { mainPath = isDev ? path.join(app.getAppPath(), __EIU_ELECTRON_DIST_PATH__, "main", __EIU_MAIN_FILE__) : path.join(path.dirname(app.getAppPath()), __EIU_ASAR_BASE_NAME__, "main", __EIU_MAIN_FILE__), updater, onInstall = defaultOnInstall, beforeStart, onStartError } = appOptions;
|
|
250
|
-
const
|
|
278
|
+
const useAutoLocalDevProvider = isDev && __EIU_LOCAL_DEV_UPDATE__ && typeof updater !== "function";
|
|
279
|
+
const updaterInstance = typeof updater === "object" || !updater ? new Updater(resolveUpdaterOption(updater)) : await updater();
|
|
280
|
+
if (useAutoLocalDevProvider && updaterInstance.provider?.name === "LocalDevProvider") updaterInstance.forceUpdate = true;
|
|
251
281
|
const logger = updaterInstance.logger;
|
|
252
282
|
try {
|
|
253
283
|
const tempAsarPath = `${appNameAsarPath}.tmp`;
|
|
@@ -256,8 +286,10 @@ async function createElectronApp(appOptions = {}) {
|
|
|
256
286
|
await onInstall(() => fs.renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
|
|
257
287
|
}
|
|
258
288
|
await beforeStart?.(mainPath, logger);
|
|
259
|
-
if (__EIU_IS_ESM__)
|
|
260
|
-
|
|
289
|
+
if (__EIU_IS_ESM__) {
|
|
290
|
+
const { pathToFileURL } = await import("node:url");
|
|
291
|
+
runWithDefaultExport(await import(pathToFileURL(mainPath).href), updaterInstance);
|
|
292
|
+
} else runWithDefaultExport(require(mainPath), updaterInstance);
|
|
261
293
|
} catch (error) {
|
|
262
294
|
logger?.error("Fail to startup", error);
|
|
263
295
|
onStartError?.(error, logger);
|
|
@@ -268,6 +300,5 @@ async function createElectronApp(appOptions = {}) {
|
|
|
268
300
|
* @deprecated Use {@link createElectronApp} instead
|
|
269
301
|
*/
|
|
270
302
|
const initApp = createElectronApp;
|
|
271
|
-
|
|
272
303
|
//#endregion
|
|
273
|
-
export { Updater, UpdaterError, autoUpdate, createElectronApp, initApp, startupWithUpdater };
|
|
304
|
+
export { Updater, UpdaterError, autoUpdate, createElectronApp, initApp, startupWithUpdater };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { c as defaultIsLowerVersion, i as defaultVerifySignature, s as defaultDecompressFile, u as isUpdateJSON } from "./crypto-DZzMmoz2.mjs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
//#region src/provider/base.ts
|
|
5
|
+
var BaseProvider = class {
|
|
6
|
+
name = "BaseProvider";
|
|
7
|
+
/**
|
|
8
|
+
* @inheritdoc
|
|
9
|
+
*/
|
|
10
|
+
isLowerVersion = defaultIsLowerVersion;
|
|
11
|
+
/**
|
|
12
|
+
* @inheritdoc
|
|
13
|
+
*/
|
|
14
|
+
verifySignature = defaultVerifySignature;
|
|
15
|
+
/**
|
|
16
|
+
* @inheritdoc
|
|
17
|
+
*/
|
|
18
|
+
decompressFile = defaultDecompressFile;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/provider/local.ts
|
|
22
|
+
/**
|
|
23
|
+
* Update Provider for local development
|
|
24
|
+
* - download update json from `{baseDir}/{versionPath}`
|
|
25
|
+
* - download update asar from `{baseDir}/{name}-{version}.asar.br`
|
|
26
|
+
*
|
|
27
|
+
* This provider is useful for testing updates during development without
|
|
28
|
+
* needing to deploy to a remote server.
|
|
29
|
+
* @param options provider options
|
|
30
|
+
*/
|
|
31
|
+
var LocalDevProvider = class extends BaseProvider {
|
|
32
|
+
name = "LocalDevProvider";
|
|
33
|
+
verifySignature;
|
|
34
|
+
options;
|
|
35
|
+
constructor(options) {
|
|
36
|
+
super();
|
|
37
|
+
const resolvedOptions = {
|
|
38
|
+
chunkSize: 64 * 1024,
|
|
39
|
+
chunkDelay: 30,
|
|
40
|
+
...options
|
|
41
|
+
};
|
|
42
|
+
if (resolvedOptions.chunkSize <= 0) throw new Error("localDevUpdate.chunkSize must be greater than 0");
|
|
43
|
+
if (resolvedOptions.chunkDelay < 0) throw new Error("localDevUpdate.chunkDelay must be greater than or equal to 0");
|
|
44
|
+
this.options = resolvedOptions;
|
|
45
|
+
this.verifySignature = async function verifySignature() {
|
|
46
|
+
return true;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @inheritdoc
|
|
51
|
+
*/
|
|
52
|
+
async downloadJSON(name, versionPath, signal) {
|
|
53
|
+
signal.throwIfAborted();
|
|
54
|
+
const { beta, version, ...info } = await this.readJSON(versionPath);
|
|
55
|
+
const getURL = (ver) => path.join(this.options.baseDir, `${name}-${ver}.asar.br`);
|
|
56
|
+
return {
|
|
57
|
+
...info,
|
|
58
|
+
version,
|
|
59
|
+
url: getURL(version),
|
|
60
|
+
beta: {
|
|
61
|
+
...beta,
|
|
62
|
+
url: getURL(beta.version)
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* @inheritdoc
|
|
68
|
+
*/
|
|
69
|
+
async downloadAsar(info, signal, onDownloading) {
|
|
70
|
+
signal.throwIfAborted();
|
|
71
|
+
const fileBuffer = await fs.readFile(info.url);
|
|
72
|
+
await this.emitProgress(fileBuffer, signal, onDownloading);
|
|
73
|
+
return fileBuffer;
|
|
74
|
+
}
|
|
75
|
+
async readJSON(versionPath) {
|
|
76
|
+
const fullPath = path.join(this.options.baseDir, versionPath);
|
|
77
|
+
const content = await fs.readFile(fullPath, "utf-8");
|
|
78
|
+
const json = JSON.parse(content);
|
|
79
|
+
if (!isUpdateJSON(json)) throw new Error(`Invalid update json: ${content}`);
|
|
80
|
+
return json;
|
|
81
|
+
}
|
|
82
|
+
async emitProgress(fileBuffer, signal, onDownloading) {
|
|
83
|
+
if (!onDownloading) return;
|
|
84
|
+
const total = fileBuffer.length;
|
|
85
|
+
let transferred = 0;
|
|
86
|
+
let lastTime = Date.now();
|
|
87
|
+
while (transferred < total) {
|
|
88
|
+
signal.throwIfAborted();
|
|
89
|
+
const currentTime = Date.now();
|
|
90
|
+
const delta = Math.min(this.options.chunkSize, total - transferred);
|
|
91
|
+
transferred += delta;
|
|
92
|
+
onDownloading({
|
|
93
|
+
delta,
|
|
94
|
+
percent: Math.round(transferred / total * 100),
|
|
95
|
+
total,
|
|
96
|
+
transferred,
|
|
97
|
+
bps: Math.round(delta / Math.max(currentTime - lastTime, 1) * 1e3)
|
|
98
|
+
});
|
|
99
|
+
lastTime = currentTime;
|
|
100
|
+
if (transferred < total && this.options.chunkDelay > 0) await new Promise((resolve) => setTimeout(resolve, this.options.chunkDelay));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
export { BaseProvider as n, LocalDevProvider as t };
|