electron-incremental-update 2.4.3 → 3.0.0-beta.3

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.
Files changed (47) hide show
  1. package/README.md +48 -40
  2. package/dist/download-BN4uMS4_.d.mts +39 -0
  3. package/dist/download-DO7iuxEJ.d.cts +39 -0
  4. package/dist/electron-DH-Uyikp.cjs +321 -0
  5. package/dist/electron-OKQIYbcw.mjs +181 -0
  6. package/dist/index.cjs +261 -331
  7. package/dist/index.d.cts +179 -169
  8. package/dist/index.d.mts +204 -0
  9. package/dist/index.mjs +273 -0
  10. package/dist/provider.cjs +142 -330
  11. package/dist/provider.d.cts +113 -114
  12. package/dist/provider.d.mts +133 -0
  13. package/dist/provider.mjs +152 -0
  14. package/dist/types-BM9Jfu7q.d.cts +154 -0
  15. package/dist/types-DASqEPXE.d.mts +154 -0
  16. package/dist/utils.cjs +43 -381
  17. package/dist/utils.d.cts +120 -85
  18. package/dist/utils.d.mts +164 -0
  19. package/dist/utils.mjs +5 -0
  20. package/dist/version--eVB2A7n.mjs +72 -0
  21. package/dist/version-aPrLuz_-.cjs +129 -0
  22. package/dist/vite.d.mts +521 -0
  23. package/dist/vite.mjs +1094 -0
  24. package/dist/zip-BCC7FAQ_.cjs +264 -0
  25. package/dist/zip-Dwm7s1C9.mjs +185 -0
  26. package/package.json +66 -64
  27. package/dist/chunk-AAAM44NW.js +0 -70
  28. package/dist/chunk-IVHNGRZY.js +0 -122
  29. package/dist/chunk-PD4EV4MM.js +0 -147
  30. package/dist/index.d.ts +0 -194
  31. package/dist/index.js +0 -309
  32. package/dist/provider.d.ts +0 -134
  33. package/dist/provider.js +0 -152
  34. package/dist/types-CU7GyVez.d.cts +0 -151
  35. package/dist/types-CU7GyVez.d.ts +0 -151
  36. package/dist/utils.d.ts +0 -129
  37. package/dist/utils.js +0 -3
  38. package/dist/vite.d.ts +0 -533
  39. package/dist/vite.js +0 -945
  40. package/dist/zip-Blmn2vzE.d.cts +0 -71
  41. package/dist/zip-CnSv_Njj.d.ts +0 -71
  42. package/provider.d.ts +0 -1
  43. package/provider.js +0 -1
  44. package/utils.d.ts +0 -1
  45. package/utils.js +0 -1
  46. package/vite.d.ts +0 -1
  47. package/vite.js +0 -1
package/dist/index.mjs ADDED
@@ -0,0 +1,273 @@
1
+ import { a as getPathFromAppNameAsar, f as isDev, i as getEntryVersion, r as getAppVersion, y as restartApp } from "./electron-OKQIYbcw.mjs";
2
+ import { r as isUpdateJSON } from "./version--eVB2A7n.mjs";
3
+ import { BrowserWindow, app } from "electron";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { EventEmitter } from "node:events";
7
+
8
+ //#region src/entry/types.ts
9
+ var UpdaterError = class extends Error {
10
+ code;
11
+ constructor(code, info) {
12
+ super(`[${code}] ${info}`);
13
+ this.code = code;
14
+ }
15
+ };
16
+
17
+ //#endregion
18
+ //#region src/entry/updater.ts
19
+ var Updater = class extends EventEmitter {
20
+ CERT;
21
+ controller;
22
+ info;
23
+ tmpFilePath;
24
+ processing = false;
25
+ provider;
26
+ /**
27
+ * Updater logger
28
+ */
29
+ logger;
30
+ /**
31
+ * Whether to receive beta update
32
+ */
33
+ receiveBeta;
34
+ /**
35
+ * Whether force update in DEV
36
+ */
37
+ forceUpdate;
38
+ /**
39
+ * Initialize incremental updater
40
+ * @param options UpdaterOption
41
+ */
42
+ constructor(options = {}) {
43
+ super();
44
+ this.provider = options.provider;
45
+ this.receiveBeta = options.receiveBeta;
46
+ this.CERT = options.SIGNATURE_CERT || __EIU_SIGNATURE_CERT__;
47
+ this.logger = options.logger;
48
+ this.controller = new AbortController();
49
+ if (isDev && !this.logger) {
50
+ this.logger = {
51
+ info: (...args) => console.log("[EIU-INFO ]", ...args),
52
+ debug: (...args) => console.log("[EIU-DEBUG]", ...args),
53
+ warn: (...args) => console.log("[EIU-WARN ]", ...args),
54
+ error: (...args) => console.error("[EIU-ERROR]", ...args)
55
+ };
56
+ this.logger.info("No logger set, enable dev-only logger");
57
+ }
58
+ if (!this.provider) this.logger?.debug("WARN: No update provider");
59
+ }
60
+ async fetch(format, data) {
61
+ if (typeof data === "object") if (format === "json" && isUpdateJSON(data) || format === "buffer" && Buffer.isBuffer(data)) return data;
62
+ else {
63
+ this.err("Invalid type", "ERR_PARAM", `Invalid type at format '${format}': ${JSON.stringify(data)}`);
64
+ return;
65
+ }
66
+ this.logger?.debug(`Download from \`${this.provider.name}\``);
67
+ try {
68
+ const result = format === "json" ? await this.provider.downloadJSON(app.name, __EIU_VERSION_PATH__, this.controller.signal) : await this.provider.downloadAsar(this.info, this.controller.signal, (info) => this.emit("download-progress", info));
69
+ this.logger?.debug(`Download ${format} success${format === "buffer" ? `, file size: ${result.length}` : ""}`);
70
+ return result;
71
+ } catch (e) {
72
+ this.err(`Fetch ${format} failed`, "ERR_NETWORK", e instanceof Error ? e.message : e.toString());
73
+ }
74
+ }
75
+ cleanup() {
76
+ if (this.tmpFilePath && fs.existsSync(this.tmpFilePath)) try {
77
+ fs.unlinkSync(this.tmpFilePath);
78
+ this.tmpFilePath = void 0;
79
+ this.logger?.debug("Cleaned up temporary update file");
80
+ } catch (error) {
81
+ this.logger?.warn(`Failed to clean up temporary update file: ${error}`);
82
+ }
83
+ }
84
+ /**
85
+ * Handle error message and emit error event
86
+ */
87
+ err(msg, code, errorInfo) {
88
+ const err = new UpdaterError(code, errorInfo);
89
+ this.logger?.error(`[${code}] ${msg}`, err);
90
+ this.cleanup();
91
+ this.emit("error", err);
92
+ }
93
+ async checkForUpdates(data) {
94
+ const emitUnavailable = (msg, code, info) => {
95
+ this.logger?.info(`[${code}] ${msg}`);
96
+ this.logger?.debug("Check update end");
97
+ this.processing = false;
98
+ this.emit("update-not-available", code, msg, info);
99
+ return false;
100
+ };
101
+ if (this.processing) {
102
+ this.logger?.info("Updater is already processing, skip check update");
103
+ return false;
104
+ }
105
+ this.processing = true;
106
+ this.logger?.debug("Check update start");
107
+ if (!data && !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
+ }
112
+ const _data = await this.fetch("json", data);
113
+ if (!_data) return emitUnavailable("Failed to get update info", "UNAVAILABLE_ERROR");
114
+ const { signature, version, minimumVersion, url, ...rest } = this.receiveBeta ? _data.beta : _data;
115
+ const info = {
116
+ signature,
117
+ minimumVersion,
118
+ version,
119
+ url
120
+ };
121
+ const extraVersionInfo = {
122
+ signature,
123
+ minimumVersion,
124
+ version,
125
+ appVersion: getAppVersion(),
126
+ entryVersion: getEntryVersion(),
127
+ ...rest
128
+ };
129
+ this.logger?.debug(`Checked update, version: ${version}, signature: ${signature}`);
130
+ if (isDev && !this.forceUpdate && !data) return emitUnavailable("Skip check update in dev mode. To force update, set `updater.forceUpdate` to true or call checkUpdate with UpdateJSON", "UNAVAILABLE_DEV");
131
+ const isLowerVersion = this.provider.isLowerVersion;
132
+ try {
133
+ if (isLowerVersion(extraVersionInfo.entryVersion, minimumVersion)) return emitUnavailable(`Entry Version (${extraVersionInfo.entryVersion}) < MinimumVersion (${minimumVersion})`, "UNAVAILABLE_VERSION", extraVersionInfo);
134
+ this.logger?.info(`Current version is ${extraVersionInfo.appVersion}, new version is ${version}`);
135
+ if (!isLowerVersion(extraVersionInfo.appVersion, version)) return emitUnavailable(`Current version (${extraVersionInfo.appVersion}) > New version (${version})`, "UNAVAILABLE_VERSION", extraVersionInfo);
136
+ this.logger?.info(`Update available: ${version}`);
137
+ this.info = info;
138
+ this.processing = false;
139
+ this.logger?.debug("Check update end");
140
+ this.emit("update-available", extraVersionInfo);
141
+ return true;
142
+ } catch {
143
+ const msg = "Fail to parse version string";
144
+ this.err("Check update failed", "ERR_VALIDATE", msg);
145
+ return emitUnavailable(msg, "UNAVAILABLE_ERROR", extraVersionInfo);
146
+ }
147
+ }
148
+ async downloadUpdate(data, info) {
149
+ const emitError = (code, errorInfo) => {
150
+ this.err(`Download update failed`, code, errorInfo);
151
+ this.logger?.debug("Download update end");
152
+ this.processing = false;
153
+ return false;
154
+ };
155
+ if (this.processing) {
156
+ this.logger?.info("Updater is already processing, skip download update");
157
+ return false;
158
+ }
159
+ this.processing = true;
160
+ this.logger?.debug("Download update start");
161
+ const _sig = info?.signature ?? this.info?.signature;
162
+ const _version = info?.version ?? this.info?.version;
163
+ if (!_sig || !_version) return emitError("ERR_PARAM", "No update signature, please call `checkUpdate` first or manually setup params");
164
+ if (!data && !this.provider) return emitError("ERR_PARAM", "No update asar buffer and provider");
165
+ const buffer = await this.fetch("buffer", data ? Buffer.from(data) : void 0);
166
+ if (!buffer) return emitError("ERR_PARAM", "No update asar file buffer");
167
+ this.logger?.debug("Validation start");
168
+ if (!await this.provider.verifySignaure(buffer, _version, _sig, this.CERT)) return emitError("ERR_VALIDATE", "Invalid update asar file");
169
+ this.logger?.debug("Validation end");
170
+ try {
171
+ this.tmpFilePath = `${getPathFromAppNameAsar()}.tmp`;
172
+ this.logger?.debug(`Install to ${this.tmpFilePath}`);
173
+ fs.writeFileSync(this.tmpFilePath, await this.provider.unzipFile(buffer));
174
+ this.logger?.info(`Download success, version: ${_version}`);
175
+ this.info = void 0;
176
+ this.emit("update-downloaded");
177
+ this.processing = false;
178
+ this.logger?.debug("Download update end");
179
+ return true;
180
+ } catch (error) {
181
+ this.cleanup();
182
+ return emitError("ERR_DOWNLOAD", `Failed to write update file: ${error instanceof Error ? error.message : error}`);
183
+ }
184
+ }
185
+ /**
186
+ * quit App and install
187
+ */
188
+ quitAndInstall() {
189
+ this.logger?.info("Quit and install");
190
+ restartApp();
191
+ }
192
+ cancel() {
193
+ if (this.controller.signal.aborted) return;
194
+ this.controller.abort();
195
+ this.cleanup();
196
+ this.logger?.info("Cancel update");
197
+ this.emit("update-cancelled");
198
+ this.controller = new AbortController();
199
+ }
200
+ };
201
+ /**
202
+ * Auto check update, download and install
203
+ */
204
+ async function autoUpdate(updater) {
205
+ if (await updater.checkForUpdates() && await updater.downloadUpdate()) updater.quitAndInstall();
206
+ }
207
+
208
+ //#endregion
209
+ //#region src/entry/core.ts
210
+ /**
211
+ * Utils to startup with updater
212
+ * @param fn startup function
213
+ * @example
214
+ * // in electron/main/index.ts
215
+ * export default startupWithUpdater((updater) => {
216
+ * updater.checkUpdate()
217
+ * })
218
+ */
219
+ function startupWithUpdater(fn) {
220
+ if (isDev) process.on("message", (msg) => {
221
+ if (msg === "electron-vite&type=hot-reload") for (const window of BrowserWindow.getAllWindows()) window.reload();
222
+ });
223
+ return fn;
224
+ }
225
+ function runWithDefaultExport(mod, args) {
226
+ return (mod.default || mod)(args);
227
+ }
228
+ const defaultOnInstall = (install, _, __, logger) => {
229
+ install();
230
+ logger?.info(`update success!`);
231
+ };
232
+ /**
233
+ * Initialize Electron with updater
234
+ * @example
235
+ * createElectronApp({
236
+ * updater: {
237
+ * provider: new GitHubProvider({
238
+ * username: 'yourname',
239
+ * repo: 'electron',
240
+ * }),
241
+ * },
242
+ * beforeStart(mainFilePath, logger) {
243
+ * logger?.debug(mainFilePath)
244
+ * },
245
+ * })
246
+ */
247
+ async function createElectronApp(appOptions = {}) {
248
+ const appNameAsarPath = getPathFromAppNameAsar();
249
+ 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 updaterInstance = typeof updater === "object" || !updater ? new Updater(updater) : await updater();
251
+ const logger = updaterInstance.logger;
252
+ try {
253
+ const tempAsarPath = `${appNameAsarPath}.tmp`;
254
+ if (fs.existsSync(tempAsarPath)) {
255
+ logger?.info(`Installing new asar from ${tempAsarPath}`);
256
+ await onInstall(() => fs.renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
257
+ }
258
+ await beforeStart?.(mainPath, logger);
259
+ if (__EIU_IS_ESM__) runWithDefaultExport(await import(`file://${mainPath}`), updaterInstance);
260
+ else runWithDefaultExport(require(mainPath), updaterInstance);
261
+ } catch (error) {
262
+ logger?.error("Fail to startup", error);
263
+ onStartError?.(error, logger);
264
+ app.quit();
265
+ }
266
+ }
267
+ /**
268
+ * @deprecated Use {@link createElectronApp} instead
269
+ */
270
+ const initApp = createElectronApp;
271
+
272
+ //#endregion
273
+ export { Updater, UpdaterError, autoUpdate, createElectronApp, initApp, startupWithUpdater };